ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Agent与chain的调用工具的区别

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 调用工具的两种常见方式

  1. 手动串联工具步骤(硬编码)你可以用RunnableLambda把工具函数插进 Chain 里,提前规定好「第几步调用工具」。大模型只负责生成工具参数,不负责决策是否调用。 比如你可以设计固定流程:先让 LLM 从用户问题里提取年份参数 → 自动调用时间计算工具 → 把计算结果塞回提示词 → LLM 整理成最终答案。整个链路是你设计好的,模型没有选择权。
  2. 单次工具调用链(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 思考逻辑推理:

  1. 用户要统计各部门平均薪资
  2. 我需要用 execute_python_code 工具来执行 pandas 代码
  3. 已知 employees_df 有 department 和 salary 字段
  4. 生成对应代码:
    result = employees_df.groupby('department')['salary'].mean() print(result)
  5. 按照工具调用格式,把这段代码作为code参数的值,输出给 Agent 框架

简单说:code 是 LLM 根据用户问题 + 数据字段 + 工具规则,自己「写」出来的

三、完整调用链路:一次提问的完整旅程

我把你这段代码的完整执行流程串起来,你就彻底懂了:

  1. 用户发起提问

    visualization_agent.invoke("分析各部门平均薪资并画柱状图")
  2. Agent 组装上下文,发给 LLM框架自动把「系统提示 + 用户问题 + 工具说明」拼成对话,发给大模型。

    注意:你的系统提示词里不需要写{user_input}占位符 —— 用户问题是作为「用户消息」单独传入的,系统提示是固定的角色规则,二者由框架自动拼接,不需要你手动写模板变量。

  3. LLM 推理并生成工具调用LLM 输出结构化的工具调用指令,大概长这样(不同模型格式略有区别):

    工具名称:execute_python_code 工具参数:{ "code": "plt.figure(figsize=(10, 6))\nemployees_df.groupby('department')['salary'].mean().plot(kind='bar')\n..." }
  4. Agent 框架执行工具框架解析 LLM 的输出,自动调用:

    execute_python_code(code="LLM生成的那段代码字符串")

    函数内部用exec()在沙箱环境里运行代码,捕获输出和异常,返回结果。

  5. 结果回传 LLM,生成最终回答工具执行结果(比如统计数值、图表生成成功提示)会被框架塞回对话里,再发给 LLM。 LLM 基于执行结果,用中文整理成业务洞察,返回给你。


四、补充:为什么提示词里没有用户输入占位符?

这是 LangChaincreate_agent封装后的结果:

  • 底层的 Agent 模板里其实已经内置了用户输入、工具描述、思考过程的占位符
  • 你写的VISUALIZATION_PROMPT只是系统角色提示(System Prompt),负责设定身份、规则、数据说明
  • 用户的问题在你调用.invoke()时传入,框架会自动把它放到对话的「用户消息」位置,不需要你手动写{question}

如果你用的是普通的PromptTemplate + Chain,才需要自己写占位符;而 Agent 是更高层的封装,把输入输出、工具调度、多轮思考都帮你做了。

返回列表