目录
- 二、让模型开始调用工具
- [1. 让模型开始调用工具](#1. 让模型开始调用工具)
- [2. Agent 如何把工具暴露给模型](#2. Agent 如何把工具暴露给模型)
- [3. Agent 如何识别模型发起工具调用](#3. Agent 如何识别模型发起工具调用)
- [4. Agent 如何把工具结果回填给模型](#4. Agent 如何把工具结果回填给模型)
- [5. 这个过程为什么会持续到模型直接回答为止](#5. 这个过程为什么会持续到模型直接回答为止)
- [6. 小结:模型调用工具的关键环节](#6. 小结:模型调用工具的关键环节)
二、让模型开始调用工具
1. 让模型开始调用工具
第一篇里,我先让 Agent 跑通了最基础的多轮对话,但只会对话还不够。如果模型只能基于已有上下文回答问题,那与普通聊天应用并无本质区别;只有模型能借助工具接触外部环境时,Agent 才真正具备"做事"的能力。
本篇围绕四个问题展开:
- Agent 如何把工具暴露给模型
- Agent 如何识别模型发起的工具调用
- Agent 如何把工具结果回填给模型
- 这个过程为什么会循环下去,直到模型给出最终回答
回答完这些问题便可以理清模型调用工具的链路: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_reason和tool_calls判断是否发起工具调用,并解析工具名称与参数。 - 结果回填 :将工具执行结果按
tool_call_id、content对应工具标识ID和结果回填上下文,交还模型继续推理。 - 循环控制:持续处理"调用工具---回填结果---继续推理"的过程,并限制调用次数避免无限循环。
Agent 的关键是把工具清单、调用识别、结果回填和流程控制连接成一条完整链路,只要这条链路闭合之后,模型便能获取外部信息完成推理。
从本篇可以看出,Tool 是原子化、可执行的外部能力单元 ,模型调用一次工具,就获得一次结果。但面对流程化任务时,把流程逻辑堆进单个工具,工具就会变繁重,程序故障率更高,复用性也会下降。这里抛出一个问题:如何让模型学习任务流程,并对工具能力进行组织、复用与组合。 下一篇将展开 Skill 帮助模型应用知识与工具解决问题的能力。