Agent与chain的调用工具的区别
普通chain和 Agent 调用工具的核心区别
| 对比维度 | 普通 Chain 调工具 | Agent 调工具 |
|---|---|---|
| 决策权 | 人提前写死调用时机、顺序和次数 | 大模型自主决定是否调用、调用哪个、调用几次 |
| 执行流程 | 线性固定,一次走完 | 「思考→调用工具→再思考」的多轮循环 |
| 适用场景 | 流程固定的任务(如 RAG、标准化数据处理) | 复杂、不确定的任务(如自由数据分析、问题排查) |
简单总结:Chain 是「你安排好工具怎么用」,Agent 是「告诉模型有这些工具,它自己按需使用」。
普通 Chain(提示词模板):
-
普通 Chain:写好模板占位符,手动填参数,按固定流程执行
##LCEL表达式
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
# 定义对话模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个中国历史专家,回答简洁明了"),
("user", "{input}")
])
# StrOutputParser 把 AIMessage 转成纯字符串
parser = StrOutputParser()
# 三段式链:Prompt → LLM → Parser
chain = prompt | llm | parser
result = chain.invoke({"input": "秦始皇统一六国的顺序是什么?"})
print(result)
#加了parser这个输出解析器之后,链的输出就是纯字符串,不需要 .content即可打印
这种方法需要把用户问题传入提示词,一并发送给大模型,做出解答。
-
普通 Chain 的本质:固定执行流水线
Chain 是「写死步骤的执行管道」:输入 → 提示词模板 → LLM → 输出,全程流程线性固定。大模型不会自己决定「要不要调用工具、调用哪个工具、传什么参数、调用几次」,所有调用逻辑都由你提前编排好。 最典型的例子就是 RAG 检索链:检索工具是提前固定在流程里的,每次提问都会走检索步骤,模型没有选择权。
-
普通Chain 调用工具的两种常见方式
- 手动串联工具步骤(硬编码) 你可以用
RunnableLambda把工具函数插进 Chain 里,提前规定好「第几步调用工具」。大模型只负责生成工具参数,不负责决策是否调用。 比如你可以设计固定流程:先让 LLM 从用户问题里提取年份参数 → 自动调用时间计算工具 → 把计算结果塞回提示词 → LLM 整理成最终答案。整个链路是你设计好的,模型没有选择权。 - 单次工具调用链(bind_tools) LangChain 支持给 LLM 直接用
bind_tools绑定工具,让模型输出工具调用参数。但它只会输出一次调用指令,不会像 Agent 一样形成「调用工具 → 拿到结果 → 再推理 → 再调用」的多轮循环,也不会自己判断是否需要多次调用工具。
Agent调用工具:
Agent 的核心特点:
你只需要定义「有什么工具、工具能干什么」,以及「给模型设定角色和规则」;至于什么时候调用工具、用哪个工具、参数填什么,全部由大模型自主决策,Agent 框架负责执行调度
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
import requests
# ─── 第一步:定义工具 ───
@tool
def get_weather(location: str) -> str:
"""查询指定城市的天气"""
url = f"https://wttr.in/{location}?format=j1&lang=zh"
data = requests.get(url).json()
current = data['current_condition'][0]
desc = current['weatherDesc'][0]['value']
temp = current['temp_C']
return f"{location}:{desc},{temp}°C"
tools = [get_weather]
# ─── 第二步:配置大模型 ───
# ─── 第三步:创建 Agent ───
# create_agent 把模型、工具、prompt 组装成 Agent
agent = create_agent(
model=llm,
tools=tools,
system_prompt="你是一名智能助手,可以调用工具帮助用户解决问题。"
)
# ─── 第四步:使用 ───
res = agent.invoke({"messages": [
{"role": "user",
"content": "成都的天气怎么样?"
}]})
print(res['messages'][-1].content)
print(res)
举例:为什么在这个Agent的提示词中没有用户输入的占位符?沙箱函数的入参code也找不到?
import traceback
from io import StringIO
from contextlib import redirect_stdout
from langchain.tools import tool
# ============================================================
# 定义沙箱的"白名单"——只有这些库和数据可以被代码访问
# ============================================================
#环境初始化——初始化上下文(传入必要的变量:三张表)和权限控制(限制沙箱能访问的模块/函数)
SANDBOX_GLOBALS = {
# 数据:Agent 可以分析这三张表
"employees_df": employees_df,
"products_df": products_df,
"orders_df": orders_df,
# 工具库:Agent 可以用这些库做分析和画图
"pd": pd, # pandas — 数据处理
"plt": plt, # matplotlib — 基础绑图
"sns": sns, # seaborn — 统计可视化
"np": np, # numpy — 数值计算
}
##定义函数
@tool
def execute_python_code(code: str) -> str:
"""
执行 Python 代码进行数据分析和可视化。
可用变量:
- employees_df: 员工表 DataFrame(字段:id, name, department, salary, hire_date)
- products_df: 产品表 DataFrame(字段:id, product_name, category, price, stock)
- orders_df: 订单表 DataFrame(字段:id, employee_id, product_id, quantity, order_date)
- pd: pandas 库
- plt: matplotlib.pyplot
- sns: seaborn
- np: numpy
使用示例:
# 统计各部门平均薪资
result = employees_df.groupby('department')['salary'].mean()
print(result)
# 画柱状图
plt.figure(figsize=(10, 6))
employees_df.groupby('department')['salary'].mean().plot(kind='bar')
plt.title('各部门平均薪资')
plt.show()
"""
# 准备隔离的执行环境
# globals_dict 提供白名单变量,locals_dict 收集执行过程中产生的新变量
exec_globals = dict(SANDBOX_GLOBALS)
exec_locals = {}
output_buffer = StringIO()#output_buffer是io.StringIO的实例
##代码执行器——代码执行
try:
with redirect_stdout(output_buffer):
exec(code, exec_globals, exec_locals)
result = output_buffer.getvalue()#output_buffer.getvalue()会返回缓冲区中存储的所有文本内容。
# 如果代码没有 print 任何东西,给个默认提示
if not result.strip():
result = "✅ 代码执行成功(无文本输出,可能已生成图表)"
return f"执行成功:\n{result}"
#安全防护——异常捕获
except Exception as e:
# 出错时返回完整的错误堆栈,方便 Agent 自我修正
error_detail = traceback.format_exc()
return f"❌ 执行出错:{e}\n\n{error_detail}"
print("✅ Python 代码执行沙箱创建成功")
##搭建可视化 Agent
from langchain.agents import create_agent
# ============================================================
# 定义可视化 Agent 的 System Prompt
# ============================================================
VISUALIZATION_PROMPT = """你是一名资深数据分析师,精通 Python、Pandas 和 Matplotlib 数据可视化。
## 可用数据
1. employees_df — 员工表(字段:id, name, department, salary, hire_date)
2. products_df — 产品表(字段:id, product_name, category, price, stock)
3. orders_df — 订单表(字段:id, employee_id, product_id, quantity, order_date)
## 工作流程
1. 理解用户的分析需求
2. 用 execute_python_code 工具编写并执行 Python 代码
3. 先做数据探索(head、describe、info),再做深入分析
4. 用中文解释分析结果,给出业务洞察
## 代码规范
- 绑图前设置中文字体:plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC', 'DejaVu Sans']
- 设置 plt.rcParams['axes.unicode_minus'] = False
- 图表尺寸统一用 plt.figure(figsize=(10, 6))
- 必须添加标题、坐标轴标签,让图表自解释
- 用 print() 输出关键统计量,不要只画图不说话
- 图表标题用英文(避免渲染问题),但用中文向用户解释结果
## 注意事项
- 每次只执行一段完整的代码,不要拆成多段
- 先探索数据结构,再做分析——不要上来就画图
- 结果要有业务洞察,不只是"最大值是 XXX"
"""
# ============================================================
# 组装可视化 Agent(langchain 1.3.1 写法)
# ============================================================
#将工具函数存入列表,供LangChain Agent调用
viz_tools = [execute_python_code]
# 同样用 create_agent 一行搞定,和 SQL Agent 的创建方式完全一致
visualization_agent = create_agent(
model=llm,
tools=viz_tools,
system_prompt=VISUALIZATION_PROMPT,
)
print("数据可视化 Agent 创建完成")
一、核心结论
code 参数不是手动传入的,也不需要在提示词里写占位符 —— 它是由大模型(LLM)在推理过程中自动生成的,再由 Agent 框架自动传给 execute_python_code 函数。
二、逐层拆解:code 到底从哪来
1. @tool 装饰器做了什么?
你写的 @tool 不只是个装饰,它会自动完成两件事:
- 把
execute_python_code函数包装成 LangChain 标准的Tool对象 - 自动提取函数名、参数列表、docstring(函数说明),生成一段「工具说明书」
这段说明书会和你的系统提示词一起,在调用时塞给大模型。相当于告诉 LLM:
你现在有一个工具叫
execute_python_code,它接收一个字符串类型的参数code,作用是执行 Python 数据分析代码;可用的变量有 employees_df、pd、plt 等。
大模型看到这份说明书,就知道调用这个工具时,必须生成一个叫 code 的字符串参数。
2. 大模型如何生成 code?
当你调用 Agent 时,比如:
visualization_agent.invoke("帮我统计各部门的平均薪资")
LangChain 会在后台把这些内容一起发给 LLM:
- 你的
VISUALIZATION_PROMPT系统提示(角色、数据字段、工作流程、代码规范) - 用户的问题:
"帮我统计各部门的平均薪资" - 工具列表的「说明书」(包含 execute_python_code 的参数要求)
LLM 会按照 ReAct 思考逻辑推理:
- 用户要统计各部门平均薪资
- 我需要用 execute_python_code 工具来执行 pandas 代码
- 已知 employees_df 有 department 和 salary 字段
- 生成对应代码:
result = employees_df.groupby('department')['salary'].mean() print(result) - 按照工具调用格式,把这段代码作为
code参数的值,输出给 Agent 框架
简单说:code 是 LLM 根据用户问题 + 数据字段 + 工具规则,自己「写」出来的。
三、完整调用链路:一次提问的完整旅程
我把你这段代码的完整执行流程串起来,你就彻底懂了:
-
用户发起提问
visualization_agent.invoke("分析各部门平均薪资并画柱状图") -
Agent 组装上下文,发给 LLM 框架自动把「系统提示 + 用户问题 + 工具说明」拼成对话,发给大模型。
注意:你的系统提示词里不需要写
{user_input}占位符 —— 用户问题是作为「用户消息」单独传入的,系统提示是固定的角色规则,二者由框架自动拼接,不需要你手动写模板变量。 -
LLM 推理并生成工具调用 LLM 输出结构化的工具调用指令,大概长这样(不同模型格式略有区别):
工具名称:execute_python_code 工具参数:{ "code": "plt.figure(figsize=(10, 6))\nemployees_df.groupby('department')['salary'].mean().plot(kind='bar')\n..." } -
Agent 框架执行工具 框架解析 LLM 的输出,自动调用:
execute_python_code(code="LLM生成的那段代码字符串")函数内部用
exec()在沙箱环境里运行代码,捕获输出和异常,返回结果。 -
结果回传 LLM,生成最终回答 工具执行结果(比如统计数值、图表生成成功提示)会被框架塞回对话里,再发给 LLM。 LLM 基于执行结果,用中文整理成业务洞察,返回给你。
四、补充:为什么提示词里没有用户输入占位符?
这是 LangChain create_agent 封装后的结果:
- 底层的 Agent 模板里其实已经内置了用户输入、工具描述、思考过程的占位符
- 你写的
VISUALIZATION_PROMPT只是系统角色提示(System Prompt),负责设定身份、规则、数据说明 - 用户的问题在你调用
.invoke()时传入,框架会自动把它放到对话的「用户消息」位置,不需要你手动写{question}
如果你用的是普通的 PromptTemplate + Chain,才需要自己写占位符;而 Agent 是更高层的封装,把输入输出、工具调度、多轮思考都帮你做了。
更多推荐



所有评论(0)