(参考:https://opencode.ai/v2/docs)
2026年7月,OpenCode 悄然上线了V2 beta。
如果你只是把它当作"又一个工具的版本更新"来浏览,你会看到:运行时从 Bun 换到了 Node,Desktop 从 Tauri 换到了 Electron,Plugin API 全部重写,配置字段大量重命名。这些是表面变化。
但如果你带着一个问题去读它的文档——"这个工具的设计者认为,驾驭一个 AI Agent 最难的事情是什么?"——你会看到一些更深层的东西。
V2 的每一个重大设计决策,都在回答同一个问题:当 Agent 的能力越来越强,人类如何既充分利用它,又不失去对它的控制?
答案藏在四个变化里:Permission 变成有序规则数组、Plugin 获得 transform + runtime 双层能力、Compaction 变成带版本号的 checkpoint 机制、Instructions 引入 durable deltas 和 epoch 概念。
这四个变化,恰好对应了上下文工程和驾驭工程的三个发展趋势。
趋势一:从配置到策略——Permission的有序规则数组
V1 的样子
V1 的 permission 是一个按工具分组的对象:
这个设计的问题在于:当多条规则可能同时匹配时,谁优先? V1 没有给出明确答案。规则之间的优先级是隐式的、依赖实现的、不可预测的。
V2 的样子
V2 把 permission 变成了一个有序数组,每条规则有三个字段:action、resource、effect:
官方文档给出了明确的语义:"The last matching rule wins."(最后匹配的规则生效。)
这看起来只是一个数据结构的变化,但它代表了一个根本性的思维转变:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
追加
|
最后一点尤其重要。V2 明确说:
"Global permissions are applied to every agent before its agent-specific rules, so a later agent rule can refine a global rule." [ref:agents]
这意味着你可以写一套全局策略(比如"所有 shell 命令默认 ask"),然后给特定 agent 追加更细的规则(比如"reviewer agent 的 git diff 直接 allow"),而不用担心 agent 规则会覆盖全局规则。
这就是"策略即代码"(Policy as Code)的思路——和 Kubernetes 的 RBAC、AWS IAM 的 policy evaluation 逻辑如出一辙。
这个趋势意味着什么?
驾驭工程正在从"给 Agent 配几个开关"走向"为 Agent 编写可审计、可组合、可预测的策略体系"。
当我们团队有 5 个不同的 agent(build、plan、reviewer、explorer、deployer),每个 agent 有不同的权限边界时,我们需要的不是 5 份独立的配置,而是一套分层的策略系统:全局策略 + agent 级追加规则 + 显式的优先级语义。
V2 的 permission 数组就是这个思路的雏形。
一个容易被忽略的细节
V2 文档中有一句非常诚实的话:
"Shell runs with the host user's filesystem, process, and network authority. Its resource is raw text, not a parsed command. [...] Prefer a narrow shell allowlist over patterns intended to identify every dangerous command."
翻译过来就是:shell 命令是原始文本,不是结构化命令,我们不可能通过模式匹配识别所有危险命令。与其写黑名单,不如写白名单。
这句话暴露了驾驭工程的一个根本困境:你无法穷举所有危险操作。所以正确的策略不是"列出所有不能做的事",而是"只列出允许做的事"。
这正是我们常强调的原则:红线用 deny 硬执行,白名单用 allow 放行,其余全部 ask。 V2 的设计把这个原则变成了配置层面的默认行为。
趋势二:从回调函数到组合式中间件——Plugin的双层能力
V1的Plugin能做什么?
V1的plugin本质上是一组回调函数:
它能做的事情有限:在工具执行前后拦截、注入环境变量、订阅事件。它无法修改 Agent 的定义、无法修改模型请求、无法添加工具。
V2 的 Plugin 能做什么
V2 把 plugin 能力分成了两层:Transform hooks(修改配置)和 Runtime hooks(拦截运行时操作)。
Transform hooks 让我们修改 OpenCode 的配置本身:
Runtime hooks让我们在运行时拦截操作。其中最强大的一个是ctx.session.hook("context"):
这个hook让我们可以在模型请求发出之前,修改system prompt、消息列表、工具集。
为什么这很重要?
在 V1 中,如果我们想让某个agent不能使用某个工具,只有两个选择:
-
在 permission 里 deny 那个工具(但 agent 仍然"知道"这个工具存在,只是被拒绝) -
在 AGENTS.md 里写"不要使用这个工具"(但 agent 可能忽略)
在 V2 中,我们可以直接从模型请求中删除这个工具。模型根本不知道这个工具存在。这不是"拒绝",这是"不存在"。
这是驾驭工程的一个质的飞跃:从"告诉 Agent 不要做什么"到"让 Agent 根本不知道可以做什么"。
更深层的设计:Hook failure fails the operation
V2 文档中有一句关键的话:
"A hook failure fails the operation it intercepts." [ref:plugins]
这意味着:如果plugin hook 抛出异常,被拦截的操作会直接失败。不是"记录一条日志然后继续",而是"操作被阻断"。
这给了我们一个非常重要的能力:用 plugin 实现硬性门禁。
在 V1 中,tool.execute.before 抛出异常也能阻断操作,但 V2 把这个行为明确写进了文档,并且扩展到了 HTTP 请求/响应层面。这意味着你可以在模型请求发出之前就拦截不合规的请求,而不仅仅是在工具执行时拦截。
这个趋势意味着什么?
驾驭工程正在从"在Agent外面包一层防护"走向"把防护逻辑嵌入 Agent 的执行管线"。
V1 的plugin像是在 Agent 外面装了一个监控摄像头——它能看到 Agent 做了什么,但很难阻止 Agent 做什么。
V2 的plugin像是在 Agent 的执行管线里插入了一组可编程的阀门——你可以在任何一个环节关闭阀门,让后续的操作根本不会发生。
趋势三:从"遗忘"到"有版本的状态管理"
V1 的Compaction
V1 的compaction是一个相对简单的机制:当上下文快满时,把旧消息压缩成一段摘要,保留最近几轮对话。
问题是:压缩之后,之前注入的指令(比如 AGENTS.md 里的红线)还在不在? V1 没有给出明确答案。实践中,很多团队发现compaction之后Agent 开始"忘记"关键约束。
V2 的Compaction:Checkpoint 机制
V2 把compaction重新设计为checkpoint机制:
"Compaction replaces the active model context from an older part of a session with a generated checkpoint. The checkpoint contains a structured summary and a serialized tail of recent context." [ref:compaction]
Checkpoint 包含两部分:
- 结构化摘要:目标、重要细节、已完成和进行中的工作、阻塞项、下一步、相关文件
- 序列化的最近上下文尾部:保留最近 keep.tokens(默认 15000)个token的原始对话
更关键的是,V2引入了上下文溢出自动恢复:
"If an overflow occurs before the provider produces assistant output, V2 can compact and retry that step once." [ref:compaction]
也就是说,如果模型返回"context overflow"错误,V2会自动compact并重试一次。这在 V1 中是不存在的。
Instruction Epoch:上下文工程的"版本号"
这是 V2 最精妙的设计之一。
V2 把instructions(AGENTS.md 等)的变更存储为durable deltas(持久化增量):
"It stores source values as durable deltas, then renders initial instructions and chronological updates when assembling each model request." [ref:instructions]
每次compaction完成后,instruction epoch推进:
"Completed compaction advances the instruction epoch, making the currently admitted values initial without rereading sources or authoring an instruction event." [ref:compaction]
翻译成人话:
-
Compaction之前,instructions 是"初始值 + 一系列增量变更" -
Compaction之后,当前已准入的值变成新的"初始值",之前的增量历史被折叠 -
下次请求装配时,从新的初始值开始渲染
这本质上是给上下文引入了"版本号"的概念。
为什么这很重要?
在 V1 中,上下文管理是一个"黑箱":我们不知道compaction之后哪些信息还在、哪些丢了,我们只能祈祷关键约束没被压缩掉。
在 V2 中,上下文管理变成了一个有版本、有增量、有明确语义的状态系统:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nested AGENTS.md:按需加载的上下文
V2 还引入了一个 V1 没有的机制:嵌套 AGENTS.md 的按需发现。
"An AGENTS.md below the Location is not part of the initial upward scan. When the read tool successfully reads a file or lists a directory, OpenCode discovers AGENTS.md files from that target upward to, but not including, the Location." [ref:instructions]
也就是说:位于当前工作目录之下的 AGENTS.md,不会在启动时加载。只有当 Agent 用 read 工具读到那个目录时,才会被发现并注入。
这是上下文工程的一个重大进步:上下文不再是一次性全量加载的,而是按需、动态、增量装配的。
它解决了上下文工程的一个核心矛盾:
-
想让 Agent 知道所有规则(完整性) -
但不希望所有规则同时占用上下文窗口(效率)
嵌套发现机制的回答是:只在 Agent 真正需要的时候,才注入相关的规则。
一个意外但重要的变化:Undo 与 Snapshots
V2 还引入了一个看起来和上下文工程无关、但实际上非常重要的功能:基于 Git 的 per-step 快照和 Undo/Redo。
"For each model step, OpenCode attempts to capture the worktree immediately before the model call and after a cleanly completed step." [ref:snapshots]
这意味着 Agent 的每一步操作都被快照了。我们可以用 /undo 回滚到任意一步之前的状态,包括文件内容和对话历史。
这给 Agent 的动作引入了"事务语义":每一步操作要么完整执行、要么可以完整回滚。
在驾驭工程的语境下,这是一个重要的安全网:即使 Agent 做了错误的事情,我们也可以一键回滚,而不需要手动修复。
总结:三个趋势,一个方向
把这三个趋势放在一起看,我们会发现它们指向同一个方向:
|
|
|
|
|
|---|---|---|---|
| 策略化 |
|
|
|
| 管线化 |
|
|
|
| 版本化 |
|
|
|
这三个趋势合在一起,指向一个结论:
驾驭 AI Agent 正在从"提示工程"走向"系统工程"。
在提示工程时代,我们通过写好的 prompt 来引导 Agent,控制手段是"说清楚"。
在系统工程时代,我们通过策略规则、执行管线、状态版本来驾驭 Agent。控制手段是"让它不能不知道、不能做、做了也能回滚"。
OpenCode V2 不是第一个走这条路的工具,但它是目前把这三件事做得最完整、最公开的开源实现。
OpenCode V2 目前还是 beta。官方明确说"we may wipe your data, things may break, and APIs may change"。
但它的设计方向是清晰的。即使 V2 的 API 还会变化,它背后的三个趋势——策略化、管线化、版本化——不会变。
因为这三个趋势不是 OpenCode 发明的,而是整个行业在驾驭 AI Agent 的过程中,一步一步摸索出来的。
OpenCode V2 只是把它们写成了代码。

