第 1.9.4 节:把校验失败、重试与契约测试写成可校验、可复用的工程契约
校验失败、重试与契约测试不能只停留在口头约定,还需要落实为字段、校验和失败处理。完成本节后,你应该能够把校验失败、重试与契约测试落成字段表、校验规则、错误处理和验收样例。
权限、状态和日志
数据契约治理不是只管字段格式,还要管字段是否有权进入下一步。
权限
| 权限问题 | 契约如何参与 |
|---|---|
| 用户能不能查这个订单 | tool_args(工具参数)里的订单编号必须和当前用户身份校验。 |
| 模型能不能建议某个工具 | tool_name(工具名称)必须在允许工具清单里。 |
| 工具能不能自动执行 | risk_level(风险等级)和 next_action(下一步动作)要触发风险策略。 |
| 是否需要人工确认 | fallback_action(兜底动作)或审批状态要明确写入响应。 |
| 是否能记录日志 | 日志契约要区分可记录摘要和不可记录敏感数据。 |
权限不能只写在 Prompt(提示词)里。Prompt 可以提醒模型,但真正的拒绝、阻断和审批必须由系统规则执行。
状态
客服工作台至少要统一这些状态:
| 状态 | 含义 | 用户或客服看到什么 |
|---|---|---|
| passed | 契约校验通过 | 可以继续回答、调用工具或展示结果。 |
| failed | 契约校验失败 | 不展示不可信结果,进入错误处理。 |
| needs_retry | 可以有限重试 | 用户通常无感,系统重新请求模型或要求补全。 |
| fallback(降级方案) | 已进入兜底 | 展示安全回复、追问或转人工提示。 |
| rejected | 已拒绝执行 | 告诉用户当前请求不能自动处理,必要时转人工。 |
状态要少而清楚。状态越多,前端、测试和运营越难保持一致;状态太少,又无法表达真实失败路径。
日志
日志要回答 5 个问题:
| 问题 | 对应字段 |
|---|---|
| 这是谁的一次请求 | trace_id(追踪编号)、会话编号、用户身份摘要。 |
| 模型判断了什么 | intent(意图)、risk_level(风险等级)、next_action(下一步动作)。 |
| 校验是否通过 | validation_status(校验状态)、validation_error(校验错误)。 |
| 是否调用工具 | tool_name(工具名称)、工具执行状态、拒绝原因。 |
| 最后如何兜底 | retry_allowed(是否允许重试)、fallback_action(兜底动作)、人工处理状态。 |
有了这些日志,面试时你就能讲清:这个项目不是只做了一个会回答的机器人,而是有可观测、可审计、可复盘的数据链路。
失败场景与兜底
真实 Agent(智能体)系统一定会遇到不合格数据。优秀项目和玩具项目的区别,不在于永远不失败,而在于失败时不会乱执行。
| 失败场景 | 表现 | 处理方式 | 验收标准 |
|---|---|---|---|
| 模型输出无法解析 | 不是稳定结构,或混入解释文字 | 有限重试;仍失败则降级为安全回复或转人工 | 无法解析的输出不能进入工具调用。 |
| 必填字段缺失 | 缺 intent(意图)、risk_level(风险等级)或 next_action(下一步动作) | 允许低风险场景重试;高风险场景转人工 | 日志记录 missing_required_field。 |
| 枚举值漂移 | 风险等级出现 urgent、severe 等未定义值 | 触发校验失败,不能自动映射到高权限动作 | 未定义值不会驱动业务流程。 |
| 缺少工具参数 | tool_args(工具参数)缺订单编号或问题类型 | 追问用户或让用户选择订单 | 工具不会被空参数调用。 |
| 工具名称不在白名单 | 模型生成不存在或不允许的 tool_name(工具名称) | 拒绝工具执行,记录 tool_not_allowed | 不允许模型创造工具。 |
| 业务对象越权 | 用户传入他人订单编号 | 拒绝查询或转人工核验 | 不泄露他人订单信息。 |
| 高风险动作缺确认 | 退款、补偿、投诉升级没有人工或用户确认 | 阻断执行,进入人工审批或安全提示 | 不自动完成资金或高风险写入。 |
| 重试次数过多 | 模型多次输出仍不合格 | 停止重试,转人工或降级 | 防止无限循环和成本失控。 |
| 日志缺追踪编号 | 请求能返回,但无法复盘 | 生成补救追踪记录并触发监控 | 线上问题有定位入口。 |
| 前端状态不识别 | 新状态未同步给前端 | 返回安全兜底状态,避免页面误导用户 | 未识别状态不展示为成功。 |
兜底原则可以记成一句话:
能补信息就追问,能安全重试就有限重试,涉及工具和高风险就先校验,无法确认就降级、转人工或拒绝执行。
不适合展开语法学习的场景
本章刻意不展开 Pydantic(数据校验库)语法。原因不是语法不重要,而是这些场景里优先级不应该放在语法细节上。
| 场景 | 为什么不适合在本章展开语法 |
|---|---|
| 还没确定业务字段 | 先学语法会让你过早沉迷模型类写法,忽略字段语义。 |
| 团队还没统一意图和风险枚举 | 写出校验模型也会不断返工。 |
| 前后端状态还没对齐 | 后端校验再完整,前端仍可能误展示。 |
| 工具权限边界还没定 | 语法不能替代权限、审批和风控策略。 |
| 只是为了面试背概念 | 面试官更关心你如何处理校验失败、越权、日志和兜底。 |
| 框架版本还在变化 | 具体 API(应用程序接口)写法可能随版本调整,本书更关注稳定工程原则。 |
你可以在实现阶段再系统学习 Pydantic(数据校验库)的字段定义、枚举、嵌套模型、错误处理和与 FastAPI(后端接口框架)的集成。本章先帮你建立“为什么要这样设计”的能力。
工程检查清单
- 是否列出模型输出、工具输入、API 响应、前端状态、日志和测试这些数据边界?
- 是否定义
schema_version(契约版本),并说明版本变化如何兼容? - 是否统一
intent(意图)的枚举和业务含义? - 是否统一
risk_level(风险等级)的判断标准? - 是否明确
next_action(下一步动作)和前端展示状态的关系? - 是否用
missing_fields(缺失字段)阻止信息不足时调用工具? - 是否限制
tool_name(工具名称)只能来自工具白名单? - 是否对
tool_args(工具参数)做字段、权限和业务对象归属校验? - 是否用
validation_status(校验状态)表达通过、失败、重试、兜底和拒绝? - 是否记录
validation_error(校验错误),并能区分字段缺失、枚举错误、越权和高风险动作? - 是否明确
retry_allowed(是否允许重试),避免无限重试? - 是否定义
fallback_action(兜底动作),让失败路径可执行? - 是否全链路记录
trace_id(追踪编号)? - 是否防止日志记录密钥、完整隐私资料和敏感原文?
- 是否准备正常、缺字段、枚举漂移、越权、工具失败、高风险和前端状态异常的验收样例?