Chapter 16 · Domain 4(本章 skill 权重合计 2.6%)
调试与错误处理先判 integration layer 还是 model output,再选恢复策略
TS 4.1 不奖励「看到 exception 就重试」。它考的是从 trace 识别错误类型、隔离失败源头,再把代码/配置/网络问题与 prompt/schema/输出校验问题交给不同修复路径。
一、第一刀:这次调用有没有形成完整 Message
诊断从证据边界开始,而不是从异常栈最末一行开始。先找 HTTP status、SDK exception、SSE event 与最终 Message:请求若在认证、权限、payload、rate limit、网络或服务端处理阶段失败,源头在 integration layer (集成层);API 若已经返回成功的 Message,再看 stop_reason 与 content,才能判断是正常完成、截断、工具交接,还是 model output (模型输出)不满足业务契约。
Trace 证据 先归哪一层 第一修法
非 2xx、typed SDK exception、没有 Message Integration 修 request / credential / permission / payload;瞬时错误走 bounded retry
SSE 已是 HTTP 200,但出现 event: error,没有 final message_stop Integration / stream 把 partial response 标为未完成;按 event type 恢复或重试
成功 Message,stop_reason 是 max_tokens / tool_use 等 Generation / output path 按停止原因继续、执行工具或调整输出预算,不把它伪装成 parser bug
end_turn 且 content 完整,但 schema / business validation 失败Model output contract 收紧 prompt / schema,并保留确定性 validation failure branch
P6 先分源头 — JSON.parse() 抛错只说明失败被 parser 看见,不说明根因在 JSON。上游若把 429 吞成空字符串,修的是 integration;上游若给出 end_turn 且正文多了一句 preamble,修的是 output contract。相同 exception 名可以来自两层。
二、错误名决定恢复;stop_reason 决定下一步
API 错误 body 是 JSON:顶层 error 对象含 type 与 message,另有 request_id;每个响应也有唯一 request-id header。把这些字段写进 trace,才能按类型聚合,而不是 string-match 一段会变化的自然语言错误。
HTTP / error type 它指向什么 恢复动作
400 invalid_request_error request format / content 修请求;不要重写业务 prompt 来掩盖无效 payload
401 authentication_error · 402 billing_error · 403 permission_error credential / billing / access 修配置或授权;模型没有机会生成答案
404 not_found_error · 409 conflict_error · 413 request_too_large resource / state / bytes 核对 ID、先解决冲突、或缩小 payload
429 rate_limit_error rate limit 或 spend cap 遵守 retry-after;无该 header 的 spend-cap 429 不能靠紧密重试恢复
500 api_error · 504 timeout_error · 529 overloaded_error server / processing / temporary capacity 指数退避;长请求考虑 streaming 或 batch,并保留 request ID
官方 SDK 会对 connection errors、rate limits 与 5xx 等瞬时失败用 exponential backoff 自动重试,默认两次,并在存在时遵守 retry-after。Trace 因此要记录 attempt:否则你会把「SDK 已重试三次总尝试」误读为三位用户各发了一次,或在外层再套无界重试。
stop_reason含义 集成层下一步
end_turn自然完成 使用 content,但仍做 schema / business validation
max_tokens触到请求或模型输出上限 视为截断;提高预算或缩短输出后再校验
stop_sequence命中自定义 stop sequence 读 stop_sequence 判断是哪条边界触发
tool_use模型发起一个或多个工具调用 执行 client tool,并回传匹配的 tool_result
pause_turnserver-tool loop 触到 iteration limit 把 assistant content 带回后续请求继续
refusalClaude 拒绝回应 按 refusal 分支处理,不归为 network error
model_context_window_exceededgeneration 触到 context window 视为截断并缩减 context / output 预算
三、让 trace 能分堆,而不是只会报一个 “parse_error”
最小可用 trace 至少保留:request_id、attempt、elapsed_ms、HTTP status / SDK exception、最后一个 SSE event、stop_reason、content block types、tool / permission stage,以及独立的 validation result。关键是不要把上游事实覆盖成下游症状:
{"req":"req_A","attempt":2,"http":529,"error":"overloaded_error","message":null}
{"req":"req_B","http":200,"stop_reason":"max_tokens","validation":"truncated_json"}
{"req":"req_C","http":200,"stop_reason":"end_turn","validation":"missing:currency"}
分堆 证据 该改什么 不要改什么
Integration req_A:无 Message,529retry / backoff / capacity handling prompt 与 output schema
Output-side limit req_B:成功 Message,明确截断max_tokens、response scope、截断校验HTTP retry helper
Model output req_C:自然完成但契约不合格prompt / Structured Outputs / validation credential 与 network timeout
Streaming 更要保留层级:SSE event stream 可能出现 event: error,而正常 flow 以 final message_stop 收口;收到 partial blocks 甚至 HTTP 200 都不能覆盖后续 error event。Claude 4.6 及之后如因 network / timeout 中断,可保存已收 text,再以 user message 携带 partial response 并要求继续;partial tool use 与 thinking block 不能这样恢复。没有 message_stop 的 partial text 不能直接当完整 model output 入库。
Claude Code 的 permission path 也是 integration/control plane 的子层:auto mode classifier 在 permissions system 之后运行;managed permissions.deny 会在 classifier 被咨询前阻断且不可覆盖。Trace 若写着 deny_match=true、classifier_invoked=false、tool_started=false,应修 permission 配置或应用的状态传播,不能靠改 prompt 让被 deny 的动作“更可信”。
P6 + P7 — 先把 failure 按源头分堆,再给每堆自己的 recovery;成功 Message 的 content 仍是待校验数据。若 529 与 schema mismatch 同时存在,正确答案必须同时修 integration 与 model-output contract,不能用一个统一的 “retry everything” 抹平层级。
考点回链 — 本章覆盖:TS 4.1(API / streaming / tool / permission 错误类型识别;按可恢复性选择策略;从 request ID、status、event、
stop_reason 与 validation trace 隔离 integration layer 和 model output)。相邻考点:Messages / streaming / tool loop 机制见
ch02 ;prompt、Structured Outputs 与 defensive validation 见
ch10 ;Claude Code permission / classifier 分层见
ch15 。
本章题组
QUESTION 01 · TS 4.1 · AUTHENTICATION TRACE
A production call fails after 74 ms. The trace is {"http":401,"error":{"type":"authentication_error","message":"invalid x-api-key"},"request_id":"req_01K","message":null}. A downstream worker reports “Claude returned no JSON.” What should the team change first?
A Add two valid JSON examples to the prompt and require the model to emit no preamble, then replay the same request with the unchanged credential loader.
B Catch authentication_error and return {} to the downstream worker, preserving the current success-shaped interface while the key issue is investigated separately.
C Fix API-key loading and surface the typed authentication error with request_id; no model output exists, so prompt tuning and output parsing are downstream.
D Move the call to a more capable model so it can recover from malformed credentials and still produce the JSON contract expected by the worker.
正确 C 401 authentication_error、74 ms、message:null 已把失败定位在 credential/integration 层。先修 key loading,并让错误按错误传播;此时不存在可供 prompt 优化的模型输出。
D2 无关杠杆 违反 P6 A :few-shot 能影响成功调用后的输出形态,却不能让一个 401 请求进入生成阶段;它作用在错误发生之后的另一层。
D6 半对半错 违反 P6 B :catch typed error 是对的,伪造成空 JSON 则把 integration failure 再次改名为 output failure,破坏了 trace 的源头边界。
D4 换模型当解法 违反 P6 D :认证发生在模型生成之前;换模型不会改变 key 的有效性,也不会创造不存在的 Message。
QUESTION 02 · TS 4.1 · OUTPUT CONTRACT
An invoice extractor returns HTTP 200 with stop_reason:"end_turn". Its text is Here is the result:\n{"invoice_id":"I-73","total":91.4}, followed by SyntaxError: Unexpected token 'H' at JSON.parse (worker.ts:88:19). The same preamble appears in 116 of 1,000 successful calls. What is the best fix?
A Classify it as a model-output contract failure; enforce output_config.format with a JSON schema, retain application validation, and track it separately from transport errors.
B Retry every HTTP 200 response three times inside the network client, because a parser exception proves the transport delivered an incomplete response even when end_turn is present.
C Catch SyntaxError and forward the raw text to billing as if it were validated JSON, eliminating worker crashes while preserving every token the model generated.
D Upgrade the model and remove schema validation, relying on the larger model to stop adding preambles consistently enough for billing to parse the string directly.
正确 A 请求成功并自然结束,失败对象是 text 与 JSON contract 不一致。Structured Outputs 用 output_config.format 约束 schema;集成层仍保留 validation,符合 P7。
D2 无关杠杆 违反 P6 B :116/1,000 的稳定 preamble 是 output shape,不是 transport 中断;重试 network client 没有修 schema 契约。
D6 半对半错 违反 P7 C :catch 能防进程崩溃,但把未解析字符串冒充 validated JSON,正好删掉了下游需要的确定性边界。
D4 换模型当解法 违反 P6 D :trace 已定位为可表达的 output contract;换模型还顺带撤掉 validation,让概率性格式直接进入 billing。
QUESTION 03 · TS 4.1 · MID-STREAM ERROR
A streaming summarizer logs HTTP/1.1 200, two content_block_delta events containing 312 characters, then event:error data:{"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}. The socket closes at 8.4 s and no message_stop arrives. How should the application classify and handle this trace?
A Accept the 312 characters as a complete model answer because HTTP 200 proves generation succeeded, then run normal business validation and store any validation failure as model-output drift.
B Increase max_tokens and replay immediately, because overloaded_error indicates the response exhausted its output-token budget before the final event could be emitted.
C Append a stricter instruction asking Claude never to overload the service, then parse the partial text if another stream ends without message_stop.
D Classify it as an integration/stream failure: without message_stop the partial text is incomplete, so quarantine it and use bounded backoff or documented continuation recovery.
正确 D SSE 可以在 HTTP 200 之后发 error event;overloaded_error 对应非 streaming 的 529。没有 final message_stop,partial text 不能冒充完整 output,应走 stream recovery。
D6 半对半错 违反 P6 A :200 只证明 stream 已建立;后续 error event 已否定「完整成功」。把 partial validation failure 记到模型层会污染两层指标。
D2 无关杠杆 违反 P6 B :overloaded_error 是容量错误,不是 max_tokens;调输出预算没有作用在已命名的失败类型上。
D3 措辞冒充控制 违反 P3 C :prompt 无法控制 API capacity;后半句还把未收口的 stream 当完成结果,既没有闸门也没有恢复分支。
QUESTION 04 · TS 4.1 · MAX_TOKENS
A non-streaming request returns {"http":200,"stop_reason":"max_tokens","usage":{"output_tokens":96},"content":[{"type":"text","text":"{\"items\":[{\"sku\":\"A1\""}]}. The parser raises JSONDecodeError: Expecting ',' delimiter. Network latency is 640 ms and no SDK exception was raised. What should be changed first?
A Make the parser append the missing brackets whenever output is invalid, then pass the repaired object downstream without distinguishing truncation from an actually malformed complete response.
B Treat it as max_tokens truncation: raise the output budget or reduce response scope, require a complete stop, and validate before use instead of repairing brackets.
C Apply exponential backoff to every parse exception, because max_tokens is a 5xx transport condition that the SDK failed to expose as a typed error.
D Switch to a more capable model while keeping max_tokens:96, expecting model quality to compress the full item list into the same hard output ceiling.
正确 B max_tokens 明示成功调用停在 output-side limit,parser 只是下游观察点。先调 budget 或缩小 response scope,再由 validator 决定是否可用。
D6 半对半错 违反 P7 A :补括号可能让字符串可解析,却不能证明被截掉的 items 已恢复;它把 syntax repair 冒充 semantic completeness。
D2 无关杠杆 违反 P6 C :max_tokens 是成功 Message 的停止原因,不是 5xx;把 parser exception 送进 transport retry 分错了层。
D4 换模型当解法 违反 P1 D :题干给的是 96-token hard ceiling,不是能力不足;换模型并未放宽或缩减输出约束。
QUESTION 05 · TS 4.1 · TOOL LOOP
An order-status endpoint receives HTTP 200 with {"stop_reason":"tool_use","content":[{"type":"tool_use","id":"toolu_72","name":"lookup_order","input":{"id":"O-19"}}]}. The application stores that object as the final customer answer, never invokes lookup_order, and records “model returned no status text.” Where is the failure?
A Complete the integration loop: execute the authorized client tool, return a matching tool_result, then continue to final customer text; tool_use is not the answer.
B Move the tool_use JSON into an ordinary user text message so Claude can read its own request as context without the application executing external code.
C Add a system instruction requiring Claude to infer a plausible order status whenever it wants to call a tool, avoiding the latency and failure modes of client-side execution.
D Retry the original model call until it returns end_turn, treating every tool_use response as malformed model output that should be discarded before the customer sees it.
正确 A tool_use 是正式交接信号,不是缺文本。client tool 要由应用执行,再以相同 ID 回传 tool_result;漏掉这段代码才是 integration failure。
D5 错层承载 违反 P4 B :结构化 tool request 属于应用执行协议,把它降成普通 text 不会触发订单系统,也失去 ID 配对。
D5 错层承载 违反 P4 C :实时订单状态应来自外部 tool,不该让模型凭 prompt 生成;它把确定性数据访问搬回模型层。
D2 无关杠杆 违反 P6 D :trace 已显示正常 tool_use,重采样只是在逃避 integration 必须完成的 tool-result 往返。
QUESTION 06 · TS 4.1 · RATE-LIMIT RECOVERY
A worker trace shows 429 rate_limit_error with retry-after: 12. The SDK log records attempt=0 t=0.0s, attempt=1 t=12.1s, and attempt=2 t=36.4s, then raises the typed error; no Message was created. What is the best next step?
A Increase max_tokens so each future request is allowed more output, expecting a larger generation budget to raise the organization's request-rate ceiling.
B Convert the final typed error into an empty assistant string and let output validation request another completion, hiding the exhausted SDK retries behind the parser layer.
C Keep it in the integration bucket: honor retry-after and bounded SDK retries, then surface or reschedule the typed failure instead of invoking output validation.
D Switch models and immediately replay all queued requests in parallel, assuming rate limits attach only to the selected model and cannot recur at organization level.
正确 C 429、typed error、无 Message 是 integration failure。日志还证明 SDK 已按 retry-after 做完默认两次 retry;下一步应显式 backpressure / reschedule 或向上游报错,而不是让 output path 再试。
D2 无关杠杆 违反 P6 A :max_tokens 管输出上限,不管 rate limit;它没有作用在已命名的 429 源头上。
D6 半对半错 违反 P6 B :让 worker 不中断听起来稳健,但空字符串会把 integration failure 再包装成 model-output failure,并触发重复请求。
D4 换模型当解法 违反 P1 D :题干没有证明限额只绑定 model;立即并发回放还与已经观测到的 rate-limit signal 反向。
QUESTION 07 · TS 4.1 · PERMISSION LAYER
A Claude Code automation reports success even though production cleanup did not run. Its trace is {"permission_stage":"managed.permissions.deny","deny_match":true,"classifier_invoked":false,"tool_started":false}, followed by AdapterError: expected tool result, received PermissionDenied. Which diagnosis is most precise?
A Remove the managed deny and add “never delete production unless requested” to CLAUDE.md, allowing the prompt to preserve the same hard boundary while the tool can now start.
B Retry with a stricter success-response schema and instruct Claude to emit completion only after the cleanup tool returns, giving the adapter a consistent success payload.
C Calibrate the auto-mode classifier for approved production-maintenance targets and retry the cleanup, so recognized infrastructure and user intent can be evaluated under the automation's existing policy.
D Keep the deny gate and fix the adapter's PermissionDenied propagation; the classifier and model output are downstream of the block.
正确 D managed deny 在 classifier 前阻断且不可覆盖;trace 也明确写着 classifier 未调用、tool 未启动。控制本身按设计工作,bug 是 adapter 把 PermissionDenied 映成 success。
D3 措辞冒充控制 违反 P3 A :CLAUDE.md 是 guidance,不是能替代 managed deny 的闸门;移除 deny 会破坏题干原有的强制边界。
D2 无关杠杆 违反 P6 B :exception 来自 adapter 收到 PermissionDenied,不来自一句成功措辞;重写输出没有补上状态传播代码。
D2 无关杠杆 违反 P5 C :官方层序和 trace 都说明 classifier 根本没运行;调它无法越过更早的 deny。
QUESTION 08 · TS 4.1 · MIXED FAILURE SET
A 10,000-call trace reports 800 failures. Of those, 300 are {"http":529,"error":"overloaded_error","message":null}. The other 500 are HTTP 200 with stop_reason:"end_turn", but validation says required property 'currency' missing. Which remediation plan matches the evidence?
A Apply one broad retry policy to all 800 calls, because both groups eventually surface in the same worker and a fresh model sample can repair either an overloaded API or a missing field.
B Split the groups: bounded backoff for 529s; schema-constrained output plus validation for the 200 responses.
C Add currency to the output schema and classify all 800 failures as model output, assuming the 529 responses would also have contained valid JSON if the schema were stricter.
D Move every call to a larger model and keep the existing retry and validation code, treating model capability as the shared cause behind both the named overload and the schema miss.
正确 B 300 条没有 Message,是 integration/capacity failure;500 条自然完成却少字段,是 model-output contract failure。两堆要分别用 bounded retry 与 schema + validation,正是 P6。
D6 半对半错 违反 P6 A :retry 对 529 是正当恢复,对稳定的 schema miss 却只是重新采样;一个动作只对了一半。
D6 半对半错 违反 P6 C :schema 正确修 500 条,但 529 根本没有 content;把无 Message 的失败归到输出层抹掉了 300 条 integration evidence。
D4 换模型当解法 违反 P1 D :题干已经给出两个不同的直接原因,换模型既不处理 API overload,也不建立字段校验契约。