应用部分 11. 与真实 API 集成:从规范到部署
状态:建议。 SDD 阶段划分 Specify/Plan/Tasks/Implement/Validate 和 25 分就绪度模型——建议性框架。它在学习路径中不需要真正的 Kubernetes、GitOps 或外部执行器。
前沿。 关键路径上完全自动化的自动修复,无需人工审核(human-review),仍然属于前沿领域:即使拥有丰富 SDD 经验的团队也会在流程中保留人工参与。Qwen Code 的内置命令中这里只有 /plan;其余步骤均为用户自定义命令或通过项目脚本直接执行 qwen -p。
对于学习路径,本地流水线 examples/real-api/ 已足够:规范化 Webhook、通过就绪度网关并阻止禁止的操作。GitOps、Kubernetes API 和完全自动修复属于完整生产路径。
> [可运行] ——「Webhook → 规范化 → 就绪度网关 → 试运行」流水线的可运行版本位于 [examples/real-api/](examples/real-api/README.md)。脚本仅使用标准库,无外部依赖;它们不能替代生产基础设施,但允许在本地运行网关并查看哪些条件会阻止操作。
high_memory_usage 场景是我们在第一卷第 12 部分中构建的同一个 SQLite 的读取峰值,以及同样的幂等迁移技术。只是现在从运维角度审视它。在第 7 部分、第 8 部分和第 9 部分中演练过的 Specify → Plan → Tasks → Implement 循环,在这里不会被取消或替代。它被生产网关包裹,并以第 16 部分风格的证据包团队审核结束。
阅读前
- 第一卷的依托:第 7–9 部分设定了规范-计划-验证循环,第 16 部分——团队审核。
- 本地学习案例:
high_memory_usage,整个第一遍的标准案例。
capstone/的追踪:就绪度判定、两个阻塞条件以及允许操作的试运行。- 第一遍的主要术语:
readiness和 dry-run。25 分评分表、audit_trace、GitOps、执行器——为参考资料。 - 可推迟的内容:GitOps、Kubernetes API、完整执行器和无需人工确认的自动修复。
目标
在学习最小范围内,本章验证 high_memory_usage 的短链 webhook -> normalization -> readiness -> dry-run。完整生产路径将其扩展为 GitOps 部署、变更回滚(rollback)和有限自动修复前的就绪度评估。每个操作都必须与 specify/plan/tasks/implement/validate 的工件关联,而非消失在手动命令中。
第一遍的实际成果不是生产编排器,而是证明允许的操作通过就绪度,禁止的操作在系统变更前被阻止。
这里的 readiness(就绪度)是流水线按 25 分制的正式评估,阈值为 23/25。本章中的自动修复指具有预先批准动作(pre-approved actions)、回滚条件和人工确认(human-review)的有限剧本。这不是代理随意更改生产的权限。
此流水线中 Qwen Code 的内置命令只有 /plan。其余步骤——/sdd:specify、/sdd:tasks、/sdd:validate——请设置为 .qwen/commands/sdd/ 中的用户自定义命令,或通过 qwen -p 和普通提示以及项目脚本替代。
最小学习场景
学习案例
appointments-api 的生产事件 high_memory_usage——源自book/part-12-mvp.md 的 MVP 阶段和 SQLite 迁移。流水线:Webhook Grafana+PagerDuty → normalize_webhook.py → 25 分模型就绪度网关 → 针对预先批准动作列表的试运行。目标——从原始有效载荷到受控的 restart_pod 的完整路径,并确认阻塞条件(审计、有状态)恰好在应拦截的位置捕获故障。
准备
book2/examples/real-api/fixtures/webhook_grafana.json、webhook_pagerduty.json—— 具有相同incident_key的原始有效载荷。book2/examples/real-api/fixtures/incident_event.expected.json—— 规范化事件的标准。book2/examples/real-api/fixtures/readiness_pass.json(24/25)、readiness_block_audit.json(22/25 + 审计低于 1.0)、readiness_block_stateful.json(24/25,但有状态且无备份确认)。book2/examples/real-api/specs/high_memory_usage/specify.md—— 预先批准的restart_pod和scale_up_replicas_one。book2/examples/real-api/scripts/normalize_webhook.py、check_readiness.py、dry_run.py。
步骤
cd book2/examples/real-api。 预期:您在示例目录中,无需额外依赖。python3 scripts/normalize_webhook.py --grafana fixtures/webhook_grafana.json --pagerduty fixtures/webhook_pagerduty.json --expected fixtures/incident_event.expected.json。 *预期:返回码 0,规范化后的incident_event与标准匹配。*python3 scripts/check_readiness.py --readiness fixtures/readiness_pass.json。 *预期:返回码 0,PASS incident=HM-2026-05-17-01 score=24/25。*
python3 scripts/check_readiness.py --readiness fixtures/readiness_block_audit.json。 *预期:返回码 1,原因——audit_trace_coverage=0.7 < 1.0,加上总分不足(22/25)。*python3 scripts/check_readiness.py --readiness fixtures/readiness_block_stateful.json。 *预期:返回码 1,原因——stateful workload 无确认备份,尽管总分为 24/25。*
错误: 在就绪度网关之前运行 dry_run.py —— 操作在规范中形式上被允许,但 audit_trace_coverage 或 backup_verified 可能缺失。 正确: 先过就绪度网关,仅当网关返回码为 0 时才试运行——该顺序确保在检查动作列表前已知影响范围。
python3 scripts/dry_run.py --spec specs/high_memory_usage/specify.md --action restart_pod。 *预期:返回码 0,PASS: action=restart_pod 已允许(spec 中有 2 个 actions)。*python3 scripts/dry_run.py --spec specs/high_memory_usage/specify.md --action delete_namespace。 *预期:返回码 1,BLOCK: action="delete_namespace" 未在 pre-approved 中找到。*
- 对于学习最小范围,到此为止:可运行链展示了规范化、允许路径的 PASS 以及 audit/stateful/delete-namespace 的 BLOCK。
如果您已安装 Qwen Code 并需要审核说明,请执行单独的可选步骤:
qwen -p "阅读 @fixtures/readiness_block_audit.json 和 @specs/high_memory_usage/specify.md。需要补充什么才能使就绪度达到 23/25 且 audit_trace_coverage=1.0?不要修改文件。" --approval-mode plan
此请求不属于可运行最小范围。其输出可附加到审核中,但就绪度准入必须依赖 check_readiness.py 和 dry_run.py。
控制事实
步骤 3、6 —— PASS。步骤 4、5、7 —— BLOCK,stderr 中有具体原因。如果步骤 5 在 stateful=true, backup_verified=false 时通过,则就绪度网关损坏:无法绕过有状态的硬性阻塞。
如何进入 capstone/
将就绪度结果、两个阻塞条件和允许操作的 dry_run.py 结果转移到 capstone/readiness.md。在 capstone/validation.md 中注明实际运行的命令。如果未实现,GitOps、Kubernetes API 和完整执行器不属于学习最小范围。
如此阅读此片段:一个正向夹具展示允许路径,两个 blockers 固定具体拒绝原因,dry_run 展示允许和阻止操作的边界情况。如果缺少任何一行,就绪度包不完整。
readiness:
pass_fixture: "readiness_pass.json -> 24/25"
blockers:
- "audit_trace_coverage=0.7 blocks auto mode"
- "stateful=true without backup_verified blocks action"
dry_run: "restart_pod PASS; delete_namespace BLOCK"
可审核的追踪
脚本写入 stdout/stderr 且不创建 out/。用可读的工件固定运行:简短的 capstone/readiness.md 或您项目中的 CI 报告(如有)。最小内容——与上述 YAML 块中相同的四行(pass_fixture、两个 blockers、dry_run);完整 25 分报告仅在完整路径中需要。
不要仅为提交标记而创建提交。对于教材,重要的是无需聊天历史即可阅读的、可复现的追踪。
关键思想
追踪的起点是 audit_trace(Qwen Code 的实时日志),其中传入的 Webhook 和规范差异(diff)被记录为单一因果链。对于事件 HM-2026-05-17-01,第一条记录关联 incident_event.json、用户命令 /sdd:specify 和创建的文件 specs/high_memory_usage/specify.md。如果任一元素缺失,流水线已失去可证明性。日志最小片段:webhook_received -> incident_event_normalized -> /sdd:specify -> spec_diff_created;每个后续差异引用同一 incident_id。/sdd:specify 为项目扩展;将其设置为 .qwen/commands/sdd/specify.md 中的用户自定义命令,或用直接 qwen -p 替代。
将 Grafana 和 PagerDuty 告警规范化为统一的 incident-event。否则不同来源将规定同一事故的不同版本。Grafana 提供指标和观察窗口,例如 memory_percent=93 持续 10m。PagerDuty 添加优先级、服务关联和升级状态。规范化器将其汇总为字段 service、namespace、pod、severity、window_minutes、metric_context、source_refs。此后 specify 步骤仅描述 WHY 和 WHAT:为何需要干预以及什么结果算成功。它不选择库、SDK 或具体 API 端点。
这在实践中意味着什么。比较同一事件的两种 specify 变体:
错误:
> high_memory_usage 的 Specify:通过 kubectl delete pod ... 重启 pod
问题:specify 直接选择实现命令,阻塞 Plan。
正确:
> high_memory_usage 的 Specify:操作后 5 分钟内保持 memory_percent < 80%。预先批准的动作:restart_pod、scale_up_replicas_one。审计追踪为必需。
SDD 阶段分离保护流水线免受过早实现。每个阶段负责各自:
- Specify 固定用户故事、成功标准、功能和非功能约束;
- Plan 选择策略;
- Tasks 将其转化为可执行步骤;
- Implement 通过受控机制应用变更。
此结构对应 GitHub Spec Kit 的实用阶段框架 Specify → Plan → Tasks → Implement(另见 GitHub Spec Kit Quickstart)。在生产中这很重要,因为模型无权在证明原因、干预边界和验证方式之前「立即修复」事件。
不要将本章核心扩展到整个生产编排器。第一遍中这里仅验证链 webhook -> normalization -> readiness -> dry-run。前几章的其他机制作为检查点:
- 第 4 和 8 部分的验证器,在试运行产生争议反例时需要。
- 第 9 部分的分层预算,如果
frontier-reviewer开始服务不仅是高风险分支时需要。 - 第 10 部分的 Anti-Goodhart,如果内存下降以 5xx、延迟或手动审计为代价时需要。
如果这些机制尚未集成,不要试图在第 11 章内模拟它们。将其记录为阻塞器或指向相应章节的链接,并以就绪度判定和试运行结果完成最小运行。
对于 high_memory_usage,从最小影响开始规划。基础 /plan 选择重启特定 pod,优先考虑影响范围。然后检查是否需要扩容。仅在此之后才允许在保留回滚路径的前提下扩展操作。
tasks 步骤将其分解为操作:确认 workload 的无状态特性、执行无实际变更的试运行(dry-run)、仅删除目标 pod、观察 RSS、CPU、5xx;如果在设定窗口内无改善——激活回滚并创建 human_review。
验证仅在检查真实指标、安全网关和 GitOps 固定后(此为前沿场景的一部分,见本章开头)才完成自动修复闭环。在 validation.md 中检查四个条件:
- 内存在连续两个窗口中保持低于阈值;
- 5xx 不增长;
- 延迟(latency)不降级;
- 回滚已描述且可执行。
成功验证后,六个基本工件进入 GitOps:规范、计划、任务、差异(diff)、决策日志和 25 分报告。必要时添加宪法更新。没有这些,事件可能在技术上被缓解,但不算受控关闭。
完整路径:25 分就绪度模型
第一遍只需理解两个事实:readiness_pass.json 通过,audit/stateful 夹具被阻塞。当您将此网关转移到真实生产流程并需要解释为何阈值如此选择时,才需要下面的完整评分表。
模型评估五个类别,每项 0–5 分,给出总分。分数基于工件而非印象。如果标准无法通过文件、日志或模式确认,则给较低分数。下面是每个类别的评分表。
阈值 23/25 —— 对 AgentClinic-production 学习模型的「严格但不瘫痪」折中:不同类别中最多两个可消除的「4」投诉(4+4+5+5+5 = 23),或一个「4」其余为「5」(24/25)。任一类别「3」或更低立即将总分降至 22 或以下,并取消自动准入。低于 23:20–22/25 仅允许半手动模式,每个 implement 步骤后人工确认。更高——阈值 24/25——使任何小投诉都转入半手动,团队开始忽视模型。根据风险画像校准:支付和医疗——自动 ≥24/25;内部工具允许 21–22/25,但仅作为半手动或金丝雀,不作为生产就绪自动修复。
Spec —— WHY/WHAT/约束 的完整性
| 分数 | Spec |
|---|---|
| 5 | WHY/WHAT/约束 明确,有验收标准,计划内无 out-of-scope,有 Given/When/Then |
| 4 | WHY/WHAT 明确,约束存在,但计划内一项无 implements: |
| 3 | WHY 存在,WHAT 模糊,约束部分 |
| 2 | 三个块之一(WHY/WHAT/约束)缺失 |
| 1 | 仅症状描述,无 WHY、WHAT 或约束 |
| 0 | 无规范 |
Implementation —— 幂等性和可控变更
| 分数 | Implementation |
|---|---|
| 5 | 所有任务幂等,有试运行(dry-run),影响范围在 pod/deployment 级别明确,变更通过 GitOps |
| 4 | 幂等性和试运行存在,但一项任务无预检即变更状态 |
| 3 | 仅部分步骤有试运行,影响范围文字描述,无明确字段 |
| 2 | 无试运行,变更直接应用于集群绕过 GitOps |
| 1 | 任务不幂等,重复运行破坏状态 |
| 0 | 手动执行,未记录于 tasks |
Verification —— Given/When/Then、模式、压力、监控
| 分数 | Verification |
|---|---|
| 5 | Given/When/Then 覆盖 happy 和 negative 路径,JSON Schema 验证输入输出,有压力规范和双窗口后指标 |
| 4 | 所有元素存在,但压力规范仅覆盖一类违规 |
| 3 | Given/When/Then 和模式存在,但监控仅单窗口验证 |
| 2 | 仅有 Given/When/Then,无模式和后指标 |
| 1 | 验证简化为返回码检查或单张截图 |
| 0 | validation.md 缺失或无法运行 |
Process ——「Webhook → CLI → 差异 → 重放」追踪
| 分数 | Process |
|---|---|
| 5 | 每步(Webhook、规范化、CLI 命令、差异、提交、验证)通过 incident_id 关联,日志可复现,重放产生相同差异 |
| 4 | 追踪完整,但重放需手动替换一个变量 |
| 3 | Webhook 和 CLI 关联,但差异未绑定 incident_id |
| 2 | 有日志,但只能按时间恢复步骤顺序 |
| 1 | 动作记录在聊天中,非文件中 |
| 0 | 无追踪,事件来源未知 |
Security —— 护栏、紧急停止、回滚、升级
| 分数 | Security |
|---|---|
| 5 | 护栏(guardrails)禁止扩展影响范围,有紧急停止(emergency stop),回滚条件执行前记录,不确定时升级至人工确认 |
| 4 | 所有元素存在,但升级仅文字描述,无正式触发器 |
| 3 | 回滚和护栏存在,无紧急停止 |
| 2 | 仅有回滚,无护栏和升级 |
| 1 | 声称「手动回滚」,但未描述可执行路径 |
| 0 | 安全网关未定义,动作无限制执行 |
如何计算以及什么阻止合并
分数总和给出 0 到 25 的结果。自动准入的通过阈值——23/25:低于此边界流水线即使三类满分也不获得生产就绪状态。Security 任何总分下禁止零分。该列 0 意味着保护回路缺失,阻止甚至半手动模式,直到出现最小回滚、护栏和升级。
阻塞条件不依赖总分。以下每种情况单独阻止合并:
- 验证失败(Verification ≤ 2);
- 无回滚(Security ≤ 2);
- 影响范围未定义(Implementation ≤ 2 无明确字段)。
总分 20–22 时,流水线仅半手动模式准入,且上述无阻塞条件:每个 implement 步骤后停止,明确人工确认,强制更新规范和重新评估后才能返回自动回路。
生产切换前检查清单(cutover)
将网关转移到真实流程时使用——每项绑定到可能有隐藏扣分的评分表:
- [ ] Spec 包含 WHY/WHAT/约束 并绑定
incident_id;每项任务有指向 REQ 标识符的implements:。 - [ ] 试运行在真实变更前记录;影响范围固定在 pod 或 deployment 级别,非文字。
- [ ] JSON Schema 验证
incident_event和最终validation_report;Given/When/Then 覆盖 happy 和 negative 路径。 - [ ] 回滚条件执行前记录并在测试环境验证;紧急停止操作员无需进入集群即可使用。
- [ ]
webhook → CLI → diff → commit → validate追踪通过incident_id可复现;重复失败或影响范围扩展时自动启动人工确认。
high_memory_usage 的填写评分表示例
| 类别 | 分数 | 依据 |
|---|---|---|
| Spec | 5 | WHY(防止 OOMKill)、WHAT(10 分钟内 RSS 低于 80%)、约束(不碰有状态,6 分钟无改善则回滚)明确,Given/When/Then 完整 |
| Implementation | 4 | 任务幂等,有试运行,但扩容分支无单独试运行步骤 |
| Verification | 5 | Given/When/Then,JSON Schema 于 incident_event 和 validation_report,隐藏泄漏压力规范,双窗口后指标 |
| Process | 5 | incident_id=HM-2026-05-17-01 关联 Webhook、/sdd:specify、差异、提交和重放 |
| Security | 4 | 有状态 workload 护栏,回滚和紧急停止存在,升级仅文字描述无正式触发器 |
| 总分 | 23/25 | 达到阈值的生产就绪,但扩容分支保持半手动至单独试运行 |
完整路径:阈值校准
「低/默认/高」就绪度阈值表、THRESHOLD 覆盖练习和重审信号——见附录 D,D.5 节。第一遍中,若 readiness_pass.json 通过、audit/stateful 夹具被阻塞、且 delete_namespace 不在预先批准动作列表中,本章最小范围已得证。
示例和应用
Qwen Code 的实际输入日志可能如此开始:POST /hooks/grafana 报告 memory_percent=93、pod=api-7b4、namespace=appointments-api、window=10m。然后 POST /hooks/pagerduty 确认 severity=critical 并将事件关联至服务 appointments-api。规范化器创建 incident_event,incident_id=HM-2026-05-17-01,移除敏感字段,附加来源引用,并启动用户命令 /sdd:specify --event incident_event.json --preset high_memory_usage 或等效提示 qwen -p——两者均属本章开头建议框架,通过 Qwen Code 周边的项目命令实现。
specify.md 中的首个差异(diff)固定三个块:WHAT(10 分钟内 RSS 低于 80%)、WHY(防止 OOMKill 和延迟增长)、约束(不碰有状态 workload、不改 HPA、6 分钟无改善则回滚)。在 /plan 上系统比较两种策略:(A) 重启目标 pod 并观察;(B) 重启加临时扩容至四个副本。验证器运行 Given/When/Then:given pod 无状态且 10 分钟内内存高于 90%;when 仅执行目标 pod 重启;then 内存应低于 80% 且 5xx 不超允许阈值。若压力规范显示扩容需要更改滚动策略或通过增加副本数掩盖内存泄漏,则方案 B 保留为需人工确认的分支,非自动动作。
implement 步骤先执行试运行。然后提交通过 GitOps,仅在验证器绿色状态时同步到 ArgoCD。执行器不在重启后立即关闭 PagerDuty 事件。它等待两个监控窗口,核对 validation.md,检查安全网关,并在注释中添加规范、任务、提交和验证结果的链接。若 6 分钟后内存未下降或 5xx 增长,激活回滚路径,创建 human_review,并就失败验证标准重新计算就绪度。
总结
生产流水线的就绪度由 25 分模型固定:五个类别(Spec、Implementation、Verification、Process、Security)等权各 5 分,重复 SDD 循环阶段。等权是原则:无一类别可补偿另一类别缺失,因此 23 阈值最多允许总计两个部分缺失。生产就绪——不低于 23/25 且无验证和安全网关的关键违规。低于阈值将自动修复转入半手动模式,直至规范、策略或执行路径修复。完全自动化修复仍是本章开头的前沿场景:仅在积累重放证据和操作员试运行后才允许。此回路将每个未来事件转化为系统的可验证改进。
工件和就绪标准
| 工件 | 就绪条件 |
|---|---|
规范化 incident_event | 与 examples/real-api/fixtures/incident_event.expected.json 字段级匹配;Specify 固定 WHY/WHAT/约束 且不选择修复命令 |
| 本地就绪度网关运行 | readiness_pass.json 通过;audit/stateful 夹具以具体原因阻塞 |
dry_run.py 于允许和禁止动作 | restart_pod PASS,delete_namespace BLOCK |
capstone/readiness.md 记录 | 分数、阻塞条件、一条实际运行的命令 |
完整路径添加 specs/high_memory_usage/specify.md、plan.md、tasks.md 和 validation.md、绑定 incident_id 的 GitOps 差异或提交、webhook → CLI → diff → commit → validate 决策日志和带证据的填写 25 分就绪表。当 plan 和 tasks 有影响范围、试运行、回滚条件和人工确认触发器时视为就绪;validation 检查双窗口指标、5xx、延迟和安全网关;用户命令已设置为项目命令,或用 qwen -p 提示或项目脚本替代;就绪总分不低于 23/25 且无回滚、验证或影响范围阻塞条件。
实践
cd book2/examples/real-api && python3 scripts/normalize_webhook.py --grafana fixtures/webhook_grafana.json --pagerduty fixtures/webhook_pagerduty.json --expected fixtures/incident_event.expected.json—— *预期:返回码 0,规范化incident_event与标准字段级匹配。*- 分别运行四项检查(每项返回自身返回码,因此它们之间不适合用
&&):
python3 scripts/check_readiness.py --readiness fixtures/readiness_pass.json
python3 scripts/check_readiness.py --readiness fixtures/readiness_block_audit.json
python3 scripts/dry_run.py --spec specs/high_memory_usage/specify.md --action restart_pod
python3 scripts/dry_run.py --spec specs/high_memory_usage/specify.md --action delete_namespace
*预期:readiness_pass → 返回码 0,PASS incident=HM-… score=24/25;readiness_block_audit → 返回码 1,BLOCK … score=22/25,原因「score 22/25 低于阈值 23」和「audit_trace_coverage=0.7 < 1.0 —— 必须完全覆盖」;restart_pod PASS,delete_namespace BLOCK。*
- 按 25 分模型评估您的案例并填写下表。每类别注明分数、证据工件和若低于 5 的扣分原因。计算总分,检查阻塞条件,并说明需更改什么才能使流水线通过 23/25 阈值。 *预期:表格每行三字段均填写;「证据工件」指向具体文件或运行,非泛泛表述;总分格含
N/25形式和阻塞条件列表,或明确「无阻塞」。*
| 类别 | 分数 (0–5) | 证据工件 | 扣分原因 |
|---|---|---|---|
| Spec | |||
| Implementation | |||
| Verification | |||
| Process | |||
| Security | |||
| 总分 | 阻塞条件: | 切换前需更改: |
检查问题
- 为什么 specify 不应选择具体修复命令?
- 哪些条件使自动修复不可接受?
- 若就绪度低于 23/25,什么阻止准入?
high_memory_usage的 Webhook 在非工作时间到达,自动修复准备重启 pod。就绪度模型给出 22/25(审计扣 3 分)。您会怎么做——重启、等到早晨还是呼叫值班人员?