-
-
AI Agent 工程化原理与工作流插件套件实现
-
发表于: 1天前 559
-
AI Agent 工程化原理与工作流插件套件实现
第一部分:原理
一、AI 编码的工程瓶颈转移
软件工程数十年来围绕一个核心约束运转——编码成本高昂。瀑布模型的需求规格化、敏捷迭代的 Sprint 规划、代码评审制度、架构决策流程,本质上都在管理"工程师时间"这一稀缺资源。
AI Agent 时代改变了这一前提。编码执行不再是成本瓶颈,瓶颈转移至验证(代码是否正确)、治理(是否符合架构约束)、可续接性(跨会话、跨模型、跨设备如何保持工程连续性)。
这一变化影响五个维度:规划方式(产出速率数量级提升)、代码所有权(生成者归属模糊化)、代码评审(规模与工具的根本变化)、团队构成(技能组合重新定义)、知识共享(文档不再是唯一知识载体)。
二、上下文质量决定输出质量
2.1 信噪比决定输出质量
LLM 的输出质量与输入上下文的信噪比强相关。无关信息占据 token 预算,会降低模型对关键信息的注意力。实践中应遵循:
- 项目文件精简:清除编译缓存、构建产物、无关文档;引用文件时使用绝对路径而非让 Agent 自行搜索。
- 输入去噪:去除修饰词和语气词;将富文本转换为纯文本(Markdown/TXT),减少非语义标记干扰。
- 无倾向性输入:提问时避免引导性表述,让模型独立判断而非拟合用户预期。
2.2 上下文污染与上下文腐烂
在 Agent 工作流中,有两个核心上下文退化机制:
上下文污染(Context Pollution):不相关的信息进入模型的可见上下文,干扰当前任务的推理。典型场景——3 个并行任务共享同一个上下文窗口时,任务 A 的代码搜索结果会占据任务 B 的注意力。
上下文腐烂(Context Decay):随着对话增长,模型对早期信息的回忆准确度下降。一个 200K token 的对话在第 150K token 时,对第 10K token 处的架构决策的引用可能出现幻觉。
这两个问题要求对上下文进行主动的边界管理——不是让上下文自由增长,而是在多个尺度上持续控制其质量和规模。
2.3 三层上下文边界模型
有效的上下文管理需要在三个尺度上同时建立边界:
| 层级 | 边界定义 | 解决的问题 |
|---|---|---|
| 会话级 | 压缩旧对话,保留摘要 + 近期消息 | 上下文腐烂——长对话中早期信息被遗忘 |
| 任务级 | 每个任务使用独立上下文,不继承调度器历史 | 上下文污染——并行任务之间互相干扰 |
| 项目级 | 结构化文档(AGENTS.md、ADR、C4)作为跨会话认知载体 | 认知断裂——换会话/换模型/换设备后丢失项目理解 |
三层边界的协同效果:会话级保证单次对话的质量,任务级保证并行执行的质量,项目级保证跨时间跨空间的连续性。
2.4 上下文压缩的信息保留策略
上下文压缩不应该是简单的截断,而是分层的信息保留策略:
- 永久保留层:最近 N 条消息逐字保留,不送入压缩模型——这是当前工作状态的"工作记忆"
- 高优先级保留层:文件路径、架构决策、未解决的 TODO、用户目标——这些是不可推导的项目事实
- 低优先级丢弃层:探索性搜索结果、已覆盖的文件内容、重复搜索、"looks good" 式中间确认——这些是一次性消费品
这一分层策略的目标是:用远小于原始上下文的 token 数,保留恢复工作所需的全部关键信息。
V2 进一步引入压缩质量校验——压缩后自动验证关键模式(文件路径、ADR 引用、TODO/FIXME、不变量引用)的保留率是否 ≥ 70%。校验失败时触发三级降级:重试(换 prompt)→ 换模型 → 截断(保留原始上下文并通知用户),保证坏摘要不会静默损坏上下文。
2.5 上下文隔离与并行效率的关系
上下文隔离通常被视为质量保障手段,但它同时也是并行调度的效率前提。
共享上下文下的并行:每个 worker 的工具调用结果都进入共享上下文 → 并发数越高,上下文膨胀越快 → 更快触发上下文窗口限制 → 更频繁的压缩 → 输出质量下降。
隔离上下文下的并行:每个 worker 的上下文独立增长 → 并发数不受上下文窗口约束 → 每个 worker 的上下文保持稳定规模 → 输出质量恒定。
这意味着:没有上下文隔离,并行度越高,质量衰减越快。隔离使并行加速比可以线性扩展而非在并发数增加时边际递减。
三、并行调度原理
3.1 依赖感知调度
朴素并行(所有任务同时启动)在有文件写集冲突时会导致并发任务互相覆盖,产出的代码需要大量人工修复,实际效率反而低于串行。有效的并行调度必须:
- 分析依赖关系:识别任务之间的前置依赖(任务 B 依赖任务 A 的产出)
- 检测写集冲突:识别哪些任务会修改相同文件
- 波次分组:将无依赖、无冲突的任务组织为可并行执行的波次
- 序列化冲突点:对有冲突的任务强制串行执行
3.2 并行加速比模型
设 N 个任务,平均执行时间 T,依赖深度 D:
| 调度策略 | 总时间 | 加速比 | 结果可靠性 |
|---|---|---|---|
| 串行执行 | N × T | 1x | 可靠 |
| 朴素并行(无冲突分析) | ~N/C × T | ~C x | 不可靠——写集冲突导致覆盖 |
| 依赖感知波次调度 | D × T | N/D x | 可靠——冲突已消除 |
关键洞察:加速比的上限取决于依赖深度 D(关键路径长度),而非并发数 C。依赖越浅、独立任务越多,加速比越高。
3.3 调度器的可交互性
调度器在并行执行期间应始终保持可交互状态——用户可以随时查询进度、修改需求、取消任务。这要求:
- 调度器与 worker 运行在不同的上下文/进程中
- 调度器的状态通过持久化文件(而非内存)暴露
- 轮询间隔是无人值守时的巡检节奏,用户主动查询时同步响应
V2 进一步引入 ScheduleWakeup 机制——调度器不自行循环轮询,而是通过系统的定时唤醒功能(每 5 分钟)被唤醒执行检查。这消除了"Agent 忘记轮询"的风险,将轮询从 Agent 的自觉行为升级为系统级保障。后台 Worker 完成时系统还会主动推送通知,调度器可以立即处理而不必等到下一个 5 分钟窗口。
四、证据驱动原理
4.1 AI Agent 的虚假验证问题
AI Agent 在验证自身产出时存在系统性偏差:倾向于以"命令返回 0"、"进程存在"、"日志无异常"等间接指标判定通过,而这些指标与实际功能正确性之间没有必然关系。尤其在 GUI 场景中,窗口拉起 ≠ 界面渲染正确,端口监听 ≠ 业务逻辑正确。
4.2 证据先于修复
正确的调试流程必须强制要求直接证据先于任何修复行为:
- GUI 问题需要截图/图像证据
- 网络问题需要抓包/pcap 证据
- 代码质量问题需要静态分析报告
修复后必须用同类证据再次验证。不能以"代码改了"代替"问题验证了"。
4.3 闭环自动修复
执行 → 失败 → 收集证据 → 诊断 → 修复 → 重新执行,形成自动化循环。设置干预预算(如最多 2 次自动重试),耗尽后升级到人工决策。这避免了无限循环,也避免了过早打扰用户。
4.4 任务类型感知的证据门控(V2 新增)
V1 的证据门控是无差别触发——所有任务完成后都尝试触发 AirXDB 截图,导致非 GUI 任务(如纯后端逻辑修改)产生 11+ 次假阳性阻塞,每次都需要人工覆盖。
V2 引入 EvidenceGatePolicy——基于任务特征的差异化证据分类:
| 证据类别 | 触发条件(关键词匹配) | 要求的证据类型 |
|---|---|---|
GUI_REQUIRED |
gui, ui, render, layout, dialog, widget, canvas, 界面, 按钮… | 截图 + GUI 操作验证 |
NETWORK_REQUIRED |
network, rtsp, http, tcp, socket, stream, 网络, 抓包… | 抓包 + 连通性验证 |
STATIC_ANALYSIS |
cppcheck, clang-tidy, mypy, lint, static analysis… | 静态分析报告 |
CODE_ONLY |
不匹配以上任何关键词 | 代码审查 + 测试结果 |
关键词匹配而非 LLM 分类的设计决策:
- 确定性:相同输入总是产生相同输出,可测试
- 零成本:不需要额外 API 调用
- 可解释:用户可以理解为什么某个任务被分类为 GUI 任务
- 可覆盖:用户可在 todo.md 中用
[no-xdb]/[no-ndb]/[no-sdb]标记显式跳过
五、多模型交叉审计原理
5.1 单模型审计的系统性盲区
每个 LLM 有其固有的偏见和遗漏模式:某些模型倾向于关注文件完整性而忽视语义正确性,某些模型对安全问题的敏感度高于其他模型,某些模型在特定领域的推理深度更强。单模型审计无法识别这些盲区——你无法用同一个模型来验证它自己的遗漏。
5.2 交叉确认与置信度分级
多个独立模型对同一制品进行审计后,通过交叉确认矩阵对发现进行置信度分级:
| 独立确认的模型数 | 置信度 | 处置策略 |
|---|---|---|
| ≥ 3 | 高置信 | 必须立即修复,不复核 |
| 2 | 中置信 | 应当修复,可快速复核 |
| 1 | 低置信 | 需人工复核确认 |
核心逻辑:如果 3 个独立模型都发现了同一个问题,这个问题几乎一定是真实的。如果只有 1 个模型发现,可能是该模型的特有视角,也可能是误报。
5.3 评级不一致也是一种信息
当不同模型对同一制品给出显著不同的评级时,分歧本身就是有价值的信息——它揭示了不同模型的评价维度差异。例如:一个模型以"文件创建完成度"为主轴给出高评价,而另一个模型以"与规范的语义一致性"为主轴给出低评价。这种分歧恰恰指向了"文件存在 ≠ 语义正确"这一深层问题。
5.4 三种交叉审计模式
| 模式 | 结构 | 适用场景 |
|---|---|---|
| 并行审计 | N 个模型同时独立审计,结果汇总 | 开发阶段审计、代码质量评估 |
| 递进审计 | N 轮串行,每轮读取前轮发现并深挖 | 详细设计审查、根因分析 |
| 多视角审计 | 扮演不同角色(架构师/开发者/用户) | 需求覆盖性检查、UX 缺口发现 |
六、架构状态持久化原理
6.1 架构即项目认知骨架
软件项目的架构知识通常存在于架构师脑中。AI Agent 时代,执行者每次可能是不同的模型实例——架构认知必须外化为结构化文档,成为任何执行者都能加载的项目认知。
两类核心文档承担这一角色:
- C4 模块文档:定义模块边界、职责、公共接口、依赖关系、数据所有权。模块边界直接影响调试时的范围判定和并行调度的写集冲突分析
- ADR(架构决策记录):记录每条架构决策的上下文(为什么)、决策(选了什么)、后果(正反面影响)和被拒绝的替代方案
6.2 C4 与 ADR 的联动:决策图谱
C4 定义了系统的静态边界——哪些模块存在、边界在哪、接口是什么。ADR 记录了边界的演化历史——为什么这样划分、拒绝了哪些替代方案、已知哪些代价。
两者构成决策图谱:C4 回答"现在是什么",ADR 回答"为什么是这样"。当新任务到来时,执行者加载决策图谱即可理解项目全貌,而不需要与前任执行者对话。
6.3 ADR 后果分析作为影响面定位工具
每条 ADR 的 Consequences 段落列出正面和负面影响——这些影响本质上定义了该决策的作用面。当出现问题时:
- 从问题症状出发,定位涉及的模块(C4)
- 从模块关联的 ADR 后果中,快速收窄根因搜索范围
- 如果修复与某条 ADR 的后果冲突,要么创建新 ADR 覆盖旧决策,要么放弃修复方向
这形成不可绕过的决策审计链——每次架构变更都有理由记录,每个理由都可追溯。
6.4 架构状态不丢失的保证(原理)
架构文档与代码同步的核心原则:不更新架构文档的任务无法标记为完成。
这意味着每次任务合并时,系统必须强制验证 Worker 是否提交了所要求的架构文档更新——缺失则拒绝合并。架构文档因此成为代码合并的门控条件,而不是"事后补写"的附属物。
具体的标记块命名空间、6 阶段合并流水线、合并去重等实现细节,见第二十章 § 20.1。
6.5 ADR 变更级联失效(原理,V2 新增)
V1 暴露的深层问题:当架构方案变更(如 ffmpeg → gstreamer)时,基于旧 ADR 已完成的任务不会自动失效,旧代码残留与新方案冲突,下游任务基于过期产出继续执行。
原理层面的要求:架构决策一旦变更,所有引用该决策的已完成任务必须自动失效、进行中任务必须自动中止、下游依赖必须级联失效、基于旧决策的代码必须回滚、受影响的任务必须局部重规划。这五个动作构成一个架构变更的闭环——缺少任何一环,都会留下"幽灵代码"。
具体的 10 步级联闭环(ADRWatcher hash 对比 → TaskGraph.invalidate_by_adr → 调度冻结 → git revert → PartialReplanner 局部重规划 → 解冻)见第二十章 § 20.2。
6.6 认知卸载:从"记在脑中"到"写在文件中"
传统工程依赖架构师的持续在场来维护架构一致性。AI 工程将架构认知卸载到文件:
- AGENTS.md:项目级指令与工作流规则——任何 AI 加载即获项目上下文
- ADR:架构决策的永久记录——新模型或新设备上的新会话也能理解历史决策
- C4:模块边界的权威定义——约束任务写集和调试范围
- debug-log.md:问题生命周期的完整记录——从引入到解决的全链路可追溯
这些文件的集合构成项目的认知基础设施——不依赖任何特定人或特定 AI 会话。
七、范围约束降本原理
7.1 规划-执行分离与智能放大
传统开发中规划和执行混杂在同一上下文:开发者同时理解需求、设计架构、编写代码。范围约束将规划与执行分离:
- 规划阶段(高能力模型):定义范围、验收标准、验证命令、依赖关系、写集冲突分析
- 执行阶段(任意模型):在预定义的窄化切片内执行,不需要理解全局
关键洞察:当执行者的上下文被精确约束到6 个文件 + 1 个任务切片 + 预声明的写集时,执行者不需要"理解整个项目"——只需要在预先确定的范围内执行。
7.2 上下文约束使廉价模型可用
当任务上下文被约束在有限文件和结构化模板中时,执行者面对的是一个高度简化的问题空间:
- 不需要仓库探索(写集已预声明)
- 不需要架构决策(ADR/C4 已作为必读文件提供)
- 不需要任务规划(只有一个任务切片)
- 不需要结果格式化(结构化模板已预填充)
执行者只需要:在预声明的文件中编写片段代码 → 按模板填入结果 → 运行预声明的验证。这个能力门槛远低于"理解一个项目并规划开发"——廉价模型完全可以胜任。
7.3 弱模型安全保障(V2 新增)
廉价模型的固有限制是字面理解、无推断能力。V2 在 AirArc 规划阶段引入 INV-16 弱模型安全约束,从四个维度保障任务描述的精确性:
| 约束维度 | 具体要求 | 防止的问题 |
|---|---|---|
| 禁止歧义词 | 不用"清理"、"重构"、"优化"等宽泛动词,指明具体改什么 | Worker 误解任务意图 |
| 否定约束显式化 | 写明不做什么(如"不删除 src/ 下现有模块") | Worker 过度执行 |
| 文件范围精确化 | files_dirs 精确到文件级,不写 src/ 目录级 |
Worker 越界修改 |
| 完成标准可验证 | done_when 能用 grep/diff/cmake --build 客观验证 |
Worker 无法判定完成 |
AirArc 在生成 execution-plan.json 时自动扫描所有 TODO 任务,检测危险词("清理"、"删除所有"、"重构整个"等)和目录级文件范围,产出 safetyWarnings 列表。
7.4 成本结构的反转
传统模式下,规划和执行都由同一高能力模型完成:
传统: 每个任务都需要昂贵模型(因为需要完整项目上下文 + 探索 + 规划 + 执行)
成本 = N × 昂贵模型单价
范围约束: 规划一次(昂贵模型),执行 N 次(廉价模型)
成本 = 规划费用 + N × 廉价模型单价
当 N 较大且廉价模型单价为昂贵模型的 1/10 时,边际成本降低约一个数量级。
7.5 约束边界与质量的关系
约束越严格,执行者的搜索空间越小,偏离预期的可能性越低:
| 约束类型 | 约束内容 | 防止的问题 |
|---|---|---|
| 写集约束 | 只能修改预声明的文件 | 越界修改导致回归 |
| 验收约束 | 必须满足 Done When 条件 | 不完整交付 |
| 验证约束 | 必须运行预声明的验证命令 | 遗漏测试 |
| 文档约束 | 必须更新预声明的架构文档 | 架构腐化 |
这些约束将执行者的行动空间从"修改仓库中的任何文件"收窄到"修改这 3 个文件并满足这 2 个条件"——搜索空间缩小约两个数量级。
八、长期工程迭代管理原理
8.1 状态持久化与会话连续性
AI Agent 时代,执行者每次可能是不同的模型实例。项目状态不能依赖会话内存——必须外化到磁盘文件:
- 项目目录包含完整状态:规划文档、架构记录、执行状态、调试历史、修复记录
- 任何新会话从磁盘文件恢复,获得与上一会话完全一致的项目认知
- 会话中断不丢失任何进度——所有状态变更即时写入磁盘
8.2 波次递进与增量交付
任务按依赖关系组织为波次(wave)。每个波次完成后自动触发下一波次。已完成任务的文档更新在合并时即时应用到项目文档——后续波次的执行者看到的是包含所有前序成果的最新上下文。
增量交付的保证:第 N 波次的所有产出在第 N+1 波次启动前已合并到项目文档和架构记录中。
8.3 动态图调度替代静态表格(原理,V2 新增)
V1 的调度基于静态 todo.md 表格——AirArc 产出表格,AirEng 基于表格调度。当需求变更时 Arc 重新生成表格,Eng 无法增量吸收差异,需多轮 AI 迭代才能恢复调度。
原理层面的要求:调度结构必须是一个活的有向无环图(DAG),而非静态表格。它需要具备四项核心能力:
- 增量吸收:重规划只更新变化的部分,已调度任务不受影响
- 全量替换时保留完成态:避免已完成任务被重新调度
- 图差异计算:新旧 DAG 对比产出精确的变更集(PlanDelta)
- 就绪计算:返回入度为 0 且未开始的节点,调度冻结时返回空
这四项能力共同支撑**"需求变更是非破坏性的"**这一工程承诺——用户在执行中途修改任务表,系统能够增量吸收而非推倒重来。
TaskGraph 的具体数据结构(TaskNode 含 adr_refs/test_required/write_set)、PlanDelta 的 added/removed/modified 结构、apply_delta 的实现细节见第二十章 § 20.3。
8.4 范围变更的非破坏性
用户可以在执行中途修改任务表(添加、修改、取消任务)。V2 的 TaskGraph 使这一过程变为增量操作:
- 用户修改
todo.md - AirEng 检测到 todo.md mtime > task-graph.json mtime
- 自动触发
incremental_replan:全量重建新 DAG → diff 旧 DAG → 产出 PlanDelta apply_delta()增量更新,保留已调度任务的 DISPATCHED/DONE 状态- 新任务自动进入后续波次调度
8.5 回归防护机制
- 状态过滤:已完成任务不参与重新调度(
ready_tasks()只返回status == "TODO") - 分组追踪:已完成的波次不会被重复派发
- 合并验证:结果必须包含实质产出才能标记为完成
- 文档强制:涉及全局文档的任务必须提交架构文档更新
- 证据强制:GUI 任务必须有截图证据才能关闭
- TaskGraph 状态同步(V2):merge 后 Phase 6.5 自动同步
task-graph.json节点 status,防止重复派发已完成任务
8.6 跨模型、跨设备、跨时间的连续性
所有状态都是纯文件(JSON、Markdown),可通过版本控制或文件同步在多个维度实现连续性:
- 跨模型:不同模型实例读取同一套制品,获得一致的项目认知
- 跨设备:不同物理设备通过远程访问同一状态目录
- 跨时间:任意时间点中断,从文件恢复完整执行历史
九、工具扩展与自动化原理
9.1 从语言模型到工程平台
LLM 本身不具备工具能力,但通过 CLI 工具注册、MCP 协议桥接、Skill 封装等机制,可以将其扩展为具备完整工程能力的平台。关键设计原则:
- 工具注册与路径声明:显式注册工具路径,避免 Agent 在执行时重复发现或误用
- 持久记忆:通过结构化文档(AGENTS.md、ADR、plan.md)为 Agent 提供跨会话记忆
9.2 重复的事情应该被自动化
如果一件事要重复五次,那么它应该被自动化
在以前,自动化涉及开发,是一件成本很高的事情,但 AI 发展后的现在,自动化的难度已经被极大的降低了,如果一件事你至少要重复五次,那为什么不拿出 2-3 次的时间把它自动化,然后省下几次的时间去做其他更重要的事?
AI 工程迭代路径恰好与以前工业时代的一句话对应:
复杂的事情简单化
简单的事情标准化
标准的事情自动化
自动的事情智能化
十、L1 代码级保障原理(V2 新增)
10.1 从"建议性"到"强制性"的范式跃迁
V1 的许多关键约束(证据先于修复、AirDbg 路由、AirArc 只读)仅通过 SKILL.md 的自然语言指令传达——本质上是建议性约束,依赖 LLM 的"自觉"遵守。V1 真实项目数据证明了这一范式的失效:
| 约束 | V1 表达方式 | 实际违规率 | 根因 |
|---|---|---|---|
| AirDo 调用 AirDbg | SKILL.md 建议 | 频繁跳过 | Worker 倾向直接返回 |
| AirArc 不写代码 | SKILL.md 声明 | 被 plan mode 劫持 | Agent 框架覆盖 |
| AirEng 自主推进 | SKILL.md 期望 | 反复询问用户 | 无强制决策指令 |
| AirDbg 先取证 | 7 步工作流 | 不取证就改代码 | 步骤可跳过 |
V2 的核心设计原则:凡是造成过实际损失的约束,必须从自然语言建议升级为 L1 代码级保障——即通过 Python 代码的门控逻辑、工具白名单、数据结构约束来硬性执行。
10.2 五种 L1 保障机制(原理层枚举)
L1 代码级保障体系在五个层面叠加防御,每一层针对不同类型的违规模式:
| 层面 | 针对的违规模式 | 硬化方式 |
|---|---|---|
| ① 工具白名单 | Agent 越权操作(如 AirArc 写代码) | 命令文件 frontmatter 声明 |
| ② Python 门控函数 | 跳步执行(如未取证就改代码) | 运行时返回值强制 |
| ③ 数据结构约束 | 数据不合法(如 task_id 路径注入) | 契约层校验 |
| ④ 强制路由链 | 跳过协作环节(如 AirDo 不调 AirDbg) | finish_worker 强制派发 |
| ⑤ 原子操作 + 并发控制 | 状态损坏(如并发写竞态) | 基础设施层保证 |
五层叠加后,任何一层失守都不会直接造成事故——其余层仍能阻断违规。这是纵深防御在 AI 工程中的体现。
每一层的具体代码实现(allowed-tools frontmatter、ArcPhaseGate/EvidenceFirstGate、WorkerResult.validate_for_finalize、finish_worker 6 级路由链、atomic_json_write + FileLock)见第二十章 § 20.4。
10.3 指令操作化:消除 Agent 推理歧义(原理)
V1 的命令文件使用意图描述(如"读取派发清单,为每个任务 spawn 隔离的 Worker 子代理"),Agent 需要多轮推理才能翻译成具体操作:用什么工具?参数格式?task-text 从哪取?猜错就多一轮,猜不出来就回退自己执行。
原理层面的要求:关键操作路径必须从意图描述升级为可执行伪代码——给出确切的工具名、参数结构、执行顺序、并发约束。Agent 不再需要推理,只需要按步骤执行。
这背后的原则是:人类读意图,机器读指令。SKILL.md 同时服务于人类理解("为什么要派发子代理")和 Agent 执行("用什么工具、什么参数派发子代理"),但这两个目标对表达精度的要求完全不同。V2 的做法是在人类可读的意图描述之后,紧跟一份机器可执行的操作步骤——两套表达服务于两类读者,互不替代。
具体操作化示例(如 AirEng 派发 Worker 的 Agent 工具调用步骤、AirDo 路由链的 finish_worker 伪代码)见第二十章 § 20.5。
10.4 前置条件注入:在派发点强制补齐缺失制品(原理)
很多工作流约束失败,不是因为下游 Agent 不够聪明,而是因为上游在错误的前提条件下启动了它。例如:Scheduler 的运行前提本应是 plan.md 和 task-graph.json 已存在;如果这个前提只靠 Main Agent "记得先做架构设计",那么一旦它漏掉一步,整个后续调度都会在错误世界里开始。
原理层面的要求:关键前置条件不能只写在文档里,而要在派发点由系统主动检查和补齐。
- 当上游试图直接派发 Scheduler 时,运行时先检查
.air/shared/plan/plan.md和task-graph.json是否存在 - 如果缺失,不是让 Scheduler 自己"发现后再说",而是系统在派发前直接改写/注入指令,强制先派发 Architect 生成规划
- 下游 Agent 看到的永远是"前置条件已满足"的世界,而不是带缺口的半成品上下文
这条原则很重要,因为它把"先做架构设计"从流程约定升级成了入口门控。约束不再依赖 Agent 的记忆,而是依赖系统在工作流接缝处的主动校验。
10.5 自由文本也必须进入协议:把 Agent 输出转化为可审计信号(原理)
结构化字段(如 status=completed)只能表达"Agent 自称完成",却不能表达它是如何完成的。真实工程里,很多违规恰恰藏在自由文本里:例如 Worker 一边写着 completed,一边说"for now 先这样";Reviewer 一边给 PASS,一边整份报告都只在说"build 通过、测试通过、函数存在"。
原理层面的要求:凡是会参与关闭任务、放行结果的自由文本,都必须被视作协议的一部分,进入机器可检查的门控链路。
- Worker 输出不仅要有状态字段,还必须包含编译 / 测试 /
cppcheck证据,且不得出现降级关键词 - Reviewer 报告不仅要给 verdict,还必须包含 Code-to-Design 逐行对照表,不能只凭"表面证据"判定 PASS
- 调度器读取的不只是结构化结果,还要读取
output_text片段,把文本中的软违规纳入状态机判断
这背后的设计思想是:自然语言不是日志附属物,而是可被滥用的接口面。一旦把它纳入协议,系统就能拦住那些"字段合法、语义违规"的软逃逸行为。
第二部分:实践——Air 插件套件 V2 与 AirCoding Alpha
十一、V2 架构总览
11.1 V1→V2 核心命题
V1 证明了制品驱动 + 上下文隔离 + 波次并行的架构方向成立。V2 要解决三个系统性问题:
- 可靠性:状态写入不丢失,并发操作不竞态,崩溃后可自愈
- 可观测性:所有引擎操作可追溯,指标可导出,异常主动通知
- 智能化:证据门控感知任务类型,轮询频率自适应,修复模式可学习
补充:AirCoding V1.0.0 Alpha 的当前完成态(2026-07)
AirCoding 已经不再只是"下一步想做什么"的路线图。到 V1.0.0 Alpha / 0.1.0 release 这个时间点,它已经完成了首个公开可用闭环并开源。但它的落地路径并不是"完整自研运行时已经成熟",而是更克制也更现实的一条路线:基于 OpenCode fork 的最小改造,把多 Agent 调度层、权限矩阵和关键门控内嵌进宿主运行时。
当前 alpha 已实装的关键能力:
- 5 类 Agent 已代码注册:Main / Scheduler / Worker / Architect / Reviewer 都已在运行时注册,不再只是文档里的角色想象
- 权限矩阵已代码化:Scheduler 无写权限、Architect 仅可写
.air/shared/plan/**、Worker 无task权限,这些边界由代码控制而非 Prompt 自觉 - 确定性调度器已落地:
coordinator_tick已承担task-graph.json的 DAG 就绪计算、状态迁移、重试预算、里程碑审查预算、scheduler-state.json实时落盘 - 关键门控已进入 hook / tool 层:派发 Scheduler 前强制检查
plan.md + task-graph.json;Worker 缺少cppcheck或输出降级关键词会被打回;Reviewer 缺少 Code-to-Design 对照表或只凭表面证据判 PASS 会被强制重审 - 最小工程闭环已成立:架构产物、任务图、调度状态、调试记录都已有明确目录约定,系统已具备可恢复、可审计、可追踪的最小工程能力
当前 alpha 仍未完全到位的部分:
- 仍受宿主框架约束:当前主实现仍主要复用 OpenCode 的 Agent、Session、BackgroundJob、Plugin Hook 和 Tool Registry,而不是完整自研 EventBus + NDJSON IPC 运行时
- 理想形态仍在后续路线:语言无关运行时、经验学习/记忆层、独立事件存储、动态权限切换等更完整的设计,仍属于后续演进目标
因此,对 AirCoding Alpha 最准确的表述不是"只有 shell 雏形",也不是"完整独立运行时已完成",而是:它已经完成了一版可公开使用、可公开审视的工程化 Alpha,用宿主内嵌的方式验证了关键约束能否从插件层继续推进到 Agent 框架层。
11.2 统一插件架构
V1 由 8 个独立插件组成,各自有独立的安装、注册和运行时。V2 将 8 个插件统一为 1 个插件(airplan-v2)12 种模式:
| 模式 | 对应 V1 插件 | V2 核心改进 |
|---|---|---|
| /arc | AirArc | 三阶段门控、plan mode 阻断、工具白名单只读、弱模型安全审计、DAG 产出、边界测试注入 |
| /eng | AirEng | 中文锁定、自主决策、ScheduleWakeup 轮询、调度职责边界、事务化合并、ADR 级联失效、worktree 并行 |
| /do | AirDo | 全专家插件强制路由、UI 任务 frontend-design Skill、task_id 注入防护 |
| /dbg | AirDbg | EvidenceFirstGate 先读后写门控、步骤追踪不可跳过、修复前 git snapshot、选择性快照 |
| /xdb | AirXDB | DRM/KMS 原生截图、Xvfb headless CI、多后端自动降级 |
| /ndb | AirNDB | TLS 解密、pcapng 支持 |
| /sdb | AirSDB | 六语言后端(cppcheck/clang-tidy/clippy/go-vet/tsc/mypy)、diff 模式 |
| /ctx | AirContext | 压缩质量校验、自适应 Token 估算、陈旧锁检测、三级降级压缩 |
| /dep | 新增 | SSH 远程构建 + scp + MD5 校验 + systemd 生命周期 + 冒烟验证 |
| /tst | 新增 | 统一测试执行(pytest/googletest/jest/go test/cargo test)+ 结构化报告 |
| /sec | 新增 | 制品敏感数据扫描 + 白名单 + advisory/blocking 模式 |
| /rvr | 新增 | 需求一致性审查 + Code-to-Design 对照 + 高风险审计 + verdict 控制合并 |
11.3 流水线拓扑
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ /arc │────►│ /eng │────►│ /do │────►│ /dbg │
│ (规划) │ │ (调度) │ │ (执行) │ │ (调试) │
└──────────┘ └──────────┘ └──────────┘ └────┬─────┘
│ │ │ │
│ task-graph │ Agent 子代理 │ finish 路由链 │
│ + plan-delta │ run_in_bg │ │
│ │ ├──────────────────┤
│ │ ▼ ▼
│ │ ┌──────────┐ ┌──────────┐
│ │ │ /xdb │ │ /ndb │
│ │ │(GUI证据) │ │(网络证据)│
│ │ └──────────┘ └──────────┘
│ │ │ │
│ │ ▼ ▼
│ │ ┌──────────┐ ┌──────────┐
│ │ │ /sdb │ │ /rvr │
│ │ │(静态分析)│ │(需求审查)│
│ │ └──────────┘ └──────────┘
│ │ │
│ │ ┌──────────────┐ │
│ │ │ /dep │ │
│ │ │ (部署) │ │
│ │ └──────────────┘ │
│ │ ┌──────────────┐ │
│ │ │ /tst │ │
│ │ │ (测试) │ │
│ │ └──────────────┘ │
│ │ ┌──────────────┐ │
│ │ │ /sec │ │
│ │ │ (安全扫描) │ │
│ │ └──────────────┘ │
│ │ │
│ └───────────────────────────────────┘
│ │
│ ┌──────────┐
└───────────────────►│ /ctx │
│(上下文) │
└──────────┘
关键变化:V1 的 AirDo 只路由到 AirDbg/AirXDB。V2 的 /do 在 finish 时执行全专家插件强制路由链——根据任务类型和状态,依次路由到 /dbg、/xdb、/ndb、/sdb、/rvr,无强制路由时才允许 merge。
11.4 基于制品的通信协议(V2 扩展)
AirPlan/
├── AGENTS.md # 项目级 AI 上下文(多模式标记块共管)
├── plan.md # 总体执行计划
├── todo.md # 结构化任务表(人可读,DAG 的辅助视图)
├── docs/
│ ├── architecture/
│ │ ├── adr/ADR-NNNN-*.md # 架构决策记录
│ │ └── c4/module.md # C4 模块边界文档
│ ├── debug/
│ │ ├── debug-log.md / gui-debug-log.md
│ │ └── airxdb-artifacts/
│ ├── network/
│ │ ├── airndb-log.md
│ │ └── airndb-captures/
│ ├── reviews/
│ │ └── {task_id}-review.md # V2: AirRvr 审查报告
│ └── staticanalysis.md
└── state/
├── airarc/reviews/
│ ├── execution-plan.json
│ ├── parallel-review.json
│ ├── task-graph.json # V2: 动态 DAG(调度权威来源)
│ └── plan-delta.json # V2: 增量重规划差异
├── aireng/
│ ├── state.json / plans/
│ ├── dispatch/{wave-id}.json
│ ├── archive/{task-id}-{ts}.json # V2: 已合并结果归档
│ └── repairs/{task-id}/{repair-id}/
├── airdo/tasks/{task-id}/
│ ├── brief.md / subagent-handoff.md
│ ├── result.json / worker-state.json
├── airdbg/{state,sessions,snapshots}/ # V2: 新增 snapshots 目录
├── airxdb/{state,requests,sessions}/
├── airndb/
├── airsdb/reports/
├── airdep/sessions/ # V2: 部署会话
├── airtst/reports/ # V2: 测试报告
├── airrvr/reviews/ # V2: 审查报告
├── airsec/ # V2: 安全扫描
├── aircontext/ # V2: 上下文管理
└── events.jsonl # V2: 事件日志(完整时间线)
V2 新增 events.jsonl——结构化事件日志(JSONL 格式),与 state.json 互补:state.json 是当前快照,事件日志是完整时间线。事件类型覆盖全生命周期:
| 事件类型 | 触发时机 | 负载信息 |
|---|---|---|
task.dispatched |
Eng 派发任务 | taskId, waveId |
task.entered |
Worker 进入 | taskId, uiRouting |
task.finished |
Worker 完成 | taskId, status, routingTargets |
task.completed |
合并成功 | taskId, archivePath |
task.blocked |
任务阻塞 | taskId, status |
merge.started / merge.completed |
合并开始/完成 | taskId, appliedDocCount |
intervention.stall |
停滞检测 | taskId |
worker.timeout |
Worker 超时 | taskId, ageSeconds |
eng.replan.triggered |
增量重规划 | added, removed, modified |
adr.change.detected |
ADR 变更检测 | adrId, kind |
adr.invalidation |
ADR 级联失效 | adrId, invalidatedCompleted, cascadedDownstream |
worktree.merge.conflict |
Worktree 合并冲突 | taskId, action |
context.compacted |
上下文压缩 | compressionLevel, tokens |
十二、核心实现详解
12.1 调度算法:从静态表格到动态 DAG
V1 的静态表格调度
V1 的 AirArc 产出 todo.md 表格,AirEng 基于表格解析任务、构建依赖边、波次分组。当需求变更时 Arc 全量重新生成表格,Eng 无法增量吸收,需多轮 AI 迭代恢复。
V2 的 DAG 调度
V2 的 AirArc 同时产出 task-graph.json(动态 DAG)和 todo.md(人可读辅助视图)。调度逻辑从 DAG 计算而非表格解析:
输入: todo.md + task-graph.json
1. 构建 DAG → TaskGraph (TaskNode + Edge)
2. 注入边界测试任务 → _inject_boundary_tests()
- 按 files_dirs 推断模块(取第一级目录作为模块名)
- 每个模块创建接口测试 + 单元测试任务
- 实现任务 → 测试任务建立依赖边
3. 依赖边构建 → review.py build_parallel_review()
4. 波次调度 (拓扑排序):
ready_tasks() → 入度 = 0 且 status = TODO 的任务
调度冻结时返回空列表
5. 区域冲突检测 → RegionConflictDetector
NONE: 直接并行
SOFT: worktree 隔离并行
HARD: 强制串行
6. 产出 execution-plan.json + task-graph.json
增量重规划(需求变更时):
1. todo.md mtime > task-graph.json mtime → 触发 maybe_replan()
2. 全量重建新 DAG → new_graph.diff(old_graph) → PlanDelta
3. old_graph.apply_delta(delta) → 保留已调度任务的 DISPATCHED/DONE 状态
4. 写回 task-graph.json + plan-delta.json
5. emit ARC_REPLANNED 事件
12.2 全链路上下文隔离
AirEng 派发 /do Worker 时使用 Agent 工具(run_in_background: true),每个子 Agent 拥有独立上下文,天然满足 fork_context=false。
V2 的 spawn_workers() 标准化了派发流程:
def spawn_workers(project_root, task_ids) -> list[dict]:
"""为每个 ready 任务准备 Agent 派发指令。
返回 Agent 调用参数列表,Eng Agent 遍历列表逐个调用。"""
for tid in task_ids:
node = graph.nodes.get(tid)
instructions.append({
"description": f"Do Worker: {tid}",
"subagent_type": "general-purpose",
"run_in_background": True, # 关键:后台运行,Eng 不阻塞
"prompt": f"你是 AirDo Worker,任务 ID: {tid}...\n"
f"## 任务\n{task_text}\n"
f"## 文件范围\n{files}\n"
f"## 完成标准\n{done_when}\n"
f"## 工作流程\n1. 初始化 Worker 状态\n"
f"2. 读取项目文件\n3. 实现任务需求\n"
f"4. 运行 finish 命令\n",
})
传递的信息(5K-20K token):任务描述 + 文件范围 + 完成标准 + 6 个必读文件路径 + 10 条执行契约。
不传递的信息:调度器 200K 对话历史、其他 Worker 状态、引擎内部 state。
信噪比提升约一个数量级。
12.3 全专家插件强制路由链
V1 的 AirDo finish 时只有两条路由(GUI 关键词 → AirXDB,blocked → AirDbg),且为建议性而非强制。V2 将路由升级为 6 级强制链:
finish_worker() 路由决策(按优先级):
┌─ 1. blocked / failed → 强制 AirDbg ────────────── (最高优先级)
│ "AirDbg mandatory before return"
│
├─ 2. done 但无 validations + 无 filesChanged → 强制 AirDbg
│ "done without evidence — mandatory debug review"
│
├─ 3. GUI 任务(关键词命中)且无 xdbSessions → 强制 AirXDB
│ "GUI task requires screenshot evidence"
│
├─ 4. 网络任务(关键词命中)且无 ndbSessions → 强制 AirNDB
│ "network task requires packet capture evidence"
│
├─ 5. C/C++ 文件变更(.cpp/.h/.hpp)且无 sdbReports → 强制 AirSDB
│ "C/C++ task requires static analysis"
│
├─ 6. 所有 done 任务且无 rvrReviews → 强制 AirRvr
│ "completed task requires requirements review"
│
└─ 无强制路由触发 → merge ──────────────────────── (最低优先级)
返回 routingDecisions 列表(可能有多个路由目标),Worker 依次处理后重新 finish。路由决策由 Python 代码生成,不依赖 LLM 判断——即使 LLM 尝试跳过,代码层仍然强制执行。
12.4 事务化合并流水线
V1 的 merge_worker_result() 执行 8+ 次文件写入,中间崩溃导致不一致。V2 引入事务语义的 6 阶段合并流水线:
merge_worker_result(project_root, result_path):
state_lock = FileLock(state.json)
todo_lock = FileLock(todo.md)
with state_lock:
┌─ Phase 1: 验证 ──────────────────────────────────────┐
│ enforce_doc_sync_requirements(result) │
│ - deployRequired → 必须有 deploy 验证 │
│ - documentUpdates 路径必须在 AirPlan/ 内 │
│ 失败 → 抛 ValueError,不触碰文件系统 │
├─ Phase 1.5: Rvr 审查(可选)─────────────────────────┤
│ reviewPolicy.requireBeforeMerge 或 result.requireReview │
│ verdict=fail → 阻止合并 │
│ verdict=conditional-pass → 记录遗留项但允许合并 │
├─ Phase 2: 归档 ──────────────────────────────────────┤
│ archive/{task_id}-{timestamp}.json │
│ 原子写入,可重试 │
├─ Phase 3: 应用文档更新 ──────────────────────────────┤
│ apply_document_updates(result.documentUpdates) │
│ write / append 两种动作 │
├─ Phase 4: 同步引擎管理文档 ──────────────────────────┤
│ sync_engine_managed_docs(plan.md, debug-log.md, ...) │
│ 去重:检查 taskId 标记行是否已存在 │
├─ Phase 5: 更新 todo(嵌套 FileLock)────────────────┤
│ update_todo_after_merge() │
│ 动态定位 Status 列(不硬编码列索引) │
│ 附加 <!-- merged:path --> 引用便于追溯 │
├─ Phase 6: 更新引擎状态 ──────────────────────────────┤
│ state.json 原子写入 │
│ mergedResults 截断至 100 条(防止无界增长) │
│ 移除 activeWorkers 中已完成的任务 │
├─ Phase 6.5: TaskGraph 状态同步 ─────────────────────┤
│ task-graph.json 节点 status → DONE │
│ 防止下次 dispatch 重复派发已完成任务 │
└──────────────────────────────────────────────────────┘
emit MERGE_COMPLETED + TASK_COMPLETED / TASK_BLOCKED
12.5 AirArc 三阶段门控
V1 中 AirArc 频繁被 Agent 内置 plan mode 劫持,且在用户仅说一两句时就立即生成执行计划。V2 从工具层和代码层双重阻断:
工具层(命令文件 frontmatter):
allowed-tools: "[Read, Glob, Grep]" # 只有只读工具
deny-plan-mode: true # 硬性阻断 plan mode
代码层(ArcPhaseGate):
三阶段流程(不可跳过):
Phase 1: discussing(默认)
- 与用户反复讨论需求细节、边界条件、隐含约束
- 主动提问澄清模糊点
- 分析现有代码库结构
- 提出多种架构方案及优劣对比
- execution-plan.json 写入被禁止
Phase 2: proposing
- 向用户呈现推荐架构方案
- 明确等待确认:"请确认此架构方案是否符合预期"
- 用户有异议 → 回到 Phase 1
- execution-plan.json 写入被禁止
Phase 3: confirmed
- 仅在用户说"确认"/"可以"/"同意"后自动推进
- 允许生成 execution-plan.json 和 task-graph.json
- 规划产出严格对应用户确认的架构方案
parallel_review_mode() 在写入前检查 gate.can_write_plan(),phase 不是 confirmed 则返回 {"blocked": true, "reason": "arc phase is 'discussing'..."}。
12.6 AirDbg 先读后写门控
V1 的 AirDbg 7 步工作流为建议性——模型经常跳过取证直接修改代码,引入新问题且污染代码库。V2 通过 EvidenceFirstGate 硬性执行:
class EvidenceFirstGate:
EVIDENCE_TYPES = [
"screenshot", # AirXDB 截图
"packet_capture", # AirNDB 抓包
"static_analysis", # AirSDB 静态分析
"log_analysis", # 日志分析
"code_trace", # 代码追踪(读取相关文件、调用链分析)
"reproduction", # 复现步骤执行
]
def can_modify_code(self) -> bool:
return len(self._collected_evidence) > 0
def gate_check(self) -> None:
if not self.can_modify_code():
raise WorkflowViolation(
"未执行任何取证行为,禁止修改代码。")
步骤追踪机制:
| 步骤 | 名称 | 推进条件 | 特殊规则 |
|---|---|---|---|
| 1 | confirm_symptoms | 提供 symptom/expected/actual | 取证步骤,计入 collectedEvidence |
| 2 | load_context | 无强制证据 | 取证步骤,计入 collectedEvidence |
| 3 | reproduce | 提供 reproduction_steps | 可跳过(标记为 non-reproducible) |
| 4 | locate_root_cause | 提供 root_cause_analysis | 取证步骤,计入 collectedEvidence |
| 5 | fix | 提供 fix_description + files_changed | 硬性门控:collectedEvidence 非空 |
| 6 | verify | 提供 validation_result | 同类证据验证 |
| 7 | close_out | 提供 residual_risk + adr_updates | 更新项目文档 |
修复前快照:pre_fix_snapshot() 在步骤 5 执行前自动创建 git tag 回滚点。V2 改进为选择性快照——只提交 Worker result 中声明的 filesChanged 范围内的文件,避免全量 commit 混入无关变更。
12.7 Worktree 隔离并行(同文件不同区域)
V1 的冲突检测粒度为文件级。实际场景中,同一文件的不同区域可能互不影响(如 Qt 组件样式 vs 状态机逻辑),被迫串行降低了并行效率。
V2 引入三级冲突检测 + git worktree 隔离:
RegionConflictDetector.detect():
file_overlap = set(task_a.write_set) & set(task_b.write_set)
if not file_overlap → NONE(直接并行)
if 无区域信息 → SOFT(worktree 隔离并行)
for fpath in file_overlap:
ra = regions_a[fpath] # [(start_line, end_line), ...]
rb = regions_b[fpath]
if 行号区间重叠 → HARD(必须串行)
else → SOFT(worktree 隔离并行)
WorktreeIsolation 生命周期:
1. create_worktree(task_id, base_ref="HEAD")
→ git worktree add -b air-{task_id} {wt_path} HEAD
→ Worker 在独立 worktree 目录中执行
2. merge_back(task_id, wt_path)
→ git merge --no-ff air-{task_id}
→ 成功: cleanup(task_id) → git worktree remove + branch -D
→ 失败: _abort_merge() → 返回 Conflict 列表
3. 合并失败时的三级降级:
→ 升级到 AirDbg(调试冲突)
→ AirDbg 也失败 → 降级为串行重执行
→ emit WORKTREE_MERGE_CONFLICT 事件
Eng 的 monitor_engine() 在每轮轮询中自动检查 .git/worktrees/air-* 目录,处理已完成但未 merge 的 worktree。
12.8 AirEng 调度引擎 V2
角色边界硬性约束
V2 从 SKILL.md 和代码层双重约束 AirEng 的职责边界:
核心职责:调度,不是编码
默认禁止:编写源代码、修改项目文件
极端接管(唯一例外,全部条件满足才允许):
1. 子代理陷入循环阻塞,修复预算已耗尽
2. 问题已通过 AirDbg 定位到明确的根因
3. 修复范围极小(≤5 行改动)
4. 继续等待 Worker 重派发已无意义
→ 进入前必须记录 EXTREME_TAKEOVER 日志
→ 即使接管也必须调用相关专家插件(Dbg/XDB/NDB/SDB/Rvr)
监控循环 V2
monitor_engine():
1. 遍历 activeWorkers:
a. Worker 存活时间 > 2 小时 → wall-time-exceeded → terminate
b. state 文件 mtime > 5 分钟 → stalled → re-dispatch-or-block
c. status = done → ready_to_merge
2. 资源压力检测: loadavg > 2× CPU 数 → 暂停派发
3. ADR 变更检测: ADRWatcher.detect_changes()
→ superseded/modified → handle_adr_invalidation()
4. Worktree 合并检查:
→ 已完成但未 merge 的 worktree → check_worktree_merge_status()
→ merge 失败 → 升级到 AirDbg → 再失败 → 降级串行
5. emit ENGINE_CYCLE 事件(stalledCount, readyToMerge, interventionCount)
派发决策链
dispatch_worker_group():
1. maybe_replan() — 检查 todo.md mtime vs task-graph.json mtime
→ todo 更新 → 触发增量重规划
2. 检查调度冻结(dispatch_frozen = true → 返回 blocked)
3. 检查 block-release verdict(AirRvr 终审 → 阻止所有派发)
4. _select_ready_tasks() — 从 DAG 计算入度为 0 的 TODO 任务
→ DAG 中 ready 为空时不 fallback 到 todo.md(空列表也是正确答案)
5. 区域冲突检测(多任务时)
→ HARD 冲突 → 强制串行,只派第一个
→ SOFT 冲突 → 标记 worktree 隔离
6. 写 dispatch payload → emit TASK_DISPATCHED
12.9 AirRvr 需求审查器(V2 新增)
V1 中任务"完成"的判定仅依赖 Worker 自报 + AirEng 结构验证。没有任何组件将交付物与原始需求进行独立比对。AirRvr 填补了这一空白。
多维度审查:
| 审查维度 | 检查内容 | 产出 |
|---|---|---|
| 需求覆盖度 | 原始需求中的每个要求点是否被交付物覆盖 | coverage: [{requirement, status, evidence}] |
| 意图一致性 | 交付物是否解决了需求想解决的真正问题 | intentAlignment: aligned / divergent |
| 回归风险 | 变更是否破坏了需求的已有功能 | regressionRisk: none / low / medium / high |
| 代码质量 | 复杂度、可读性、重复率、异常处理 | codeQuality: {complexity, readability, ...} |
| 生命周期健壮性 | 资源释放、连接管理、超时/重试/降级 | lifecycleHealth: {resourceLeak, ...} |
| 运行时稳定性 | 内存泄漏、竞态条件、崩溃路径 | runtimeStability: {crashRisk, ...} |
| Code-to-Design | 代码实现与设计文档逐行对照 | codeToDesignTable: [{designRef, codeLocation, status}] |
| 日志标准 | spdlog 集成、非标准日志、debug/release 开关 | loggingChecks: {spdlogIntegrated, ...} |
| 高风险审计 | 生命周期/空指针/悬垂指针/异常安全/并发 | highRiskAudit: {lifecycle, nullPointer, ...} |
高风险审计五项检查(里程碑审查时强制执行):
生命周期风险:
- 资源申请与释放是否配对(new/delete, malloc/free, open/close)
- RAII 是否覆盖所有资源持有
- 异步操作的回调/完成是否保证执行
空指针/悬垂指针:
- 指针使用前是否判空
- 智能指针生命周期是否覆盖使用范围
- 回调闭包中捕获的指针是否仍然有效
- 容器元素删除后迭代器是否失效
异常安全:
- 异常路径中资源是否正确释放
- 是否存在异常吞没(catch 后无处理)
- 跨模块边界是否有异常传播保护
并发风险:
- 共享状态是否有锁保护
- 锁顺序是否一致(防死锁)
- 条件变量是否有虚假唤醒保护
verdict 控制合并:
| verdict | 行为 | 集成点 |
|---|---|---|
pass |
正常合并 | merge Phase 1.5 |
conditional-pass |
合并但记录 residualItems | state.json |
fail |
阻止合并,要求修订 | merge 抛 ValueError |
deliveryVerdict = block-release |
阻止所有后续派发 | dispatch_worker_group() |
三种审查模式:
| 模式 | 触发时机 | 审查范围 |
|---|---|---|
| per-task | 单个任务完成后(/do finish 自动路由) | 单任务 |
| per-wave | 一个波次所有任务完成后 | 整波次 |
| per-milestone | 项目阶段结束时 | 全量(比对 requirements.md) |
12.10 AirDep 部署器(V2 新增)
V1 无部署插件,导致"完成但未部署"事故(T-028b 发现 4 个 "done" 任务未实际部署,延迟发布一整天)。AirDep 提供标准化的部署流水线:
deploy() 完整流程:
Step 1: 远程构建(可选)
SSH → cd {build_dir} && {build_cmd}
超时 600s
Step 2: 二进制传输 + MD5 校验
scp local_binary → remote:/tmp/
local_md5 = md5_file(local)
remote_md5 = SSH md5sum remote
不匹配 → 返回失败 "md5 mismatch after transfer"
Step 3: 部署二进制
SSH mv /tmp/{binary} → {deploy_dir}/
Step 4: systemd 生命周期
SSH systemctl daemon-reload
SSH systemctl restart {service_name}
SSH systemctl is-active {service_name}
返回 service_status
Step 5: 冒烟验证(可选)
SSH {smoke_test_cmd}
记录 smoke_test_passed
Step 6: 持久化
DeploymentRecord → state/airdep/sessions/
emit DEPLOY_COMPLETED 事件
与合并流水线集成:deployRequired=true 时,enforce_doc_sync_requirements() 验证 result 中必须包含 remote-deploy-verify 或 remote-binary-md5 类型的 validation。
12.11 AirTst 测试运行器(V2 新增)
统一测试执行接口,支持 5 种框架:
| 框架 | 命令 | 解析方式 |
|---|---|---|
| pytest | python -m pytest --json-report -q |
JSON summary |
| GoogleTest/CTest | ctest --output-on-failure |
文本 + JSON 双解析 |
| jest/vitest | npx jest --json |
JSON testResults |
| go test | go test -json ./... |
JSONL 事件流 |
| cargo test | cargo test -- --format=json |
JSONL 事件流 |
产出结构化 TestRunResult:{framework, total, passed, failed, disabled, duration, failures}。
与 AirArc 集成:规划阶段自动注入边界测试任务(T-TEST-001 等),标记 test_required=true,Done When 强制包含"测试通过"。
12.12 AirSec 安全扫描器(V2 新增)
扫描制品中的敏感数据,防止 API 密钥、令牌、密码泄露到项目文档:
SECRET_PATTERNS (6 种):
- api_key: api_key = "..."
- aws_key: AKIA...
- private_key: -----BEGIN RSA PRIVATE KEY-----
- token: token = "..."
- jwt: eyJ...
- url_credential: 603K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6#2M7$3g2J5i4K6y4m8M7r3q4K6M7%4N6G2M7X3c8Q4y4o6m8Q4x3X3g2Q4x3X3g2Q4x3X3f1`.
三层过滤:
1. 内容模式匹配 → 原始发现
2. 允许列表过滤(EXAMPLE, YOUR_API_KEY, placeholder 等)
3. 文件名白名单过滤(.example., test_, mock_, _test.py, .fixture.)
两种运行模式:
- advisory: 只报告,不阻止合并
- blocking: 发现敏感数据时阻止合并(merge Phase 1 检查 clean=false)
12.13 AirContext V2 改进
压缩质量校验
MUST_PRESERVE_PATTERNS = [
r"[A-Za-z0-9_\-/]+\.(py|ts|js|cpp|h|md|json|yaml)", # 文件路径
r"ADR-\d{4}", # ADR 引用
r"TODO|FIXME|HACK", # 未完成项
r"INV-\d+", # 不变量引用
]
校验逻辑:对比原始文本和摘要中各模式的匹配集合,丢失 > 30% 则标记为失败。失败触发三级降级:
| 降级级别 | 策略 | 适用场景 |
|---|---|---|
RETRY |
重新压缩(换 prompt) | 首次失败 |
FALLBACK_MODEL |
换模型 + 简化 prompt + 放宽 token 限制 | 重试失败 |
TRUNCATE |
激进截断(保留最近 50 行 + 所有 ADR 引用行) | 最终兜底 |
陈旧锁检测
def acquire_compactor_lock(lock_path):
try:
fd = os.open(lock_path, O_CREAT | O_EXCL | O_WRONLY)
os.write(fd, str(os.getpid()))
return True
except FileExistsError:
pid = int(lock_path.read_text())
os.kill(pid, 0) # 不发信号,只检查进程存在
→ 进程存活 → 返回 False(锁有效)
→ 进程不存在 → 删除陈旧锁 → 重试
12.14 AirSDB V2 多语言静态分析
V1 仅支持 Cppcheck + C/C++。V2 扩展为 6 种后端:
| 后端 | 语言 | 工具 |
|---|---|---|
| Cppcheck | C/C++ | cppcheck --check-level=exhaustive |
| Clang-Tidy | C/C++ | clang-tidy |
| Clippy | Rust | cargo clippy |
| go vet | Go | go vet + staticcheck |
| tsc | TypeScript | tsc --noEmit |
| mypy + ruff | Python | mypy + ruff |
新增 diff 模式:比较两次扫描结果,高亮新增/消除的 finding。通过 (file, line, rule_id) 三元组匹配,产出 DiffReport(new_findings, resolved_findings, unchanged_count)。
12.15 AirXDB V2 扩展截图能力
V1 仅支持通用桌面截图。V2 扩展为多后端自动降级:
| 后端 | 适用场景 | 技术实现 |
|---|---|---|
| KMS grab | 嵌入式 DRM/KMS 显示 | ffmpeg -f kmsgrab -i /dev/dri/card0 |
| Xvfb | CI headless 环境 | Xvfb :99 + xwd -root |
| fallback | 通用桌面环境 | Midscene.js / Playwright |
--prefer auto 时按 kms → xvfb → fallback 顺序自动检测。
十三、基础设施层
13.1 原子 I/O(消除 V1 数据损坏)
V1 使用 path.write_text() 直接覆盖 JSON 文件——进程崩溃时 state.json 截断,下次加载 JSONDecodeError。V2 的 atomic_json_write():
写入流程:
1. 旧文件 → os.replace(path, path.bak) # 单级轮转备份
2. tempfile.mkstemp(dir=path.parent) # 同目录临时文件
3. os.write(fd, json_data) # 写入临时文件
4. os.close(fd)
5. os.replace(tmp, path) # POSIX 原子替换
安全加载:
1. json.loads(path.read_text()) # 正常加载
2. JSONDecodeError → 尝试 .bak 恢复 # 自动从备份恢复
3. .bak 不存在 → 返回 None + 日志告警 # 不静默吞异常
13.2 文件锁(消除 V1 并发竞态)
V1 无任何锁、互斥量或原子操作。两个 Worker 同时完成时 todo.md 读-改-写竞态。V2 的 FileLock:
class FileLock:
"""基于 fcntl.flock 的进程级文件锁"""
def __enter__(self):
self._fd = os.open(path, O_CREAT | O_RDWR)
while True:
fcntl.flock(self._fd, LOCK_EX | LOCK_NB) # 非阻塞获取
→ 成功 → return self
→ 超时 → raise TimeoutError
→ 等待 0.1s 重试
def __exit__(self):
fcntl.flock(self._fd, LOCK_UN)
os.close(self._fd)
所有 state.json 和 todo.md 的读-改-写操作必须持有对应锁。合并流水线中嵌套两层锁(state_lock + todo_lock),保证跨文件一致性。
13.3 公共工具层(消除 V1 代码重复)
V1 中 _json_dump 5 份、_ordered_unique 4 份、policy normalization 3 份、marker block upsert 2 份、_session_stamp 格式不一致。V2 统一为 air_runtime/utils.py:
| 函数 | 消除的重复 | 功能 |
|---|---|---|
ordered_unique() |
4 份 | 保序去重,支持字符串和字典列表 |
session_stamp() |
格式不一致 | 统一文件系统安全时间戳 |
now_iso() |
多处 | ISO 格式 UTC 时间戳 |
normalize_policy() |
3 份 | 通用策略合并,类型自动转换 |
sanitize_task_id() |
路径注入风险 | 正则校验 [A-Za-z0-9_\-\.]+ |
sanitize_marker() |
HTML 注入风险 | 拒绝 --> 和 <!-- |
truncate_history() |
无界增长 | 截断至 max_items(默认 100) |
13.4 air_runtime 模块结构
air_runtime/
__init__.py
contracts.py # 数据契约(WorkerResult, TaskRecord, DeploymentRecord)
io.py # 原子 I/O(替代 5 份 _json_dump)
lock.py # 文件锁(fcntl.flock)
utils.py # 公共工具(消除重复代码)
events.py # 事件日志(JSONL + 轮转截断)
task_graph.py # 动态任务依赖图(DAG + PlanDelta + ADR 级联失效)
adr_watcher.py # ADR 文件变更监控(SHA256 hash 对比)
worktree.py # git worktree 隔离并行(区域冲突检测)
partial_replanner.py # 局部重规划(仅受影响任务子集)
evidence_gate.py # 任务类型感知证据门控
paths.py # 路径约定
todo_parser.py # TODO 解析(动态列索引)
review.py # 并行审查(依赖环检测、写集冲突)
project_bootstrap.py # 项目引导(幂等创建 17 个制品)
installer.py # 安装器(动态路径解析 + 安装后验证)
deploy_runtime.py # AirDep 运行时
test_runtime.py # AirTst 运行时(5 框架解析器)
sec_runtime.py # AirSec 运行时(6 模式 + 3 层过滤)
review_runtime.py # AirRvr 运行时(审查报告 + 高风险审计)
sdb_backends.py # AirSDB 多后端
xdb_capture.py # AirXDB 多后端截图
modes/
arc_mode.py # AirArc 模式(三阶段门控 + DAG 构建 + 弱模型安全)
eng_mode.py # AirEng 模式(调度引擎 + 事务化合并 + ADR 级联)
eng_orchestrator.py # AirEng 编排器
do_mode.py # AirDo 模式(全专家路由链 + UI 检测)
dbg_mode.py # AirDbg 模式(7 步追踪 + 先读后写 + 快照)
merge_pipeline.py # 合并管线(6 阶段纯函数集合)
xdb_mode.py # AirXDB 模式
sdb_mode.py # AirSDB 模式
ndb_mode.py # AirNDB 模式
ctx_mode.py # AirContext 模式(三级降级 + 质量校验)
dep_mode.py # AirDep 模式
tst_mode.py # AirTst 模式
sec_mode.py # AirSec 模式
rvr_mode.py # AirRvr 模式
十四、架构状态持久化机制
14.1 标记块命名空间:多模式共管同一文件
AirPlan/AGENTS.md 和 AirPlan/docs/architecture/c4/module.md 被所有模式共同维护,通过两层标记块命名空间避免互相覆盖:
模式层(各模式独立维护):
| 标记块 | 所有者 | 内容 |
|---|---|---|
<!-- AIRARC:BEGIN/END --> |
/arc | 架构规划工作流指令 |
<!-- AIRENG:BEGIN/END --> |
/eng | 调度引擎工作流指令 |
<!-- AIRDO:BEGIN/END --> |
/do | 任务执行器工作流指令 |
<!-- AIRDBG:BEGIN/END --> |
/dbg | 调试工作流指令 |
<!-- AIRXDB:BEGIN/END --> |
/xdb | GUI 证据采集工作流 |
<!-- AIRNDB:BEGIN/END --> |
/ndb | 网络证据采集工作流 |
<!-- AIRSDB:BEGIN/END --> |
/sdb | 静态分析工作流 |
引擎层(merge_pipeline.py 在每次合并时自动更新):
| 标记块 | 所在文件 | 自动写入内容 |
|---|---|---|
<!-- AIR-ENGINE:AGENTS-SYNC:BEGIN/END --> |
AGENTS.md |
最新合并任务的完整审计记录 |
<!-- AIR-ENGINE:C4-SYNC:BEGIN/END --> |
c4/module.md |
最新合并对模块边界的影响 |
<!-- AIR-ENGINE:TODO-RUN-LOG:BEGIN/END --> |
todo.md |
累积合并日志 |
14.2 合并去重(V2 修复 P3-1)
V1 中 AGENTS.md 持续膨胀——同一任务记录重复 2-3 次。V2 的 sync_engine_managed_docs() 在追加标记行前检查是否已存在:
# 去重:若该 taskId 的标记行已存在,则不再追加
if any(line.lstrip().startswith(marker_prefix) for line in existing.splitlines()):
continue
同样,update_todo_after_merge() 在更新行内 <!-- merged:... --> 引用前先剥离已有引用:
cleaned = _strip_merged_refs(line) # 去除行内所有已存在的 merged 引用
十五、复杂项目长期迭代管理
15.1 任务生命周期与状态管理
V2 的任务生命周期扩展了 INVALIDATED 状态(ADR 级联失效):
TaskGraph 节点状态:
TODO ──(调度)──→ DISPATCHED ──(合并成功)──→ DONE
│ │
└──(合并失败)──→ BLOCKED │
│ │
DONE/DISPATCHED ──(ADR变更)──→ INVALIDATED ◄───┘
Worker 状态:
entered → implementing → finished → archived
引擎状态:
idle → planning → dispatching → monitoring → merging → completed | blocked
修复状态:
queued → active → resolved | queued(预算内重试)
ADR 失效流程:
ADR superseded → dispatch_frozen → INVALIDATED → git revert → Arc replan → unfreeze
15.2 修复预算与自动重试
当任务返回 blocked 或验证失败时,系统自动创建修复尝试:
执行 → blocked/failed
→ ensure_repair_attempts_for_result()
→ 创建 RepairAttempt
→ 写入 attempt.json(完整失败上下文)
→ 写入 repair-brief.md(修复指引)
→ 重新派发 Worker
→ done: 修复成功 → resolved
→ blocked: 预算未耗尽 → 再试
→ 预算耗尽 → 升级到用户
V2 配置:repairPolicy.maxAttempts = 3。
15.3 停滞检测与干预
V2 的停滞检测增加了 Worker 超时和资源压力维度:
| 检测类型 | 条件 | 动作 |
|---|---|---|
| 文件停滞 | state 文件 mtime > 300s | re-dispatch-or-block |
| 存活超时 | Worker 存活 > 7200s | terminate-and-block |
| 资源压力 | loadavg > 2× CPU 数 | 暂停派发 |
| Worktree 冲突 | merge_back 失败 | upgraded-to-airdbg → downgraded-to-serial |
| ADR 变更 | SHA256 hash 变化 | invalidate-by-adr |
15.4 文档级联:前序任务如何影响后续任务
Wave 1 (T-001, T-002) 完成并合并
→ todo.md: T-001 DONE, T-002 DONE
→ task-graph.json: 节点 status 同步为 DONE(Phase 6.5)
→ ADR/C4/plan.md: 文档更新已应用
→ AGENTS.md: AGENTS-SYNC 块已刷新(去重后)
→ events.jsonl: MERGE_COMPLETED + TASK_COMPLETED 事件已记录
Wave 2 (T-003, T-004) 派发
→ Worker 读取 Required Reads (6 个文件)
→ 看到的是已包含 Wave 1 产出的最新文档
→ Worker 无需与 Wave 1 的 Worker 通信
→ 自动获得前序工作的全部上下文
→ AirRvr 审查时可引用 Wave 1 的审查报告
十六、多模型交叉审计实践
16.1 AirCoding V1.0.0 Alpha 交叉审计
4 个模型对 146 个源文件独立审计,产出 18+ 份报告:
| 模型 | 评级 | 发现数 | 阻断级 | 审计角度 |
|---|---|---|---|---|
| DeepSeek | B+ | 97 | 10 | 任务完成度 |
| Opus 4.8 | C+ | 140+ | 18 | 逐字段对照规范 |
| MiniMax-M3 | C+ | 38+ | 18 | 可执行性 + 治理 |
| Qwen3.7-Max | D+ | 84 | 31 | 需求覆盖 + 规范一致性% |
评级分歧根因:DeepSeek 以"123/123 文件创建"为主轴 → B+;其余三模型以"与冻结规范的语义一致性"为主轴 → C+/D+。Meta 裁决:文件存在 ≠ 语义正确,综合评级 C。
16.2 4 轮递进审查(系统详细设计)
| 轮次 | 模型 | 重点 | 评分 |
|---|---|---|---|
| 1 | DeepSeek | 基线覆盖性全量核对 | 9.6/10 |
| 2 | MIMO 2.5 Pro | 内在一致性 + 架构合理性 | 9.4/10 |
| 3 | GPT-5.5 Pro | 基线间冲突检测 | Requires repair |
| 4 | Opus 4.8 | 前轮验证 + 根因分析 | 9.1/10 |
16.3 三视角审查(概要设计)
| 视角 | 模型 | 独有发现 |
|---|---|---|
| 架构师 | MIMO 2.5 Pro | 模块边界、依赖方向 |
| 开发者 | DeepSeek V4 Pro | 接口完整性、测试覆盖 |
| 用户 | Opus 4.7 | 原始 UX 需求未进入 plan/todo(其他视角不可见) |
十七、配套工程实践
| 实践 | 方案 | 解决的问题 |
|---|---|---|
| air_runtime 共享库 | 36 模块 ~6,000 行 | 12 模式核心逻辑去重 |
| 统一插件安装器 | 动态路径解析 + 安装后自动验证 | 安装后插件不可用 |
| sub2api 多账号整合 | 代理层整合多个 Codex Plus 账号 | 5x PLUS 无中断长任务执行 |
| New API 多模型路由 | one-api 分支的统一 API 代理 | 多模型交叉审计的异构 API 聚合 |
| CC-Switch 本地代理 | 本地供应商管理与故障转移 | 供应商可用性保障 |
| ScheduleWakeup | 系统级定时唤醒替代 Agent 自觉轮询 | Agent 遗忘轮询导致无限等待 |
| Hook 自动化 | Agent Hook 机制 | 项目打开前自动 git pull 等 |
十八、V1→V2 演进:从真实损失到系统性修复
18.1 P0 缺陷修复清单(已造成实际损失)
| V1 缺陷 | 实际影响 | V2 修复方案 | 保障层级 |
|---|---|---|---|
| AirXDB 假阳性阻塞 | 11+ 任务触发虚假修复循环 | EvidenceGatePolicy 任务类型感知 | L1 代码 |
| 部署验证缺口 | 4 个 "done" 任务未实际部署 | deployRequired + deploy 验证强制 | L1 契约 |
| 非原子写入 | state.json 截断致 JSONDecodeError | atomic_json_write (tempfile + os.replace) | L1 基础设施 |
| 零并发控制 | todo.md 读-改-写竞态 | FileLock (fcntl.flock) | L1 基础设施 |
| AirArc 被 plan mode 劫持 | 架构器偏离规划职责 | allowed-tools 只读 + deny-plan-mode | L1 工具 |
| AirEng 停下来问不自主决策 | 调度流程反复中断 | SKILL.md 中文锁定 + 自主决策指令 | L1 指令 |
| AirEng 无状态轮询 | 子线程卡死后无限等待 | ScheduleWakeup + 硬编码监控循环 | L1 指令+代码 |
| AirDo 不调用 AirDbg | 直接报 blocked 或 false-done | finish_worker 强制路由链 | L1 代码 |
| 安装器路径错误 | 安装后插件无法识别 | 动态路径解析 + post_install_verify | L1 代码 |
| AirEng 偏离调度写代码 | 破坏隔离架构 | 极端接管条件 + 工具权限分层 | L1 指令+代码 |
18.2 P1 缺陷修复清单(限制可靠性)
| V1 缺陷 | V2 修复方案 |
|---|---|
| 硬编码开发者路径 | 路径约定模块 paths.py |
_json_dump 5 份重复 |
air_runtime/io.py 统一 |
_ordered_unique 4 份重复 |
air_runtime/utils.py 统一 |
| todo.md 列索引硬编码 | 动态列定位(已知状态词搜索) |
| 并发度上限硬编码为 3 | state.concurrency 可配置 |
| 子进程无超时 | 所有 subprocess.run 加 timeout |
| task_id 路径注入 | sanitize_task_id() 正则校验 |
| 标记注入风险 | sanitize_marker() 拒绝注释分隔符 |
| 静默吞异常 | 日志告警 + safe_json_load .bak 恢复 |
| Arc 重规划后 Eng 无法衔接 | TaskGraph + PlanDelta 增量吸收 |
| 同文件无冲突任务被迫串行 | RegionConflictDetector + WorktreeIsolation |
| AirArc 跳过需求探讨 | ArcPhaseGate 三阶段门控 |
| AirDbg 未取证就改代码 | EvidenceFirstGate 先读后写门控 |
| 项目缺乏标准化日志 | AirArc 强制 spdlog + AirRvr 检查 |
| 边界无测试 + 终审缺高风险检查 | _inject_boundary_tests + HighRiskAudit |
| UI 任务无专业 Skill | frontend-design Skill 自动安装 + 强制路由 |
| ADR 变更无级联失效 | ADRWatcher + invalidate_by_adr + 10 步闭环 |
| Dispatch → Worker 断链 | spawn_workers + 指令操作化伪代码 |
| Dispatch 指令歧义 | 可执行步骤替代意图描述 |
| Merge 后 TaskGraph 不同步 | Phase 6.5 自动同步节点 status |
18.3 V2 度量目标
| 指标 | V1 基线 | V2 目标 |
|---|---|---|
| AirXDB 假阳性率 | ~60%(11/18 任务) | < 5% |
| 状态文件损坏率 | 已知发生 | 0%(原子写入 + .bak 恢复) |
| 部署一致性事故 | 1 次关键事故 | 0 次(deployRequired 强制) |
| 空壳修复循环 | 11+ 次 | 0 次(证据门控 + 强制路由) |
| 代码重复度 | _json_dump 5 份 |
每函数 1 份 |
| AirArc plan 模式劫持 | 频繁发生 | 0 次(工具白名单硬阻断) |
| AirEng 轮询遗忘 | 频繁发生 | 0 次(ScheduleWakeup) |
| AirDo 跳过 AirDbg | 频繁发生 | 0 次(强制路由链) |
| AirDbg 未取证就改代码 | 频繁发生 | 0 次(EvidenceFirstGate) |
| 需求变更后调度恢复 | 多轮 AI 迭代 | < 1 次(增量 delta 吸收) |
| 同文件无冲突任务串行率 | 100% 串行 | < 20%(worktree 并行) |
| ADR 变更后旧代码残留 | 无自动清理 | 0 次(级联失效 + git revert) |
| Dispatch → Worker 断链 | Agent 回退自己写代码 | 0 次(spawn_workers + 操作化指令) |
| Merge 后重复派发 | 已完成任务再次 dispatch | 0 次(Phase 6.5 同步) |
十九、演变史:从 Prompt 插件到代码级 Agent
Air 插件套件的架构不是一次设计出来的——它经历了 9 个阶段、多次生产事故驱动的迭代,才从 3 个纯 Markdown 指令插件演化为具备代码级保障的统一调度平台。这条演变路径本身就是 AI Agent 工程化的一个缩影:每一次架构跃迁都源于一次真实的失败。
19.1 时间线总览
2026 Q1 初 01 三个 Codex CLI 工作流插件(AirArc + AirDo + AirDbg)
│ 纯 Markdown 指令,无代码执行,人工串联
▼
2026 Q1 中 02 AirDbg 不好用 → 增加 AirXDB(GUI 截图)+ AirNDB(网络抓包)
│ "证据"概念萌芽,但仍靠 SKILL.md 建议
▼
2026 Q1 末 03 增加 AirSDB(静态分析)→ 6 插件 + 统一安装器 = 第一代插件包
│ 证据三件套(截图/抓包/静态分析)齐全
▼
2026 Q1-Q2 04 优化插件包 → 第一代手动插件包的生产版本
│ 打磨 SKILL.md 指令、修复安装器、完善模板
▼
2026 Q2 初 05 上下文爆炸 → AirContext(Hook + 外部 LLM 压缩 + JSONL DAG)
│ 上下文管理从"不管"变成"必须管"
▼
2026 Q2 中 06 插件多了、文件多了、太慢 → AirPlan-Para(air_runtime 共享库 + 表格调度)
│ 架构跃迁:从"独立插件集合"到"有共享引擎的调度系统"
▼
2026 Q2 末 07 多个版本迭代 → AirPlan-ParaV2(稳定并发版本)
│ 修复并发 bug、稳定 air_runtime ~4,500 行
▼
2026 Q3 初 08 中途需求变更 + LLM 不按预期执行 → AirPlan V2(统一插件 + 12 模式)
│ 三个周末重写:8 插件合 1、DAG 动态调度、L1 代码级保障
▼
2026 Q3 中 09 碰撞到 Plugin 边界 → AirCoding(独立 Agent,Fork OpenCode)【Alpha 已完成并开源】
从"插件"到"宿主内嵌调度层":在 OpenCode 内注册 Agent、coordinator 工具与 plugin hook,把工具白名单、状态机与审查门控落到代码;独立运行时仍是下一阶段目标
19.2 阶段 01:三个工作流插件(起源)
组件:AirArc(架构规划)、AirDo(任务执行)、AirDbg(调试)
架构:三个独立的 Codex CLI 插件,每个由 SKILL.md(自然语言指令)+ 命令文件(.md 入口)+ Python 引导脚本 + plugin.json 清单组成。
核心设计决策(贯穿至今):
- AirPlan/ 目录约定:plan.md、todo.md、docs/、state/ 的目录结构在此阶段就已确立
- AGENTS.md + ADR + C4 三件套:项目认知通过结构化文档外化,不依赖特定会话
- 7 步调试工作流:confirm → load → reproduce → locate → fix → verify → close 的流程在第一天就存在
控制方式:100% Markdown 指令。SKILL.md 告诉 AI "你应该这样做",AI 是否遵守完全取决于模型的自觉性。
驱动下一阶段的问题:
- AirDbg 的调试质量差——没有证据支撑就猜测修复,引入更多 bug
- 没有跨插件协调——AirArc 规划完需要人工切换到 AirDo,AirDo 完成后需要人工切换到 AirDbg
- GUI 问题无法验证——嵌入式设备上跑的应用,"进程存在"不等于"界面渲染正确"
- 上下文全在一起运行十分钟直接1M爆满
19.3 阶段 02:增加图形和网络取证
新增:AirXDB(GUI 截图取证)、AirNDB(网络抓包取证)
关键概念萌芽:证据——不同类型的问题需要不同类型的直接证据。
AirXDB 基于 Midscene.js,支持 Playwright(Web 应用)、Chrome Bridge(Chrome 扩展)、Desktop(桌面应用)、MCP(协议桥接)四种模式。支持远程设备截图(SSH → 远程执行 → base64 传输 → 本地解码)。
AirNDB 基于 tcpdump/WinDump,支持 BPF 过滤器、定时捕获、远程 SSH 抓包。
学到的教训:
"证据"这个概念看似简单,但它是整个 Air 体系的基石。没有证据约束的 AI 调试器,和一个随机修改代码的脚本没有区别。AirDbg 在没有截图的情况下"修复"了 GUI 问题,结果引入 3 个新 bug——因为它修复的是自己猜测的原因,而不是实际的问题。
驱动下一阶段的问题:
- C/C++ 代码质量问题——仅靠调试和截图无法覆盖内存泄漏、空指针等静态缺陷
19.4 阶段 03:静态分析 + 第一代插件包
新增:AirSDB(Cppcheck 静态分析)+ 统一安装器 + manifest.json
AirSDB 的亮点是跨平台自动安装——自动检测系统包管理器(winget/choco/scoop/apt/dnf/yum/apk/pacman/brew),下载安装 cppcheck,支持本地和远程 SSH 扫描,产出 XML 报告解析为 JSON。
统一安装器(install_air_suite.py)将 6 个插件打包部署:
- 复制插件到用户目录
- 同步 skills 到
.agents/skills/ - 更新 marketplace.json
- 支持
--verify-only、--dry-run、--plugins过滤
证据三件套成型:
| 证据类型 | 插件 | 适用场景 |
|---|---|---|
| GUI 截图 | AirXDB | 界面渲染、布局、交互验证 |
| 网络抓包 | AirNDB | RTSP/HTTP/TCP 协议调试 |
| 静态分析 | AirSDB | C/C++ 内存安全、代码质量 |
驱动下一阶段的问题:
- 6 个插件的 SKILL.md 指令打磨不均匀,有些插件的执行质量明显低于其他
- 安装器在不同系统上路径解析不一致
- 人工串联插件的效率瓶颈——一个完整的开发流程需要在 AirArc → AirDo → AirDbg → AirXDB 之间反复切换
19.5 阶段 04:第一代手动插件包(生产版本)
这是阶段 03 的打磨版——相同的 6 插件架构,但每个插件的 SKILL.md 指令经过多轮优化,安装器路径问题修复,文档模板标准化。
关键改进:
- AirArc 增加了工作分类(分析/设计/重构/执行),产出 requirements.md → solution-architecture.md → C4 → ADR → plan.md → todo.md 的完整链路
- AirDo 增加了 plan.md 和 todo.md 的读取,按顺序执行任务
- AirDbg 增加了与 AirXDB/AirNDB/AirSDB 的协作指令
学到的教训:
Markdown 指令优化存在天花板。无论 SKILL.md 写得多详细、多精确,AI 仍然会偶尔偏离——跳过步骤、忘记调用协作插件、在不该修改代码时修改代码。这不是模型质量问题,而是控制方式的根本局限:自然语言指令是建议性的,不是强制性的。
驱动下一阶段的问题:
- 长会话中上下文窗口爆炸——对话到后期,AI 对早期架构决策的记忆出现幻觉
19.6 阶段 05:上下文爆炸 → AirContext
问题:AI Agent 执行复杂开发任务时,对话历史快速膨胀。一轮完整的开发流程(读代码 → 搜索 → 修改 → 测试 → 调试)就可以产生 50K-100K token 的上下文。当接近模型的上下文窗口上限时,AI 框架的内置自动压缩(auto-compact)会粗暴截断,丢失关键的架构决策和未完成工作项。
解决方案:AirContextServer——一个独立的上下文管理插件,替代框架的内置压缩。
架构:
┌────────────────────────────────────────────────┐
│ Wrapper (bin/aircontext) │
│ 包装 claude CLI,劫持启动和恢复流程 │
├────────────────────────────────────────────────┤
│ 4 个 Hook: │
│ SessionStart → 验证配置 │
│ UserPromptSubmit → 配置无效时阻止 prompt │
│ PostToolUse → 估算 token,超阈值触发压缩 │
│ PreCompact → 阻止框架内置自动压缩 │
├────────────────────────────────────────────────┤
│ Compactor 后台进程: │
│ 1. 获取 compactor.lock(O_CREAT | O_EXCL) │
│ 2. 从 JSONL 文件加载消息链(DAG 遍历) │
│ 3. 切分:head(送入压缩)| tail(逐字保留 10 条) │
│ 4. 序列化 head → 纯文本(丢弃 thinking blocks) │
│ 5. 调用外部 LLM + rules.md 规则 → 压缩摘要 │
│ 6. 写入 JSONL:summary (parentUuid=null) + │
│ continuation prompt → 形成新链根 │
│ 7. SIGTERM → claude --resume → 加载压缩上下文 │
└────────────────────────────────────────────────┘
关键设计创新:
parentUuid=null技巧:摘要消息的 parentUuid 设为 null,在 JSONL DAG 中创建一个新的"孤岛"根节点。后续消息从摘要开始形成新链,旧消息变为不可达的死链。claude --resume加载时只遍历到新链,获得一个"干净"的起点- 外部 LLM 压缩:不使用会话自身的模型做压缩——避免"自己压缩自己"的认知偏差。压缩模型只看序列化的文本,不了解对话历史,产出更客观的摘要
- 三级信息保留策略:永久保留(最后 10 条)→ 高优先级(文件路径、ADR、TODO)→ 低优先级(搜索结果、完成确认)
学到的教训:
上下文管理不是"锦上添花"——它是 AI Agent 长时间运行的生存前提。没有上下文压缩,一个 200K token 窗口的模型在 3-4 小时的开发任务中就会耗尽空间。而框架内置的压缩策略太粗暴,无法区分"架构决策"和"一次性搜索结果"的价值差异。
驱动下一阶段的问题:
- 6 个插件串行执行太慢——一个包含 20 个任务的项目,每个任务 15 分钟,串行需要 5 小时
- 插件之间的协调全靠人工——AirArc 规划完后需要人工启动 Airdo,Airdo后需要人工启动 Airdbg
19.7 阶段 06:AirPlan-Para(架构跃迁——共享引擎)
这是整个演变史中最关键的架构跃迁——从"独立插件集合"到"有共享引擎的调度系统"。
新增核心组件:lib/air_runtime/(~3,700 行共享 Python 运行时库)
air_runtime/
contracts.py (~618 行) 结构化数据契约
engine.py (~500 行) 调度引擎
worker.py (~373 行) Worker 生命周期
review.py (~239 行) DAG 并行审查
todo_parser.py (~161 行) Markdown 表格解析
doc_sync.py (~351 行) 文档同步
debug_runtime.py (~414 行) 自动调试
airxdb_runtime.py (~818 行) 自动 XDB
repair_runtime.py (~374 行) 自动修复
paths.py 路径约定
三个划时代的设计决策:
① 结构化数据契约替代 Markdown 通信
V1 之前,插件之间通过 Markdown 文件传递信息——AirArc 产出 todo.md,AirDo 读取 todo.md。但 todo.md 是给人看的,不是给机器解析的。contracts.py 引入了 TaskSpec、WorkerResult、ValidationRecord、DocumentUpdate 等类型化数据结构:
class WorkerResult:
task_id: str
status: str # done | blocked | failed
files_changed: list[str]
validations: list[ValidationRecord]
document_updates: list[DocumentUpdate]
这意味着:引擎可以程序化地验证 Worker 的产出,而不是靠 AI 阅读 Markdown 来判断。
② DAG 依赖感知的并行调度
review.py 的 build_parallel_review() 实现了第一版并行调度算法:
1. 解析 todo.md → TaskRecord 列表
2. 构建依赖边([deps: T-xxx] 标注)
3. 拓扑排序 → 波次分组
4. 贪心并行分组:每个任务放入第一个无写集冲突的组
5. 冲突检测:写集重叠的任务强制串行
③ 隔离 Worker 子代理
engine.py 的 dispatch_worker_group() 为每个任务创建独立的 AirDo 子代理,传递 fork_context=false——子代理不继承调度器的对话历史,只获得 brief.md 和 handoff.md。这是上下文隔离原则的第一次代码实现。
学到的教训:
并行执行的正确性取决于冲突检测的完备性。第一版上线后,两个任务同时修改同一个 CMakeLists.txt,后完成的覆盖了先完成的——产出需要人工修复 3 个文件,效率反而低于串行。这证明了"朴素并行"在有写集冲突时是反效率的。
驱动下一阶段的问题:
- 并发不稳定——偶尔出现状态文件损坏(非原子写入)
- AirXDB 假阳性率 ~60%——非 GUI 任务也被要求提供截图
- 引擎的 5 分钟轮询依赖 AI "自觉执行",经常遗忘
19.8 阶段 07:AirPlan-ParaV2(稳定并发版本)
经过多个版本的迭代修复,air_runtime 稳定在 ~4,500 行。这一阶段主要修复了:
- 并发竞态:引入基础的锁机制,防止两个 Worker 同时完成时的 todo.md 读-改-写冲突
- AirXDB 误触发:增加了基础的关键词过滤(但仍不够精确,假阳性率仍高)
- 修复预算:
maxAttemptsPerTask = 2,防止无限修复循环 - 引擎状态持久化:state.json 包含完整的运行时状态,崩溃后可恢复
学到的教训:
并发系统的可靠性不是一步到位的——它需要在真实负载下反复暴露问题、反复修复。AirPlan-Para 经历了 3 个小版本才达到"稳定可用"状态。每次版本迭代都伴随着一次 state.json 损坏或 todo.md 竞态的事故报告。
驱动下一阶段的问题(V2 设计文档中的 P0/P1 缺陷清单):
- 非原子写入导致 state.json 截断 → JSONDecodeError
- AirArc 被 Agent 框架的 plan mode 劫持
- AirEng 停下来问用户而不是自主决策
- AirDo 跳过 AirDbg 直接返回 blocked
- AirDbg 不取证就改代码
- 中途需求变更后调度需多轮 AI 迭代恢复
- 同文件无冲突任务被迫串行
19.9 阶段 08:AirPlan V2
这是从"建议性约束"到"代码级保障"的范式跃迁。花费三个周末,将 8 个分散插件重构整合为 1 个统一插件 12 种模式,重写了整个调度引擎。
核心动机:V1(阶段 06-07)证明了制品驱动 + 上下文隔离 + 波次并行的架构方向成立,但所有关键约束都停留在 SKILL.md 的自然语言层面——AI 可以选择遵守,也可以选择忽略。真实项目数据(DecodePlayer 系列、AirCoding V1.0.0 Alpha)证明这种"建议性约束"不够。
V2 的哲学转变:
V1: "你应该在修改代码前进行取证" → AI 可以跳过
V2: can_modify_code() == False → 代码层面不允许
V1: "AirArc 不应该写代码" → AI 可以被 plan mode 劫持
V2: allowed-tools: [Read, Glob, Grep] → Agent 框架层面没有写工具
V1: "AirDo 应该调用 AirDbg" → AI 可以直接返回 blocked
V2: finish_worker() 返回 routing → 代码层面必须经过 AirDbg
V1: "调度器应该每 5 分钟轮询" → AI 可以忘记
V2: ScheduleWakeup(delaySeconds: 300) → 系统级定时唤醒
8 合 1 的工程价值:
| V1(8 个独立插件) | V2(1 个统一插件 12 模式) |
|---|---|
| 每个插件独立安装、注册、版本 | 一次安装,12 个模式全部可用 |
| 插件间通信靠文件 + 人工切换 | 统一的 air_runtime 库 + 自动路由链 |
| 每个插件维护自己的 _json_dump | 统一的 atomic_json_write |
| SKILL.md 约束不跨插件 | L1 代码级保障覆盖全链路 |
| 静态 todo.md 表格调度 | 动态 TaskGraph DAG 调度 |
新增的 4 个模式:
| 模式 | 填补的空白 |
|---|---|
| /dep(AirDep) | V1 无部署 → "完成但未部署"事故 |
| /tst(AirTst) | V1 无统一测试 → 边界无测试覆盖 |
| /sec(AirSec) | V1 无安全扫描 → 制品敏感数据泄露风险 |
| /rvr(AirRvr) | V1 无需求审查 → 交付物偏离需求无人检出 |
19.10 阶段 09:AirCoding——碰撞到 Plugin 边界并完成 Alpha
核心发现:当 Air 插件套件在 Claude Code CLI 上运行时,无论 V2 的 L1 代码级保障做得多好,有一个层面始终无法控制——Agent 框架本身的行为。
具体表现:
- Agent 框架的 plan mode 可以覆盖 SKILL.md 的角色指令(AirArc 被劫持)
- Agent 框架的 auto-compact hook成 AirContext 并不稳定
- Agent 框架的 allowed-tools 是 per-command 而非 per-context 的,无法在一个 Agent 内动态切换工具权限
- Agent 框架不保证"自觉执行"的循环(轮询遗忘)
结论:插件范式有天花板。你可以在插件层做代码级保障,但你无法控制宿主 Agent 框架的行为。当宿主框架的行为与你的工程约束冲突时,你只能二选一:要么忍受宿主框架的限制,要么拥有自己的运行时。
当前状态:AirCoding 现在已经不是"只剩路线图"的原型了。Alpha 版本已经完成首个公开可用闭环并开源,但它的实现形态也需要准确描述:它并不是"完整自研运行时已成型",而是基于 OpenCode v1.17.4 fork 的最小改造,通过 Agent 注册、Tool Registry、coordinator 工具、Plugin Hook 和权限矩阵,把 V2 里验证过的关键约束直接植入宿主运行时。
Alpha 已经落地的能力:
- Main / Scheduler / Worker / Architect / Reviewer 五类 Agent 已进入运行时注册表,不再只是文档角色
- 子 Agent 的工具边界已由代码级权限矩阵硬控,例如 Scheduler 无 Write/Edit/Bash,Architect 只能写
.air/shared/plan/** coordinator_tick已承担最小确定性调度闭环:读取task-graph.json、做 DAG ready 计算、处理状态迁移、执行 retry / milestone budget,并把状态实时写入scheduler-state.json- Worker 的
cppcheck强制、降级关键词扫描,Reviewer 的 Code-to-Design 对照表检查、表面证据 PASS 拦截,已经进入 hook / tool 层,而非只靠 Prompt 自觉 .air/shared/plan/*与.air/local/*的目录分层已成型,架构认知、执行状态和调试记录开始有了稳定的文件落点
当前仍未完成的部分:
- 目前主要复用 OpenCode 的 Session / BackgroundJob / Plugin Hook / Tool Registry,而不是完整自研的 EventBus + NDJSON IPC runtime
- 更理想的语言无关运行时、持久事件总线、学习记忆层、动态权限切换等能力,仍处于后续演进目标
- 宿主框架的约束仍然存在,因此这版 Alpha 更准确的定义是:把关键工程约束嵌进宿主框架的一次成功验证,而不是独立运行时的终点
这个阶段的意义已经从"勾勒边界"前进到"验证路线":它不再只是告诉我们插件范式的边界在哪里,而是进一步证明了一个更重要的判断——要想让关键约束可靠生效,必须把它们推进到宿主运行时层,而不能永远停留在插件层的自然语言约定里。
19.11 演变史的核心规律
回顾 9 个阶段,可以提炼出三条贯穿始终的演变规律:
规律一:控制方式的硬化
阶段 01-05: 自然语言指令(SKILL.md) → "请遵守这个规则"
阶段 06-07: 运行时检查(Python 函数返回值) → "不遵守就报错"
阶段 08: 代码级门控(工具白名单 + 数据契约) → "不遵守就阻断"
阶段 09: 架构级不可能(运行时所有权) → "不可能违反"(方向已定,仍在原型阶段)
每次硬化都由一次真实失败驱动:AirDbg 不取证就改代码 → EvidenceFirstGate;AirArc 被 plan mode 劫持 → deny-plan-mode;AirEng 忘记轮询 → ScheduleWakeup;Agent 框架覆盖插件行为 → Fork 拥有自己的运行时。
规律二:问题驱动而非设计驱动
没有任何一个架构决策是"提前设计好的"——它们都是问题暴露后的被迫应对:
| 暴露的问题 | 驱动的架构决策 |
|---|---|
| AirDbg 盲改代码引入 bug | 证据先于修复原则(阶段 02) |
| 长会话上下文爆炸 | AirContext 透明压缩(阶段 05) |
| 串行执行太慢 | DAG 并行调度(阶段 06) |
| 朴素并行写集覆盖 | 写集冲突检测 + 波次分组(阶段 06) |
| 非原子写入导致状态损坏 | atomic_json_write + .bak 恢复(阶段 08) |
| 两个 Worker 同时完成竞态 | FileLock (fcntl.flock)(阶段 08) |
| 需求变更后调度无法恢复 | TaskGraph DAG + PlanDelta(阶段 08) |
| ADR 变更后旧代码残留 | ADR 级联失效 + git revert(阶段 08) |
| Agent 框架覆盖插件行为 | Fork OpenCode + 宿主内嵌调度层(阶段 09,Alpha 已完成并开源) |
规律三:可检查性的坚持
从阶段 01 到阶段 09,无论架构如何变化,有一条线始终未断:所有中间状态都是人类可读文件。
- 阶段 01-07:AirPlan/ 目录树(Markdown + JSON)
- 阶段 08:events.jsonl 补充了完整时间线
- 阶段 09:继续坚持纯文件状态(
plan.md/task-graph.json/scheduler-state.json),同时把调度逻辑和门控逻辑推进到宿主运行时;独立 EventBus / 持久事件流仍是后续目标
这意味着:即使在最复杂的并行调度场景中,开发者随时可以 cat task-graph.json、cat scheduler-state.json,或在需要时 tail events.jsonl 了解系统的精确状态。没有二进制数据库、没有私有格式、没有需要特殊工具才能解读的状态。
可检查性是信任的前提——如果你无法观察一个系统的内部状态,你就无法信任它的决策。对于 AI Agent 这样的非确定性系统,这一原则的价值比任何算法优化都大。
二十、原理篇实现细节补充
本章集中承载第一部分(原理篇)各章交叉引用过来的实现细节。每一条都可追溯到原理篇的具体小节,避免原理与实践混杂。
20.1 架构状态同步的合并流水线(对应 6.4)
每次任务合并时,merge_pipeline.py 按 6 个阶段顺序执行——任一阶段失败则整个合并回滚:
- Phase 1 — enforce_doc_sync_requirements:验证 Worker 是否提交了所要求的架构文档更新;deploy_required 的任务必须有远程部署验证;路径必须落在项目根目录内
- Phase 2 — apply_document_updates:将 Worker 提交的
DocumentUpdate应用到 ADR、C4、AGENTS.md 等项目文档 - Phase 3 — sync_engine_managed_docs:引擎自动写入同步标记块(AIR-ENGINE:AGENTS-SYNC / C4-SYNC / TODO-RUN-LOG),追加前检查去重
- Phase 4 — update_todo_after_merge:更新任务表中的状态和验证摘要,支持动态列定位(按已知状态词搜索列头)
- Phase 5 — atomic persist:使用
atomic_json_write()(tempfile + os.replace())原子写入 state.json,失败时自动从 .bak 恢复 - Phase 6 — FileLock release:释放
FileLock(fcntl.flock)
Phase 6.5 — TaskGraph sync:若启用了动态 DAG,合并后还需把 Worker 的 filesChanged、验证摘要、documentUpdates 反映回 TaskGraph,更新对应 TaskNode 的状态。
标记块命名空间(两层隔离避免模式间互相覆盖):
- 模式层(各模式独立维护):
<!-- AIRARC:BEGIN/END -->、<!-- AIRENG:BEGIN/END -->、<!-- AIRDO:BEGIN/END -->、<!-- AIRDBG:BEGIN/END -->、<!-- AIRXDB:BEGIN/END -->、<!-- AIRNDB:BEGIN/END -->、<!-- AIRSDB:BEGIN/END --> - 引擎层(merge_pipeline.py 自动写入):
<!-- AIR-ENGINE:AGENTS-SYNC:BEGIN/END -->、<!-- AIR-ENGINE:C4-SYNC:BEGIN/END -->、<!-- AIR-ENGINE:TODO-RUN-LOG:BEGIN/END -->
20.2 ADR 变更级联失效的 10 步闭环(对应 6.5)
V2 的 handle_adr_invalidation() 实现完整的 10 步闭环:
1. ADRWatcher 每轮轮询时 SHA256 对比所有 ADR 文件 hash
2. 检测到 superseded / modified 变更 → 触发级联失效
3. TaskGraph.invalidate_by_adr() 冻结调度(dispatch_frozen = true)
4. 标记所有引用该 ADR 的已完成任务为 INVALIDATED
5. 标记进行中任务为 INVALIDATED,中止对应 Worker
6. BFS 遍历下游依赖 → 级联失效所有受影响的后继任务
7. 创建 git tag 回滚快照
8. git revert 已合并的旧代码(按 task_id 查找对应 commit)
9. PartialReplanner 生成局部重规划请求(仅重新规划受影响部分)
10. AirArc 基于新 ADR 重新生成任务 → apply_delta() → 解冻调度
关键数据结构:
- TaskNode.adr_refs:每个任务节点记录它引用的 ADR ID 列表,建立架构决策 → 具体任务的溯源链
- PartialReplanner:提取未受影响 DONE 任务的公共接口约束,确保重规划不破坏稳定依赖
- dispatch_frozen:级联失效期间
ready_tasks()返回空列表,阻止任何新任务派发 - git tag 回滚点:精确定位需要回退的 commit,避免全量回滚
20.3 TaskGraph 数据结构与 PlanDelta(对应 8.3)
class TaskGraph:
nodes: dict[str, TaskNode] # 每个任务是一个节点
edges: list[Edge] # 依赖/冲突/同步边
dispatch_frozen: bool # ADR 级联失效时冻结
class TaskNode:
id: str
status: str # TODO | DISPATCHED | DONE | BLOCKED | INVALIDATED
task: str # 任务描述
write_set: list # 声明的写集(用于 RegionConflictDetector 冲突检测)
adr_refs: list # 引用的 ADR(溯源链,供 invalidate_by_adr 使用)
test_required: bool # 边界测试标记(AirArc 在 _inject_boundary_tests 时设置)
PlanDelta 结构:
class PlanDelta:
added: list[TaskNode] # 新增任务
removed: list[str] # 移除的任务 ID
modified: list[TaskNode] # 修改的任务
edge_changes: list[Edge] # 新增/移除的依赖边
四项核心能力的实现:
- apply_delta():增量更新图结构,已调度(DISPATCHED/DONE)任务不受影响
- apply_full_replace():保留已完成任务的 DONE 状态,避免重新调度
- diff():对比新旧两个 DAG,自动产出精确的 PlanDelta
- ready_tasks():返回入度为 0 且状态为 TODO 的节点;调度冻结时返回空列表
20.4 五种 L1 机制的具体代码实现(对应 10.2)
① 工具白名单:命令文件 frontmatter 声明 allowed-tools: [Read, Glob, Grep],AirArc 配合 deny-plan-mode: true 在 Agent 框架层面阻断写操作和 plan mode。
② Python 门控函数:
ArcPhaseGate:AirArc 写入前必须处于confirmed阶段(discussing → proposing → confirmed),否则拒绝EvidenceFirstGate:AirDbg 未取证前can_modify_code()返回 FalseEvidenceGatePolicy:根据任务类型(GUI / NETWORK / STATIC_ANALYSIS / CODE_ONLY)分类,替代 V1 的无差别触发
③ 数据结构约束:
WorkerResult.validate_for_finalize():deployRequired 必须有 deploy 验证;done 必须有 validations 或 filesChangedsanitize_task_id():正则校验防止路径注入sanitize_marker():拒绝 HTML 注释分隔符,防止标记注入
④ 强制路由链:finish_worker() 按 6 级优先级路由——blocked/failed → AirDbg、无取证 → AirDbg、GUI 任务 → AirXDB、网络任务 → AirNDB、C/C++ 任务 → AirSDB、所有 done → AirRvr。路由是代码级强制,不可跳过。
⑤ 原子操作 + 并发控制:
atomic_json_write():写入前创建 .bak 备份,使用 tempfile + os.replace() 原子替换safe_json_load():JSONDecodeError 时自动从 .bak 恢复FileLock:fcntl.flock(LOCK_EX | LOCK_NB)带 timeout 重试
20.5 指令操作化的具体示例(对应 10.3)
AirEng 派发 Worker 的操作化步骤(从"读取派发清单 spawn 子代理"这一意图描述升级而来):
dispatch 返回 {waveId, taskIds, dispatchPath}。然后按以下步骤操作,不可跳过:
1. 从 dispatch 返回值中取 taskIds 列表
2. 对 taskIds 中的每个 tid,在同一条消息中并发调用 Agent 工具:
Agent(
description: "Do Worker: {tid}",
subagent_type: "general-purpose",
run_in_background: true,
prompt: "你是 AirDo Worker..."
)
3. 所有 Worker spawn 完成后,进入 monitor 状态
AirDo 路由链的操作化(对应 20.4 ④ 强制路由链):
def finish_worker(task_id, result):
if result.status in ("blocked", "failed"):
return route_to("airdbg", task_id)
if not result.evidence and needs_evidence(result):
return route_to("airdbg", task_id)
if is_gui_task(result):
return route_to("airxdb", task_id)
if is_network_task(result):
return route_to("airndb", task_id)
if is_cpp_task(result):
return route_to("airsdb", task_id)
return route_to("airrvr", task_id)
每一步都是确定的操作,消除了 Agent 的推理负担——不再需要猜测工具名、参数格式或数据来源。
二十一、总结
Air 插件套件 V2 的十五个工程原则:
- 制品驱动通信 — 插件间通过结构化文件通信,实现可检查、可恢复、可审计的松耦合
- 三层上下文边界 — 会话级压缩 + 任务级隔离 + 项目级制品,三个尺度管理上下文质量
- 隔离驱动的并行效率 — 上下文隔离是并行调度的前提;没有隔离,并行度越高,腐烂越快
- 证据先于修复 — 截图、抓包、静态分析作为修复前置条件,消除虚假验证
- 闭环自动修复 — 执行→失败→调试→修复→重执行的自动循环,预算耗尽才升级人工
- 透明上下文压缩 — 三级降级 + 质量校验,~10 倍压缩比,保留关键决策
- 多模型交叉审计 — 并行/递进/多视角审查 + 交叉确认矩阵,将单模型盲区转化为可量化置信度
- 架构状态持久化 — C4 + ADR + 标记块 + 6 阶段合并流水线,架构文档不可能落后于代码
- 范围约束降本 — 规划-执行分离 + 6 文件必读 + 预填充模板 + 弱模型安全,廉价模型在约束上下文中达到昂贵模型效果
- 长期迭代管理 — 文件状态 + 波次递进 + 修复预算 + 文档级联 + 回归防护,跨会话/跨模型/跨设备的工程连续性
- L1 代码级保障(V2) — 关键约束从自然语言建议升级为 Python 门控 + 工具白名单 + 数据契约的硬性执行
- 动态图调度(V2) — TaskGraph DAG 替代静态表格,增量重规划 + ADR 级联失效 + worktree 隔离并行
- 全专家插件路由(V2) — finish 时 6 级强制路由链(Dbg→XDB→NDB→SDB→Rvr),路由不是建议而是代码级强制
- 指令操作化(V2) — 关键操作路径从意图描述升级为可执行伪代码,消除 Agent 推理歧义
- 需求一致性审查(V2) — AirRvr 独立审查交付物与需求的一致性,含高风险审计 + Code-to-Design 逐行对照
将 AI Agent 从不可控的对话式工具,转变为可审计、可续接、可验证、可交叉检验的工程化执行平台。V2 在 V1 的基础上,将"建议性约束"系统性升级为"代码级保障",针对真实项目中暴露的 P0/P1 缺陷逐项给出工程化对策。而阶段 09 的 AirCoding,则把这条路线继续推进到了宿主运行时内部:它已经完成首个公开 Alpha 并开源,用 OpenCode fork + Agent 注册 + coordinator 工具 + plugin hook 验证了"关键约束必须宿主内嵌"这一路线;但完全独立的运行时、事件总线和语言无关内核,仍是下一阶段。
[内核课程]《Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。