使用RAG(检索增强生成)技术进行的基于PostgreSQL的助手AI的原型试验
这篇文章是NTT Comware Advent Calendar 2023的第四天的文章。
你好,我是NTT Comware的平塚。我正在寻找适合2023年冬季Chill Season的手感舒适的工具。
有一种名为RAG(Retrieval Augmented Generation,检索增强生成)的架构,用于补充大规模语言模型缺少的最新信息和内部公司信息。简单来说,它通过准备外部数据库并在该数据库中检索结果,让大规模语言模型对其进行解释。以下是RAG的示意图。

我认为现在许多公司正在努力进行RAG验证。这次我们使用RAG来试制一个对 PostgreSQL 了解详细的助理人工智能,并且我会分享一些我所注意到的地方。
概括一下
-
- PostgreSQLアシスタントAIはある程度使えるものになりそう
-
- 回答品質を高めるためには、やはりドキュメントの前処理が重要
- 一問一答よりは、散在する回答群をまとめあげるユースケースに期待
PostgreSQL助手AI的问题回答示例
那我们立刻来试试吧。PostgreSQL助手AI已经加载了PostgreSQL 15附带文档的日文版本。首先,我试着向原始的GPT-4(gpt-4-0613)提出了一个问题:“请告诉我有关于PostgreSQL 15中PUBLIC模式规范变更的内容。”由于gpt-4-0613的截止日期是2021年9月,它会告诉我它不知道2022年10月发布的PostgreSQL 15。

我把同样的问题投给了GPT-4 Turbo(gpt-4-1106-preview)。尽管gpt-4-1106-preview的截止日期是2023年4月,但它似乎并不了解PostgreSQL 15。由于大型语言模型的知识是基于收集到的训练数据,所以不能轻易指望它知道截止日期之前的事情。至少幸好这次没有引发幻觉。

当我们向我们最新开发的PostgreSQL助手AI提问时,它会给出适当的回答。看起来它的运行非常正常。

让我们尝试另一个问题。我们来提出一个比较模糊的问题,不指定版本,如“在PostgreSQL中,查询性能很差。您有什么方法可以调查和改善呢?”现在我们来看看GPT-4 Turbo的回答。

我将继续提出深入挖掘内容的问题。GPT-4 Turbo真是非常聪明啊。

接下来,我将同样的问题提交给PostgreSQL助手AI。虽然给人一种稍微杂乱的印象,但可以看出它是在参考多个搜索结果来生成回答。

我接下来会向您提出更加深入的问题,希望您能给出合适的回答。

由于我在选择方便的问题和答案进行介绍,所以我无法否认PostgreSQL助手AI的可用性。希望有机会能够实际构建并测试它。
关于RAG系统的构成
这个PostgreSQL助手AI是参考了微软公司发布的Azure-Samples/azure-search-openai-demo而创建的。

主要处理过程集中在chatreadretrieveread.py文件中,通过修改系统提示语为日语等进行了一些更改。
prompt_for_query = """以下はこれまでの会話の履歴と、ユーザーからの新たな質問です。
新たな質問にはナレッジベースを検索して回答する必要があります。
会話と新たな質問を元に、検索クエリーを生成してください。
検索クエリーは日本語で生成してください。
検索クエリーにinfo.txtやdoc.pdfといった引用元のファイル名やドキュメント名を含めないでください。
検索クエリーに[]または<<>>で囲まれた文字列を含めないでください。
検索クエリーに'+'のような特殊文字を含めないでください。
検索クエリーをダブルクォーテーションで囲わないでください。
検索クエリーを生成できない場合は、数字の0だけを返してください。"""
prompt_for_answer = """アシスタントはユーザーからの質問をサポートします。
詳細な回答を心がけてください。
日本語で回答してください。
以下にリストされた出典に記載されている事実のみを用いて回答してください。
以下の情報が十分でない場合は、分からないと回答してください。
以下の出典を用いない回答は作成しないでください。
ユーザーに明確化のための質問をすることが役立つ場合は、質問してください。
それぞれの出典は、名前の後にコロンと実際の情報が続きます。
回答で使用するそれぞれの事実については、必ず出典名を含めてください。
出典を参照するには大括弧を使用してください(例:[info1.txt])。
出典は結合せず、それぞれの出典を分けて記載してください(例:[info1.txt][info2.txt])。"""
请注意,本文撰写时的chatreadretrieveread.py (2023-11-16)依赖于旧版本的openai和azure-search-documents库。如果您更新了库的最新版本,它将无法运行。如果要构建,请参考以下文档,建议您调整程序以适应库的最新版本。
-
- OpenAI Python v1.x に移行する方法 – Azure OpenAI Service | Microsoft Learn
- Azure AI Search Vector Search Code Sample with Azure OpenAI
我們的前端使用了Mattermost。在azure-search-openai-demo的前端中,我們選擇使用Mattermost的主要原因是它不需要用戶認證功能和查看過去日誌的功能,同時我們也想避免自行實現前端的麻煩。我們使用azure-openai-mattermost-bot作為Mattermost Bot的基礎。
Azure的配置如下所示。
Azure的设置如下所列。
-
- 大規模言語モデル: Azure OpenAI Service
Embeddingモデル: text-embedding-ada-002
ChatCompletionモデル: gpt-4-1106-preview
外部データベース: Azure AI Search
SKU: Standard
ベクトル検索を使用
ハイブリッド検索は未使用 (検索精度に不満がなかったので)
关于搜索目标文本的预处理。
在使用RAG的外部数据库中,将要搜索的文本适当地进行分割和整理非常重要。无论分割得太大还是太小,RAG都无法正确地运行。以下列举了一些需要考虑的限制。
-
- 埋め込みモデルの制約
text-embedding-ada-002の最大トークン数が8,191であまり大きくない
分割サイズを大きくしすぎると、文章の特徴が丸められてしまい適切な検索結果を得られにくくなる
チャットモデルの制約
gpt-4の最大トークン数が8,192であまり大きくない
分割サイズを大きくしすぎると、検索結果を数件しか大規模言語モデルに渡せなくなる
分割サイズを小さくしすぎると、検索結果が文章の断片になってしまい内容が把握できなくなる
在RAG中,建议将文本分割成500到1,000个标记的大小。本次我们按照1,000个标记作为指导,将文本进行分割。需要注意的是,gpt-4-32k和gpt-4-1106-preview的聊天模型限制已经得到大幅放宽。
文本分割程序 初版
在RAG中,使用LangChain的text_splitter.py来进行文本分割似乎是很常见的。起初,我也使用LangChain,但很快意识到需要进行大规模改造,因此我决定以规模较小的azure-search-openai-demo的textsplitter.py为基础,并逐步添加功能。在初始版本中,我已经给textsplitter.py添加了以下功能。
-
- 区切り文字に日本語の句読点を追加
- 文字数ではなくトークン数で数えるように変更
请参考document_preprocessor.py文件以获取具体实现。另外,我们建议您查看已将第26章 “备份和恢复” 拆分为chunked_ja.txt文件的实际例子。这一章被分成了25个文本段落。
文本分割程序升级版
尽管初始版本的文本分割程序也能在某种程度上使用RAG功能,但仍会出现意想不到的文本分割或所希望分割的文本段落连在一起等问题,因此无法完全按照期望的方式运行。
在改进后的文本分割程序中,我们利用了PostgreSQL文档使用的SGML标记语言来根据文章结构进行分割。由于PostgreSQL文档具有以下结构,我们首先按的单位进行分割,如果的大小超过1,000个令牌,我们将继续使用初始版本的算法进行进一步的分割。
<chapter><title>1.章タイトル</title>
<sect1><title>1-1.セクション(大)タイトル</title>
<sect2><title>1-1-1.セクション(中)タイトル</title>
<para>本文</para>
</sect2>
<sect2><title>1-1-2.セクション(中)タイトル</title>
<para>本文</para>
</sect2>
</sect1>
<sect1><title>1-2.セクション(大)タイトル</title>
<sect2><title>1-2-1.セクション(中)タイトル</title>
<para>本文</para>
</sect2>
</sect1>
</chapter>
请参考”第26章 备份和恢复”中的示例chunked_ja_custom.txt,document_preprocessor_custom.py的具体实现被改进为将文本分割为34个部分。
在改良版本中,我们对于每个文本都添加了文档标题、章节标题和小节标题,以提高向量搜索的准确性。
# PostgreSQL 15 文書
## バックアップとリストア
### 継続的アーカイブとポイントインタイムリカバリ(PITR)
#### WALアーカイブの設定
(パス名は現在の作業ディレクトリ、つまりクラスタのデータディレクトリからの相対パスです。)
実際の%文字をコマンドに埋め込む必要がある場合は%%を使用してください。
最も簡単で便利なコマンドは以下のようなものです。
~
本文开头所介绍的问答示例是使用此程序准备的。
中文版本的文本分割程序-大规模语言模型 (失败案例)
我认为,由于GPT-4-1106预览版的最大令牌数已经增加到128,000个,我们可以将这些文本处理任务交给GPT-4-1106预览版来完成。然而,这个想法并没有成功,原因如下。
-
- 入力には128,000トークンを使えるが、出力には4,096トークンしか使えない
-
- 分割したテキストを出力させると、元のテキストからわずかに改変されてしまう
- 別のアプローチとして分割する行番号を出力させると、でたらめな数字を返してくる
虽然我努力尝试了一段时间的提示工程,但始终没有获得令人满意的结果。如果我对大规模语言模型的机制有着透彻的理解,也许就不用去尝试了,就能明白这个任务不会成功。
关于RAG在实际应用中的用途
在社交网络上搜集信息时,有时会看到一种观点:“RAG的本质是向量检索,是否真的不需要大型语言模型呢?”确实有时候会让人觉得可能是这样。
在处理只有一个问题对应一个答案的任务,比如搜索内部规程,我认为通常只需要进行向量检索就可以满足要求。如果能够找到一个信息源,就没有必要费力将其解释拆解为大型语言模型来获取答案了,对吧。
從系統結構逆推來看,我們認為RAG對於有多個答案的使用案例是有用的。在這樣的使用案例中,使用向量檢索以稍微寬鬆的搜尋條件收集大量資訊,並且有效地整理多樣化的資訊是非常有效的。

冒头的PostgreSQL助手AI在回答有关查询性能改进的问题时,会参考10个搜索结果来制作回答。这可以说是其中一个使用案例。虽然只是一时的想法,但以下这样的使用案例也很有趣。
-
- 図書館の蔵書検索システム
-
- 「おいしいパンがでてくる絵本を教えて」
-
- 「主人公が異世界で人間以外に転生するファンタジー小説を教えて」
-
- 特許検索システム
- 「ジョイスティックを模した操作を行うためのタッチパネル制御に関する特許を教えて」
还有一个可以利用大规模语言模型的多语种用例。事实上,我们这次制作的PostgreSQL助手AI可以接受用日语提出的问题,并以日语回答针对英文版文档的问题。这意味着即使只有英文信息源,也可以进行日语的问答,这可以说是大规模语言模型和向量搜索的优势。

再度总结
-
- PostgreSQLアシスタントAIはある程度使えるものになりそう
-
- 回答品質を高めるためには、やはりドキュメントの前処理が重要
- 一問一答よりは、散在する回答群をまとめあげるユースケースに期待
结束
非常感謝日本PostgreSQL用户协会的各位,您们一直提供着高质量的翻译文件。
所记载的公司名称、产品名称和服务名称均为各自公司的商标或注册商标。