跳到正文

问题所在

你的Agent一直在逍遥法外。

在第1到第4模块期间,你们一直在执行短任务。读一个文件,找到TODO,列出目录。五步,最多十步。上下文窗口保持舒适,Agent 保持敏锐,一切都很顺利。

这部分我们要转身看看真实任务中会发生什么。二十步。三十。那种Agent读取三个文件,搜索代码库两次,运行测试,修复一个问题,再运行测试,然后写摘要的任务。

在解决问题之前,我们需要先看到它。修正不大。看见才是难的部分。

学习成果

onStepFinish在每一步记录输入和输出token。运行多步任务使上下文增长可见:输入token线性上升,而输出大致保持平稳。

快速路径

  1. ToolLoopAgentonStepFinish回调
  2. 每步记录usage.inputTokensusage.outputTokens
  3. 运行一个多步任务,看着输入数字不断上升

动手练习 5.1

接线token日志,运行一个足够显示曲线的任务。

要求:

  1. onStepFinish: ({ usage, stepNumber }) => { ... }传给ToolLoopAgent
  2. 使用console.error(这样它会显示在Agent正常输出旁边,但不会出现在stdout)
  3. 运行一个强制4+工具调用的提示词,这样曲线就能看到
  4. 读数字。别急着修复任何东西

实现提示:

  • onStepFinish每一步都跑,不仅仅是成功的。usage字段是相关的
  • console.error来遥测。console.log和Agent的反应混在一起,变得很糟糕
  • 提示词需要做真正的工作。“读package.json”只是一步。“读package.json,然后tsconfig,再读入口点,最后总结”是四。

添加日志记录

ts
const agent = new ToolLoopAgent({
  // ... existing config
  onStepFinish: ({ usage, stepNumber }) => {
    console.error(
      `Step ${stepNumber}: ${usage.inputTokens} input, ${usage.outputTokens} output`,
    );
  },
});

这就是全部插桩代码。每一步后都会SDK 会替你调用。

执行一项痛苦的任务

bash
bun run index.ts . "Read package.json, then tsconfig.json, then index.ts, then summarize everything"

你应该看到类似这样的内容:

Step 0: 1,200 input, 450 output
Step 1: 2,800 input, 200 output
Step 2: 4,100 input, 180 output
Step 3: 8,900 input, 350 output
Step 4: 9,200 input, 600 output

具体数字会在你的项目中有所不同。形状不会变。输入token每一步都要攀爬。输出token大致保持平稳。

为什么输入token增长

每一步都会将整个消息历史发送给模型。用户提示词。系统提示词。Agent的每一次工具调用。Agent收到的每一个工具结果。

第一步的package.json在第四步仍然处于上下文中,尽管Agent已经结束了。第二步的tsconfig还在。没有什么东西会自己离开。

组成部分token行为
系统提示词~500修复了,每隔一调用
每一个工具结果200到2000始终保留在历史记录中
20工具后调用4000到40000线性累积

上下文窗口是20万token。一个忙碌的Agent读取大文件,通常只需30到50步就能完成。当它出现时:

  • 顶部的指示被忽视了
  • 模型开始忽视自己的系统提示词
  • 工具选择会退化
  • Agent会循环或产生幻觉

什么不行

三个诱人的非修复方案:

  • **Hoping这并不happen.**在实际任务中总是这样。
  • **Reducing步count.**十步对真正的工作来说太少了。五十是正常的
  • **Using更大的model.**更大的上下文窗口会拖延问题,并不能解决问题。而且每只token的费用也更高

解决办法是把旧工具结果从消息历史中移除,避免它们溢出注意力。第5.2课正是做到这一点的。

**注意:遥测先修,修第二**

这课并不能解决问题。这是故意的。除非先测量问题,否则无法判断修复是否有效。token日志会保留到模块的其余部分,方便你在每一步前后进行比较。

动手试试

执行多步骤任务。看看这些数字。确认:

  1. 输入token随着每一步增长
  2. 产量token保持相对较小
  3. 到最后一步,你发送的token是第0步的三倍以上
bash
bun run index.ts . "Read package.json, then tsconfig.json, then index.ts, then summarize everything"

试试更长的任务,看看曲线变陡:

bash
bun run index.ts . "Read every .ts file in src/, then tell me what each one does"
bash
npx tsc --noEmit

提交

bash
git add index.ts
git commit -m "feat(telemetry): log token usage per step"

完成标准

  • [ ] onStepFinish接线用于日志和usage.inputTokensusage.outputTokens
  • [ ] 一个4+步骤的任务显示输入token攀爬
  • [ ] 输出token在各步间保持相对平稳
  • [ ] 日志记录是console.error的,不是console.log
  • [ ] npx tsc --noEmit

**注意:绘制曲线**

记录数字给stderr没问题。把它们记录在CSV上更好。在onStepFinish中将step,inputTokens,outputTokens附加到文件中,然后加载到你选择的电子表格中。曲线的形状告诉你任务是读取量大(陡峭爬升)还是计算量大(较缓和爬升)。Agent一样,曲线不同,取决于它在做什么。

参考实现

ts
const agent = new ToolLoopAgent({
  model: "anthropic/claude-haiku-4-5",
  instructions: buildSystemPrompt({
    workingDirectory: cwd,
    sandboxType: sandbox.type,
    toolNames: Object.keys(tools),
    projectContext,
  }),
  tools,
  stopWhen: stepCountIs(15),
  onStepFinish: ({ usage, stepNumber }) => {
    console.error(
      `Step ${stepNumber}: ${usage.inputTokens} input, ${usage.outputTokens} output`,
    );
  },
});

非官方简体中文翻译 · 原课程来自 Vercel Academy