LangChain を触っている。学習途中ではあるが、簡単にメモ。
概要
- 講義元では「gpt-3.5-turbo」を使っているが、それ以外のモデルでも使うことは可能
- 但し記述を少し変えなくてはならない
- 例えばhuggingfaceのモデルではhuggingface 用のライブラリを用いる
-
from langchain.llms import HuggingFacePipelinefrom transformers import AutoModelForCausalLM, AutoTokenizer, pipelineimport torch
# GPUの確認device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model_id = "google/gemma-7b-it"tokenizer = AutoTokenizer.from_pretrained(model_id)model = AutoModelForCausalLM.from_pretrained(model_id).to(device)pipe = pipeline("text-generation",model = model,tokenizer = tokenizer,max_new_tokens = 512,)llm = HuggingFacePipeline(pipeline=pipe)
- プロンプトのテンプレートを作っておき、ユーザーの入力部分を変数にしておく
-
template = '''<bos><start_of_turn>user次のコマンドの概要を説明してください。コマンド:{command}<end_of_turn><start_of_turn>model'''
commandがそれにあたる。
-
- 最新のバージョンでは、「LCEL」(LangChain Expression Language) という記述でプロンプトとモデルを結びつける。
-
qa_chain = ({'command': RunnablePassthrough()}| PromptTemplate.from_template(template)| llm| StrOutputParser())
- 1行目:入力部分 (commandにユーザーが入力したテキストが代入される)
- 2行目:テンプレート (先程作ったもの)
- 3行目:モデル (llm = HuggingFacePipeline(pipeline=pipe))
- 4行目:恐らく出力
-
- .invoke()で入力
- プロンプトを繋げたい場合は、以下のように記述する。
-
cot_summarize_chain = ({'question': RunnablePassthrough()}| PromptTemplate.from_template(cot_template)| llm| {'input': StrOutputParser()} # 1つ目のプロンプトの出力を代入| PromptTemplate.from_template(summarize_template)| llm| StrOutputParser()) - 1つ目のプロンプトの出力 (StrOutputParser() ) を2つ目のプロンプトの入力に入れる。
- このようにしてプロンプトを繋げていくことができる
- 1つ目のプロンプトの出力を、2つ目のプロンプトで要約させる、といった使い方がある
-
- vectorDB を作る際にも、プラットフォームに合わせて関数を変えなくてはならない
- 講義ではOpenAI embedding を使っていた
- 多分、APIを使えるのならばこれが簡単だし知見もたくさんある
- 自分はFAISS (Facebook のembedding)を用いた
-
from langchain.document_loaders import DirectoryLoaderfrom langchain.indexes import VectorstoreIndexCreatorfrom langchain_community.vectorstores.faiss import FAISSfrom langchain.embeddings import HuggingFaceEmbeddingsfrom langchain.text_splitter import RecursiveCharacterTextSplitter
loader = DirectoryLoader("./langchain/docs", glob="**/*.md")docs = loader.load()
# チャンクの分割text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, # チャンクの最大文字数chunk_overlap=10, # オーバーラップの最大文字数)
vectorstore = FAISS.from_documents(docs,embedding=HuggingFaceEmbeddings(model_name='intfloat/multilingual-e5-base'))
- ドキュメントとモデルを結びつけるのも1行で可能
-
qa_chain = ({'context': vectorstore.as_retriever(search_kwargs={'k': 3}), 'question': RunnablePassthrough()}| PromptTemplate.from_template(template)| llm| StrOutputParser())
1行目:vectorstore.as_retrieverを追加
- search_kwargsはよく分かってない (パラメータ用の設定?多分 'k' はtop_k?)
-
- チャットボットのように会話するためには、ConversationChainで良いらしい
-
import langchainfrom langchain.chains import LLMChainfrom langchain.prompts import PromptTemplatefrom langchain.schema.runnable import RunnablePassthroughfrom langchain.schema import StrOutputParserfrom langchain.chains import ConversationChainfrom langchain.memory import ConversationBufferMemory
template = '''<bos><start_of_turn>user以下は、人間とAIが会話している様子です。AIは会話内容を考慮し、人間の質問に対して回答してください。AIは質問に対する答えを知らない場合は「知らない」と答えてください。会話内容:{history}人間: {input}AI:<end_of_turn><start_of_turn>model'''prompt = PromptTemplate(template=template)
conversation = ConversationChain(llm = llm,prompt=prompt, memory=ConversationBufferMemory())
while True:user_message = input("You: ")ai_message = conversation.predict(input=user_message)print(f"AI:{ai_message}")
-
所感
- 講義元がgptモデルを使っていたので、huggingface用に変えるのが大変だったが、分かれば数行で設定できるを実感した
- 所謂RAGの設定も、複雑ではなく、数行のコードを実行すればモデルがドキュメントを基にした回答をしてくれることを確認した
- 個人的にもう少し難しいものだと思っていたから、実際に触って容易だったので、驚いた
- 利用用途も多いので、これは基本的な知識として覚えておきたい
- LangChainは現在もバージョンアップが頻繁に起きているため、記法などが頻繁に変わっているようである
- GPTモデル使えるなら、講義元と同様のバージョンを使うのが無難
- ただLCELはデフォルトスタンダードになっていく可能性があるようで、ここはあえて最近のバージョンをつかって書いて学習するというのもアリだと思う
- 講義の目的は、Webアプリケーションに組み込む、またSlackのチャットボットを作るの2つ
- なので、ここから形にしていくのが楽しみである。
- 分かりやすく説明してくださっているので、やってて楽しい