01Bread Agent · 第 3 章
总进度 3 / 33

让 Agent 连续调用工具

ch01 我们让 AI 调了 一次 工具。但真实任务往往要 多步配合 :

2026-09-28约 45 分钟140 行代码难度 ★★★

如果想获取全套课程资料,请关注微信公众号 「AI面包君」,回复 「课程资料」 即可领取。

1. 一个任务可能需要几次工具调用

ch01 我们让 AI 调了一次工具。但真实任务往往要多步配合:

用户:把 README.md 第一行内容写到 hello.txt

AI 内部要做的事情:

  1. 调 read_file("README.md") 拿到全文
  2. 切出第一行(这一步 LLM 自己脑子里就能做)
  3. 调 write_file("hello.txt", first_line)
  4. 用中文告诉用户"完成了"

这个任务要先读文件,再写文件,最后回复用户。ch01 在一次工具执行后就结束,处理不了这种需要接着行动的过程。

这就是为什么我们需要一个循环——反复地:"调模型 → 拿到工具请求 → 执行工具 → 把结果写回 messages → 再调模型 ...",直到模型不再要求调工具为止。

下面先用一小段代码表示这个循环,后面再看完整实现:

for step in range(MAX_STEPS):
    response = client.chat.completions.create(messages=messages, tools=TOOLS_SCHEMA)
    msg = response.choices[0].message
    messages.append(msg)

    if not msg.tool_calls:
        return msg.content        # ← 出口:模型不要求调工具了,任务结束

    for call in msg.tool_calls:
        result = TOOLS_IMPL[call.function.name](**json.loads(call.function.arguments))
        messages.append({"role": "tool", "tool_call_id": call.id, "content": str(result)})

读这段时,可以拿刚才的文件任务逐步对应:读文件的结果在哪一轮加入 messages?写文件发生在哪一轮?什么时候停止?理解这些位置,比背下代码更有用。

<!-- bread-visual:start -->

Agent 的心脏:做完一步,再想一步

图解: 工具执行结果进入 messages,成为下一次决策的依据。 循环还需要 MAX_STEPS 兜底;工具报错也可以作为结果回填。

<!-- bread-visual:end -->

2. 跑起来

cd ch02_loop
python main.py

此时main函数中输入的需求是:读取origin.txt文件的前3行,并把第1行内容写入到一个到文件new.txt中

Anaconda 同学:D:\anaconda3\envs\yutong\python.exe main.py

image-20260526171739842

预期输出

[step 0] 调用 read_file({'path': 'origin.txt'})
[step 0] 结果: 你好,我是这个文件的第一行
你好,我是这个文件的第二行
你好,我是这个文件的第三行
[step 1] 调用 write_file({'path': 'new.txt', 'content': '你好,我是这个文件的第一行\n'})
[step 1] 结果: 已写入 new.txt (14 chars)

[最终回答] 已完成:origin.txt 的前3行分别是「你好,我是这个文件的第一行」「你好,我是这个文件的第二行」「你好,我是这个文件的第三行」,其中第1行已写入 new.txt。

image-20260526171819542

试读到这里 · 后续内容已封存

关注公众号,继续把这章学完

在「AI面包君」发送关键词「学习AI」拿到口令。验证一次,这个浏览器就能继续阅读全部课程。