Jason Pan

Agent 如何使用大模型和工具

潘忠显 / 2026-03-30


Agent 如何使用大模型和工具

前段时间,把自己手头的机器人做了一个整理,接入了大语言模型。

原来的机器人,需要这样 lol clear_cache openid uid 类似的方式使用严格的指令来调用工具。

接入大语言模型之后,有几个明显的便利:

比如下边这个回话,在前面我是告诉他了哪个活动,然后让其清理缓存。工具中我只写了一个清理单个缓存的函数,但是 ReAct 模式能够利用大模型把 3 组帐号都清理掉。

react-batch-cache-clear

而如果缺少信息,也可以通过多轮回话要求补充:

missing-env-followup-dialog

借着这个改造,给大家介绍一下 Agent 到底是如何利用大模型的。

改造成本

因为原来使用自己写的框架 wecom-bot-svr,入口是一个 handle_command() 的函数,输入的内容会在这个函数中进行路由到不同的工具上。

而原来的工具也比较规整的按照业务存放了文件、按照命令定义了函数,这样非常方便改造

这个改造任务我直接让 Cursor 去完成的,改造完之后的结果就是,多了以下 3 部分:

  1. 抽象出工具注册层:自动发现 cmd_* 函数并生成标准 tool schema。
  2. 抽象出工具执行层:统一按 tool_name + arguments + user_id 做函数定位、权限校验和执行。
  3. 增加自然语言工具调用链路:在消息处理流程中引入基于 LLM tool calling 的多轮执行机制。这套实现更接近“LLM function calling/tool calling 循环”,可以类比 ReAct,但不算那种完整显式的 Thought/Action/Observation 的 ReAct Agent。
  4. 增加会话级历史管理,多轮对话可以继承上下文,不是一次性单轮调用。

这里简单的把第 3 条里 handle_command 的 Tool Calling 循环部分,画一个时序图表示一下:

tool-calling-sequence-diagram

大语言模型的作用

这里边大语言模型到底起到什么作用呢?大模型是「脑子」:

大模型知识一个脑子,脑子是不直接使用工具的——只判断应该使用哪个工具,大模型并不具备执行工具的能力

想清楚这点也很容易:首先,你告诉大模型的只有工具名和描述;其次,工具的调用肯定是在你服务器的环境才能运行的。

什么是 ReAct 模式

ReAct 模式由 Google 在 2022 年提出,其核心公式是: 推理 (Thought) + 行动 (Action) + 观察 (Observation) = 下一步决策

一个简单的例子:

Task: 今天天气怎么样

Thought: 模型分析用户的需求,意识到自己不知道位置,于是决定:“我需要先调用获取位置的工具”。
Action: 调用 `get_location` 工具
Observation: 获取工具返回的结果(例如:深圳)

Thought: 模型拿到深圳后,再次思考:“现在我有位置了,我需要调用天气工具来获取深圳的天气”。
Action: 调用 `get_weather(深圳)` 工具。
Observation: 获取深圳天气数据下雨

Thought: 我已经得到了所需的信息
Action: finish(answer="深圳今天会下雨")

通过伪代码,我们在此理解一下这里的 ReAct 模式:

# 简化版 Agent 循环逻辑
while not final_answer:
    # 1. 将对话历史和提示词发给 LLM
    response = llm.predict(prompt + history)
    
    # 2. 解析 LLM 的输出 (解析出 Thought 和 Action)
    action, action_input = parser.parse(response)
    
    if action == "Final Answer":
        final_answer = action_input
    else:
        # 3. 执行工具 (Action)
        observation = tools[action](action_input)
        
        # 4. 将结果反馈给下一次循环 (Observation)
        history.append(observation)

再对照我机器人的代码,可以看看这里的对应上边循环中的各个部分:

react-code-mapping-diagram

这个简单的循环,能解决很多很多的问题,只要 tools 和 给的信息足够。

即使不够,大模型也会在第二个框处终止,要求更多的信息。

回到最初的问天气的例子,如果问的是「北京天气怎么样」,上边的循环就会跳过调用查询位置,直接调用查询天气。

更简单的 ReAct 实现

上边那个循环,实际是实现了 langchain 中的 AgentExecutor 概念,也就是使用 AgentExecutor 直接简化掉前面的 for 循环:

# 创建 Agent 执行器(替代那个控制循环)
agent_executor = AgentExecutor(
    agent=agent, 
    tools=tools, 
    verbose=True, # 开启 verbose 可以看到 Thought/Action/Observation 的过程
    handle_parsing_errors=True # 处理 LLM 输出格式不规范的情况
)

但是,这个AgentExecutor 也被 langchain 废弃了,因为它太像一个“黑盒”,开发者很难干预中间状态。于是就有了 LangGraph 这个库,在该框架中,ReAct 模式被抽象为一个有状态的图 (State Graph):

上边的这些类型是通过 LangGraph Graph API 来实现的。

langgraph-state-graph

但是为了简化线性循环这样简单的场景,langgraph 又分装出了 Functional API,比如这样:

# Functional API 示例 (非常简洁)
from langgraph.prebuilt import create_react_agent

# 这一行代码其实就在底层帮你构建了一个包含 "agent" 和 "tools" 节点的图
app = create_react_agent(model, tools)

前面提到的手动定义边、节点、状态的这种复杂的图,它允许你像画流程图一样精密地控制 Agent 的每一个动作。适用于一些复杂场景:

小结

搞清楚了 Agent 中 LLM 如何发挥作用,了解了 Agent 工作原理,然后就可以顺利地开发自己的 Agent。

提个思考题,这里为什么不用 OpenClaw 和 Skill?

后边会分享一下 Agent 中多模型协同使用、langchain/langgraph 的一些学习和应用。

欢迎关注。