[LLM] ラングチェーンの使用法 [3] (ドキュメントベースの質疑応答)

1. 文書によるQ&A

1. ベクター ストアを作成する

  • CSVLoader は CSV データをロードし、ローダーはモデルと組み合わせて使用​​されます。
  • Dock Array メモリ検索ベクトル ストレージをメモリ ベクトル ストレージとして使用し、外部データベースに接続する必要はありません。
  • ベクター ストアの作成: インデックス、ベクター ストア インデックス クリエーターをインポートします。
from langchain.chains import RetrievalQA #检索QA链,在文档上进行检索
from langchain.chat_models import ChatOpenAI #openai模型
from langchain.document_loaders import CSVLoader #文档加载器,采用csv格式存储
from langchain.vectorstores import DocArrayInMemorySearch #向量存储
from IPython.display import display, Markdown #在jupyter显示信息的工具

file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file)
#查看数据
import pandas as pd
data = pd.read_csv(file,header=None)

データはテキスト データで、name次のようなフィールドがあります。description
ここに画像の説明を挿入

# 创建向量存储
from langchain.indexes import VectorstoreIndexCreator #导入向量存储索引创建器
'''
将指定向量存储类,创建完成后,我们将从加载器中调用,通过文档记载器列表加载
'''
index = VectorstoreIndexCreator(
    vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])
query ="Please list all your shirts with sun protection \
in a table in markdown and summarize each one."
response = index.query(query)#使用索引查询创建一个响应,并传入这个查询
display(Markdown(response))#查看查询返回的内容

ここに画像の説明を挿入
日焼け止め効果のあるすべてのシャツの名前と説明を記載したマークダウン表を入手し、説明を要約します。

'''
为刚才的文本创建embedding,准备将它们存储在向量存储中,使用向量存储上的from documents方法来实现。
该方法接受文档列表、嵌入对象,然后我们将创建一个总体向量存储
'''
db = DocArrayInMemorySearch.from_documents(
    docs, 
    embeddings
)
query = "Please suggest a shirt with sunblocking"
docs = db.similarity_search(query)#使用这个向量存储来查找与传入查询类似的文本,如果我们在向量存储中使用相似性搜索方法并传入一个查询,我们将得到一个文档列表
len(docs)# 我们可以看到它返回了四个文档

# 回答文档的相关问题
retriever = db.as_retriever() #创建检索器通用接口
llm = ChatOpenAI(temperature = 0.0,max_tokens=1024) #导入语言模型
qdocs = "".join([docs[i].page_content for i in range(len(docs))])  # 将合并文档中的所有页面内容到一个变量中
response = llm.call_as_llm(f"{
    
    qdocs} Question: Please list all your \
shirts with sun protection in a table in markdown and summarize each one.") #列出所有具有防晒功能的衬衫并在Markdown表格中总结每个衬衫的语言模型

使用されるベクトル データベースは ですchromadbLangChain チェーンによってカプセル化され、取得されたドキュメントに関する質問に答えるための取得 QA チェーンを作成します。このようなチェーンを作成するには、いくつかの異なるものを渡します。

  • 1. 言語モデル、最後にテキスト生成
  • 2. ここで使用されている受信チェーン タイプはstuff、すべてのドキュメントをコンテキストに詰め込み、言語モデルを呼び出します。
  • 3. レトリーバーを渡す
qa_stuff = RetrievalQA.from_chain_type(
    llm=llm, 
    chain_type="stuff", 
    retriever=retriever, 
    verbose=True
)
query =  "Please list all your shirts with sun protection in a table \
in markdown and summarize each one."#创建一个查询并在此查询上运行链
response = qa_stuff.run(query)
display(Markdown(response))#使用 display 和 markdown 显示它

RetrievalQAチェーンは実際には、テキスト フラグメントのマージと言語モデルの呼び出しの 2 つのステップをカプセル化します。RetrievalQA チェーンがない場合は、次のように実装する必要があります。

# 将检索出来的文本片段合并成一段文本
qdocs = "".join([docs[i].page_content for i in range(len(docs))])
# 将合并后的文本和问题一起传给LLM
response = llm.call_as_llm(f"{
    
    qdocs} Question: Please list all your \
shirts with sun protection in a table in markdown and summarize each one.") 

2. チェーンの種類

多くの異なるタイプのブロックに対して同じタイプの質問応答を実行したい場合はどうすればよいでしょうか? 上記の実験では 4 つのドキュメントのみが返されました。複数のドキュメントがある場合は、いくつかの異なる方法を使用できます。

  • Map Reduce は、
    すべてのチャンクを質問とともに言語モデルに渡し、応答を取得し、別の言語モデル呼び出しを使用して個々の応答をすべて最終的な応答に要約し、任意の数のドキュメントを操作できます。1 つの問題を並行して処理できるため、さらに多くの呼び出しが必要になります。すべてのドキュメントを独立したものとして扱います
  • Refine は
    多くのドキュメントを反復的にループするために使用され、実際には前のドキュメントからの回答に基づいて構築されます。前方および後方の因果情報に最適で、以前の呼び出しの結果に応じて時間の経過とともに徐々に回答を構築します。通常は時間がかかり、基本的に Map Reduce と同じくらい多くの呼び出しが必要になります。
  • Map Re-rank
    はドキュメントごとに 1 つの言語モデル呼び出しを行い、スコアを返すように要求し、最も高いスコアを選択します。これは、スコアがどうあるべきかを認識する言語モデルに依存し、ドキュメントに関連しているかどうかを言語モデルに伝える必要があります。それは高いスコアである必要があり、そこに微調整命令があり、バッチで比較的迅速に処理できますが、コストが高くなります
  • すべてを 1 つのドキュメント
    に結合します

2. ローカルナレッジベースの Q&A

1.1 全体の枠組み

ここに画像の説明を挿入

  • 改善点(方向性):
    • LLM モデルの変更
    • 埋め込みモデル
    • テキスト分割方法
    • マルチカードアクセラレーションモデルの展開
    • Top-k 検索リコールの品質の向上
  • データプライバシーと民営化の展開に基づいて、推論にはLangchain+の大規模モデルを使用すると便利です

2. テキストの分割

ラングチェーンのソースコード: https://github.com/hwchase17/langchain/blob/master/langchain/text_splitter.py

Langchain の組み込みテキスト分割モジュールの共通パラメータ:

  • chunk_size: テキスト ブロックのサイズ、つまりテキスト ブロックの最大サイズ。
  • chunk_overlap: 2 つのセグメント化されたテキスト間の重なりの程度、テキスト ブロック間の重なりの最大量を示します。ある程度の重なりを保持すると、テキスト ブロック間の連続性が維持され、スライディング ウィンドウを使用して構築できます。これはより重要です。
  • length_function: テキスト ブロックの長さを計算するために使用される方法。デフォルトでは単純に文字数を計算します。

その他のテキスト分割ツール:
 Text Splitter LatexTextSplitter は、Latex タイトル、タイトル、列挙型などに沿ってテキストを分割します。MarkdownTextSplitter は、Markdown 見出し、コード ブロック、または水平罫線に沿ってテキストを分割します。NLTKTextSplitter は、NLTK のスプリッター PythonCodeTextSplitter を使用して、Python クラスおよびメソッド定義に沿ってテキストを分割します。RecursiveCharacterTextSplitter 一般的なテキストのスプリッター。引数として文字のリストを受け取り、すべての段落 (次に文章、それから単語) をまとめる SpacyTextSplitter Spacy のスプリッター TokenTextSplitter を使って openAl \begin{array}{|c|c|} \hline \text { text splitter} & \\ \hline \text { LatexTextSplitter } & のトークン数に応じて分割します\text { Latex の見出し、タイトル、列挙型などに沿ってテキストを分割します。} \\ \hline \text { MarkdownTextSplitter } & \begin{array}{l} \text { Markdown の見出し、コード ブロック、または水平方向の罫線に沿って分割します} \\ \text { テキストを分割します。} \end{array} \\ \hline \text { NLTKTextSplitter } & \text { NLTK のスプリッターを使用する} \\ \hline \text { PythonCodeTextSplitter } & \text { Python のクラスとメソッドの定義に沿ってテキストを分割します。} \\ \hline \text { RecursiveCharacterTextSplitter } & \begin{array}{l} \text { 一般的なテキストのスプリッター。文字のリストを } \\ \text { 引数として受け取り、すべての段落 (次に文、} \\ \text { 次に単語) を可能な限りまとめます} \end{array} \\ \hline \ text { SpacyTextSplitter } & \text { Spacy のスプリッターを使用} \\ \hline \text { TokenTextSplitter } & \text { openAl のトークン数に応じて分割} \\ \hline \end{array} テキストスプリッター  LatexTextSplitter  MarkdownTextSplitter  NLTKTextSplitter  PythonCodeTextSplitter  RecursiveCharacterTextSplitter  SpacyTextSplitter トークンテキストスプリッター  Latex の見出し、見出し、列挙などに沿ってテキストを分割します。  Markdownの見出し、コード ブロック、または横罫線に沿って分割します。  テキストをカットします。  NLTKを使用したスプリッタ  Pythonクラスおよびメソッド定義に沿ってテキストを分割します。  一般的なテキストのスプリッター。文字のリストを次のように受け取ります  パラメータ、 すべての段落を入力してみます (次に文、  それから言葉)  をまとめます Spacyのスプリッターを使用する  openAlトークン数に応じて 分割
CharacterTextSplitter中国語テキストのセグメント化やlangchainのクラスの継承など、栗を直接取り上げてみましょうChineseTextSplitter中国語の文の区切り文字に一致する正規表現sent_sep_pattern(ピリオド、感嘆符、こんにちは、セミコロンなど):

# 中文文本切分类
class ChineseTextSplitter(CharacterTextSplitter):
    def __init__(self, pdf: bool = False, **kwargs):
        super().__init__(**kwargs)
        self.pdf = pdf

    def split_text(self, text: str) -> List[str]:
        if self.pdf:
            text = re.sub(r"\n{3,}", "\n", text)
            text = re.sub('\s', ' ', text)
            text = text.replace("\n\n", "")
        sent_sep_pattern = re.compile('([﹒﹔﹖﹗.。!?]["’”」』]{0,2}|(?=["‘“「『]{1,2}|$))')  # del :;
        sent_list = []
        for ele in sent_sep_pattern.split(text):
            if sent_sep_pattern.match(ele) and sent_list:
                sent_list[-1] += ele
            elif ele:
                sent_list.append(ele)
        return sent_list

3. グラフィカルなプロセス

ここに画像の説明を挿入

参照

[1] MedicalGPT: 医療 GPT モデルのトレーニング
[2]レート制限の処理方法.openai
[3] langchain 大規模モデル プラグインのコア コンポーネントについての話、知識ベースの質問応答システム: 複雑な非構造化テキストをより適切に解析してセグメント化する方法
[ 4]データサイエンスに向けた最初の LLM アプリを構築するために知っておくべきこと
[5] LLM シリーズ | 15: LangChain を使用して長い文書の質疑応答を行う方法
[6]ローカル知識ベース対話システムの大規模モデル.tx 技術工学

おすすめ

転載: blog.csdn.net/qq_35812205/article/details/131741245