Learn Claude Code
s01

Agent 循环

工具与执行

Bash is All You Need

35 LOC1 个工具Single-tool agent loop
The minimal agent kernel is a while loop + one tool

[ s01 ] s02 > s03 > s04 > s05 > s06 | s07 > s08 > s09 > s10 > s11 > s12

"One loop & Bash is all you need" -- 一个工具 + 一个循环 = 一个智能体。

Harness 层: 循环 -- 模型与真实世界的第一道连接。

问题

语言模型能推理代码, 但碰不到真实世界 -- 不能读文件、跑测试、看报错。没有循环, 每次工具调用你都得手动把结果粘回去。你自己就是那个循环。

解决方案

+--------+      +-------+      +---------+
|  User  | ---> |  LLM  | ---> |  Tool   |
| prompt |      |       |      | execute |
+--------+      +---+---+      +----+----+
                    ^                |
                    |   tool_result  |
                    +----------------+
                    (loop until stop_reason != "tool_use")

一个退出条件控制整个流程。循环持续运行, 直到模型不再调用工具。

工作原理

  1. 用户 prompt 作为第一条消息。
messages.push({ role: "user", content: query });
  1. 将消息和工具定义一起发给 LLM。
const response = await client.messages.create({
  model: MODEL,
  system: SYSTEM,
  messages,
  tools: TOOLS,
  max_tokens: 8000,
});
  1. 追加助手响应。检查 stop_reason -- 如果模型没有调用工具, 结束。
messages.push({ role: "assistant", content: response.content });
if (response.stop_reason !== "tool_use") {
  return;
}
  1. 执行每个工具调用, 收集结果, 作为 user 消息追加。回到第 2 步。
const results = [];
for (const block of response.content) {
  if (block.type === "tool_use") {
    const output = runBash(String(block.input.command ?? ""));
    results.push({
      type: "tool_result",
      tool_use_id: block.id,
      content: output,
    });
  }
}
messages.push({ role: "user", content: results });

组装为一个完整函数:

async function agentLoop(query: string) {
  const messages = [{ role: "user", content: query }];
  while (true) {
    const response = await client.messages.create({
      model: MODEL,
      system: SYSTEM,
      messages,
      tools: TOOLS,
      max_tokens: 8000,
    });
    messages.push({ role: "assistant", content: response.content });

    if (response.stop_reason !== "tool_use") {
      return;
    }

    const results = [];
    for (const block of response.content) {
      if (block.type === "tool_use") {
        const output = runBash(String(block.input.command ?? ""));
        results.push({
          type: "tool_result",
          tool_use_id: block.id,
          content: output,
        });
      }
    }
    messages.push({ role: "user", content: results });
  }
}

不到 30 行, 这就是整个智能体。后面 11 个章节都在这个循环上叠加机制 -- 循环本身始终不变。

变更内容

组件之前之后
Agent loop(无)while (true) + stop_reason
Tools(无)bash (单一工具)
Messages(无)累积式消息列表
Control flow(无)stop_reason !== "tool_use"

试一试

cd learn-claude-code-typescript
npx tsx agents/s01_agent_loop.ts

试试这些 prompt (英文 prompt 对 LLM 效果更好, 也可以用中文):

  1. Create a file called hello.ts that prints "Hello, World!"
  2. List all TypeScript files in this directory
  3. What is the current git branch?
  4. Create a directory called test_output and write 3 files in it