pip install torch==2.4.0+cu118 --index-url https://download.pytorch.org/whl/cu118 pip install transformers accelerate bitsandbytes sentencepiece gradio pip install pdfminer.six pip install langchain langchain_community langchain_huggingface pip install faiss-cpu
使用したモデル
LLMとしてサイバーエージェントが公開している「CyberAgentLM3-22B-Chat」を使いました。touch-sp.hatenablog.com
Pythonスクリプト
テキストデータをベクトル化して保存
目的のPDFファイルからテキストを抽出して、それを適当に分割してテキストファイルに保存しています。方法はこちらを参照して下さい。
今回は「pdfminer.six」を使いました。
from pathlib import Path from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS from langchain_core.documents import Document embed_model_id = "pkshatech/GLuCoSE-base-ja" embeddings = HuggingFaceEmbeddings(model_name=embed_model_id) text_files = Path("textdata").glob("*.txt") text_data = [] for text_file in text_files: with open(text_file.as_posix(), "r", encoding="utf-8") as f: text_data.append(f.read()) docs = [Document(page_content=x) for x in text_data] db = FAISS.from_documents(docs, embeddings) db.save_local("faiss_index")
チャットボットの実行
import gradio as gr from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer from threading import Thread from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS system_prompt_base = '''あなたは親切なAIアシスタントです。以下の与えらえた文章を参照してユーザーの質問にできるだけ丁寧に日本語で回答して下さい。与えられた文章に記載されていない内容の質問には「わかりません」と回答して下さい。 ``` {context} ```''' model = AutoModelForCausalLM.from_pretrained( "calm3-22b-chat-4bit", device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained("cyberagent/calm3-22b-chat") streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True) embed_model_id = "pkshatech/GLuCoSE-base-ja" embeddings = HuggingFaceEmbeddings(model_name=embed_model_id) db = FAISS.load_local( "faiss_index", embeddings=embeddings, allow_dangerous_deserialization=True ) def call_llm( message: str, history: list[dict], max_tokens: int, temperature: float, top_p: float, ): history_openai_format = [] if len(history) == 0: # langchain part query = message docs = db.similarity_search(query, k=1) context = docs[0].page_content system_prompt = system_prompt_base.format(context=context) init = { "role": "system", "content": system_prompt, } history_openai_format.append(init) history_openai_format.append({"role": "user", "content": message}) else: # langchain part query="" for human, assistant in history: query += f" {human}" query += f" {assistant}" query += f" {message}" docs = db.similarity_search(query, k=1) context = docs[0].page_content system_prompt = system_prompt_base.format(context=context) init = { "role": "system", "content": system_prompt, } history_openai_format.append(init) for human, assistant in history: history_openai_format.append({"role": "user", "content": human}) history_openai_format.append({"role": "assistant", "content": assistant}) history_openai_format.append({"role": "user", "content": message}) input_ids = tokenizer.apply_chat_template( history_openai_format, add_generation_prompt=True, return_tensors="pt" ).to(model.device) generation_kwargs = dict( inputs=input_ids, streamer=streamer, max_new_tokens=max_tokens, temperature=temperature, top_p=top_p ) thread = Thread(target=model.generate, kwargs=generation_kwargs) thread.start() generated_text = "" for new_text in streamer: generated_text += new_text yield generated_text demo = gr.ChatInterface( fn=call_llm, title="calm3-22b-chat-4bit", stop_btn="Stop Generation", cache_examples=False, additional_inputs_accordion=gr.Accordion( label="Parameters", open=False, render=False ), additional_inputs=[ gr.Slider( minimum=1, maximum=4096, step=1, value=1024, label="Max tokens", visible=True, render=False, ), gr.Slider( minimum=0, maximum=1, step=0.1, value=0.3, label="Temperature", visible=True, render=False, ), gr.Slider( minimum=0, maximum=1, step=0.1, value=1.0, label="Top-p", visible=True, render=False, ), ], ) demo.launch(share=False)
補足
続きの記事を書いています。【RAG】ユーザーの質問に対して適切なテキストファイルを選択する工夫 - パソコン関連もろもろ
チャット中のユーザーの質問を拡張する機能を ollama-python と flask で実装しました - パソコン関連もろもろ
【LangChain】【RAG】ハイブリッド検索を見よう見まねで実装してみる - パソコン関連もろもろ