AI代码开发宝库系列:LangChain 应用开发全解析与参考代码
LangChain 多任务应用开发全解析

一、LangChain 基础核心
1.1 核心定位与价值
LangChain 是一套用于简化大语言模型(LLM)应用开发的框架,通过提供工具、组件和接口,降低 LLM 与外部系统(如工具、知识库)集成的复杂度,支持快速构建多任务、多流程的 AI 应用。
1.2 七大核心组件
| 组件 | 功能描述 | 典型应用场景 |
|---|---|---|
| Models(模型) | 集成各类 LLM(如 GPT-4o、通义千问 qwen-turbo),提供统一调用接口 | 文本生成、推理决策 |
| Prompts(提示) | 管理提示词模板、优化提示逻辑、支持提示序列化 | 标准化问答、动态生成提示 |
| Memory(记忆) | 存储对话上下文,实现 LLM 的 "短期记忆" 能力 | 多轮对话、上下文关联任务 |
| Indexes(索引) | 处理文档结构化(加载、切割、向量计算、存储),支持知识库交互 | 本地知识问答(RAG) |
| Chains(链) | 串联多个组件(如 Prompt→LLM→Parser),定义固定执行流程 | 线性任务(翻译→分析→总结) |
| Agents(代理) | 基于 LLM 自主决策工具调用顺序,支持 "思考 - 行动 - 观察" 循环 | 复杂任务(故障诊断、多工具组合) |
| Tools(工具) | 集成外部能力(搜索、计算、文件操作等),作为 Agent 的执行单元 | 实时信息查询、数学计算、API 调用 |
1.3 基础代码示例(Prompt 与 Chain)
通过PromptTemplate定义提示模板,结合 LLM 形成可运行的链式结构,简化任务执行流程:
from langchain.prompts import PromptTemplate
from langchain_community.llms import Tongyi
import os
import dashscope
# 初始化API密钥与LLM
api_key = os.environ.get('DASHSCOPE_API_KEY')
dashscope.api_key = api_key
llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key)
# 定义提示模板
prompt = PromptTemplate(
input_variables=["product"],
template="What is a good name for a company that makes {product}?"
)
# 构建链式结构(LCEL风格,|表示数据流传递)
chain = prompt | llm
# 执行任务
result = chain.invoke({"product": "colorful socks"})
print(result) # 输出:如"Vibrant Sock Co."等公司名称建议
二、关键工具(Tools)解析
2.1 常用工具类型与功能
LangChain 支持内置工具与自定义工具,核心工具包括:
| 工具名称 | 核心功能 | 依赖与安装 | 典型使用场景 |
|---|---|---|---|
| SerpAPI | 集成 Google、百度等搜索引擎,获取实时信息 | pip install google-search-results+SerpAPI 密钥 |
日期查询、名人诞辰、实时数据获取 |
| llm-math | 基于 LLM 实现数学计算(支持复杂公式) | 依赖 LLM(如 GPT-4、通义千问) | 温度换算、次方计算、数据统计 |
| File System Tools | 本地文件读写、目录操作 | 无额外依赖(需文件权限) | 文档加载、结果保存 |
| Python REPL | 执行 Python 代码片段,支持数据处理 | 无额外依赖(需代码执行权限) | 数据分析、公式计算 |
2.2 工具调用示例(SerpAPI+llm-math)
核心工具参考我的另外博文
LangChain 50个核心工具完全指南
https://blog.csdn.net/chenchihwen/article/details/150392604?ops_request_misc=%257B%2522request%255Fid%2522%253A%25228735e3240eecad389915c17acde7c8d4%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=8735e3240eecad389915c17acde7c8d4&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-150392604-null-null.nonecase&utm_term=langchain&spm=1018.2226.3001.4450LangChain Community 50个核心工具
https://blog.csdn.net/chenchihwen/article/details/150391920?ops_request_misc=%257B%2522request%255Fid%2522%253A%25228735e3240eecad389915c17acde7c8d4%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=8735e3240eecad389915c17acde7c8d4&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-3-150391920-null-null.nonecase&utm_term=langchain&spm=1018.2226.3001.4450
需求:查询当前北京温度(华氏度),并计算该温度的 1/4:
from langchain.agents import load_tools, initialize_agent
from langchain_community.llms import Tongyi
import os
import dashscope
# 初始化LLM
api_key = os.environ.get('DASHSCOPE_API_KEY')
dashscope.api_key = api_key
llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key)
# 加载工具(SerpAPI用于搜索温度,llm-math用于计算)
tools = load_tools(["serpapi", "llm-math"], llm=llm)
# 初始化Agent(Zero-Shot ReAct模式,自主决策工具调用)
agent = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True # 打印执行详情
)
# 执行任务
agent.run("当前北京的温度是多少华氏度?这个温度的1/4是多少?")
执行流程:
-
Thought:需先获取北京当前华氏度,再计算 1/4
-
Action:调用 SerpAPI,输入 "当前北京温度 华氏度"
-
Observation:返回温度(如 "77°F")
-
Action:调用 llm-math,输入 "77 / 4"
-
Observation:返回计算结果("19.25")
-
Final Answer:当前北京温度 77°F,其 1/4 为 19.25°F
三、记忆(Memory)机制
3.1 核心作用
解决 LLM "无状态" 问题,通过存储对话历史,让 AI 记住前序交互内容,支持多轮上下文关联(如 "上一个问题中的产品价格是多少?")。
3.2 四种常用 Memory 类型
| Memory 类型 | 功能特点 | 适用场景 |
|---|---|---|
| BufferMemory | 完整存储所有对话历史,无压缩 | 短对话、需完整上下文的场景 |
| BufferWindowMemory | 仅存储最近 K 组对话(如最近 3 轮),减少 token 消耗 | 长对话、仅需近期上下文的场景 |
| ConversationMemory | 对对话历史进行摘要压缩,存储关键信息 | 超长对话、需控制 token 成本的场景 |
| VectorStore-backed Memory | 将对话历史向量化存储,通过相似度匹配召回相关上下文 | 对话历史量大、需精准关联旧内容的场景 |
3.3 Memory 代码示例(ConversationChain)
from langchain.chains import ConversationChain
from langchain_community.llms import Tongyi
import os
import dashscope
# 初始化LLM
api_key = os.environ.get('DASHSCOPE_API_KEY')
dashscope.api_key = api_key
llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key)
# 构建带Memory的对话链
conversation = ConversationChain(llm=llm, verbose=True)
# 多轮对话
output1 = conversation.predict(input="Hi there! I'm Jim.")
print(output1) # 输出:"Hi Jim! It's nice to meet you. How can I help today?"
output2 = conversation.predict(input="Do you remember my name?")
print(output2) # 输出:"Yes, I remember your name is Jim! Is there something specific you'd like to talk about?"
四、核心案例实战
4.1 案例 1:本地知识智能客服(ReAct 范式)
4.1.1 核心目标
基于自有知识库(如特斯拉产品数据),构建能自主调用工具、分步推理的客服系统,回答用户关于产品的问题(如 "Model 3 怎么样?")。
4.1.2 实现步骤
-
定义工具:
-
「查询产品名称」:根据产品名获取描述(如 Model 3 的设计、价格)
-
「公司相关信息」:获取品牌背景(如特斯拉的核心技术)
-
-
设计 ReAct 提示模板:
AGENT_TMPL = """按照以下格式回答: Question: 需回答的问题 Thought: 下一步要做什么 Action: 工具名称(从{tools}中选) Action Input: 工具输入参数 Observation: 工具返回结果(可重复多轮) Thought: 已获取足够信息 Final Answer: 最终答案 Question: {input} {agent_scratchpad} """ -
初始化 Agent 与执行:
from langchain.agents import AgentExecutor, LLMSingleActionAgent from langchain.chains import LLMChain from langchain.prompts import CustomPromptTemplate from langchain.schema import AgentOutputParser # 定义提示模板与解析器 agent_prompt = CustomPromptTemplate(template=AGENT_TMPL, input_variables=["input", "intermediate_steps"]) output_parser = AgentOutputParser() # 解析Agent输出的Action与Input # 构建LLM Chain与Agent llm_chain = LLMChain(llm=llm, prompt=agent_prompt) agent = LLMSingleActionAgent( llm_chain=llm_chain, output_parser=output_parser, allowed_tools=["查询产品名称", "公司相关信息"], stop=["\nObservation:"] ) # 初始化执行器 agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True) # 运行客服问答 agent_executor.run("Model 3怎么样?") -
执行流程:
-
Thought:需先查 Model 3 的产品描述,再查特斯拉公司信息
-
Action:调用「查询产品名称」,Input:"Model 3"
-
Observation:返回 "Model 3 设计简洁,定价 23.19-33.19 万"
-
Action:调用「公司相关信息」,Input:"特斯拉"
-
Observation:返回 "特斯拉专注电动汽车,有驾驶辅助功能"
-
Final Answer:整合结果,输出 Model 3 的详细信息
-
4.2 案例 2:工具链组合设计(多工具串联)
4.2.1 核心目标
通过组合「文本分析」「数据转换」「文本处理」三种工具,解决复杂任务(如情感分析 + 行数统计、CSV 转 JSON)。
4.2.2 工具定义
| 工具名称 | 功能 | 输入参数 | 输出结果 |
|---|---|---|---|
| 文本分析工具(TextAnalysisTool) | 提取文本字数、字符数、情感倾向 | 文本内容 | {"word_count": 34, "sentiment": "positive"} |
| 数据转换工具(DataConversionTool) | 实现 CSV 与 JSON 互转 | 输入数据、输入格式、输出格式 | 转换后的 JSON/CSV 字符串 |
| 文本处理工具(TextProcessingTool) | 统计行数、查找 / 替换文本 | 操作类型(如 count_lines)、文本内容 | {"line_count": 3} |
4.2.3 任务示例(情感分析 + 行数统计)
# 定义工具链(LCEL风格)
from langchain.schema.runnable import RunnableLambda
# 初始化工具实例
text_analysis = TextAnalysisTool()
text_processing = TextProcessingTool()
# 构建工具链(先分析情感,再统计行数)
tools_chain = {
"analysis": RunnableLambda(lambda x: text_analysis.run(x["text"])),
"line_count": RunnableLambda(lambda x: text_processing.run("count_lines", x["text"]))
}
# 执行任务
text = "这个产品非常好用,我很喜欢它的设计!\n价格合理,推荐购买。"
result = tools_chain.invoke({"text": text})
print(result)
# 输出:{"analysis": {"sentiment": "positive"}, "line_count": {"line_count": 2}}
4.3 案例 3:网络故障诊断 Agent
4.3.1 核心目标
构建能自主串联工具、分步诊断网络问题的 Agent(如 "无法访问www.example.com"),支持工具输出作为下一个工具的输入。
4.3.2 核心工具与串联逻辑
| 工具名称 | 功能 | 输入 | 输出(供下一个工具使用) |
|---|---|---|---|
| DNS 解析工具(DNSTool) | 将域名解析为 IP | 域名(如www.example.com) | IP 地址(如 93.184.216.34) |
| 网络连通性工具(PingTool) | 检查 IP 连通性与延迟 | IP 地址 | 连通状态(成功 / 超时)、延迟 |
| 本地接口检查工具(InterfaceCheckTool) | 检查本地网络配置 | 接口名称(可选) | 接口状态、IP / 子网掩码 |
| 日志分析工具(LogAnalysisTool) | 搜索网络错误日志 | 关键词(如 timeout)、时间范围 | 匹配的错误日志条目 |
4.3.3 诊断流程示例
-
用户问题:"无法访问www.example.com"
-
Agent 推理:
-
Thought:需先解析域名 IP,再检查连通性
-
Action1:DNS 解析工具,Input:www.example.com → Observation:IP=93.184.216.34
-
Action2:Ping 工具,Input:93.184.216.34 → Observation:连接超时
-
Action3:本地接口检查工具 → Observation:接口正常
-
Action4:日志分析工具,Input:关键词 timeout → Observation:发现路由错误日志
-
-
Final Answer:诊断为 "路由问题或目标服务器不可用",建议检查路由配置
五、LCEL(LangChain Expression Language)
5.1 核心定位
LCEL 是 LangChain 推出的链式表达式语言,通过|(管道符)实现组件间的数据流传递,支持灵活的任务编排(串联、分支、并行)。
5.2 核心优势
-
简洁性:用
A | B | C表示 "A 的输出作为 B 的输入,B 的输出作为 C 的输入",代码逻辑清晰 -
灵活性:支持分支(
{"x": A, "y": B})、条件判断、并行执行 -
可调试性:每个组件可单独测试,便于定位问题
5.3 典型用法示例
5.3.1 多步串联(翻译→分析→回译)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# 定义子任务
translate_to_en = ChatPromptTemplate.from_template("Translate to English: {input}") | llm | StrOutputParser()
process_text = ChatPromptTemplate.from_template("Analyze sentiment: {text}") | llm | StrOutputParser()
translate_to_cn = ChatPromptTemplate.from_template("Translate to Chinese: {output}") | llm | StrOutputParser()
# 组合任务链
workflow = {"text": translate_to_en} | process_text | translate_to_cn
# 执行(流式输出)
for chunk in workflow.stream({"input": "北京有哪些好吃的地方,简略回答不超过200字"}):
print(chunk, end="", flush=True)
5.3.2 条件分支(根据文本长度选择处理方式)
def lcel_conditional_chain(text):
# 定义工具
text_analysis_chain = ChatPromptTemplate.from_template("Analyze: {text}") | llm | StrOutputParser()
line_count_chain = ChatPromptTemplate.from_template("Count lines: {text}") | llm | StrOutputParser()
# 条件判断:文本长度>20则分析,否则统计行数
if len(text) > 20:
return text_analysis_chain.invoke({"text": text})
else:
return line_count_chain.invoke({"text": text})
# 测试
print(lcel_conditional_chain("短文本")) # 输出:行数统计结果
print(lcel_conditional_chain("这是一段超过20个字符的长文本,用于测试情感分析功能")) # 输出:情感分析结果
六、AI Agent 工具对比
6.1 主流 Agent 工具核心差异
| 工具 | 核心定位 | 架构特点 | 适用场景 | 优势 | 局限性 |
|---|---|---|---|---|---|
| LangChain | 开源 LLM 应用开发框架 | 基于 Chain 的线性 / 分支工作流,支持 Agent 模式 | 快速构建 RAG、对话系统、简单工具调用 | 组件丰富、文档完善、生态成熟 | 复杂流程(循环 / 多 Agent 协作)支持较弱 |
| LangGraph | LangChain 扩展,专注复杂工作流 | 基于图(Graph)的循环、条件逻辑,支持多 Agent 协作 | 自适应 RAG、多轮决策、多 Agent 系统 | 动态流程调整、状态管理强 | 学习成本高,需理解图结构 |
| Qwen-Agent | 通义千问 AI Agent 框架 | 基于阿里云大模型,支持多模态、MCP 调用 | 开源项目、多模态交互、工具集成 | 与通义千问深度适配、支持三级索引 | 生态相对较小,依赖阿里云资源 |
| Coze | 字节跳动无代码 AI Bot 平台 | 可视化拖拽界面,内置知识库、多模态插件 | 快速部署社交机器人、轻量级工作流 | 无代码 / 低代码、部署便捷 | 灵活性低,定制化能力弱 |
| Dify | 开源 LLM 应用开发平台 | API 优先,支持 Prompt 工程、灵活编排 | 企业私有化部署、定制化 LLM 应用 | 开源可控、支持深度集成 | 需开发者具备一定编码能力 |
6.2 选择建议
-
无代码开发:优先 Coze(可视化界面,快速出成果)
-
快速原型(线性任务):LangChain(组件丰富,开发效率高)
-
复杂系统(多 Agent / 循环流程):LangGraph(图结构支持动态逻辑)
-
企业私有化部署:Dify(开源可控)或 Qwen-Agent(适配国产大模型)
七、总结
LangChain 作为 LLM 应用开发的核心框架,通过 "组件化 + 流程化" 的设计,降低了 AI 应用的开发门槛。其核心价值在于:
-
工具集成:无缝对接搜索、计算、文件操作等外部能力,扩展 LLM 边界;
-
流程编排:通过 Chain(固定流程)和 Agent(自主决策),支持从简单到复杂的任务;
-
生态丰富:支持多模型(GPT、通义千问等)、多记忆类型、多部署方式,适配不同场景需求。
无论是构建本地知识库客服、网络故障诊断系统,还是复杂的多工具任务链,LangChain 都能提供灵活的解决方案,是当前 AI 应用开发的核心工具之一。
smple python
CASE-LangChain使用 product_llm.py
import re
from typing import List, Union
# Python内置模块,用于格式化和包装文本
import textwrap
import time
from langchain.agents import (
Tool, # 可用工具
AgentExecutor, # Agent执行
LLMSingleActionAgent, # 定义Agent
AgentOutputParser, # 输出结果解析
)
from langchain.prompts import StringPromptTemplate
# LLMChain,包含一个PromptTemplate和一个LLM
from langchain_community.llms import Tongyi # 导入通义千问Tongyi模型
from langchain import LLMChain
# Agent执行,Agent结束
from langchain.schema import AgentAction, AgentFinish
# PromptTemplate: 管理LLMs的Prompts
from langchain.prompts import PromptTemplate
from langchain.llms.base import BaseLLM
# 定义了LLM的Prompt Template
CONTEXT_QA_TMPL = """
根据以下提供的信息,回答用户的问题
信息:{context}
问题:{query}
"""
CONTEXT_QA_PROMPT = PromptTemplate(
input_variables=["query", "context"],
template=CONTEXT_QA_TMPL,
)
# 输出结果显示,每行最多60字符,每个字符显示停留0.1秒(动态显示效果)
def output_response(response: str) -> None:
if not response:
exit(0)
# 每行最多60个字符
for line in textwrap.wrap(response, width=60):
for word in line.split():
for char in word:
print(char, end="", flush=True)
time.sleep(0.1) # Add a delay of 0.1 seconds between each character
print(" ", end="", flush=True) # Add a space between each word
print() # Move to the next line after each line is printed
# 遇到这里,这个问题的回答就结束了
print("----------------------------------------------------------------")
# 模拟公司产品和公司介绍的数据源
class TeslaDataSource:
def __init__(self, llm: BaseLLM):
self.llm = llm
# 工具1:产品描述
def find_product_description(self, product_name: str) -> str:
"""模拟公司产品的数据库"""
product_info = {
"Model 3": "具有简洁、动感的外观设计,流线型车身和现代化前脸。定价23.19-33.19万",
"Model Y": "在外观上与Model 3相似,但采用了更高的车身和更大的后备箱空间。定价26.39-36.39万",
"Model X": "拥有独特的翅子门设计和更加大胆的外观风格。定价89.89-105.89万",
}
# 基于产品名称 => 产品描述
return product_info.get(product_name, "没有找到这个产品")
# 工具2:公司介绍
def find_company_info(self, query: str) -> str:
"""模拟公司介绍文档数据库,让llm根据信息回答问题"""
context = """
特斯拉最知名的产品是电动汽车,其中包括Model S、Model 3、Model X和Model Y等多款车型。
特斯拉以其技术创新、高性能和领先的自动驾驶技术而闻名。公司不断推动自动驾驶技术的研发,并在车辆中引入了各种驾驶辅助功能,如自动紧急制动、自适应巡航控制和车道保持辅助等。
"""
# prompt模板 = 上下文context + 用户的query
prompt = CONTEXT_QA_PROMPT.format(query=query, context=context)
# 使用LLM进行推理
return self.llm(prompt)
AGENT_TMPL = """按照给定的格式回答以下问题。你可以使用下面这些工具:
{tools}
回答时需要遵循以下用---括起来的格式:
---
Question: 我需要回答的问题
Thought: 回答这个上述我需要做些什么
Action: "{tool_names}" 中的一个工具名
Action Input: 选择这个工具所需要的输入
Observation: 选择这个工具返回的结果
...(这个 思考/行动/行动输入/观察 可以重复N次)
Thought: 我现在知道最终答案
Final Answer: 原始输入问题的最终答案
---
现在开始回答,记得在给出最终答案前,需要按照指定格式进行一步一步的推理。
Question: {input}
{agent_scratchpad}
"""
class CustomPromptTemplate(StringPromptTemplate):
template: str # 标准模板
tools: List[Tool] # 可使用工具集合
def format(self, **kwargs) -> str:
"""
按照定义的 template,将需要的值都填写进去。
Returns:
str: 填充好后的 template。
"""
# 取出中间步骤并进行执行
intermediate_steps = kwargs.pop("intermediate_steps")
print('intermediate_steps=', intermediate_steps)
print('='*30)
thoughts = ""
for action, observation in intermediate_steps:
thoughts += action.log
thoughts += f"\nObservation: {observation}\nThought: "
# 记录下当前想法 => 赋值给agent_scratchpad
kwargs["agent_scratchpad"] = thoughts
# 枚举所有可使用的工具名+工具描述
kwargs["tools"] = "\n".join(
[f"{tool.name}: {tool.description}" for tool in self.tools]
)
# 枚举所有的工具名称
kwargs["tool_names"] = ", ".join(
[tool.name for tool in self.tools]
)
cur_prompt = self.template.format(**kwargs)
#print(cur_prompt)
return cur_prompt
"""
对Agent返回结果进行解析,有两种可能:
1)还在思考中 AgentAction
2)找到了答案 AgentFinal
"""
class CustomOutputParser(AgentOutputParser):
def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
"""
解析 llm 的输出,根据输出文本找到需要执行的决策。
Args:
llm_output (str): _description_
Raises:
ValueError: _description_
Returns:
Union[AgentAction, AgentFinish]: _description_
"""
# 如果句子中包含 Final Answer 则代表已经完成
if "Final Answer:" in llm_output:
return AgentFinish(
return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
log=llm_output,
)
# 需要进行 AgentAction
regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)" # 解析 action_input 和 action
match = re.search(regex, llm_output, re.DOTALL)
if not match:
raise ValueError(f"Could not parse LLM output: `{llm_output}`")
action = match.group(1).strip()
action_input = match.group(2)
# Agent执行
return AgentAction(
tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output
)
if __name__ == "__main__":
# 定义LLM
llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=DASHSCOPE_API_KEY) # 使用通义千问qwen-turbo模型
# 自有数据
tesla_data_source = TeslaDataSource(llm)
# 定义的Tools
tools = [
Tool(
name="查询产品名称",
func=tesla_data_source.find_product_description,
description="通过产品名称找到产品描述时用的工具,输入的是产品名称",
),
Tool(
name="公司相关信息",
func=tesla_data_source.find_company_info,
description="当用户询问公司相关的问题,可以通过这个工具了解公司信息",
),
]
# 用户定义的模板
agent_prompt = CustomPromptTemplate(
template=AGENT_TMPL,
tools=tools,
input_variables=["input", "intermediate_steps"],
)
# Agent返回结果解析
output_parser = CustomOutputParser()
# 最常用的Chain, 由LLM + PromptTemplate组成
llm_chain = LLMChain(llm=llm, prompt=agent_prompt)
# 定义的工具名称
tool_names = [tool.name for tool in tools]
# 定义Agent = llm_chain + output_parser + tools_names
agent = LLMSingleActionAgent(
llm_chain=llm_chain,
output_parser=output_parser,
stop=["\nObservation:"],
allowed_tools=tool_names,
)
# 定义Agent执行器 = Agent + Tools
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent, tools=tools, verbose=True
)
# 主过程:可以一直提问下去,直到Ctrl+C
while True:
try:
user_input = input("请输入您的问题:")
response = agent_executor.run(user_input)
output_response(response)
except KeyboardInterrupt:
break
代码说明
代码逻辑详解
product_llm.py 文件实现了一个基于 LangChain 的智能问答系统,专门用于回答关于特斯拉产品和公司信息的问题。下面是详细的代码逻辑分析:
1. 导入模块和依赖
这部分导入了构建 Agent 所需的各种组件,包括:
-
正则表达式模块用于解析 LLM 输出
-
LangChain 的核心组件:工具、Agent 执行器、Agent 类等
-
通义千问模型接口
-
提示模板相关类
import re from typing import List, Union import textwrap import time from langchain.agents import ( Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser, ) from langchain.prompts import StringPromptTemplate from langchain_community.llms import Tongyi from langchain import LLMChain from langchain.schema import AgentAction, AgentFinish from langchain.prompts import PromptTemplate from langchain.llms.base import BaseLLM
2. 上下文问答模板定义
定义了一个用于基于上下文回答问题的提示模板,将在公司信息查询工具中使用。
CONTEXT_QA_TMPL = """
根据以下提供的信息,回答用户的问题
信息:{context}
问题:{query}
"""
CONTEXT_QA_PROMPT = PromptTemplate(
input_variables=["query", "context"],
template=CONTEXT_QA_TMPL,
)
3. 输出显示函数
这个函数用于以动态打字效果显示回答结果,增强用户体验。
def output_response(response: str) -> None:
if not response:
exit(0)
# 每行最多60个字符
for line in textwrap.wrap(response, width=60):
for word in line.split():
for char in word:
print(char, end="", flush=True)
time.sleep(0.1)
print(" ", end="", flush=True)
print()
print("----------------------------------------------------------------")
4. 数据源类 TeslaDataSource
TeslaDataSource 类模拟了一个特斯拉产品和公司信息的数据库:
-
find_product_description 方法:根据产品名称返回产品描述信息
-
find_company_info 方法:基于公司背景信息和用户问题,使用 LLM 生成回答
class TeslaDataSource:
def __init__(self, llm: BaseLLM):
self.llm = llm
# 工具1:产品描述
def find_product_description(self, product_name: str) -> str:
"""模拟公司产品的数据库"""
product_info = {
"Model 3": "具有简洁、动感的外观设计,流线型车身和现代化前脸。定价23.19-33.19万",
"Model Y": "在外观上与Model 3相似,但采用了更高的车身和更大的后备箱空间。定价26.39-36.39万",
"Model X": "拥有独特的翅子门设计和更加大胆的外观风格。定价89.89-105.89万",
}
# 基于产品名称 => 产品描述
return product_info.get(product_name, "没有找到这个产品")
# 工具2:公司介绍
def find_company_info(self, query: str) -> str:
"""模拟公司介绍文档数据库,让llm根据信息回答问题"""
context = """
特斯拉最知名的产品是电动汽车,其中包括Model S、Model 3、Model X和Model Y等多款车型。
特斯拉以其技术创新、高性能和领先的自动驾驶技术而闻名。公司不断推动自动驾驶技术的研发,并在车辆中引入了各种驾驶辅助功能,如自动紧急制动、自适应巡航控制和车道保持辅助等。
"""
# prompt模板 = 上下文context + 用户的query
prompt = CONTEXT_QA_PROMPT.format(query=query, context=context)
# 使用LLM进行推理
return self.llm(prompt)
5. Agent 模板定义
定义了 Agent 的提示模板,指导 LLM 如何按照 ReAct(Reasoning and Action)模式进行思考和行动。
AGENT_TMPL = """按照给定的格式回答以下问题。你可以使用下面这些工具:
{tools}
回答时需要遵循以下用---括起来的格式:
---
Question: 我需要回答的问题
Thought: 回答这个上述我需要做些什么
Action: "{tool_names}" 中的一个工具名
Action Input: 选择这个工具所需要的输入
Observation: 选择这个工具返回的结果
...(这个 思考/行动/行动输入/观察 可以重复N次)
Thought: 我现在知道最终答案
Final Answer: 原始输入问题的最终答案
---
现在开始回答,记得在给出最终答案前,需要按照指定格式进行一步一步的推理。
Question: {input}
{agent_scratchpad}
"""
6. 自定义提示模板类
CustomPromptTemplate 类用于动态生成提示模板,将工具信息和中间步骤填充到模板中。
class CustomPromptTemplate(StringPromptTemplate):
template: str # 标准模板
tools: List[Tool] # 可使用工具集合
def format(self, **kwargs) -> str:
"""
按照定义的 template,将需要的值都填写进去。
Returns:
str: 填充好后的 template。
"""
# 取出中间步骤并进行执行
intermediate_steps = kwargs.pop("intermediate_steps")
print('intermediate_steps=', intermediate_steps)
print('='*30)
thoughts = ""
for action, observation in intermediate_steps:
thoughts += action.log
thoughts += f"\nObservation: {observation}\nThought: "
# 记录下当前想法 => 赋值给agent_scratchpad
kwargs["agent_scratchpad"] = thoughts
# 枚举所有可使用的工具名+工具描述
kwargs["tools"] = "\n".join(
[f"{tool.name}: {tool.description}" for tool in self.tools]
)
# 枚举所有的工具名称
kwargs["tool_names"] = ", ".join(
[tool.name for tool in self.tools]
)
cur_prompt = self.template.format(**kwargs)
#print(cur_prompt)
return cur_prompt
7. 自定义输出解析器
CustomOutputParser 类用于解析 LLM 的输出,判断是继续执行工具还是返回最终答案。
class CustomOutputParser(AgentOutputParser):
def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
"""
解析 llm 的输出,根据输出文本找到需要执行的决策。
"""
# 如果句子中包含 Final Answer 则代表已经完成
if "Final Answer:" in llm_output:
return AgentFinish(
return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
log=llm_output,
)
# 需要进行 AgentAction
regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)" # 解析 action_input 和 action
match = re.search(regex, llm_output, re.DOTALL)
if not match:
raise ValueError(f"Could not parse LLM output: `{llm_output}`")
action = match.group(1).strip()
action_input = match.group(2)
# Agent执行
return AgentAction(
tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output
)
8. 主程序逻辑
主程序逻辑包括以下步骤:
-
初始化通义千问 LLM 模型
-
创建 TeslaDataSource 实例
-
定义两个工具:产品查询工具和公司信息查询工具
-
创建自定义提示模板和输出解析器
-
构建 LLMChain
-
创建 LLMSingleActionAgent
-
创建 AgentExecutor 来执行 Agent 和工具
-
进入循环,接收用户输入并执行 Agent
if __name__ == "__main__":
# 定义LLM
llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=DASHSCOPE_API_KEY)
# 自有数据
tesla_data_source = TeslaDataSource(llm)
# 定义的Tools
tools = [
Tool(
name="查询产品名称",
func=tesla_data_source.find_product_description,
description="通过产品名称找到产品描述时用的工具,输入的是产品名称",
),
Tool(
name="公司相关信息",
func=tesla_data_source.find_company_info,
description="当用户询问公司相关的问题,可以通过这个工具了解公司信息",
),
]
# 用户定义的模板
agent_prompt = CustomPromptTemplate(
template=AGENT_TMPL,
tools=tools,
input_variables=["input", "intermediate_steps"],
)
# Agent返回结果解析
output_parser = CustomOutputParser()
# 最常用的Chain, 由LLM + PromptTemplate组成
llm_chain = LLMChain(llm=llm, prompt=agent_prompt)
# 定义的工具名称
tool_names = [tool.name for tool in tools]
# 定义Agent = llm_chain + output_parser + tools_names
agent = LLMSingleActionAgent(
llm_chain=llm_chain,
output_parser=output_parser,
stop=["\nObservation:"],
allowed_tools=tool_names,
)
# 定义Agent执行器 = Agent + Tools
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent, tools=tools, verbose=True
)
# 主过程:可以一直提问下去,直到Ctrl+C
while True:
try:
user_input = input("请输入您的问题:")
response = agent_executor.run(user_input)
output_response(response)
except KeyboardInterrupt:
break
工作流程总结
-
用户输入问题(如"Model 3怎么样?")
-
Agent 使用自定义提示模板生成提示,包含可用工具信息
-
LLM 根据提示决定采取什么行动
-
如果需要查询产品信息,Agent 会调用 find_product_description 工具
-
如果需要查询公司信息,Agent 会调用 find_company_info 工具
-
工具返回结果后,Agent 将结果作为观察信息,继续决定下一步行动
-
当收集到足够信息后,Agent 生成最终答案
-
最终答案通过动态显示函数呈现给用户
这个系统展示了如何使用 LangChain 构建一个基于 ReAct 模式的智能问答 Agent,能够根据用户问题自主决定调用哪些工具来获取信息,并最终生成答案。
更多推荐
所有评论(0)