第 04 篇 · 多轮循环:Agent 的核心执行机制
上一篇 我们做了一个最简单的工具调用,通过天气查询这个Demo,演示了工具执行的全流程。但是它目前只能调用一次工具来完成任务,而我们实际项目中,大多数情况下 都不可能只调用一次工具。而是多次调用工具来完成任务目标。
比如我们要完成一个任务 :
用户说:"帮我看看 hello.txt 里写了什么,把里面的小写字母改成大写,保存回去。"
要处理这个任务,模型会进行推理,思考要如何来完成这个任务
模型会想:先调 read_file("hello.txt") 看看内容;拿到内容以后,再调 write_file("hello.txt", "改完的内容") 保存。
整个过程是:思考 → 调工具 → 看结果 → 再思考 → 再调工具 → 最终回复。这个过程可能需要重复好多轮才会结束
这一篇我们主要来完成这个多轮循环调用工具的过程。
Agent循环
上一篇工具执行流程的伪代码如下:
response1 = call_llm(messages)
if response1.tool_calls:
execute_tool(...)
response2 = call_llm(messages + tool_result)
print(response2.content)
这段代码我们假设了一件事:模型只会调一次工具,,但是这个假设是错误的。
模型完全可能在第二次调用时,继续输出 tool_calls,要求继续调用工具。
比如它读完文件以后,说"我现在要写文件了",输出一个新的 tool_calls工具调用。
这时如果你的代码直接 print(response2.content),你会发现 content 是 None或者是一段继续使用工具的文字说明,这个时候 程序执行也结束,不能继续完成用户的任务。
所以正确的写法是:只要这一轮模型输出还需要调工具,就继续下一轮。直到某一轮模型不再输出工具调用、直接给出文字回复,循环才结束。
用循环直接把流程改一下,伪代码大概是这样:
messages = [system, user]
whileTrue:
response = call_llm(messages)
messages.append(response.assistant_msg)
ifnot response.tool_calls:
# 模型给出最终回复,结束
break
for call in response.tool_calls:
result = execute(call)
messages.append({"role": "tool", "content": result, ...})
每一次 while 循环 就等于 一次模型调用 + 可能的工具执行。退出条件简单:这一轮模型没要求调工具。