Agent调试、错误处理与成本优化

调试、错误处理与成本优化

系列第 6 篇 · 前置:第 1 篇第 2 篇第 3 篇第 4 篇第 5 篇

Workflow 跑起来不难,难的是跑出来的结果不对、或者跑得太贵。这篇讲实际踩坑中总结的调试方法和省钱技巧。


一、Agent 不按预期行事

这是最常见的问题:你让它列大纲,它写了篇全文;你让它返回 JSON,它给你加了段说明文字。

1. Prompt 不够具体

"帮我审查一下代码"和"逐行检查以下代码,每条问题输出:文件:行号 - 问题描述 - 严重程度(致命/一般/建议),没问题输出'通过'",效果天差地别。

改法:给格式、给枚举值、给示例。参考第 2 篇讲的 Prompt 写法。

2. 输出格式不对

让 Agent 返回结构化数据,它总爱加"好的,这是结果:"这种前缀。

改法 :用 schema 参数。传了 schema 之后,系统通过 constrained decoding 保证输出合法 JSON,返回的直接是 JS 对象,不用 JSON.parse

php 复制代码
const result = await agent('列出5个要点', {
  schema: {
    type: 'object',
    properties: {
      points: { type: 'array', items: { type: 'string' } }
    },
    required: ['points']
  }
})
// result.points 直接用,不用解析

3. 该触发的 Custom Agent 没触发

主 Claude 靠 description 判断什么时候派子 Agent。description 写得太模糊,它不知道什么时候该用。

改法:description 里写清楚"什么时候用",用动词开头,包含触发场景关键词。

makefile 复制代码
# 不好
description: 代码审查员

# 好
description: 审查代码变更,检查Bug、安全问题和代码风格。当用户要求review代码、检查提交、或分析代码质量时使用。

4. 上下文溢出

给 Agent 塞了太多内容,它处理不了或开始丢东西。

改法:任务拆小。不要把整个项目代码丢给一个 Agent,先让它定位文件,再让它读相关文件。搜索类任务只给相关片段,不给全文。


二、Workflow 常见错误

忘了 () =>

scss 复制代码
// 错:agent 立即执行,parallel 拿到的是结果不是任务
await parallel([agent('A'), agent('B')])

// 对
await parallel([() => agent('A'), () => agent('B')])

症状:三个任务看起来"同时"跑了,但其实是串行的,或者报错。

忘了 await

scss 复制代码
// 错:result 不是结果,是个 Promise
const result = agent('搜一下')
log(result)  // [object Promise]

// 对
const result = await agent('搜一下')

meta 里写变量

arduino 复制代码
// 错:meta 必须是纯字面量
export const meta = {
  name: TOPIC + '-workflow',  // 不行
  phases: [getPhases()],       // 不行
}

meta 在脚本执行前就被解析,不能有运行时的值。

phase 名字对不上

meta.phases 里的 title 必须和代码里 phase('xxx') 的字符串完全一致,否则进度面板分组不对。

Agent 返回 null 没处理

某个 Agent 失败了返回 null,直接拼字符串会出现 "null" 这几个字。

csharp 复制代码
// 防空
const allMaterials = [chinese || '', english || '', github || ''].join('\n')

三、调试技巧

1. 用 phase 和 label 看清执行过程

csharp 复制代码
phase('搜资料')
const result = await agent('搜中文资料', { label: '搜中文' })

进度面板会显示当前在哪个阶段、哪个 Agent 在跑、跑了多久。不写这些也能跑,但出问题时你不知道卡在哪。

2. 用 log 输出中间值

scss 复制代码
const outline = await agent('列大纲')
log('大纲内容:' + outline.slice(0, 200))  // 只打前200字

log() 会显示在进度面板上。调试时把关键中间产物打出来看,比跑完看最终结果猜哪里错了高效。

3. 返回中间产物

不要只 return 最终结果,把中间产物也带上:

kotlin 复制代码
return { draft, reviews, final }

跑完可以直接看到审查意见是什么、改了哪里。确认没问题后再精简返回值。

4. 先用小数据跑通

不要一上来就喂 10 个主题。先用 1 个主题跑通整个流程,确认每一步的输出符合预期,再加量。

5. 单独测试某个 Agent

Workflow 里某个 Agent 输出不对,把它的 Prompt 复制出来,在对话里单独跑,调 Prompt。比改完整脚本再跑一遍快。


四、错误处理

Agent 失败不影响其他

parallel 里一个 Agent 失败返回 null,其他的照常返回。这是特性不是 bug。但你要处理 null:

ini 复制代码
const results = await parallel(tasks)
const valid = results.filter(Boolean)

给默认值

ini 复制代码
const TOPIC = args.topic || '默认主题'
const materials = chinese || '(中文搜索无结果)'

关键步骤可以加重试逻辑

javascript 复制代码
async function agentWithRetry(prompt, opts, retries = 2) {
  for (let i = 0; i <= retries; i++) {
    const result = await agent(prompt, opts)
    if (result && result.length > 10) return result
    log(`第${i + 1}次结果为空,重试...`)
  }
  return null
}

不过一般不需要,Agent 失败概率不高。关键步骤加一下就行。


五、成本优化

跑 Workflow 最容易忽视的就是 token 消耗。几个立竿见影的做法:

1. 模型分层:haiku 干粗活,sonnet/opus 干细活

任务 推荐模型
搜索、分类、找问题、格式化 haiku
写正文、综合分析、改稿 sonnet(默认)
复杂推理、架构决策 opus(很少需要)
dart 复制代码
// 搜资料用 haiku
() => agent('搜中文资料', { model: 'haiku' })

// 写初稿用默认(sonnet)
const draft = await agent('写初稿')

agent() 选项里传 model 就行,哪个 Agent 该用便宜模型就给哪个加。phases 只管进度面板显示,不控制模型。

2. 能用 JS 处理的别派 Agent

javascript 复制代码
// 浪费:让Agent去重
const deduped = await agent(`把以下列表去重:${list.join('\n')}`)

// 省钱:JS去重,瞬间完成,0 token
const deduped = [...new Set(list)]

去重、过滤、排序、统计、字符串拼接,这些全用 JS。Agent 只干需要"理解"的活。

3. 只给片段,不给全文

javascript 复制代码
// 浪费:把整个搜索结果塞给Agent
const summary = await agent(`总结:${fullSearchResults}`)

// 省钱:先提取相关段落
const relevant = extractRelevant(fullSearchResults, TOPIC)
const summary = await agent(`总结:${relevant}`)

4. 审查类任务用 haiku

找 Bug、查格式、检查 AI 味,这些不需要强推理。haiku 便宜好几倍,效果差别不大。只有最终综合改稿时用好模型。

5. 别让 Agent 干它不需要干的事

scss 复制代码
// 浪费:Agent搜完还写了篇总结
() => agent('搜资料并总结成一篇文章')

// 省钱:只搜,总结交给下一步
() => agent('搜资料,列出3个来源和摘要', { model: 'haiku' })

六、常见问题速查

现象 原因 解决
Agent 没自动触发 description 写得不好 写清触发场景和关键词
输出不是想要的格式 Prompt 不够具体 用 schema 参数
parallel 里的任务串行执行了 忘了 () => 包成箭头函数
结果里出现 "null" Agent 失败返回 null 加 `
进度面板不显示阶段 phase 名字和 meta 对不上 检查字符串完全一致
跑起来特别贵 都在用默认模型 搜索/分类换 haiku
Agent 输出被截断 内容太长 任务拆小,只给相关片段
新 Agent 文件不生效 需要重启会话 重启 Claude Code
同样的输入结果不一样 温度/随机性 关键步骤加 schema 约束,或多跑几次取一致的

小结

dart 复制代码
调试:phase + label 看进度,log 打中间值,return 带产物
排错:先查 () => 和 await,再查 meta 字面量和 phase 名
省成本:haiku 干粗活、JS 干杂活、只给片段不给全文、能并行不串行
相关推荐
番茄不是西红柿kk21 分钟前
GLM-5.3-Flash 20分钟复刻《我的世界》实录
人工智能·ai·aigc·agent·我的世界
阿里云大数据AI技术26 分钟前
DataWorks Data Agent 实战课堂(六):数据集成定时任务巡检
人工智能·agent
张忠琳2 小时前
【deepseek-harness】Cordis 时空可组合性编程范式 — 三段式精读笔记(五)
ai·agent·deepseek·harness·cordis·dsh
武子康2 小时前
把生产 Agent 事故 Trace 变成可重放的回归测试集
人工智能·llm·agent
智脑API2 小时前
CCSwitch Claude Code 无法读取项目文件怎么办?工作目录、权限与忽略规则检查
claude·codex
心易行者2 小时前
从零搭建完整Web应用:7步走完全流程,配合web应用托管零门槛上线
人工智能·python·ai编程
一个处女座的程序猿3 小时前
Agent之Human-Agent Teaming:Cumora(面向人类与 AI Agent 协作的聊天应用)的简介、安装和使用方法、案例应用之详细攻略
人工智能·agent·cumora
全栈弄潮儿3 小时前
从零搭建你的 AI 编程工作流
aigc·openai·ai编程
程序员于老七3 小时前
漫话 Agent Harness · 前置:JSON-RPC 2.0——那个被 AI Agent 重新捧红的老协议
agent