Agent 一直在忙,怎样才算把事情做完了?
用一个文章链接检查器,拆开 Agent 的完成条件、失败状态和执行预算。
目录
一个 Agent 连续调用了十几次工具,最后回复“已经完成”。先别急着高兴。它可能只是把计划写得很完整,也可能拿到一次超时,就把那个链接判成了失效。
我更关心它能交出什么证据。比如检查博客里的链接,结果应该能回答:检查了哪些地址,哪些确实坏了,哪些只是暂时查不到。把这几件事说清楚,比让它多想两轮有用。
先把任务缩小到能验收
假设要检查一篇 Markdown 文章里的外链。这里只做检查,不自动修改文章。输入是一份文章内容,输出是一份报告。重复地址只请求一次,带 # 的页内定位不发网络请求,邮件地址另行跳过。
可以先写下这样的验收要求:
| 情况 | 报告应该怎样记录 |
|---|---|
| 没有外链 | 正常完成,检查数为 0 |
| 返回 200 | 地址可访问;不声称正文内容正确 |
| 返回 404 或 410 | 标记为失效候选,保留状态码 |
| 返回 403 | 标记为访问受限,不能直接认定网页不存在 |
| 超时 | 标记为未确认,记录尝试次数 |
| 工具根本没有执行 | 任务未完成,不能生成“全部正常” |
这里的“完成”是所有地址都被归入了一个明确状态。并不要求所有地址都能访问,也不要求工具永远成功。
Anthropic 在 Building effective agents 里区分了由代码规定路径的 workflow 和由模型决定下一步的 agent。上面这个小任务,其实大部分用固定流程就能完成。我会把模型留给解释报告、判断替代链接是否符合原文这些环节。读取地址、请求网页、统计状态,用普通程序更容易核对。
停止原因要单独记录
“运行结束”至少有四种意思:全部处理完了、预算用完了、缺少必要输入、遇到无法继续的错误。如果它们最后都变成一个 done,之后就只能翻聊天记录猜原因。
一个报告头可以长这样。数字只是演示,不是本站的实测结果:
{
"status": "partial",
"stop_reason": "request_budget_exhausted",
"unique_links": 18,
"checked_links": 15,
"unconfirmed_links": 3,
"changed_files": []
}
还需要每个地址自己的记录。否则总数虽然对得上,也不知道剩下三个是谁。若允许恢复任务,就从未检查的条目继续,不必把成功的请求全做一遍。
给重试一个尽头
重试不是免费保险。工具连续超时,模型可能换一种说法再调一次,表面上像在排查,实际上仍然请求同一个地址。
我会同时设置三个限制:单次请求超时、每个地址的最大尝试次数、整个任务的总时长。具体数值要看网站响应和服务预算,不能照搬成通用标准。收到限流响应时还要尊重服务端的等待提示,等不到预算内就报告未确认。
更容易漏掉的是总预算。每个地址只试两次,遇到几千个地址,任务照样能跑很久。计数器应该放在执行工具的程序里,不能只在提示词里写一句“不要调用太多次”。
如果检查器读取任意外部文章,还要限制可请求的目标,避免文章里的地址把服务引向本机或内网。这属于请求层的规则,不该由模型读完网页后临时决定。
最后一句话,应该从报告里来
结果已经是结构化数据,就让最终回复使用这些字段:检查 18 个地址,其中 2 个失效候选、3 个未确认,并附清单。没有执行记录,就没有成功结论。
这个小例子让我觉得,做 Agent 时最值得先写的往往是验收逻辑。工具和模型都可以换,但“怎样算做完”如果一直含糊,换来换去只是让同一个问题跑得更快。