工具在langchain agent中的调用

一. 工具的完整运行流程(Agent 调用工具)

  1. 用户提问
  2. LLM 判断:这件事我自己回答不了,需要调用哪个工具、传入什么参数
  3. Agent 把结构化的工具调用请求发出去
  4. 工具执行真实操作(联网搜索、运行代码、查数据库),拿到结果
  5. 把工具返回结果塞回大模型上下文
  6. LLM 结合工具输出整理答案返回给用户
    React框架)可以循环多轮:思考→调用工具→拿到结果→再思考→再调用工具,直到任务完成。

二.工具的实现方式

@tool 装饰器

最简单,装饰普通 Python 函数,自动提取参数 schema。

复制代码
from langchain_core.tools import tool

@tool
def multiply(a: int, b: int) -> int:
    """将两个数字相乘
    Args:
        a: 第一个整数
        b: 第二个整数
    """
    return a * b

# 查看工具属性
print(multiply.name)          # multiply
print(multiply.description)  # 工具描述,给LLM看!非常关键
print(multiply.args)          # 参数json schema,LLM要知道传什么参数

⚠️重点:

  • docstring 必须写清楚用途、参数,LLM 全靠 description 判断要不要调用这个工具;描述写烂,agent 就不会用或者乱调用。
  • 函数类型注解不能省,用来生成工具入参 schema。

三.把工具喂给 Agent:完整可运行示例

Function Calling Agent

现在主流是 create_openai_tools_agent,专门适配 OpenAI Function‑call(tool call)。

Agent 不是直接跑 LLM,是:LLM + Prompt 模板 + 工具列表 → 生成 Agent,再用 AgentExecutor 做循环执行。

复制代码
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

# 1. 定义工具
@tool
def multiply(a: int, b: int) -> int:
    """两个整数相乘
    Args:
        a: 乘数1
        b: 乘数2
    """
    return a * b

@tool
def add(a:int, b:int) -> int:
    """两个整数相加"""
    return a + b

tools = [multiply, add]

# 2. LLM,必须支持tool_call(gpt‑3.5‑turbo/gpt‑4)
llm = ChatOpenAI(model="gpt-3.5-turbo", api_key="xxx")

# 3. 构建agent使用的prompt模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个会使用工具的助手,遇到计算就调用工具,不要自己口算。"),
    ("user", "{input}"),
    ("placeholder", "{agent_scratchpad}"),  # !必须要有,存放agent中间思考、工具调用记录
])

# 4. 创建agent:核心!把llm、prompt、tools传进去
agent = create_openai_tools_agent(llm, tools, prompt)

# 5. AgentExecutor:执行器,负责循环:调用llm→解析工具→跑tool→回写结果,直到输出最终答案
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 6. 调用agent
res = agent_executor.invoke({"input": "3乘以5再加10等于多少"})
print(res["output"])

注意两处传 tools:

  1. create_openai_tools_agent(llm, tools, prompt):给 LLM,让它知道有哪些工具,生成 tool_call;

  2. AgentExecutor(agent=agent, tools=tools):执行器拿到 tool 列表,当 LLM 输出工具调用后,根据工具名字找到对应的 tool 对象,执行 _run

    👉 两处都需要传入 tools,缺一不可。

🚩Agent 内部完整执行链路拆解(verbose=True 可以看到每一步)

输入问题:3乘以5再加10等于多少

Step1:组装 prompt 上下文

把:system 提示词、用户问题、agent_scratchpad(初始为空),连同工具 schema 列表一起喂给 LLM。

OpenAI 接口会把 tools 数组作为单独参数传给大模型,不是塞到文本 prompt 里面。

Step2:LLM 输出 ToolCall(工具调用)

LLM 思考:需要调用 multiply (3,5),输出结构化的 tool_call,不是自然语言。

json

复制代码
{
  "name":"multiply",
  "args":{"a":3,"b":5}
}

Step3:Agent 解析 LLM 输出

create_openai_tools_agent 的输出解析器解析 LLM 返回,识别出要调用工具,生成AgentAction对象:

AgentAction:工具名、参数、思考日志。

Step4:AgentExecutor 执行工具

Executor 拿到 AgentAction,遍历传入的tools列表,匹配tool.name,找到对应 tool 对象,调用tool._run(**args),拿到工具返回结果。

如果工具抛异常,Executor 会捕获,把错误信息放回 scratchpad,回传给 LLM,让 LLM 重试。

Step5:把工具执行结果写回 agent_scratchpad

将「调用了什么工具、传入什么参数、返回结果是什么」作为消息追加到上下文。

Step6:循环回到 LLM

带着工具返回结果再次调用 LLM。

例子:multiply 返回 15,现在 LLM 看到结果 15,继续调用 add (15,10)。

Step7:LLM 判断不需要工具,输出最终答案

不再生成 tool_call,输出自然语言回答,循环终止,返回结果。

verbose=True 打印出来日志就是这一整套循环。


ReAct Agent

  1. create_react_agentReAct 范式,纯文本提示词驱动,不是 OpenAI native tool‑call。LLM 输出文本格式的思考、Action、Action Input,再由输出解析器去抠出工具调用。
  2. create_openai_tools_agent:OpenAI 原生 tool_call,结构化消息,不是 ReAct。

ReAct 的核心:Thought → Action → Action Input → Observation 循环。

要求模型输出特定格式文本,解析器去解析文本拿到工具调用,容错比原生 tool‑call 差,但是兼容所有大模型,不限于 OpenAI

完整可运行代码

复制代码
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.prompts import PromptTemplate

# ---------------------- 1. 定义自定义工具 ----------------------
@tool
def calculator_add(a: int, b: int) -> int:
    """计算两个整数相加。
    Args:
        a: 第一个整数
        b: 第二个整数
    """
    return a + b


@tool
def calculator_mul(a: int, b: int) -> int:
    """计算两个整数相乘。
    Args:
        a: 乘数a
        b: 乘数b
    """
    return a * b


tools = [calculator_add, calculator_mul]

# ---------------------- 2. LLM 实例 ----------------------
llm = ChatOpenAI(
    model="gpt-3.5-turbo",
    api_key="sk-xxx",
    temperature=0
)

# ---------------------- 3. ReAct Prompt模板(关键!) ----------------------
# ReAct 必须使用这个特定格式的prompt,告诉模型输出Thought/Action/Action Input/Observation
react_prompt = PromptTemplate.from_template("""
Answer the following question as best you can.
You have access to the following tools:

{tools}

Tool names: {tool_names}

Use the following format strictly:

Thought: you should always think about what to do
Action: the action to take, must be one of [{tool_names}]
Action Input: the input arguments for the tool, json format
Observation: the result of the tool
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

Begin!

Question: {input}
{agent_scratchpad}
""")

# ---------------------- 4. 创建 ReAct Agent & AgentExecutor ----------------------
# create_react_agent:返回原始agent(runnable),只输出AgentAction/AgentFinish
react_agent = create_react_agent(llm, tools, react_prompt)

# AgentExecutor 负责循环、解析、调用工具、维护scratchpad
agent_executor = AgentExecutor(
    agent=react_agent,
    tools=tools,
    verbose=True,          # 打印完整ReAct思考链路
    handle_parsing_errors=True,  # 解析失败时把错误丢回LLM重试,非常重要
    max_iterations=5,      # 最大循环轮次,防止死循环
)

# ---------------------- 5. 执行 ----------------------
if __name__ == "__main__":
    res = agent_executor.invoke({
        "input": "计算 (100 + 200) * 2 等于多少"
    })
    print("\n====最终输出====")
    print(res["output"])

📖 verbose=True 打印出来的完整 ReAct 链路

复制代码
> Entering new AgentExecutor chain...
Thought: I need to calculate (100+200)*2, first add 100 and 200.
Action: calculator_add
Action Input: {"a":100,"b":200}
Observation: 300
Thought: Now multiply 300 by 2
Action: calculator_mul
Action Input: {"a":300,"b":2}
Observation: 600
Thought: I now know the final answer
Final Answer: 600

> Finished chain.
====最终输出====
600

内部流程拆解(ReAct 完整链路)

  1. toolstool_names、用户问题、空的agent_scratchpad送入 prompt。
  2. LLM 输出文本 ,严格按照模板输出:Thought / Action / Action Input
  3. ReActSingleInputOutputParser 解析文本,提取工具名、参数,生成AgentAction
  4. AgentExecutor 执行对应 tool,拿到结果,作为Observation
  5. Thought/Action/ActionInput/Observation 追加到 agent_scratchpad
  6. 把完整 scratchpad 再次塞回 prompt,交给 LLM 继续思考。
  7. LLM 输出 Final Answer: → 解析为AgentFinish,循环结束。

agent_scratchpad 在 ReAct 里面就是一长段拼接的文本,不是消息数组,和 OpenAI‑tools‑agent 不一样。

相关推荐
IT_陈寒40 分钟前
Vite的HMR在我项目上突然失效,排查三天找到离谱原因
前端·人工智能·后端
牛马也想出海41 分钟前
使用Playwright被检测为机器人的原因及反检测方案
开发语言·网络·人工智能·机器人·php
一路向北North43 分钟前
Spring AI(11) :ChatPDF-向量数据库、PDF处理、向量写入和向量搜索
数据库·人工智能·spring
Wang's Blog1 小时前
AI Agent白手起家44: LangChain 文档切分实战 — 长度、文本架构与语义切片
人工智能·langchain
GrowthDiary0071 小时前
Python 常用函数总结
开发语言·python
only-qi1 小时前
大模型微调流程深度解析:从面试题到工程实践
人工智能·机器学习·ai·llm
热心网友俣先生1 小时前
2026年华数杯C 题 超详细解题思路
c语言·开发语言·人工智能
RSTJ_16251 小时前
PYTHON+AI LLM DAY ONE HUNDRED AND THIRTY
人工智能
AINative软件工程1 小时前
LLM 应用的依赖注入工程实践:解耦 Client、Prompt 和 Tool Registry,让 AI 系统真正可测试可替换
后端·llm·前端工程化