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

Agent的诞生(二):让模型开始调用工具
让模型开始调用工具1. 让模型开始调用工具第一篇里我先让 Agent 跑通了最基础的多轮对话但只会对话还不够。如果模型只能基于已有上下文回答问题那与普通聊天应用并无本质区别只有模型能借助工具接触外部环境时Agent 才真正具备“做事”的能力。本篇围绕四个问题展开Agent 如何把工具暴露给模型Agent 如何识别模型发起的工具调用Agent 如何把工具结果回填给模型这个过程为什么会循环下去直到模型给出最终回答回答完这些问题便可以理清模型调用工具的链路Agent 暴露工具 → 模型发起调用 → Agent 执行工具 → Agent 回填结果 → 模型继续推理 / 返回最终回答利用流程图可以更直观的了解这个过程。2. Agent 如何把工具暴露给模型要让模型调用工具第一步不是执行工具而是告诉模型当前有哪些工具可用它们分别能做什么。实现上Agent 会把可用工具整理成一份结构化清单并随着对话请求一起发送给模型。这份清单至少包含工具名称、功能描述和参数定义。定义越清晰模型越容易判断该用哪个工具、该传什么参数。从接口层面看这份清单通过模型 API 请求中的tools参数传递给模型。模型“看到”的不是本地函数实现而是一份由 Agent 整理好的工具说明。所谓“给模型加工具”就是先把函数转换成模型能理解的描述结构。工具名称是否稳定、用途说明是否明确、参数字段是否具体都会直接影响调用效果这是工具能否被正确调用的关键。# 工具清单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(modelmodel,messagesmessages,toolsTOOLS,streamFalse,)3. Agent 如何识别模型发起工具调用模型拿到工具清单后并不会每一轮对话都调用工具。很多时候它仍然会直接返回普通文本。对 Agent 来说下一个关键问题是如何判断模型返回的是给用户的推理结果还是工具调用请求。在模型 API 接口里本文使用的 OpenAI 接口有一些字段可以作为判断依据其中finish_reason可以检查模型的回应是要调用工具还是推理结果tool_calls则包含模型希望调用的工具名称和参数信息。Agent 根据这些字段识别调用请求再决定执行哪个工具。这里有一个关键点真正发起调用意图的是模型Agent 的职责是识别这个意图并继续处理。它更像是模型与外部能力之间的解释层和执行层。while True:....finish_reason response.choices[0].finish_reasonmessage response.choices[0].messagetool_call message.tool_calls[0]# 判断模型是否调用工具if finish_reason stop or not tool_calls: # 如果是调用工具 finish_reason tool_callsprint(AI message.content)break# 获取工具名称和参数tool_name tool_call.function.nametool_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字段则承载具体结果。只有结果被正确回填模型才能基于新信息继续推理。# 回填执行结果messages.append({role: tool,tool_call_id: tool.id,content: tool_result})5. 这个过程为什么会持续到模型直接回答为止模型收到一次工具执行结果后不一定会立刻给出最终回答。模型会先根据新信息继续判断如果信息还不够就再次发起工具调用如果信息已经足够则停止调用工具并生成最终推理结果。Agent 需要循环处理这条链路暴露工具、识别调用、执行工具、回填结果再把结果交还给模型继续推理。只要模型仍然需要外部信息这个过程就会持续直到某一轮里模型不再请求工具而是返回面向用户的回答这一轮任务才算结束。工具调用闭环不仅要能跑通还要有边界控制实现时需要限制最大调用次数。不然一旦模型持续重复请求工具系统就可能陷入无限循环token 就会快速消耗。整个流程框架如下图Agent 循环代码def run_agent_turn(messages):# 每轮对话重置工具调用次数tool_call_count 0tool_limit_reached Falsewhile 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 ))breakif 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 本轮工具调用已达到上限请下一轮继续。)breakfor tool_call in tool_calls:if tool_call_count MAX_TOOL_CALLS_PER_TURN:tool_limit_reached Truemessages.append({role: tool,tool_call_id: tool_call.id,content: error_result(TOOL_CALL_LIMIT_EXCEEDED,超过工具最大调用次数请根据已有信息直接回答问题。,),})continuetool_result execute_tool_call(tool_call)tool_call_count 1print(ftool[{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和结果回填上下文交还模型继续推理。循环控制持续处理“调用工具—回填结果—继续推理”的过程并限制调用次数避免无限循环。