把错误码表和业务规则喂给模型后,错误场景说明怎么从“失败”变成能直接用的排查步骤

很多团队用模型生成接口文档时,错误场景说明基本是废的——模型看一眼错误码表,输出一句“请求失败”或“参数错误”就交差。问题不在模型能力,而在你喂给它的上下文里根本没有“排查路径”这个维度。错误码表只告诉模型“发生了什么”,业务规则只告诉模型“什么情况下会发生”,但能直接用的排查步骤需要第三类信息:每个错误码对应的可观测信号、可执行的检查动作、以及修复后的验证方式。把这三类信息结构化地补进提示词,错误场景说明才能从“失败”变成排障手册。

先把错误码表从“枚举”升级成“诊断卡片”

多数接口文档里的错误码表长这样:

错误码 含义
1001 参数错误
1002 签名无效
1003 余额不足
1004 订单不存在

模型拿到这张表,能写出的最好结果也就是“1001 表示参数错误”。因为表里没有任何信息能让它推断出“用户该怎么排查”。你需要把每个错误码扩充成一张诊断卡片,至少包含六个字段:

  1. 错误码与含义:保留原有信息
  2. 触发条件:什么具体情况下会返回这个错误
  3. 用户可观测信号:日志里会出现什么、监控面板上哪个指标异常、响应体里除了 code 还有什么特征字段
  4. 检查动作:按顺序列出 3-5 步具体操作,每一步要能执行、能判断结果
  5. 修复动作:确认根因后用户该改什么
  6. 验证方式:修复后怎么确认问题已解决

拿“签名无效”举例,诊断卡片长这样:

错误码:1002
含义:请求签名验证失败
触发条件:
  - 请求头 X-Signature 缺失或格式错误
  - 签名算法与网关配置不一致(当前为 HMAC-SHA256)
  - 参与签名的参数与网关实际收到的参数不一致
  - 时间戳偏移超过 300 秒
可观测信号:
  - 网关访问日志中 request_id 对应的 auth_result 字段为 sign_mismatch
  - 响应体 code=1002,message 中包含 "timestamp expired" 或 "signature mismatch"
检查动作:
  1. 确认请求头 X-Signature 是否存在,长度是否为 64 位十六进制字符串
  2. 检查本地服务器时间与标准时间偏差是否在 ±300 秒内(执行 `date -u` 比对)
  3. 用网关提供的签名调试工具(https://debug.example.com/sign)输入相同参数,比对生成的签名
  4. 确认参与签名的参数拼接顺序与网关文档第 3.2 节一致
修复动作:
  - 若时间偏差超限,同步 NTP 时间后重试
  - 若签名不一致,按调试工具输出修正签名逻辑
验证方式:
  - 使用同一组参数重新请求,确认返回 HTTP 200 且 code=0
  - 连续请求 10 次,确认无间歇性 1002 出现

这张卡片写完,模型生成的错误场景说明自然就有了具体的步骤,因为它能直接从“检查动作”字段里提取并重组,而不是凭空编。

业务规则要和错误码做“场景绑定”,而不是并列喂进去

第二个常见问题是业务规则和错误码表分开喂,模型不知道哪条规则对应哪个错误码。比如你告诉模型“余额不足时返回 1003”,又告诉它“账户余额 = 可用余额 + 冻结余额”,但它不会自动推出“用户看到 1003 时应该先去查冻结余额”。

解决办法是在诊断卡片里直接嵌入业务规则,让规则和错误码在同一上下文中出现。以上面的“余额不足”为例:

错误码:1003
含义:账户余额不足
触发条件:
  - 可用余额 < 请求金额
  - 注意:余额 = 可用余额 + 冻结余额,冻结余额不可用于支付
  - 若用户同时有未结算的在途订单,可用余额可能低于用户预期
可观测信号:
  - 响应体 code=1003,message 包含 "available balance: XX.XX"
  - 账户服务日志中 balance_check 事件 result 字段为 insufficient
检查动作:
  1. 调用 GET /v1/accounts/{id}/balance 查询可用余额(字段 available_balance)
  2. 对比请求参数中的 amount 与 available_balance
  3. 若 available_balance 足够但仍报 1003,检查是否存在并发扣款导致余额被占用
  4. 调用 GET /v1/accounts/{id}/freeze 查询冻结金额,确认是否有未释放的预授权
修复动作:
  - 让用户充值或降低请求金额
  - 若冻结金额异常,联系账户服务值班处理预授权释放
验证方式:
  - 充值后重新请求,确认返回 code=0
  - 若为并发场景,连续发送 20 笔并发请求,确认无超额扣款

注意这里把“余额 = 可用余额 + 冻结余额”这条业务规则直接写进了触发条件,并且推导出了“冻结金额异常”这个用户可能想不到的排查分支。模型看到这样的上下文,生成的文档里就会保留这条规则和对应的检查动作。

提示词里要明确要求“按排查顺序输出,禁止省略步骤”

上下文准备好了,提示词也得改。默认的“请生成错误场景说明”太宽泛,模型倾向于压缩信息。你需要明确约束输出结构。

我实际用过的提示词模板(经过多次迭代):

你是接口文档撰写专家。下面提供每个错误码的诊断卡片,包含触发条件、可观测信号、检查动作、修复动作、验证方式。

请为每个错误码生成「错误场景说明」段落,要求:
1. 先描述用户遇到的具体现象(可观测信号),再给出排查步骤
2. 排查步骤必须完整保留诊断卡片中「检查动作」的所有条目,按原顺序输出,不得合并或省略
3. 每一步使用祈使句,以动词开头,指明具体操作对象和判断标准
4. 修复动作和验证方式单独成段,用「修复后验证」作为小标题
5. 不要输出「请联系客服」作为排查步骤,除非诊断卡片中明确写了该步骤
6. 每条排查步骤不超过 40 字,但必须包含可执行的命令、接口名或字段名

第 5 条很重要。模型有个坏习惯:遇到复杂排查场景时倾向于偷懒,直接写“请联系技术支持”。如果你不给负面约束,它会用这个万能答案替代真实的排查步骤。第 6 条则是防止模型把步骤写成“检查一下签名是否正确”这种废话——没有命令、没有字段名、没有判断标准,用户看完还是不知道怎么做。

用一个真实案例看前后差异

以支付接口的“订单不存在”错误(错误码 1004)为例。

改造前,模型生成的错误场景说明:

1004:订单不存在。当请求的订单号在系统中不存在时返回此错误。请检查订单号是否正确。

这就是典型的废话。

改造后,喂入诊断卡片并使用上面的提示词,模型输出:

1004 订单不存在

用户请求支付时,响应体返回 code=1004,message 为 "order not found: {order_id}",同时网关日志中 order_lookup 事件 result 字段为 miss。

排查步骤:

  1. 复制响应体 message 中的 order_id,确认与请求参数 order_id 是否一致
  2. 调用 GET /v1/orders/{order_id} 查询订单状态,确认接口返回 200 还是 404
  3. 若返回 404,登录商户后台(merchant.example.com)在订单查询页输入 order_id 确认订单是否创建成功
  4. 若订单存在但接口返回 404,检查请求的 AppID 与创建订单时的 AppID 是否一致(订单按 AppID 隔离)
  5. 若订单创建时间在 24 小时前,确认订单是否已过期被系统归档(归档订单需调用 GET /v1/archived-orders/{order_id} 查询)

修复后验证:

  • 使用正确的 order_id 重新请求,确认返回 code=0
  • 若为 AppID 不匹配,切换到创建订单时使用的 AppID 后重试
  • 若为归档订单,先调用 POST /v1/orders/{order_id}/restore 恢复订单,再发起支付

这个输出能直接用,因为每一步都有具体动作和判断标准,用户拿着文档就能排查,不需要再找开发问。

把诊断卡片维护进版本库,别只放在提示词里

这套方案的关键前提是诊断卡片的质量。如果诊断卡片本身写得含糊,模型输出一定含糊。所以诊断卡片不能是一次性的提示词素材,而应该作为接口文档的源数据维护在版本库里。

我的做法是把诊断卡片写成 YAML 文件,和接口定义放在同一仓库:

# errors/1004.yaml
code: 1004
meaning: 订单不存在
triggers:
  - 请求的 order_id 在系统中不存在
  - 订单属于其他 AppID(订单按 AppID 隔离)
  - 订单已过期归档(创建时间超过 24 小时)
observable_signals:
  - response.message 包含 "order not found: {order_id}"
  - 网关日志 order_lookup.result == "miss"
  - GET /v1/orders/{order_id} 返回 404
checks:
  - 对比响应体 message 中的 order_id 与请求参数 order_id 是否一致
  - 调用 GET /v1/orders/{order_id} 查询订单状态,确认返回 200 还是 404
  - 登录商户后台在订单查询页输入 order_id 确认订单是否创建成功
  - 检查请求的 AppID 与创建订单时的 AppID 是否一致
  - 若订单创建时间超过 24 小时,调用 GET /v1/archived-orders/{order_id} 确认是否已归档
fixes:
  - 使用正确的 order_id 重新请求
  - 切换到创建订单时使用的 AppID
  - 调用 POST /v1/orders/{order_id}/restore 恢复归档订单
verifications:
  - 使用正确的 order_id 重新请求,确认返回 code=0
  - 恢复归档订单后重新发起支付,确认无 1004 返回

然后用脚本把 YAML 转成 Markdown 表格或直接拼进提示词。这样做有两个好处:一是开发改代码时顺手更新 YAML,文档生成永远拿到最新信息;二是同一个 YAML 可以同时用于生成接口文档、排障手册、以及客服知识库,一套数据多处复用。

常见问题

诊断卡片里的检查动作写多细合适?

写到“用户拿着文档能独立执行完并定位到根因”的程度。判断标准:每一步都包含一个可执行的操作(命令、接口调用、页面操作)和一个可判断的结果(返回值、字段值、页面状态)。如果某一步写成“检查配置是否正确”但没有说怎么检查、检查什么配置项,就是不合格的。

错误码太多(上百个),逐个写诊断卡片成本太高怎么办?

按错误码的实际触发频率排序,先覆盖 Top 20。通常一个接口的错误码分布遵循二八定律,20% 的错误码覆盖 80% 的线上问题。剩下的错误码可以先用简化版卡片(只有触发条件和含义),等有真实排障案例时再补充完整。另外,同一个错误码如果出现在多个接口中,诊断卡片可以复用,只需要在 triggers 里补充接口特定的触发条件。

模型生成的排查步骤偶尔会“编造”不存在的接口或字段,怎么防止?

在提示词里加一条硬约束:“只允许使用诊断卡片中出现的接口名、字段名和命令,禁止引入任何未在诊断卡片中出现的技术细节。”同时把诊断卡片以代码块形式放在提示词最后,让模型在生成时优先参照。如果还出现幻觉,把温度参数调低(如 0.2),并在生成后用脚本校验输出中出现的接口名是否都在诊断卡片的白名单里。

诊断卡片更新后,已经生成的文档怎么同步?

不要手动改生成的文档。把生成过程做成 CI 流水线:YAML 文件变更触发文档重新生成,生成结果自动提交到文档仓库。这样诊断卡片是唯一数据源,文档永远是派生产物,不存在“改了卡片忘了改文档”的问题。