本文正在参加 ✍🏻 技术视角深入 ChatGPT 征文活动
现在ChatGPT的API是无状态的,意味着你需要自己去维持会话状态,保存上下文,每次请求的时候将之前的历史消息全部发过去,但是这里面有两个问题:1. 请求内容会越来越大;2. 费用很高。
今天在Twitter上看到有人分享的一个很好的解决方案,可以借助OpenAI
的embedding
模型和自己的数据库,现在本地搜索数据获得上下文,然后在调用ChatGPT的API的时候,加上本地数据库中的相关内容,这样就可以让ChatGPT从你自己的数据集获得了上下文,再结合ChatGPT自己庞大的数据集给出一个更相关的理想结果。
这种模式尤其适合针对一些特定著作、资料库的搜索和问答。我想之前有人做了模拟乔布斯风格的问答应该也是基于这种模式来做的。
具体解释一下它的实现原理
- 首先准备好你要用来学习的文本资料,把它变成CSV或者Json这样易于处理的格式,并且分成小块(
chunks
),每块不要超过8191
个Tokens
,因为这是OpenAI embeddings
模型的输入长度限制 - 然后用一个程序,分批调用
OpenAI embedding
的API
,目前最新的模式是text-embedding-ada-002
,将文本块变成文本向量。
platform.openai.com/docs/guides…
这里简单解释一下,对于OpenAI
来说,要判断两段文本的相似度,它需要先将两段文本变成数字向量(vector embeddings
),就像一堆坐标轴数字,然后通过数字比较可以得出一个0-1之间的小数,数字越接近1相似度越高。
所以要借助OpenAI检索相似度,将文本编码成数字向量必不可少。
- 需要将转换后的结果保存到本地数据库。注意一般的关系型数据库是不支持这种向量数据的,必须用特别的数据库,比如
Pinecone
数据库,比如Postgres
数据库(需要pgvector
扩展)。
当然你保存的时候,需要把原始的文本块和数字向量一起存储,这样才能根据数字向量反向获得原始文本。
这一步有点类似于全文索引中给数据建索引。
- 等需要搜索的时候,先将你的搜索关键字,调用
OpenAI
embedding
的API
把关键字变成数字向量。
拿到这个数字向量后,再去自己的数据库进行检索,那么就可以得到一个结果集,这个结果集会根据匹配的相似度有个打分,分越高说明越匹配,这样就可以按照匹配度倒序返回一个相关结果。
- 聊天问答的实现要稍微复杂一点
当用户提问后,需要先根据提问内容去本地数据库中搜索到一个相关结果集。
然后根据拿到的结果集,将结果集加入到请求ChatGPT
的prompt
中。
比如说用户提了一个问题:“What’s the makers’s schedule?”,从数据库中检索到相关的文字段落是:“What I worked on…”和”Taste for Makers…”,那么最终的prompt看起来就像这样:
[
{
role: "system",
content:
"You are a helpful assistant that accurately answers queries using Paul Graham's essays. Use the text provided to form your answer, but avoid copying word-for-word from the essays. Try to use your own words when possible. Keep your answer under 5 sentences. Be accurate, helpful, concise, and clear.",
},
{
role: "user",
content: `Use the following passages to provide an answer
to the query: "What's the makers's schedule?"
1. What I worked on...
2. Taste for Makers...`,
},
];
这样ChatGPT在返回结果的时候,就会加上你的数据集。
相关Twitter:twitter.com/mckaywrigle…
有个叫LlamaIndex(原来的名字是gpt_index)的库已经把这套逻辑封装了 🔗 github.com/jerryjliu/g…