面向终端构建AI编程Agent:脚手架、运行时框架、上下文工程与经验教训 Building AI Coding Agents for the Terminal: Scaffolding, Harness, Context Engineering, and Lessons Learned
首个开源CLI编程Agent完整技术报告:四层架构+五阶段自适应压缩+纵深防御安全
前置知识
ReAct循环
Reason+Act的agent推理范式,模型在每一轮先推理再行动,通过工具与环境交互。本文的Extended ReAct在标准ReAct基础上增加了显式的thinking(不带工具的独立推理调用)和可选的self-critique阶段,把"思考"和"执行"在API层面彻底解耦——思考阶段根本看不到工具schema,从而避免模型"看到工具就想立刻调用"的倾向。
OPENDEV的整个推理流水线(Algorithm 1)都建立在扩展ReAct之上,五阶段压缩、doom-loop检测、role:user提醒都嵌在这个循环的特定相位里。
Compound AI System
Zaharia等人提出的范式:把多个LLM、检索器、工具编排成一个结构化系统,而不是依赖单一巨型模型。OPENDEV把这一思想落到工程层面,定义了五个模型角色(Action、Thinking、Critique、Vision、Compact)并支持per-workflow的LLM绑定——切换模型只改配置不改代码。
这是OPENDEV"模型无关"的根本原因,也是它和单模型agent(如早期SWE-Agent)的核心架构区别。
上下文压缩(Context Compaction)
当LLM的上下文窗口接近耗尽时,对历史对话进行摘要、截断或重写以腾出空间。OPENDEV提出Adaptive Context Compaction(ACC)的五阶段渐进策略:70%警告→80%观察遮蔽→85%快速剪枝→90%激进遮蔽→99% LLM全量摘要,把"二值紧急压缩"变成"渐进调节"。
工具输出在典型session中占据70-80%的上下文,压缩策略直接决定一个session能跑多少轮——OPENDEV把典型session从15-20轮扩展到30-40轮,并把峰值上下文消耗降低约54%。
Language Server Protocol (LSP)
微软定义的编辑器与语言服务器之间的JSON-RPC协议,提供跨文件查找定义、重命名、引用解析等语义能力。OPENDEV集成了30+种语言的LSP服务器,通过两层缓存(原始响应+处理过的符号树)避免重复调用,并支持精确符号查找、引用追踪、workspace级重命名等。
代码编辑不是字符串替换——`text_search`找不出函数调用和同名变量的区别,只有LSP能给出"AuthController.validate在哪里被调用"这种语义查询。
Model Context Protocol (MCP)
Anthropic提出的标准协议,让LLM agent能动态发现并调用外部工具服务器。MCP理论上能让agent扩展无限能力,但如果把所有MCP工具的schema都塞进prompt,100个工具就能吃掉2万token。OPENDEV用lazy discovery解决:默认0个外部工具schema,agent需要时通过search_tools关键词检索,命中的工具schema才进入上下文。
MCP的"全部加载"模式让baseline占用高达40%上下文,Lazy方案把它压到<5%,这是OPENDEV扩展性的关键设计。
研究动机
现有的AI编程助手生态存在三个具体工程痛点。第一,IDE插件式copilot是被动响应型,需要开发者全程监督,无法处理长视野、多步骤的任务。第二,主流生产系统(Claude Code、各种闭源CLI)虽然终端化做得好,但都是闭源的,学术界无法复现其架构决策;开源CLI工具(Aider、Goose、OpenCode、Crush)又缺少技术报告,设计决策无从追溯。第三,真正开源且有技术报告的系统(SWE-Agent)是为benchmark评测设计的,不能日常交互使用——OpenHands虽然文档完善但跑在浏览器里而不是终端。Terminal-Bench显示即便是前沿模型也只能解决不到65%的CLI任务,LongCLI-Bench显示多类别编程任务的pass rate低于20%,这些数字暴露出专门工程化解决方案的必要性。
本文的目标是OPENDEV要交付一个"首个开源、终端原生、可交互的AI编程Agent"的完整技术报告,目标是:(1)填补"闭源工业实践"和"开放学术话语"之间的gap,让学界能复现生产级设计决策;(2)提供一个四层(Entry&UI / Agent / Tool&Context / Persistence)复合AI系统架构,用per-workflow模型路由把"单模型万能"的隐含假设解耦掉;(3)以Rust实现并在工程层面解决长视野会话必然遇到的三个根本难题——上下文窗口耗尽、危险操作防护、能力扩展时prompt过载。
与已有工作不同的是,和已有工作相比,OPENDEV切入了一个被忽视的维度:"Agent工程"本身的经验学。大部分agent论文聚焦算法改进(新训练方法、新推理框架),而OPENDEV关注的全是工程问题——什么时候用role:user而不是role:system注入提醒更有效、为什么9层模糊匹配比2层匹配好得多、为什么schema gating比runtime permission check更安全、为什么70-80%压缩阈值要靠经验调优而不是理论推导。它把这些"踩坑经验"系统化成本文第3节的transversal lessons,这是现有任何一篇agent论文都没做过的整合。
核心方法
OPENDEV的核心思路是"compound system + 渐进降级 + 透明可观测"——把一个看起来"很神奇"的AI编程助手,拆解成多个独立可替换的工程模块。直觉上,可以把它想象成一个"AI手术机器人":医生(LLM)负责思考,机械臂(工具系统)负责执行,监护仪(上下文工程)负责持续追踪"病人状态",麻醉师(安全层)负责防止过度操作,病历本(持久化层)负责记录全过程。整个架构分为四层:Entry&UI层把CLI/Web UI的请求归一化;Agent层跑扩展ReAct循环,五阶段压缩、thinking+critique都嵌在里面;Tool&Context层用注册中心(registry)管理35个内置工具+按需MCP发现,上下文工程把token预算当成一级公民来管理;Persistence层用文件系统(JSON+JSONL)做会话/快照/配置存储。最关键的工程创新是context engineering——它把"上下文"从"缓冲区"重定义为"预算",通过ACC五阶段压缩、role:user just-in-time提醒、ACE playbook记忆管线,把"会话长度"和"信息损失"之间的矛盾系统性地缓解。
本文最核心的创新点,不是某一个具体算法,而是三个相互支撑的架构原则:(1)Scaffolding vs Harness分离——Agent在第一次接收prompt前就完成全部构造(system prompt编译、tool schemas、subagent注册),运行时只关心dispatch和context管理,这消除了"初始化半成品"导致的race condition;(2)Schema-level Safety而非Runtime check——安全不是"运行时拦截危险操作",而是"让agent根本看不到它不能用的工具",这从结构上消灭了"模型推理绕过权限检查"的可能性,Planner子agent的schema里根本没有write工具,所以它永远不会尝试写入;(3)Progressive degradation of context——压缩不是一个二值的紧急操作,而是从70%就开始的五阶段渐进策略,优先使用便宜的剪枝/遮蔽,把昂贵的LLM摘要保留到99%才用。这三个原则一起构成了一个"用架构解决LLM固有缺陷"的设计哲学。
方法步骤详情
完整的工作流程分两大阶段。第一阶段是Scaffolding(预运行装配):AgentFactory.create_agents()严格按三阶段顺序装配——Phase 1扫描三个目录(builtin/user/project)发现Skill并注册use_skill工具;Phase 2创建SubAgentManager,register_defaults()编译8种内置子agent(Code Explorer、Planner、Web Clone、Security Reviewer等),每个子agent在构造时就通过allowed_tools参数过滤tool schema,所以"能力边界"在编译时就锁死;Phase 3才创建MainAgent(无工具过滤,全权限),此时Phase 2注册的spawn_subagent工具才能进入它的schema。装配完成后所有manager(ConfigManager、SessionManager、ModeManager、ApprovalManager)通过依赖注入(AgentDependencies Pydantic模型)传给agent.run_sync()。第二阶段是Harness Runtime(运行时框架):每一轮迭代跑Algorithm 1的六相位——Phase 0首先检测token利用率p,如果p>0.99触发完整LLM摘要,>0.85做fast pruning,>0.80做observation masking,>0.70只记录警告;Phase 1如果开启了thinking模式,调一个无工具的thinking LLM生成推理trace(HIGH档额外触发critique模型自评并refine);Phase 2调action LLM接收完整prompt(system prompt+playbook bullets+tool schemas+对话历史+thinking trace)返回响应;Phase 3分支:无tool calls则可能注入错误恢复nudge或todo完成检查,有tool calls则先做doom-loop检测(MD5指纹+20长滑动窗口,3次重复触发SYSTEM WARNING,再次重复升级到approval pause),然后并行或串行调度工具;最后汇总执行结果,Reflector每5条消息触发一次playbook反思,Curator决定add/update/tag/remove bullets,更新持久化的playbook JSON。整套流程最巧妙的是"中断可注入"——UI通过有界Queue(maxsize=10)注入消息,在每个iteration边界被drain,所以用户在agent执行中段发送的指令不会丢失。
技术新颖性
和已有agent框架相比,OPENDEV的技术新颖性主要体现在四个层面。第一个层面是"架构层面的新颖性":它把compound AI system范式落地为per-workflow LLM binding,这是SWE-Agent(单模型)、OpenHands(浏览器单前端)、Aider(无subagent架构)都没系统化做过的设计;同时它把"scaffolding"和"harness"显式分phase,通过eager construction在Agent构造时就把所有prompt/schema/manager锁死,消除了lazy init常见的race condition,这是工程上的"小创新"但对生产稳定性影响巨大。第二个层面是"上下文工程层面的新颖性":Adaptive Context Compaction把传统agent的单次紧急压缩(95-99%阈值)替换为五阶段渐进(70/80/85/90/99%),同时把observation的生命周期建模为active→faded→archived三态,这是对context rot现象[46]的系统性工程回应;Lazy MCP discovery解决了MCP协议在大规模外部工具下的context bloat问题(40%→<5%),这一技巧未来很可能成为所有MCP-based agent的标准设计。第三个层面是"安全层面的新颖性":纵深防御的五层架构中,"schema gating(让agent根本看不到禁用工具)"取代了"runtime permission check(允许但拦截)",这是从"guard rail"到"missing road"的范式转换——OpenHands和Claude Code都还在用runtime check,OPENDEV通过allowed_tools参数在schema构建时就把Planner子agent的write能力剥掉,从根本上消除了"模型推理绕过权限"的可能性。第四个层面是"工具设计层面的新颖性":9-pass模糊匹配把edit_file的最大单点故障(content not found)从40%以上错误率降到接近零;agent-aware truncation hints根据调用方能力(是否能spawn_subagent)给出针对性恢复建议;这些细节让系统对LLM的"近似正确输出"具备原生容忍能力。综合起来,OPENDEV的新颖性不在某一个具体算法突破,而在于"系统地把LLM固有缺陷(long context、instruction drift、approximate output、dangerous action)用架构约束系统化解决"。
实验结果
本文不是一篇benchmark-driven论文,而是一篇系统报告,所以"结果"主要是工程化指标而非排行榜分数。核心可量化的发现包括:(1)Adaptive Context Compaction(ACC)把典型session的峰值上下文消耗降低约54%,在常规30轮session中常常完全避免触发LLM摘要;(2)上下文压缩前典型session能跑15-20轮就触发overflow,加上8,000字符(~2,000 token)输出offload阈值后扩展到30-40轮;(3)单次长跑测试输出30,000 tokens经per-tool summarizer压缩后只剩不到100 tokens,某些文件读取从2,000-3,000 tokens压成"✓Read file (142 lines, 4,831 chars)"的元数据;(4)Anthropic的prompt caching在OPENDEV的stable/dynamic分割下,把cached portion的input cost降低约88%(stable部分通常占prompt总量的80-90%);(5)Lazy MCP discovery把baseline上下文占用从40%压到<5%,只有真正被搜索/调用的工具schema才会进入prompt;(6)Doom-loop检测能在3次重复调用内捕获stuck loop,而原有的"连续N次read"counter需要更多轮次且不能区分"相同工具不同参数"vs"完全相同调用";(7)9-pass模糊匹配链把edit_file的"content not found"错误率从最大单点故障源降为边缘问题,exact match短路保证零额外开销。这些数字共同说明了一个核心结论:"渐进式、分阶段、感知上下文的策略"在工程效率上明显优于"一刀切式的紧急阈值"。同时作者坦承:本文没有在SWE-bench、Terminal-Bench、LongCLI-Bench上做定量评测,这是第5节明确列出的首要未来工作。
查看结构化数据
| 任务 | 指标 | 本文 | 基线 | 提升 |
|---|---|---|---|---|
| 典型session上下文消耗峰值 | 相对降幅 | 降低约54%(采用ACC五阶段压缩) | 二值紧急压缩(95-99%阈值触发LLM摘要) | 约54%降幅,且常避免紧急压缩 |
| Prompt caching的stable portion成本节省 | Input cost reduction | 约88%降低cached部分输入成本 | 无cache时每轮重复计费的稳定prompt | 约88% |
| MCP外部工具的baseline上下文占用 | 占context budget比例 | <5%(lazy discovery) | 高达40%(所有MCP schema全部加载) | 从40%降至<5% |
| 单次长跑测试输出的上下文占用 | tokens/tool call | <100 tokens(per-tool summarizer) | 30,000 tokens(无压缩) | >99%压缩比 |
| 典型session长度(触发context overflow前) | 对话轮次 | 30-40轮(summarizer + offloading) | 15-20轮(无任何压缩) | 约2x延长 |
| Doom-loop捕获速度 | 重复次数阈值 | 3次(MD5 fingerprint) | 更多次(连续read计数器,无法区分参数) | 更早捕获+更精确(区分tool+args对) |
局限与改进
作者在第5节明确承认的最大局限是"缺乏系统化定量评测"——论文没有在SWE-bench、Terminal-Bench、LongCLI-Bench这些标准基准上跑出公开数字,所有指标都是作者在迭代开发过程中对内部session的工程观察。这意味着"54%上下文降幅""88%缓存节省"等数据虽然方向可信,但不能直接和Claude Code、Aider等竞品横向对比。其次,作者指出的特定边界条件包括:OFF-MODE下thinking被完全跳过,这对纯执行类任务(如大量文件读写)是合理的浪费;doom-loop检测只在action-phase生效,thinking-phase自身产生的无限推理无法被它捕获;9-pass模糊匹配虽然短链路short-circuit,但当LLM给出的old_content和实际文件差异极大(例如agent自己重构后用记忆写edit指令),仍然可能落入"fallback to error"。另外,本系统的per-workflow LLM routing虽然灵活,但其"哪个工作流该用哪个模型"的决策完全依赖用户配置,系统本身没有自动化模型选择能力——理论上讲,这是个隐形的调优负担,新手用户可能用错模型组合。我自己观察到的额外问题:role:user reminder的"更高salience"结论是基于作者自身测试,可能因模型而异(不同模型对system vs user message的处理方式不同);Stale-read的50ms tolerance在git checkout+立即edit的工作流下可能误触发(因为checkout更新mtime),可能需要改成"基于read_tool自己的timestamp而非文件系统mtime"。
独立分析的弱点
独立分析后我认为本文有四个具体弱点,每个都有可操作的改进方向。第一,**缺乏标准benchmark定量证据**——所有指标都是内部工程观察,缺乏与SWE-Agent、OpenHands、Aider等同行系统的A/B对比;改进方向是跑Terminal-Bench和LongCLI-Bench(已经在第5节被列为首要未来工作),特别关注"prompt caching + adaptive compaction组合"是否在长视野任务上显著优于vanilla ReAct。第二,**模型路由的决策负担全部甩给用户**——五个模型角色(Action/Thinking/Critique/Vision/Compact)都需要用户手动配置,这对小白用户门槛极高,且配置错误会导致系统行为不可预期;改进方向是引入"模型能力画像+任务复杂度估计器",自动建议配置(例如"你这个任务的thinking建议用opus,compact用haiku"),这其实就是Ye et al.的MCE工作的简化版。第三,**ACE playbook目前是扁平的自然语言bullet列表**,语义检索依赖cosine相似度,无法捕捉bullet之间的依赖/冲突/层次关系;改进方向是采用structured memory(代码依赖图、call graph、project ontology)替代部分纯文本bullet,这正是作者在第5节提出的"Structured code representations for memory"方向。第四,**安全层的approval persistence是双刃剑**——持久化在~/.opendev/permissions.json的规则很方便,但项目级与用户级规则的merge逻辑仅是"project优先级更高",这可能让恶意项目文件覆盖用户的安全边界;改进方向是引入rule的"上下文敏感性"——比如.gitignore级别的override需要显式confirm,或者某些dangerous rules(rm -rf)永远不能被任何配置文件降低安全级别,虽然现在priority=100的danger rule不会被override,但其他类型的规则还是可以被攻击。
未来方向
作者在第5节明确列出了七个未来方向:(1)在SWE-bench、Terminal-Bench、LongCLI-Bench上做系统评测(Terminal-Bench显示前沿模型<65%,LongCLI-Bench<20%,说明行业有巨大改进空间);(2)**自适应资源分配**——把当前固定的70%压缩阈值、3次nudge budget、4档thinking level,改成基于任务复杂度、当前context pressure、错误历史动态调整,这正是"用learning替代hand-engineering"的典型方向;(3)**ACE playbook的跨项目迁移**——目前playbook按项目分,未来要做hierarchical bullet organization(通用编程启发式 vs 项目特定约定)以及active learning(对不确定bullet选择性询问用户反馈);(4)**结构化代码表征**替代扁平bullet(code dependency graphs、call graphs、project-level ontologies);(5)**多agent协调超越层次委派**——目前subagent只通过completion marker通信,未来要支持peer-to-peer、共享blackboard、冲突解决协议,以实现"并行code review + 并行implementation"这类复杂workflow;(6)**学习式system reminder优化**——目前24个reminder模板是手工设计的,未来用RL基于attention-decay指标自动发现effective reminder模式;(7)**Hybrid CLI+IDE integration**——把CLI agent逻辑通过同一UICallback抽象扩展到IDE插件,复用agent logic但提供visual affordances(inline diff、symbol navigation、test result overlay)。我个人延伸的额外方向:**形式化验证safety layer的独立性**——目前五层安全是"独立设计",但缺乏formal proof,可以用model checking证明任意单层失效时剩余层仍能阻止典型攻击;**prompt injection attack的防御**——论文没有讨论MCP工具返回的内容里嵌入恶意prompt的风险,这种"tool-side prompt injection"是agent安全的新前沿。
复现评估
复现评估非常友好。代码完全开源在https://github.com/opendev-to/opendev,作者是Nghi D. Q. Bui(单人项目),代码用Rust实现,意味着编译产物轻量、运行效率高、跨平台部署容易。复现难度主要不在代码层面而在**配置层面**——要完整复现OPENDEV的context engineering行为,需要配置至少3-5个不同LLM的角色(Action+Thinking+Compact至少三个),推荐组合是Anthropic Claude Opus(thinking) + Sonnet(action) + Haiku(compact),这意味着用户需要Anthropic API key以及相应的token预算。算力门槛几乎为零——OPENDEV是client-side,不自己训练模型,所有"AI能力"通过API调用获得,普通开发笔记本即可运行。数据方面,系统启动会从远程catalog API拉取模型能力元数据(可通过OPENDEV_DISABLE_REMOTE_MODELS环境变量离线),并通过OPENDEV_MODELS_DEV_PATH指向本地catalog,air-gapped环境也能跑。最大的复现障碍其实是**评估困难**——因为没有benchmark评测,无法用单一数字判断"我的复现版本是否和论文描述一致",需要逐项跑"30轮session能否达到54%上下文降幅"等内部指标,这要求复现者理解并实现所有ACC的触发逻辑。整体复现难度:**代码层容易(开源+Rust生态成熟),配置层中等(多模型角色设置),评估层困难(缺乏benchmark锚点)**。
论文图表