[智能体-130]:LangChain中定义好的工具,会被LangChain智能体框架和大模型识别,自动会被LangChain调用,并把调用的送给大模型,由大模型做整合后回复给智能体
LangChain中定义好的工具,会被LangChain智能体框架和大模型识别,自动会被LangChain调用,并把调用的送给大模型,由大模型做整合后回复给智能体,不需要大模型应用程序员根据大模型的输出去显式的调用定义好的tool
这正是 LangChain 和 "原生 OpenAI API 手写工具调用" 的本质区别:LangChain 把 "工具调用的全流程自动化" 做成了框架内置能力,程序员只需要做两件事:
- 用标准方式定义工具(
@tool装饰器等) - 把工具列表传给 AgentExecutor
剩下的所有环节:工具定义转模型格式、解析模型的工具调用指令、执行本地函数、把结果返回给模型、循环判断是否需要继续调用、直到生成最终回答,全部由 LangChain 框架自动完成,不需要你写任何if model_output.has_tool_call() then call_tool()这样的显式判断和调用代码。
一、先看最直观的对比:原生 API vs LangChain
1. 原生 OpenAI API 手写工具调用(需要你显式写调用逻辑)
python
运行
# 原生API:你必须手动处理整个工具调用循环
import openai
client = openai.OpenAI()
tools = [{"type": "function", "function": {"name": "add", "parameters": {...}}}]
def add(a, b): return a + b
# 你必须手写这个循环
def chat(query):
messages = [{"role": "user", "content": query}]
while True:
# 1. 调用模型
res = client.chat.completions.create(model="gpt-3.5-turbo", messages=messages, tools=tools)
msg = res.choices[0].message
messages.append(msg)
# 2. 你必须显式判断:模型有没有要调用工具
if not msg.tool_calls:
return msg.content # 没有就返回
# 3. 你必须显式解析工具调用参数
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
args = eval(tool_call.function.arguments)
# 4. 你必须显式调用对应的本地函数
if func_name == "add":
result = add(**args)
# 5. 你必须显式把结果拼回消息列表
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result)
})
所有标粗的步骤,都是你必须手写的胶水代码,每加一个工具就要改一次判断逻辑。
2. LangChain Agent(完全自动,无显式调用代码)
python
运行
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
# 1. 你只需要定义工具
@tool
def add(a: int, b: int) -> int:
"""计算两个整数的和"""
return a + b
# 2. 你只需要初始化框架
llm = ChatOpenAI(model="gpt-3.5-turbo")
tools = [add]
prompt = ChatPromptTemplate.from_messages([
("system", "你是会用工具的助手"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}")
])
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)
# 3. 你只需要一行调用,剩下的全自动
result = agent_executor.invoke({"input": "123+456等于多少"})
print(result["output"])
没有任何
if判断、没有任何工具调用解析、没有任何结果拼接代码,全部由框架自动完成。
二、LangChain 自动化工具调用的完整内部流程
我把你说的这句话,拆解成框架内部精确的执行步骤,你就能清楚看到每一步是谁在做:
plaintext
用户输入 → AgentExecutor(框架)启动循环
↓
1. 框架自动:把你定义的所有@tool工具,转换成大模型能理解的JSON Schema格式
↓
2. 框架自动:把用户输入+历史对话+工具定义,打包成标准消息发给大模型
↓
3. 大模型决策:要不要调用工具?调用哪个?传什么参数?
↓
4. 框架自动:解析大模型返回的工具调用指令(不需要你写解析代码)
↓
5. 框架自动:根据工具名,找到你定义的本地Python函数,自动传入参数执行
↓
6. 框架自动:把工具执行结果,包装成标准的ToolMessage,追加到对话历史
↓
7. 框架自动:把包含工具结果的完整历史,再次发给大模型
↓
8. 大模型判断:信息足够了吗?
→ 不够:回到步骤4,继续自动调用下一个工具
→ 足够:生成最终回答
↓
9. 框架自动:终止循环,把最终回答返回给你
核心结论:
- 大模型只做决策(要不要调、调哪个、传什么)
- LangChain 框架只做执行(解析、调用、拼接、循环)
- 你只做定义(工具是什么、提示词是什么)
三、为什么 LangChain 能做到这一点?
因为它把工具调用的通用逻辑全部抽象成了框架内置组件:
@tool装饰器:统一了工具的定义标准,自动生成name/description/args_schemacreate_tool_calling_agent:自动实现了 "工具定义转模型格式" 和 "模型输出转工具调用指令" 的双向转换AgentExecutor:内置了无限循环调度器,自动处理 "调用→返回→再调用" 的整个流程,直到模型生成最终回答- 标准化消息体系:
AIMessage带tool_calls字段、ToolMessage专门存工具结果,框架内部所有组件都能统一识别
四、补充:你仍然可以干预的地方(可选)
虽然基础调用完全自动,但 LangChain 也提供了钩子让你在需要时干预流程,这些都是可选的,不影响核心自动化:
- 自定义工具执行前 / 后的回调函数(日志、监控)
- 设置最大调用次数(
max_iterations),防止无限循环 - 自定义错误处理(工具报错时怎么返回给模型)
- 强制终止循环(
return_intermediate_steps)
五、一句话总结
你说的这句话,就是 LangChain Agent 框架存在的核心意义之一:它把 "工具调用" 从一个需要程序员手动编码的复杂流程,变成了一个只需要声明式定义的配置项。你只需要告诉框架 "我有这些工具可用",剩下的所有脏活累活,框架全帮你干了。
需要我给你加一个带日志的完整示例,打印出框架内部每一步自动执行的细节,让你直观看到工具是怎么被自动调用的吗?
更多推荐



所有评论(0)