猪头少年 - 云南AI专家 - 云南独立开发者

Engineering note

错误处理、超时与取消:让失败有边界

这是「Agent 工程实战」的第 12 篇。专题从一个能聊天、能调工具的 .NET Agent 出发,逐步补齐可靠性、安全、测试与发布能力。

本篇要解决的问题: 处理 HTTP 异常、流中断、工具失败和用户取消,避免一次故障拖垮会话。

返回专题路线


本章定位:本章把异常、超时、取消和重试从偶发问题变成可设计的状态。你会学习如何划分异常边界,以及为什么副作用工具必须考虑幂等性。

建议阅读方式:先通读原理,再对照当前项目源码,最后完成本章实践。一个好的错误处理系统不是让所有请求都成功,而是让失败可解释、可恢复、可审计。

本章导读

本章把异常、超时、取消和重试从偶发问题变成可设计的状态。你会学习如何划分异常边界,以及为什么副作用工具必须考虑幂等性。

本章采用“源码观察 → 概念拆解 → 工程改造 → 实践验证”的顺序。示例中的接口和代码骨架用于说明设计方向,真正提交代码时应结合项目当前状态逐步落地。

12.1 错误分层

建议区分:

错误 处理方式
参数错误 不执行工具,把可读错误返回模型
权限错误 记录审计,返回拒绝原因
工具业务失败 返回结构化失败结果,可允许模型修正参数
网络瞬时失败 有限重试
认证/配置错误 立即终止本轮并提示用户
程序内部错误 记录完整异常,向模型返回通用错误

不要把堆栈、密钥、环境变量和任意本地路径全部暴露给模型。

12.2 取消令牌要贯穿调用链

理想调用链如下:

Console.CancelKeyPress
  -> BooAgent.Start(token)
  -> AgentLoop.RunAsync(token)
  -> IModelClient.StreamAsync(token)
  -> IToolExecutor.ExecuteAsync(token)
  -> File/Process API(token)

只有最底层支持取消还不够,上层必须把 token 传下去。

12.3 重试不能重试一切

可以重试连接中断、429 和部分 5xx;不应重试参数错误、权限拒绝和明确的业务失败。工具写入操作还要考虑幂等性,否则重复执行可能产生多份文件或重复副作用。

12.4 本章交付物

  • 统一错误码;
  • 请求、工具和整轮 Agent 的超时;
  • Ctrl+C 取消;
  • 有限重试策略;
  • 错误日志和用户可读提示。

12.5 异常边界应该在哪里

推荐每一层只捕获自己能处理的异常:

  • HTTP 层把网络异常转换为模型请求错误;
  • SSE 层把非法事件转换为协议错误;
  • 工具执行层把业务异常转换为 ToolResult
  • Agent Loop 决定错误是重试、交给模型还是结束会话;
  • UI 层把最终状态显示给用户。

不要在最外层用一个 catch (Exception) 把所有问题都变成“发生错误”。那样虽然不会崩溃,但会丢失修复问题所需的上下文。

12.6 超时的层级

一次用户请求可能包含多个模型请求和多个工具调用,应该有层级化的 deadline:

本轮总 deadline:60 秒
  模型请求:30 秒
  单个工具:10 秒

单个工具超时后,剩余总时间仍然应该受到约束。不要每次循环都重新创建一个完整时长的 timeout,否则 Agent 可以通过反复工具调用绕过总时限。

12.7 重试与幂等性

读取操作通常可以重试;写入、删除、发送消息等副作用操作需要幂等键或人工确认。一个简单的规则是:只有明确标记为 idempotent 的工具允许自动重试。

public sealed record ToolPolicy(
    bool IsIdempotent,
    bool RequiresApproval,
    TimeSpan Timeout);

重试日志要包含次数和原因,最终错误要告诉 Agent 已经尝试过几次,避免模型重复安排相同动作。

12.8 练习:故障注入

给 fake model client 和 fake tool executor 增加故障开关,分别模拟超时、取消、429、工具异常和非法 JSON。用测试验证每类故障的状态、是否重试以及最终用户看到的提示。

12.9 本章产出

完成本章后,异常不再是随机的堆栈,而是可以分类、观察、重试或安全终止的业务状态。

单篇实战作业

实践:注入网络超时、工具异常和用户取消,画出每一种错误在模型、工具和 UI 层分别如何表现。

建议把作业拆成一个独立提交,并在提交说明中写清楚:改动前的行为、改动后的行为、验证命令、尚未解决的风险。一个好的错误处理系统不是让所有请求都成功,而是让失败可解释、可恢复、可审计。

章节复盘

复盘问题:一次失败是否可能重复执行副作用?为每个可重试工具写出幂等性结论。

本章的完成标准不是把所有设计一次性做完,而是能把它变成项目中的一个明确边界,并为下一章留下可验证的接口。


下一篇:第 13 篇《记忆、会话与上下文窗口:哪些信息应该留下》

如果你正在把 Agent 放进真实工作流,建议完成本篇的实战作业后再继续:每一步都应留下可验证的代码、测试或运行记录。

Next step

不要停在单篇文章。

沿主专题继续阅读,查看同一问题从概念到实战的完整路径。

返回「Agent 工程实战」路线