应用系统体系架构-08:系统架构与 Capstone
完整的 AI Coding 平台需要把客户端、上下文、模型、工具、状态图、Sandbox 和评估连接成一个系统。用户提交 Issue 或编辑请求后,平台定位相关代码,形成受限 Patch,执行测试与审查,再按实际权限交付修改。
系统架构的重点是明确数据与控制边界:代码版本从哪里来,谁拥有任务状态,哪些操作可以执行,失败怎样恢复,以及提交是否对应已经验证的产物。单个模型回答正确,不能代替整条链路的验证。
分层架构
平台可以划分为 Client、Gateway、Engine、Sandbox 四层。

| 层次 | 主要职责 | 关键数据 |
|---|---|---|
| Client | IDE、CLI、任务输入、差异预览与交互 | 文件版本、光标、选择范围 |
| Gateway | 认证、租户、限流、任务接收和事件流 | task_id、身份、状态入口 |
| Engine | RAG、MCP、Skill、Agent 图和 Checkpoint | 目标、证据、Patch、运行状态 |
| Sandbox | 隔离应用候选代码并执行测试 | 环境版本、退出码、日志与报告 |
客户端可以偏重实时编辑辅助,也可以仅提交远端长任务。Cursor、Windsurf、Claude Code、Devin 等产品展示了不同交互形态,但不能仅凭产品名称推断其全部私有架构。自研系统应根据代码位置、部署需求和交付方式取舍。
这些交付形态可以组合不同能力:
| 形态 | 主要能力 | 与用户的关系 |
|---|---|---|
| IDE 辅助 | 光标补全、局部编辑、实时索引、Diff 预览 | 围绕当前编辑持续提供建议 |
| CLI Agent | 文件搜索、AST 导航、按需 Skill、受控终端 | 以任务和命令结果组织交互 |
| 云端任务 | 独立运行环境、长任务、编译测试与浏览器验证 | 用户提交目标并查看进展与产物 |
| 协同编辑 | 多文件 Patch、变更预览、审批和撤销 | 同步用户编辑与 Agent 候选变化 |
浏览器验证可以检查前端页面、交互与控制台错误,但也需要明确目标环境和权限。人类编辑与 Agent 修改同时发生时,应核对文档版本,防止候选覆盖刚保存的变化。
持久化状态、事件记录与产物存储属于跨层基础设施。网关多副本不应各自维护互相矛盾的任务状态,Worker 重启也不应使任务从状态库消失。
代码感知
IDE 插件可以复用 LSP 提供的符号、定义、引用和诊断能力。TypeScript、Pyright、gopls 等语言服务帮助客户端理解不同语言,而不必为每种语言重写语法器。
1 | import * as vscode from "vscode"; |
sendUpdate 由插件实现,负责授权、序列化和上传。文件保存事件只能取得已保存时点,处理未保存内容时还要监听变更,并采用去抖、版本比较和取消旧任务。
符号与诊断不是完整源码或完整调用图。插件应保留工作区、语言、文档版本和关联 Commit,避免远端使用已过期的行号生成 Patch。
增量索引
本地或服务端索引需要感知新增、修改和删除。内容哈希或 Merkle Tree 可以定位变化,Tree-sitter 可按语法结构解析不同语言,向量索引则支持语义检索。
一次增量更新应完成读取版本、解析、抽取符号、更新分块和使旧结果失效。删除文件时也要删除相关向量与依赖边,不能只持续追加新内容。
Skeleton保留类、函数签名和必要说明,适合提供辅助依赖;主修改文件、复杂实现和相关测试则可能需要全文。压缩签名不能替代真实实现,也不能保证所有动态调用都被理解。
下面用 Python 标准 AST 演示符号与签名抽取。多语言工程可以用 Tree-sitter 的语言语法和 Query 执行相应操作。
1 | import ast |
结果还需绑定文件路径、内容哈希与版本。Tree-sitter 的字节位置与文本编辑器的字符位置不总是相同,Unicode 内容尤其需要准确转换。反射、配置和运行时依赖应结合搜索与测试补充。
任务网关
耗时的 Agent 任务可以通过“接收任务—入队—返回 task_id—Worker 执行”的方式解耦。网关负责身份、输入大小、租户限流和预算,Worker 负责实际图运行。
1 | { |
任务状态可以包括 queued、running、waiting_approval、succeeded、failed、cancelled。客户端连接断开后,任务是否继续或取消应由策略决定。
FastAPI BackgroundTasks 适合轻量的进程内后台工作,不能直接提供跨进程持久任务队列。长任务需要队列、确认、重投与幂等,例如由 Celery 或持久工作流协调。内存中的 asyncio.create_task 也不能保证服务重启后继续执行。
分布式限流可以使用 Redis 统一计数或 Token Bucket,但检查与扣减需要原子处理。网关限制请求频次,运行时还要限制每个任务的步骤、Token、并发和工具费用。
流式通信
SSE适合服务端向客户端推送事件,WebSocket适合需要持续双向通信的场景。SSE 不是双向通道,用户补充、取消和审批可以通过独立 HTTP 请求发送。
1 | id: 17 |
每个 SSE 事件以空行结束,可以带 ID 支持续传。重连后应从已保存事件继续,而不是重新启动同一任务。还需心跳、代理缓冲、连接超时、客户端鉴权和慢消费者的背压处理。
事件可以表达阶段、工具请求、执行结果、产物和错误。对用户展示可核验的进展与简要解释,不必把模型全部内部推理、敏感参数或完整日志直接输出。
能力组合
平台中的六类能力承担不同职责:
| 能力 | 在平台中的作用 |
|---|---|
| Prompt | 定义目标、范围和输出契约 |
| MCP | 发现与调用外部资源和工具 |
| Codebase RAG | 定位相关文件、符号和测试 |
| Skill | 组织复用流程、校验和执行规则 |
| Graph | 管理状态、分支、循环和恢复 |
| Sandbox / Harness | 隔离执行并验证任务行为 |
MCP 工具与模型原生 Tool Calling 需要适配,但协议一致不等于业务语义一致。RAG 为 Skill 提供真实资料,Skill 的 dry_run 与 Guard 检查执行条件,Graph 根据结果路由,Sandbox 返回真实测试观察。
从外部 Server 发现工具后,仍需名称空间、过滤、权限和参数验证。工具返回的恶意文本不能成为新的系统规则,凭证也应留在受控服务配置中。
Context 打包
Context Packager把主文件、依赖 Skeleton、测试、诊断和历史失败组织成有限上下文。先按相关性选材料,再计算实际 Token;预算还应包括 System Prompt、工具 Schema、消息封装和预留输出。
1 | from dataclasses import dataclass |
count_tokens 应由目标模型分词器实现,例如匹配的 tiktoken 编码;不能把字符数除以常数当作所有语言和模型的精确计数。未纳入文件需要显式记录,必要时触发后续检索。
ElementTree 转义正文与属性,避免源码破坏 XML 结构。XML 是资料边界表达,不能独立防止 Prompt Injection。内容截断还应避免破坏必要函数、表格或标签结构。
MCP 桥接
桥接器完成初始化、能力发现、Schema 转换和执行结果映射。下面展示 stdio 连接的基本生命周期。
1 | from mcp import ClientSession, StdioServerParameters |
这是每次创建连接的简单示例,长任务可以复用会话,但需要健康检查、超时和释放。远程服务的传输应按支持版本选择,历史 SSE 与 Streamable HTTP 不应混用配置。
Server 名称与工具名称需要稳定映射,返回的 isError、内容类型和结构化结果应保留。未知工具不能自动回退到任意 Shell,模型提供的服务地址也不能自行成为可信连接。
System Prompt
Coding Agent 的任务模板需要表达角色、允许范围、工具、测试和失败处理。要求应能对应宿主的实际检查,不能只依靠模型遵守。
1 | <coding_task> |
工程可以参考代码助手的交互方式,但不应把示例模板当成产品真实的私有 System Prompt。内部推理文本不构成验证结果,测试字段必须来自实际执行。
Patch 验证
Unified Diff描述文件与局部 Hunk 的变化。--- 与 +++ 标识旧新文件,@@ 表达行范围,空格、- 和 + 分别表示上下文、删除和新增。
1 | --- a/calculate.py |
应用前需要检查目标路径、Base Commit、文件哈希、Hunk 上下文和修改规模。生成语法合法不代表行为正确,语法预检应与测试和接口检查分开。
1 | import ast |
这是 Python 单文件候选生成示例,不是完整的多语言 Patch 引擎。AST 不能替代类型检查、编译或运行测试,其他语言应使用相应解析器。应用 Diff 可以先使用 git apply --check 验证,再在任务工作区执行,避免直接正则覆盖文件全文。
Workspace 事务
多文件任务应固定不可变基线,使用独立工作区保存候选。测试、审查与提交都对应同一组变化,失败时只清理或恢复本任务范围。
1 | 记录 Base Commit 和当前授权范围。 |
git stash create 不应被简单理解为可恢复全部工作区的事务:它未必覆盖未跟踪和忽略文件,空变化也可能不产生快照。reset --hard 在共享工作区可能覆盖用户修改,不能把它作为未经限定的 Undo。
一个 Git Commit 可以把已暂存文件作为一个版本提交,但不能同时原子修改数据库、发信和远端 PR。外部操作需要明确提交顺序、幂等标识和补偿策略。
测试反馈
Sandbox Tester 准备指定版本与依赖,应用候选 Patch,运行规定命令,并返回结构化报告。
1 | { |
测试失败可能出现在 stdout,也可能出现在 stderr,不能只读取一条错误流。还需区分测试断言、环境准备失败、无测试收集、超时和进程崩溃。
E2B 或其他 Sandbox 的 SDK 需要按版本配置创建、网络、文件和销毁;不能把 Docker 的 network_mode="none" 当成所有服务通用参数。诊断可以变成 Observation,条件边在有限次数内返回 Coder。
通过现有测试不代表所有行为正确。候选修改应保持既有回归、补充相关边界,并检查测试有没有被删改来隐藏失败。
HITL 审批
需要批准的修改在真实提交、外部写入或合并前挂起。审批内容至少包括目标版本、Patch 摘要、影响范围、验证报告和风险。
人工修改 Patch 后,旧测试与审批失效,需要重新验证。interrupt() 保存待办,update_state() 形成新版本,恢复时核对审批身份、任务归属与当前产物。
审批可以来自 CLI 或业务界面,但不能以模型自报“已批准”代替真实操作。长期等待使用持久状态,不依赖一个数日不关闭的终端进程。
Trace 与状态
Tracing记录一次请求的阶段关系,Checkpoint保存任务状态,两者相关但不是同一个对象。trace_id 标识一条链路,thread_id 标识可跨多轮运行的状态历史,task_id 表达业务任务。
重试、审批恢复和分支可以产生新 Trace,因此不宜强制它们永久使用同一个 ID。可以在 Span 和任务记录中保存关联字段,用来从日志定位检查点与产物。
OpenTelemetry 可以贯穿 Java 网关、Python Worker、模型请求和 Sandbox,LangSmith 等工具可以记录 Agent 轨迹。记录应包含版本、阶段、耗时、结果和父子关系,敏感正文和凭证需要控制采集与访问。
指标归因
Prometheus 与 Grafana 可以观察请求、Token、费用、错误和延迟。输入、输出、缓存 Token 及工具费用需要分别统计,TTFT 与任务总耗时也应区分。
公式中的单价是业务配置,具体模型还可能有缓存、批处理或其他计费方式。实际监控应以返回用量和账单规则为依据。
Counter 表示累计用量,Histogram 表示耗时分布。标签宜使用稳定模型、服务或有限租户分组,不宜为每个 task_id 创建一条高基数时间序列;逐任务成本可以进入专门明细存储。告警只负责通知,预算拦截还需在运行控制器中实际实施。
质量评估
HumanEval主要评价函数级代码生成,SWE-bench围绕真实仓库 Issue 和测试环境评价修复。任务输入、环境、测试与报告不同,不能用相同标签掩盖判分差异。
**Fail-to-Pass(F2P)**要求原失败测试通过,**Pass-to-Pass(P2P)**要求原已通过行为仍然成立。只检查新用例会漏掉回归,只检查旧用例又可能没有验证 Issue。
Pass@1 是固定任务集的一次尝试成功率;单个 Patch 的 pytest 通过与否不能直接称为整个平台“Pass@1=100%”。Pass@k 还需要明确候选数量、判分和样本量。
Judge 评审
LLM-as-a-Judge 可以用 Rubric 检查正确性、安全与架构规范,并返回结构化意见。它适合补充审查,不能替代测试、静态分析或真实授权。
1 | { |
评分量表需要明确分值意义、证据要求和无法判断的状态。固定 JSON 只保证可解析性,低 temperature 也不能证明裁判客观。应与人工标注和硬断言校准,监测裁判偏差及被 Patch 内容注入的风险。
Failure Fixture
失败回放应固定初始 State、Base Commit、Patch、依赖锁文件、镜像、工具观察和模型响应。只保存异常文字无法重建完整环境。
可以分别运行两类实验:Replay使用录制响应检查控制逻辑,Live Eval使用当前模型重新生成以评价能力变化。前者可重复且不调用模型,但后者不能被“零 Token 回放”替代。
Fixture 应脱敏并版本管理,测试范围包括异常分支、缺失输出和错误工具请求。回放时未知调用需要失败,而不是偷偷访问真实支付、数据库或 GitHub 服务。
CI Gate
CI 将测试、扫描和评估结果转换成必需检查。只有仓库分支保护或 Ruleset 要求相应 Check 成功,失败退出码才会真正阻止合并。
1 | name: AI quality gate |
这是工作流骨架,ci_gate.py 需要由工程实现,且将第三方 Action 固定到审核过的版本或提交。检查应针对当前 PR Commit,不使用旧版本的成功报告。运行不可信代码时不要提供写令牌或敏感环境变量。
聚合成功率可以有项目阈值,但还需检查关键任务回归、成本、延迟和样本量。课程里的 95% 或固定影子次数应视为示例策略,不能直接成为所有系统的发布标准。
安全检查
Semgrep 可按规则扫描源码,Gitleaks 可检查潜在 Secrets,其他依赖和运行检查补充不同风险。OWASP 是风险与实践体系,不是一个自动完成所有验证的扫描器。
扫描结果应包含规则、文件、位置和证据,并映射到修复或停止分支。没有发现不代表不存在漏洞,误报需要受控审核,扫描失败也不能当成通过。
检查除了当前差异,还应考虑依赖、配置和必要历史。Secrets 不应被复制进 Prompt、Fixture、日志或 PR 评论,工具凭证也不应暴露给生成代码。
Shadow 与 Canary
Shadow Run旁路运行新版本并比较结果,不影响真实交付且应阻断写副作用。Canary让有限真实流量进入新版本,需要发布范围和回退条件。
asyncio.create_task 会使用计算、网络和存储资源,并不意味着主流程完全没有影响。影子运行应限制容量、脱敏数据、控制费用,并禁止重复发信、提 PR 或修改真实对象。
比较时固定问题类别和基线,检查质量、尾延迟、成本、拒绝和恢复;平均指标改善不能掩盖关键业务退化。达到预设要求后再逐渐增加流量,出现问题可回退到明确版本。
Webhook 入口
Issue 可以通过 GitHub Webhook 触发任务。先验证原始请求体的 HMAC SHA-256,再检查事件、action、仓库与任务权限,最后持久入队。
1 | import hashlib |
验签前不能先重新序列化 JSON,否则字节可能变化。签名证明请求来源和完整性,不替代仓库授权,也不自动防重放。X-GitHub-Delivery 可参与幂等去重,重复投递不应创建第二个修复任务。
Issue 正文可能来自不可信用户,不能把其中的“直接合并”“读取密钥”等要求提升成系统权限。Triage 负责识别类型、适用范围和是否需要补充信息。
影响定位
Scope 节点组合 Codebase RAG、符号检索与 MCP 依赖查询:主编辑文件给出相关完整实现,辅助依赖提供 Skeleton,测试和配置补足运行关系。
需要记录当前 Commit、文件哈希、检索命中与覆盖不足。Patch 生成期间仓库变化时,应重新核对范围;新版本不能沿用旧行号和测试结果。
检索不到关键定义时,系统应继续读取或说明无法完成,不应通过猜测 API 填补缺失。上下文打包还需保留排除的内容,便于下一轮有目标地补充。
Capstone 流程
综合流程可以组织为 Ingestion → Triage → Scope → Context → Coder → Test → Review → Delivery。图中的合并是可能的交付动作,必须满足当前仓库的授权和规则。

Coder Subgraph 根据目标、证据和前次错误生成 Unified Diff。语法预检失败回到 Coder;Sandbox 返回测试失败后,依据剩余次数和预算决定修复或停止。通过后执行安全扫描和 Reviewer,再形成可审查的 PR。
整个运行要保存同一候选的 Base Commit、Patch 摘要、测试、扫描和审批。Reviewer 提出新修改后,应重新测试该版本,不能用前一个 Patch 的报告批准后一个。
交付权限
创建分支、提交 Commit、创建 PR、批准 PR 和合并是不同操作。自动化身份需要分别满足权限与策略,不能因为模型输出 APPROVED 就获得合并权。
Squash Merge 可以压缩已验证提交历史,但不会修复补丁本身,也不能替代必要审核。自审限制、Required Reviews、Required Checks 和版本更新都会影响实际可合并性。
即使使用自动合并,也应等待当前 Commit 的必要检查与审批。未满足条件时保留候选和诊断,而不是扩大令牌权限或绕过分支保护。
架构验收
课程的整体要求可以归纳到可检查的系统边界:
| 方面 | 应具备的能力 |
|---|---|
| 契约与职责 | Prompt 输出契约,模型与执行分工,Skill 封装 |
| 协议与证据 | MCP 接入,Codebase RAG,明确文件与版本 |
| 业务控制 | 受控事务、授权入口、Graph 条件路由与终止 |
| 运行恢复 | Checkpoint、Time Travel、子状态隔离、循环与预算 |
| 执行验证 | Sandbox、Fixture、真实测试与安全检查 |
| 治理演进 | Trace、Metrics、Evals、CI 和受控发布 |
这些要求对应课程中的结构化契约、职责解耦、协议、事实依据、能力封装、事务授权、有环图、显式终止、快照、历史分支、多 Agent 隔离、循环拦截、沙箱、Harness、观测与评估十六个要点。
系统可靠性来自版本、状态、权限和验证证据之间的一致性。最终交付应是可审查、可复现并受授权约束的修改,而不只是模型生成的一段代码。

