Agent的诞生(二):让模型开始调用工具

目录

  • 二、让模型开始调用工具
    • [1. 让模型开始调用工具](#1. 让模型开始调用工具)
    • [2. Agent 如何把工具暴露给模型](#2. Agent 如何把工具暴露给模型)
    • [3. Agent 如何识别模型发起工具调用](#3. Agent 如何识别模型发起工具调用)
    • [4. Agent 如何把工具结果回填给模型](#4. Agent 如何把工具结果回填给模型)
    • [5. 这个过程为什么会持续到模型直接回答为止](#5. 这个过程为什么会持续到模型直接回答为止)
    • [6. 小结:模型调用工具的关键环节](#6. 小结:模型调用工具的关键环节)

二、让模型开始调用工具

1. 让模型开始调用工具

第一篇里,我先让 Agent 跑通了最基础的多轮对话,但只会对话还不够。如果模型只能基于已有上下文回答问题,那与普通聊天应用并无本质区别;只有模型能借助工具接触外部环境时,Agent 才真正具备"做事"的能力。

本篇围绕四个问题展开:

  1. Agent 如何把工具暴露给模型
  2. Agent 如何识别模型发起的工具调用
  3. Agent 如何把工具结果回填给模型
  4. 这个过程为什么会循环下去,直到模型给出最终回答

回答完这些问题便可以理清模型调用工具的链路:Agent 暴露工具 → 模型发起调用 → Agent 执行工具 → Agent 回填结果 → 模型继续推理 / 返回最终回答,利用流程图可以更直观的了解这个过程。

2. Agent 如何把工具暴露给模型

要让模型调用工具,第一步不是执行工具,而是告诉模型:当前有哪些工具可用,它们分别能做什么。

实现上,Agent 会把可用工具整理成一份结构化清单,并随着对话请求一起发送给模型。这份清单至少包含工具名称功能描述参数定义。定义越清晰,模型越容易判断该用哪个工具、该传什么参数。

从接口层面看,这份清单通过模型 API 请求中的 tools 参数传递给模型。模型"看到"的不是本地函数实现,而是一份由 Agent 整理好的工具说明。

所谓"给模型加工具",就是先把函数转换成模型能理解的描述结构。工具名称是否稳定、用途说明是否明确、参数字段是否具体,都会直接影响调用效果,这是工具能否被正确调用的关键。

python 复制代码
# 工具清单
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_system_date",
            "description": "获取系统当前日期和时间,格式为 yyyy-MM-dd HH:mm:ss。",
            "parameters": {
                "type": "object",
                "properties": {}
            }
        }
    },
    ...
]

# 模型API调用
response = client.chat.completions.create(
        model=model,
        messages=messages,
        tools=TOOLS,
        stream=False,
    )

3. Agent 如何识别模型发起工具调用

模型拿到工具清单后,并不会每一轮对话都调用工具。很多时候,它仍然会直接返回普通文本。对 Agent 来说,下一个关键问题是:如何判断模型返回的是给用户的推理结果,还是工具调用请求。

在模型 API 接口里(本文使用的 OpenAI 接口)有一些字段可以作为判断依据,其中 finish_reason 可以检查模型的回应是要调用工具还是推理结果,tool_calls 则包含模型希望调用的工具名称参数信息。Agent 根据这些字段识别调用请求,再决定执行哪个工具。

这里有一个关键点:真正发起调用意图的是模型,Agent 的职责是识别这个意图并继续处理。它更像是模型与外部能力之间的解释层和执行层。

python 复制代码
while True:
    ....
    finish_reason = response.choices[0].finish_reason
    message = response.choices[0].message

    tool_call = message.tool_calls[0]
    # 判断模型是否调用工具
    if finish_reason == 'stop' or not tool_calls:  # 如果是调用工具 finish_reason = 'tool_calls'
        print("AI > " + message.content)
        break
    # 获取工具名称和参数
    tool_name = tool_call.function.name
    tool_arguments = json.loads(tool_call.function.arguments or "{}")
    # 调用工具获取结果
    tool_result = execute_tool(tool_name, tool_arguments)
    ...

4. Agent 如何把工具结果回填给模型

识别到工具调用请求后,Agent 会执行对应工具,但执行工具不是终点。模型调用工具,是为了获取原本拿不到的外部信息;Agent 还必须把结果回填上下文,再发送给模型。

这一步 Agent 需要收集工具运行的标准输出错误信息 ,并组织成一条新的上下文消息。模型对每个调用的工具都有ID标识,回填工具结果时要与ID对应。tool_call_id 字段记录调用工具的ID标识,content 字段则承载具体结果。只有结果被正确回填,模型才能基于新信息继续推理。

python 复制代码
# 回填执行结果
messages.append(
    {
        "role": "tool",
        "tool_call_id": tool.id,
        "content": tool_result
    }
)

5. 这个过程为什么会持续到模型直接回答为止

模型收到一次工具执行结果后,不一定会立刻给出最终回答。模型会先根据新信息继续判断:如果信息还不够,就再次发起工具调用;如果信息已经足够,则停止调用工具并生成最终推理结果。

Agent 需要循环处理这条链路:暴露工具、识别调用、执行工具、回填结果,再把结果交还给模型继续推理。 只要模型仍然需要外部信息,这个过程就会持续;直到某一轮里,模型不再请求工具,而是返回面向用户的回答,这一轮任务才算结束。

工具调用闭环不仅要能跑通,还要有边界控制,实现时需要限制最大调用次数。不然一旦模型持续重复请求工具,系统就可能陷入无限循环,token 就会快速消耗。

整个流程框架如下图:

Agent 循环代码:

python 复制代码
def run_agent_turn(messages):
    # 每轮对话重置工具调用次数
    tool_call_count = 0
    tool_limit_reached = False

    while True:
        finish_reason, assistant_message = request_chat_completion(messages)
        messages.append(assistant_message)

        tool_calls = assistant_message.tool_calls or []
        if finish_reason == 'stop' or not tool_calls:
            print("AI > " + (assistant_message.content or ""))
            break

        if tool_limit_reached:
            for tool_call in tool_calls:
                messages.append(
                    {
                        "role": "tool",
                        "tool_call_id": tool_call.id,
                        "content": error_result(
                            "TOOL_CALL_LIMIT_EXCEEDED",
                            "本轮工具调用已达到上限,当前工具未执行。请下一轮继续。",
                        ),
                    }
                )
            print("AI > 本轮工具调用已达到上限,请下一轮继续。")
            break

        for tool_call in tool_calls:

            if tool_call_count >= MAX_TOOL_CALLS_PER_TURN:
                tool_limit_reached = True
                messages.append(
                    {
                        "role": "tool",
                        "tool_call_id": tool_call.id,
                        "content": error_result(
                            "TOOL_CALL_LIMIT_EXCEEDED",
                            "超过工具最大调用次数,请根据已有信息直接回答问题。",
                        ),
                    }
                )
                continue

            tool_result = execute_tool_call(tool_call)
            tool_call_count += 1
            print(f"tool[{tool_call.function.name}] > {tool_result}")
            messages.append(
                {
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": tool_result,
                }
            )

6. 小结:模型调用工具的关键环节

本篇完成模型调用工具闭环,关键环节包括四部分:

  • 工具暴露 :通过接口 tools 参数把工具清单发送给模型,让模型知道当前可用能力及参数结构。
  • 调用识别 :模型返回的数据中 finish_reasontool_calls 判断是否发起工具调用,并解析工具名称与参数。
  • 结果回填 :将工具执行结果按 tool_call_idcontent 对应工具标识ID和结果回填上下文,交还模型继续推理。
  • 循环控制:持续处理"调用工具---回填结果---继续推理"的过程,并限制调用次数避免无限循环。

Agent 的关键是把工具清单、调用识别、结果回填和流程控制连接成一条完整链路,只要这条链路闭合之后,模型便能获取外部信息完成推理。

从本篇可以看出,Tool 是原子化、可执行的外部能力单元 ,模型调用一次工具,就获得一次结果。但面对流程化任务时,把流程逻辑堆进单个工具,工具就会变繁重,程序故障率更高,复用性也会下降。这里抛出一个问题:如何让模型学习任务流程,并对工具能力进行组织、复用与组合。 下一篇将展开 Skill 帮助模型应用知识与工具解决问题的能力。

相关推荐
独隅1 小时前
Ollama 本地大模型运行效果实测
ai
Esaka_Forever1 小时前
向量数据库的Hashing Function
ai
John_ToDebug1 小时前
Claude Code Agent 使用最佳实践与底层机制全解
人工智能·经验分享·ai
Rocktech_ruixun1 小时前
智慧餐饮新机遇:全场景无人化升级,破解餐饮业降本增效难题
人工智能·嵌入式硬件·ai·机器人
追光者♂1 小时前
【测评系列6】CSDN AI数字营销实测体验官——OpenClaw 数据采集工具新手入门指南
人工智能·深度学习·机器学习·ai·大模型·openclaw·前沿科学
jiayong231 小时前
ZeroClaw 可优化空间与改进建议
人工智能·ai·智能体·zeroclaw
jiayong231 小时前
ZeroClaw 使用方式与启动指南
人工智能·ai·智能体·zeroclaw
久违 °10 小时前
【AI-Agent】TagMatrix 数据标注工具开发
人工智能·数据分析·go·agent·数据隐私
AI360labs_atyun10 小时前
腾讯推出电子牛马Marvis,好用吗?
人工智能·科技·ai