从API到Agent:万字长文洞悉LangChain工程化设计
阿里妹导读
我想做一个尝试,看看能不能用尽量清晰的逻辑,给“AI外行人士”(当然,我也是)引入一下LangChain,试着从工程角度去理解LangChain的设计和使用。同时大家也可以将此文档作为LangChain的“10分钟快速上手”手册,本意是希望帮助需要的同学实现AI工程的Bootstrap。
文中所有的示例代码都已托管到GitHub:https://github.com/TuGraph-contrib/langchain-demo,喜欢实操的小伙伴可以边阅读,边复现。
一、引言
1.1 什么是LangChain?
我:LangChain是什么? GPT-4:LangChain 是一个开源的语言模型工具链框架,旨在使研究人员和开发人员能够更轻松地构建、实验和部署以自然语言处理(NLP)为中心的应用程序。它提供了多种组件和工具,可帮助用户利用最近的语言模型进展,如大型 Transformer 模型等,并且可以与 Hugging Face 等平台集成。LangChain 的核心理念是将语言模型用作协作工具,通过它,开发者可以构建出处理复杂任务的系统,并且可以高效地对接不同的数据源和应用程序接口(APIs)。这个框架试图简化连接不同的输入和输出流,以及在流中实现语言模型的过程。
1.2 什么是AI工程?
工程是指以某组设想的目标为依据,应用有关的科学知识和技术手段,通过有组织的一群人将某个(或某些)现有实体(自然的或人造的)转化为具有预期使用价值的人造产品过程。
目标:待解决的特定AI用户需求。如内容创作、智能问答、文档摘要、图像识别等等。
人:实施AI工程的具体角色。可以是程序员,或者AI应用的研发团队、创业公司。
科学 | 技术:显然是大模型与相关工具服务,以及其后的计算科学理论。
实体:已有的文档、知识库、业务数据等生产材料。
产品:能满足目标需求的具体产品。如聊天机器人、内容生成工具等。
1.3 如何设计LangChain?
【目标 | 产品】LangChain的设计目标是什么,能解决哪些AI工程问题?
【人】LangChain的编程接口如何定义,才能提升AI工程师的研发效率?
【实体 | 科学 | 技术】LangChain的核心组件如何抽象,以提升框架的扩展能力?
作为AI工程框架,LangChain实际是对LLM能力的扩展和补充。如果把LLM比作人的大脑,LangChain则是人的躯干和四肢,协助LLM完成“思考”之外的“脏活累活”。它的能力边界只取决于LLM的智力水平和LangChain能提供的工具集的丰富程度。
LangChain提供了LCEL(LangChain Expression Language)声明式编程语言,降低AI工程师的研发成本。
LangChain提供了Models、Prompts、Indexes、Memory、Chains、Agents六大核心抽象,用于构建复杂的AI应用,同时保持了良好的扩展能力。
二、环境准备
Python环境:建议3.8版本以上。
下载链接:https://www.python.org/downloads[1]
OpenAI SK:自备。
申请地址:https://platform.openai.com/api-keys
环境变量:export OPENAI_API_KEY="<Your-OpenAI-SK>"
安装LangChain:
执行命令:pip install langchain langchain-openai
三、设计推演
3.1 造梦基础——API
3.1.1 Chat Completion API
import osimport requests# API Keyapi_key = os.getenv('OPENAI_API_KEY')# 头部信息headers = {'Content-Type': 'application/json','Authorization': f'Bearer {api_key}'}# 准备数据data = {'model': 'gpt-4','messages': [{'role': 'user', 'content': '什么是图计算?'}],'temperature': 0.7}# 调用APIurl = 'https://api.openai.com/v1/chat/completions'response = requests.post(url, json=data, headers=headers)answer = response.json()['choices'][0]['message']['content']print(answer)
代码示例输出:
图计算是一种计算模型,用于处理大规模图形结构的数据,并执行各种复杂的算法和计算。这种计算模型主要用于社交网络分析、Web搜索、生物信息学、网络路由优化、数据挖掘等领域。图计算模型的核心是将数据表示为图形结构(节点和边),这样可以更好地揭示数据之间的关系和互动。在图计算中,算法通常以迭代的方式运行,每次迭代都会更新图中节点的状态,直到达到某种停止条件。
3.1.2 Completion API
# 准备数据data = {'model': 'gpt-3.5-turbo-instruct','prompt': ['什么是图计算?'],'max_tokens': 1024}# 调用APIurl = 'https://api.openai.com/v1/completions'response = requests.post(url, json=data, headers=headers)answer = response.json()['choices'][0]['text']print(answer)
3.2 智能开端——Chat
# 对话历史messages = []def chat_with_ai(message):# 记录历史messages.append({'role': 'user', 'content': message})print(f'me: {message}')# 对话请求data = {'model': 'gpt-4','messages': messages,'temperature': 0.7}url = 'https://api.openai.com/v1/chat/completions'response = requests.post(url, json=data, headers=headers)# 解析回答if response.status_code == 200:answer = response.json()['choices'][0]['message']['content']messages.append({'role': 'assistant', 'content': answer})print(f"ai: {answer}")else:print(f'Error: {response.status_code}', response.json())# 多轮对话chat_with_ai('什么是图计算?')chat_with_ai('刚才我问了什么问题?')
代码示例输出:
me: 什么是图计算?ai: 图计算是一种计算模型,用于处理大规模图形结构数据的计算和分析。在这种计算模型中,数据被表示为图形,其中节点代表实体,边代表实体之间的关系。图计算可以用于解决许多实际问题,如社交网络分析、网络路由、生物信息学等。图计算的主要挑战是如何有效地处理大规模的图形数据,并提供快速的计算和分析结果。me: 刚才我问了什么问题?ai: 你问的问题是:“什么是图计算?”
3.3 初步封装——SDK
from langchain_openai import ChatOpenAI# 调用Chat Completion APIllm = ChatOpenAI(model_name='gpt-4')response = llm.invoke('什么是图计算?')print(response)
content='图计算是一种计算模型,主要用于处理图形结构数据的计算和分析。图计算的对象是图,图由节点和边组成,节点代表实体对象,边代表实体对象之间的关系。图计算主要用于解决实体关系复杂、关系密集的问题,如社交网络分析、网络拓扑分析、推荐系统等。图计算的主要任务是通过对图中节点和边的计算,发现和提取出图中隐含的知识和信息。'
3.4 数据抽象——IO
IO数据抽象示意
from langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAI# 创建LLMllm = ChatOpenAI(model_name='gpt-4')# 创建Promptprompt = ChatPromptTemplate.from_template("{question}")# 创建输出解析器output_parser = StrOutputParser()# 调用LLMmessage = prompt.invoke({'question': '什么是图计算?'})response = llm.invoke(message)answer = output_parser.invoke(response)print(answer)
3.5 组装成链——Chain
3.5.1 HelloWorld
# 创建Chainchain = prompt | llm | output_parser# 调用Chainanswer = chain.invoke({'question': '什么是图计算?'})print(answer)
至此,我们终于看到了LangChain版的“HelloWorld”……
3.5.2 RunnablePassthrough
from langchain_core.runnables import RunnablePassthrough# 创建Chainchain = {"question": RunnablePassthrough()} | prompt | llm | output_parser# 调用Chainanswer = chain.invoke('什么是图计算?')print(answer)
3.5.3 DAG
from operator import itemgetterfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnablePassthroughfrom langchain_openai import ChatOpenAI# 创建LLMllm = ChatOpenAI(model_name='gpt-4')# 创建输出解析器output_parser = StrOutputParser()# 创建Prompttopic_prompt = ChatPromptTemplate.from_template("生成一种'{input}'的名称")good_prompt = ChatPromptTemplate.from_template("列举{topic}的好处:")bad_prompt = ChatPromptTemplate.from_template("列举{topic}的坏处:")summary_prompt = ChatPromptTemplate.from_messages([("ai", "{topic}"),("human", "好处:\n{good}\n\n坏处:\n{bad}"),("system", "生成最终结论"),])# 创建组合Chaintopic_chain = topic_prompt | llm | output_parser | {"topic": RunnablePassthrough()}goods_chain = good_prompt | llm | output_parserbads_chain = bad_prompt | llm | output_parsersummary_chain = summary_prompt | llm | output_parserchain = (topic_chain| {"good": goods_chain,"bad": bads_chain,"topic": itemgetter("topic"),}| summary_chain)# 调用chainanswer = chain.invoke({"input": '常见水果'})print(answer)
代码示例输出:
苹果是一种营养丰富的水果,具有帮助消化、保护心脏、降低糖尿病风险、强化免疫系统、帮助减肥、保护视力、预防哮喘、抗癌和提升记忆力等多种好处。然而,过度食用或者不适当的食用方式也可能带来一些不利影响,如引发过敏、导致腹泻、对牙齿造成伤害、可能携带农药残留、影响正常饮食和钙质吸收、增加蛀牙风险和引发胃痛等。因此,我们在享受苹果带来的好处的同时,也需要注意适量和正确的食用方式。
LangChain的计算图与Trace
export LANGCHAIN_TRACING_V2="true" export LANGCHAIN_API_KEY="<Your-LangChain-AK>"
3.5.4 LangGraph
3.6 开启记忆——Memory
带记忆的问答处理
3.6.1 Memory接口
from langchain.chains import LLMChainfrom langchain.memory import ConversationBufferMemoryfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, \HumanMessagePromptTemplatefrom langchain_openai import ChatOpenAI# 创建LLMllm = ChatOpenAI(model_name='gpt-4')# 创建Promptprompt = ChatPromptTemplate.from_messages([MessagesPlaceholder(variable_name='chat_history'),HumanMessagePromptTemplate.from_template('{question}')])# 创建Memorymemory = ConversationBufferMemory(memory_key='chat_history',return_messages=True)# 创建LLMChainllm_chain = LLMChain(llm=llm, memory=memory, prompt=prompt)# 调用LLMChainprint(llm_chain.predict(question='什么是图计算?'))print(llm_chain.predict(question='刚才我问了什么问题?'))
图计算是一种计算类型,主要处理的数据结构是图。图是由节点(或顶点)和边组成的,节点代表实体,边代表实体之间的关系。在图计算中,主要解决的问题是如何在图的结构上进行有效的计算和分析。你问的问题是:“什么是图计算?”
3.6.2 History接口
from langchain_community.chat_message_histories import ChatMessageHistoryfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, \HumanMessagePromptTemplatefrom langchain_core.runnables import RunnablePassthroughfrom langchain_core.runnables.history import RunnableWithMessageHistoryfrom langchain_openai import ChatOpenAI# 创建LLMllm = ChatOpenAI(model_name='gpt-4')# 创建输出解析器output_parser = StrOutputParser()# 创建Promptprompt = ChatPromptTemplate.from_messages([MessagesPlaceholder(variable_name="chat_history"),HumanMessagePromptTemplate.from_template("{question}")])# 创建Chainchain = prompt | llm | output_parser# 添加Historyhistory = ChatMessageHistory()chain_with_history = RunnableWithMessageHistory(chain,lambda session_id: history,input_messages_key="question",history_messages_key="chat_history",)# 调用Chainprint(chain_with_history.invoke({'question': '什么是图计算?'},config={"configurable": {"session_id": None}}))print(chain_with_history.invoke({'question': '刚才我问了什么问题?'},config={"configurable": {"session_id": None}}))
3.7 消除幻觉——RAG
基于RAG的问答处理流程
大语言模型优化技术
from langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_community.vectorstores.faiss import FAISSfrom langchain_core.documents import Documentfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnablePassthroughfrom langchain_openai import OpenAIEmbeddings, ChatOpenAI# 创建LLMllm = ChatOpenAI(model_name='gpt-4')# 创建Promptprompt = ChatPromptTemplate.from_template('基于上下文:{context}\n回答:{input}')# 创建输出解析器output_parser = StrOutputParser()# 模拟文档docs = [Document(page_content="TuGraph是蚂蚁开源的图数据库产品")]# 文档嵌入splits = RecursiveCharacterTextSplitter().split_documents(docs)vector_store = FAISS.from_documents(splits, OpenAIEmbeddings())retriever = vector_store.as_retriever()# 创建Chainchain_no_context = RunnablePassthrough() | llm | output_parserchain = ({"context": retriever, "input": RunnablePassthrough()}| prompt | llm | output_parser)# 调用Chainprint(chain_no_context.invoke('蚂蚁图数据库开源了吗?'))print(chain.invoke('蚂蚁图数据库开源了吗?'))
代码示例输出:
蚂蚁图数据库目前没有公开信息表明已经开源。开源状态可能会随时间和公司政策变化,建议直接查阅蚂蚁集团或相关开源平台的官方信息获取最新和准确的消息。是的,蚂蚁的图数据库产品TuGraph是开源的。
向量存储的写入与查询
DocumentLoader:从外部系统检索文档数据。简单起见,示例中直接构造了测试文档对象。实际上LangChain提供了文档加载器BaseLoader的接口抽象和大量实现,具体可根据自身需要选择使用。
TextSplitter:将文档分割成块,以适应大模型上下文窗口。示例中采用了常用的RecursiveCharacterTextSplitter,其他参考LangChain的TextSplitter接口和实现。
EmbeddingsModel:文本嵌入模型,提供将文本编码为向量的能力。文档写入和查询匹配前都会先执行文本嵌入编码。示例采用了OpenAI的文本嵌入模型服务[13],其他参考LangChain的Embeddings接口和实现。
VectorStore:向量存储,提供向量存储和相似性检索(ANN算法)能力。LangChain支持的向量存储参考VectorStore接口和实现。示例采用了Meta的Faiss[14]向量数据库,本地安装方式:pip install faiss-cpu。需要额外提及的是,对于图数据库,可以将相似性搜索问题转化为图遍历问题,并具备更强的知识可解释性。蚂蚁开源的TuGraph数据库[15]目前正在做类似的技术探索。
Retriever:向量存储的查询器。一般和VectorStore配套实现,通过as_retriever方法获取,LangChain提供的Retriever抽象接口是BaseRetriever。
3.8 使用工具——Tool
“会使用工具”是人类和动物的根本区别。
LLM Tools执行流程示意
import randomfrom langchain_core.output_parsers.openai_tools import JsonOutputToolsParserfrom langchain_core.runnables import RunnablePassthroughfrom langchain_core.tools import toolfrom langchain_openai import ChatOpenAI# 定义Tool@tooldef get_temperature(city: str) -> int:"""获取指定城市的当前气温"""return random.randint(-20, 50)# 创建LLMllm = ChatOpenAI(model_name='gpt-4')# 创建JSON输出解析器output_parser = JsonOutputToolsParser()# 创建Chainchain = (RunnablePassthrough()| llm.bind_tools(tools=[get_temperature])| output_parser)# 调用Chainprint(chain.invoke('杭州今天多少度?'))
代码示例输出:
[{'type': 'get_temperature', 'args': {'city': '杭州'}}]
3.9 走向智能——Agent
3.9.1 什么是Agent?
Agent的核心思想是使用大型语言模型(LLM)来选择要采取的行动序列。在Chain中行动序列是硬编码的,而Agent则采用语言模型作为推理引擎来确定以什么样的顺序采取什么样的行动。
LangChain Agent工作流程示意图
规划:借助于LLM强大的推理能力,实现任务目标的规划拆解和自我反思。
记忆:具备短期记忆(上下文)和长期记忆(向量存储),以及快速的知识检索能力。
行动:根据拆解的任务需求正确地调用工具以达到任务的目的。
协作:通过与其他智能体交互合作,完成更复杂的任务目标。
3.9.2 构建智能体
import randomfrom langchain.agents import create_openai_tools_agent, \AgentExecutorfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, \HumanMessagePromptTemplate, SystemMessagePromptTemplatefrom langchain_core.tools import toolfrom langchain_openai import ChatOpenAI# 创建LLMllm = ChatOpenAI()# 定义Tool@tooldef get_temperature(city: str) -> int:"""获取指定城市的当前气温"""return random.randint(-20, 50)# 创建Agent提示词模板prompt = ChatPromptTemplate.from_messages([SystemMessagePromptTemplate.from_template('You are a helpful assistant'),MessagesPlaceholder(variable_name='chat_history', optional=True),HumanMessagePromptTemplate.from_template('{input}'),MessagesPlaceholder(variable_name='agent_scratchpad')])# 创建Agenttools = [get_temperature]agent = create_openai_tools_agent(llm, tools, prompt=prompt)# 执行Agentagent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)print(agent_executor.invoke({'input': '今天杭州多少度?'})['output'])
代码示例输出:
> Entering new AgentExecutor chain... Invoking: get_temperature with {'city': 'Hangzhou'} 16 今天杭州的气温是16度。 > Finished chain. 今天杭州的气温是16度。
hwchase17/openai-tools-agent的定义
四、LangChain架构
五、尾记
参考资料:
1. Retrieval-Augmented Generation for Large Language Models: A Survey:https://arxiv.org/abs/2312.10997
2. Chain-of-Thought Prompting Elicits Reasoning in Large Language Models:https://arxiv.org/pdf/2201.11903.pdf
3. Tree of Thoughts: Deliberate Problem Solving with Large Language Models:https://arxiv.org/pdf/2305.10601.pdf
4. ReAct: Synergizing Reasoning and Acting in Language Models:https://arxiv.org/abs/2210.03629
5. API-Bank: A Comprehensive Benchmark for Tool-Augmented LLMs:https://arxiv.org/abs/2304.08244
6. LangChain Docs:https://python.langchain.com/
7. OpenAI Docs:https://platform.openai.com/docs
8. LangGraph Docs:https://python.langchain.com/docs/langgraph
9. LangChain:[https://github.com/langchain-ai/langchain]
10. LangGraph:[https://github.com/langchain-ai/langgraph]
11. TuGraph Analytics:https://github.com/TuGraph-family/tugraph-analytics
12. TuGraph DB:https://github.com/TuGraph-family/tugraph-db
13. Langchain-Chatchat:https://github.com/chatchat-space/Langchain-Chatchat
14. LLM Powered Autonomous Agents:https://lilianweng.github.io/posts/2023-06-23-agent/
15. Emerging Architectures for LLM Applications:https://a16z.com/emerging-architectures-for-llm-applications/
16. Prompt Engineering Guide:https://www.promptingguide.ai/
[2] Chat Completion API: https://platform.openai.com/docs/api-reference/chat
[3] Completion API: https://platform.openai.com/docs/api-reference/completions
[4] OpenAI开发文档: https://platform.openai.com/docs
[5] Prompt: https://python.langchain.com/docs/modules/model_io/prompts/
[6] OutputParser: https://python.langchain.com/docs/modules/model_io/output_parsers/
[7] LCEL: https://python.langchain.com/docs/expression_language/
[8] AK: https://smith.langchain.com/settings
[9] LangGraph: https://github.com/langchain-ai/langgraph
[10] LangGraph文档: https://python.langchain.com/docs/langgraph
[11] TuGraph Analytics: https://github.com/TuGraph-family/tugraph-analytics
[12] Memory组件: https://python.langchain.com/docs/modules/memory/
[13] 文本嵌入模型服务: https://platform.openai.com/docs/guides/embeddings
[14] Faiss: https://github.com/facebookresearch/faiss
[15] TuGraph数据库: https://github.com/TuGraph-family/tugraph-db
[16] 函数调用: https://platform.openai.com/docs/guides/function-calling
[17] Assistant的函数调用: https://platform.openai.com/docs/assistants/tools/function-calling
[18] @tool: https://python.langchain.com/docs/modules/agents/tools/custom_tools#tool-decorator
[19] RunnableWithMessageHistory的方案: https://python.langchain.com/docs/modules/agents/quick_start#adding-in-memory
[20] Hub: https://smith.langchain.com/hub/
[21] hwchase17/openai-tools-agent: https://smith.langchain.com/hub/hwchase17/openai-tools-agent