普通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_toolsLangChain 支持给 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 fhttps://wttr.in/{location}?formatj1langzh 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( modelllm, toolstools, 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(kindbar) 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 # # 组装可视化 Agentlangchain 1.3.1 写法 # #将工具函数存入列表供LangChain Agent调用 viz_tools [execute_python_code] # 同样用 create_agent 一行搞定和 SQL Agent 的创建方式完全一致 visualization_agent create_agent( modelllm, toolsviz_tools, system_promptVISUALIZATION_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(kindbar)\n... }Agent 框架执行工具框架解析 LLM 的输出自动调用execute_python_code(codeLLM生成的那段代码字符串)函数内部用exec()在沙箱环境里运行代码捕获输出和异常返回结果。结果回传 LLM生成最终回答工具执行结果比如统计数值、图表生成成功提示会被框架塞回对话里再发给 LLM。 LLM 基于执行结果用中文整理成业务洞察返回给你。四、补充为什么提示词里没有用户输入占位符这是 LangChaincreate_agent封装后的结果底层的 Agent 模板里其实已经内置了用户输入、工具描述、思考过程的占位符你写的VISUALIZATION_PROMPT只是系统角色提示System Prompt负责设定身份、规则、数据说明用户的问题在你调用.invoke()时传入框架会自动把它放到对话的「用户消息」位置不需要你手动写{question}如果你用的是普通的PromptTemplate Chain才需要自己写占位符而 Agent 是更高层的封装把输入输出、工具调度、多轮思考都帮你做了。