随着ChatGPT的爆火,最近大家开始关注到大语言模型(LLM)这个领域。像雨后春笋一样,国内外涌现出了很多LLM。作为开发者,我们通常会关注LLM各自擅长的领域和能力,然后思考如何利用它们的能力来解决某个场景或下游任务。
假如现在有一个需求是实现一个私域知识的文本生成问答助手,我们应该如何去实现呢?
下面就来试验一下。
一、模型选择
首先,我们要明确需求:我们需要一个模型,能理解用户的问题并生成固定格式的回答。这就要求模型具备良好的语义分析和文本生成能力。在这种情况下,我们选择使用ChatGPT的GPT-3.5模型。
然而,像GPT这样的大模型,要训练自己的数据集是既困难又昂贵的,所以我们采用了一种称为“zero-shot-prompt”的方法,也就是“0样本”无需训练,直接使用模型。但zero-shot也存在一个难题:我们需要将我们的私域知识全部放入输入中,作为上下文和问题一起交给LLM处理。
但大家知道,OpenAI的API由于底层机制的原因,存在Token数的限制。这就意味着我们交给模型的输入内容文本长度是有限制的。因此,我们不能一次性将所有内容交给LLM处理。
二、向量数据库
向量数据库的出现为我们解决了这一问题。传统关系型数据库主要进行关键字匹配查询,而向量数据库则擅长进行语义查询,能检索出与输入内容相似的结果。这里先引入一个关键概念,即Embedding,也就是将文本知识或其他数据格式的内容通过Embedding算法转换成向量数据,然后存入向量数据库中。这样,数据库就能基于相似性算法找出最接近的数据并返回给我们。目前市面上的向量数据库有很多,这里暂不一一介绍,感兴趣的读者可以自行了解。
在ChatGPT中,使用了Pinecone和Chroma两种向量库。本例中,我们采用Milvus向量数据库来存储私域知识,Embedding算法直接使用了OpenAI提供的算法。
三、LangChain
作为应用端开发人员,我们可能对模型交互不太了解,但这并不妨碍我们使用LangChain这个开源框架来快速构建端到端的应用程序。LangChain可以帮助我们轻松管理与语言模型的交互,将多个组件链接在一起,并集成额外的资源,例如 API 和数据库等。通过使用LangChain,我们可以轻松地将模型和数据库集成起来。
下面我将开始使用LangChain将模型和数据库集成起来。
# 准备数据 提前将私域信息向量化后存入数据库中
fromlangchain.vectorstores importMilvus
fromlangchain.embeddings importOpenAIEmbeddings
embedding_function=OpenAIEmbeddings()
vector_db = Milvus(
embedding_function,
collection_name="test_01",
connection_args={"host": "127.0.0.1", "port": "19530"},
)
text1 = 'xxxx公司下有AI服务器产品:KunTai A222、KunTai A722、 KunTai A924'
text2 = 'xxxx公司下有单路服务器产品:KunTai R222、KunTai R224'
text3 = 'xxxx公司下有四路服务器产品:KunTai R822'
vector_db.add_texts([text1,text2,text3])
上图可以看到vector字段里面的数据就是Text的Embedding结果
#设置open_api_key
importos
os.environ[ "OPENAI_API_KEY"] = "自己的key"# 接入模型
fromlangchain.llms importOpenAI
llm = OpenAI(temperature=0)# 定义memory ,这里我们自定义出一个memory类,从Milvus查询相似度高的信息作为上下文,同时利用redis缓存历史用户对话信息
fromlangchain.schema importBaseMemory
frompydantic importBaseModel
fromtyping importAny, Dict, List, Union
fromlangchain.schema importDocument
fromlangchain.memory importRedisChatMessageHistory
fromlangchain.embeddings.openai importOpenAIEmbeddings
fromlangchain.vectorstores importMilvus
fromlangchain.schema import(
AIMessage,
HumanMessage
)classSelfMemory(BaseMemory, BaseModel):
........省略
@property
defmemory_variables(self)-> List[str]:
return[self.context_memory_key,self.chat_memory_key]defload_memory_variables(self, inputs: Dict[str, Any])-> Dict[str, Union[List[Document], str]]:
# 根据用户的输入先从milvus里面去检索出相识度比较高的几条信息
docs = self.vector_db.similarity_search(query = inputs[list(inputs.keys())[0]],k = 5)
result: Union[List[Document], str]
result = "\n".join([doc.page_content fordoc indocs])
# 获取用户历史对话
chat_result = self.spit_chat_history(self.chat_history.messages)
return{self.context_memory_key: result,self.chat_memory_key:chat_result}defsave_context(self, inputs: Dict[str, Any], outputs: Dict[str, str])-> None:
#只存储会话相关信息存储到redis里面
self.chat_history.add_user_message(inputs[list(inputs.keys())[0]])
self.chat_history.add_ai_message(outputs[list(outputs.keys())[0]])
# 定义PromptTemplate
fromlangchain.prompts importPromptTemplate
_DEFAULT_TEMPLATE = """以下是用户和助手之间的友好对话。助手十分智能,能够自己结果上下文进行回答问题。已知信息是在私有数据库里面检索出来比较接近的信息,
历史对话是用户之前和助手的聊天记录,请结合已知信息和对话信息来做出回答,回答请使用下面我给出的格式回答。如果不知道答案,请直接告诉我不知道。已知信息:
{context}
历史对话:
{history}
当前对话:
用户: {input}
助手:"""
PROMPT = PromptTemplate(
input_variables=["context","history", "input"], template=_DEFAULT_TEMPLATE
)
# 构造chain 模拟对话 当前用户为lisi
fromlangchain.chains importConversationChain
user_name = 'lisi'
conversation = ConversationChain(
llm=llm,
verbose=False,
memory=SelfMemory(user_name),
prompt=PROMPT
)
conversation.run("我想买一台AI服务器")
conversation.run("KunTai A222")
根据打印的日志信息,LangChain会将问题、历史对话以及通过Milvus检索到的相似信息整合到Prompt中,然后交给LLM处理。这样,我们就可以获得所需的回答。
四、总结
以上示例展示了如何利用LangChain快速接入LLM和向量库,实现本地私域知识问答的简单模拟。
关于LLM、LangChain以及向量库的应用,这里只是介绍了冰山一角。为了让大家更深入了解并构建出满足自己需求的功能更为丰富的应用程序,建议感兴趣的读者详细学习官方的文档。通过掌握这些技术,我们将能够更好地应对复杂多变的应用场景,并为用户带来更加智能、高效的使用体验。
参考资料:
- https://python.langchain.com/en/latest/
- https://milvus.io/docs
- https://www.modb.pro/db/516016
- https://www.modb.pro/db/516016
作者 :张任华 | 高级后端开发工程师
版权声明:本文由神州数码云基地团队整理撰写,若转载请注明出处。
公众号搜索神州数码云基地,了解更多AI相关技术干货。