LLM LangChainへ、これから入門 - end0tknr's kipple - web写経開発
更に上記entryの続き。
本日時点で、LangChain Retrieval の中では VectorstoreIndexCreator が楽な気がします。
参考url
LangChain Retrievalとは?【Document Loaders・Vector Stores・Indexing etc.】
LangChain Retrieval (旧Indexes)とは
- 2023時点で Retrievalというmodule名ですが、以前は Indexes
- CSVやPDF等、LLM外部にある独自dataを用いた回答生成が可能
主要機能 | 内容 |
---|---|
Document Loaders | PDFやCSV等のdataを読込み |
Document transformers | Text Splitters等、読込みdataをLLMが扱う形に変換 |
Text embedding models | textを数値ベクトルに変換 |
Vector stores | ベクトル化されたdataを管理 |
Retrievers | 長いtextを複数documentの塊に分割し検索 |
Indexing | 大量textを効率的検索の為、整理,構造化 |
LangChain Retrieval + OpenAI 使用例
0. pip installと api key設定
!pip install langchain !pip install openai
import os os.environ['OPENAI_API_KEY'] = 'sk-ないしょ'
1. Document Loaders - PDF
!pip install pypdf !pip install tiktoken !pip install faiss-cpu
from langchain.document_loaders import PyPDFLoader from langchain.vectorstores import FAISS from langchain.embeddings.openai import OpenAIEmbeddings pdf_url = 'https://blog.freelance-jp.org/wp-content/uploads/2023/03/FreelanceSurvey2023.pdf' loader = PyPDFLoader(pdf_url) pages = loader.load_and_split() # print(pages[0]) faiss_index = FAISS.from_documents(pages,OpenAIEmbeddings()) prompt = '「フリーランスのリモートワークの実態」について教えて、' docs = faiss_index.similarity_search(prompt,k=2) for doc in docs: print( str(doc.metadata['page']) , ':', doc.page_content )
↑こう書くと、↓以下のように質問文であるpromptに関連するページが表示されます
44 : フリーランスのリモートワーク実態 (1/3) 45(n=850)Q.リモートワークの実施およびその影響に関して、 それぞれ当てはまる選択肢を一つ選んでください。 (単一回答) ※リモートワークとは、情報通信技術 (ICT)を活用した、 場所や時間にとらわれない柔軟な働き方のことを指します。 <略>
2. Text Splitters ( Document transformers )
from langchain.text_splitter import CharacterTextSplitter text_splitter = CharacterTextSplitter( separator = "。", chunk_size = 50, # 分割する際の最大size chunk_overlap = 0, ) long_txt = ''' 吾輩は猫である。名前はまだない。どこで生れたか頓(とん)と見当がつかぬ。 何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。 吾輩はここで始めて人間というものを見た。 しかもあとで聞くとそれは書生という人間中で一番獰悪(どうあく)な種族であったそうだ。 この書生というのは時々我々を捕(つかま)えて煮て食うという話である。 しかしその当時は何という考(かんがえ)もなかったから別段恐しいとも思わなかった。 ''' txts = text_splitter.split_text(long_txt) print(txts) # documentというclassの塊に分割する場合、create_documents() # doc_txts = text_splitter.create_documents([long_txt]) # print(doc_txts)
↑こう書くと、↓こう表示されます。
※ 「separator="。"」の指定で必ず分割される訳でなく、 「chunk_size=50」に近い長さで分割するみたい。
※「Created a chunk of size 51」のwarningの意味は調べていません
WARNING:langchain.text_splitter:Created a chunk of size 51, which is longer than the specified 50 ['吾輩は猫である。名前はまだない。どこで生れたか頓(とん)と見当がつかぬ', '何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している', '吾輩はここで始めて人間というものを見た', 'しかもあとで聞くとそれは書生という人間中で一番獰悪(どうあく)な種族であったそうだ', 'この書生というのは時々我々を捕(つかま)えて煮て食うという話である', 'しかしその当時は何という考(かんがえ)もなかったから別段恐しいとも思わなかった', ]
3. Vector stores
!pip install chromadb
from langchain.embeddings.openai import OpenAIEmbeddings from langchain.text_splitter import CharacterTextSplitter from langchain.vectorstores import Chroma from langchain.indexes import VectorstoreIndexCreator from langchain.document_loaders import TextLoader long_txt = ''' 吾輩は猫である。名前はまだない。どこで生れたか頓(とん)と見当がつかぬ。 何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。 吾輩はここで始めて人間というものを見た。 しかもあとで聞くとそれは書生という人間中で一番獰悪(どうあく)な種族であったそうだ。 この書生というのは時々我々を捕(つかま)えて煮て食うという話である。 しかしその当時は何という考(かんがえ)もなかったから別段恐しいとも思わなかった。 ''' text_splitter = CharacterTextSplitter( separator = "。", chunk_size = 50, chunk_overlap = 0) index = VectorstoreIndexCreator( vectorstore_cls= Chroma, # default Vectorstore class embedding = OpenAIEmbeddings(), # default Embedding class text_splitter = text_splitter # text splitter class ).from_documents( text_splitter.create_documents([long_txt]) ) answer = index.query('吾輩は何ですか?') print(answer)
↑こう書くと、↓こう表示されます。
吾輩は猫です。
先程、「Vector stores=ベクトル化されたdataを管理」と記載しましたが、 VectorstoreIndexCreator がvectorstore_cls等を引数に受け取り、 様々さばいてくれますので、上記のように回答を得ることができます。
4. Retrievers
from langchain.embeddings.openai import OpenAIEmbeddings from langchain.text_splitter import CharacterTextSplitter from langchain.vectorstores import Chroma from langchain.vectorstores import FAISS long_txt = ''' 吾輩は猫である。名前はまだない。どこで生れたか頓(とん)と見当がつかぬ。 何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。 吾輩はここで始めて人間というものを見た。 しかもあとで聞くとそれは書生という人間中で一番獰悪(どうあく)な種族であったそうだ。 この書生というのは時々我々を捕(つかま)えて煮て食うという話である。 しかしその当時は何という考(かんがえ)もなかったから別段恐しいとも思わなかった。 ''' text_splitter = CharacterTextSplitter( separator = "。", chunk_size = 50, chunk_overlap = 0) docs = text_splitter.create_documents([long_txt]) db = FAISS.from_documents(docs,OpenAIEmbeddings()) retriever = db.as_retriever() # retriever objectの作成 # 関連documentを検索 ans_docs = retriever.get_relevant_documents('吾輩は何ですか?') print( ans_docs[0] )
↑こう書くと、↓こう表示されます
page_content='吾輩は猫である。名前はまだない。どこで生れたか頓(とん)と見当がつかぬ'