结合 OpenCode 讲解 Harness 的核心机制与模块
💬 问题
介绍了那么多关于harness的特点和核心机制,请结合opencode来讲讲harness的核心机制和模块
🤖 回答
如果把前面讲的 Harness 全部落到一个真实产品上,entity 是一个非常好的例子。
先给结论:
OpenCode 本质上就是一个面向 Coding Agent 的 Harness。LLM 只是其中的"推理引擎",OpenCode 真正有价值的部分是 Agent Runtime、Tool Runtime、Permission、State/Session、Context 管理、Subagent、MCP、Human-in-the-loop、Loop Control 等。
官方文档也明确把 OpenCode 定义为终端 AI coding agent,并提供 Agents、Tools、Permissions、Skills、MCP 等机制。citation:turn0search11turn0search5turn0search2
可以把 OpenCode 抽象成:
text
OpenCode Harness
│
┌───────────────────────┼───────────────────────┐
│ │ │
Agent Runtime Tool Runtime Context Runtime
│ │ │
┌────┼────┐ ┌─────┼─────┐ ┌─────┼─────┐
│ │ │ │ │ │ │ │ │
LLM Plan SubAgent File Shell MCP Prompt Memory Session
│ │ │
└───────────────────────┼───────────────────────┘
│
Control / Safety
│
┌─────────────┼─────────────┐
│ │ │
Permission Approval Loop Control
│ │ │
└─────────────┼─────────────┘
│
Execution / State
│
Session / Checkpoint
下面逐个对应你前面学到的 Harness 核心机制。
1. Harness 的第一核心:Agent Runtime
OpenCode 不是简单的:
text
User → LLM → Answer
而是:
text
User
↓
Agent
↓
LLM
↓
Tool Call
↓
Tool Result
↓
LLM
↓
Tool Call
↓
...
↓
Final Answer
也就是说 OpenCode 自己维护 Agent Loop。
这就是 Harness 最核心的东西:
把一次 LLM 调用变成一个可以持续运行、调用工具、观察结果、再次推理的 Agent Runtime。
OpenCode 当前有 Primary Agent 和 Subagent 两类 Agent。Primary Agent 是用户直接交互的主体,例如 Build、Plan;Subagent 则用于专门任务,例如 General、Explore、Scout。citation:turn0search5
2. OpenCode 的 Agent 就对应 Harness 的"智能体"
例如:
text
Build Agent
负责:
text
读取代码
↓
分析
↓
修改代码
↓
执行测试
↓
查看错误
↓
继续修改
而:
text
Plan Agent
则限制自己:
text
分析
↓
制定方案
↓
输出计划
不直接修改代码。
官方文档明确说明,Plan 是受限制的分析/规划 Agent,而 Build 是具有完整工具访问能力的默认开发 Agent。citation:turn0search5
这说明一个非常重要的 Harness 思想:
Agent 不只是一个 Prompt,而是 Prompt + Model + Tools + Permissions + Runtime Policy。
3. 第二核心:Tool Runtime
OpenCode 给 LLM 的不是无限的操作能力,而是有限的 Tool:
text
read
edit
write
patch
grep
glob
bash
lsp
webfetch
websearch
task
skill
MCP tools
官方文档明确说明,OpenCode 内置 Tool,同时可以通过 MCP 扩展 Tool。citation:turn0search2turn0search10
于是:
text
LLM
↓
Tool Calling
↓
Tool Runtime
↓
真实环境
例如:
text
LLM:
我要读取 UserService.java
↓
read("UserService.java")
↓
OpenCode Tool Runtime
↓
文件系统
这就是 Harness 中:
Reasoning 和 Execution 分离。
LLM 负责:
text
"我要读这个文件"
Harness 负责:
text
"是否允许读"
"怎么读"
"读取结果是什么"
4. 第三核心:Permission / Guardrail
OpenCode 在这一点上非常典型。
它不是简单:
text
Tool = enable / disable
而是:
text
ALLOW
ASK
DENY
例如:
json
{
"permission": {
"bash": {
"*": "ask",
"git status *": "allow",
"git push *": "deny"
},
"edit": "deny"
}
}
也就是说:
text
LLM
↓
bash("git status")
↓
Permission
↓
ALLOW
而:
text
LLM
↓
bash("git push")
↓
Permission
↓
DENY
或者:
text
LLM
↓
bash("npm install xxx")
↓
Permission
↓
ASK
↓
Human
OpenCode 当前权限系统支持按 action + resource 匹配,并采用 allow / ask / deny 三种结果;还可以针对 Agent 单独配置权限。citation:turn0search0turn0search8
这就是我们前面讲的:
text
Guardrail
+
Policy
+
Human-in-the-loop
5. OpenCode 的 Permission 本质上就是一个小型 Policy Engine
例如:
text
Action Resource Effect
read *.env ask
read *.java allow
edit src/** allow
edit production/** deny
shell git status * allow
shell git push * deny
webfetch * ask
subagent reviewer allow
这已经非常接近企业级 Policy Engine:
text
Subject
+
Action
+
Resource
↓
Policy
↓
ALLOW / DENY / ASK
所以如果把 OpenCode 放到你之前的 DBA Agent 场景:
text
Subject = DBA Agent
Action = mysql_execute
Resource = prod-mysql-01
SQL = ALTER TABLE
然后:
text
Policy
↓
HIGH_RISK
↓
ASK
↓
Human Approval
两者本质上是同一类设计。
6. 第四核心:Human-in-the-loop
OpenCode 的 ask 就是非常典型的 HITL。
text
Agent
↓
Tool Call
↓
Permission
↓
ASK
↓
用户
├── Allow once
├── Allow always
└── Reject
官方文档明确支持这三种审批结果;并且 deny 始终具有更高约束,自动批准模式也不能绕过显式 deny。citation:turn0search0turn0search3
所以:
text
LLM → Tool
实际上变成:
text
LLM
↓
Proposal
↓
Policy
↓
Human
↓
Executor
这就是企业 Agent 非常重要的:
LLM 只能提出操作请求,不能天然拥有操作权限。
7. 第五核心:Subagent / Multi-Agent
OpenCode 还有一个非常典型的 Harness 能力:
text
Primary Agent
│
├── Explore Agent
├── General Agent
└── Scout Agent
Primary Agent 可以把专业任务交给 Subagent。
这对应我们前面讨论的:
Delegation
例如:
text
Build Agent
↓
发现项目很大
↓
Task → Explore Agent
↓
Explore Agent
↓
返回代码结构
↓
Build Agent
这就是:
text
Coordinator
↓
Subagent
↓
Result
↓
Coordinator
OpenCode 官方把 Subagent 明确作为专门任务的 Agent,并允许通过 @ 调用或由主 Agent 调用。citation:turn0search5
8. 第六核心:Skills
Skills 是 Harness 中非常重要但容易被忽略的一层。
OpenCode 的 Skill 可以理解为:
按需加载的领域能力/工作流程知识。
例如:
text
skills/
├── git-release
├── code-review
├── mysql-dba
├── kubernetes
└── security-audit
Agent 不需要把所有知识一次性塞进 System Prompt。
而是:
text
Agent
↓
发现需要某能力
↓
skill("mysql-dba")
↓
加载 Skill
↓
执行
OpenCode 官方的 Skill 机制就是 Agent 通过 skill Tool 按需加载能力,同时 Skill 本身也受到权限控制。citation:turn0search7
这对应 Harness 的:
text
Capability / Skill Runtime
9. 第七核心:MCP
OpenCode 把 MCP 作为 Tool 扩展机制:
text
OpenCode
│
├── Built-in Tools
│
└── MCP
├── Prometheus
├── GitHub
├── Database
└── Kubernetes
LLM 看起来:
text
read()
bash()
mysql_query()
prometheus_query()
但真正执行的是:
text
OpenCode
↓
MCP Client
↓
MCP Server
↓
External System
而且 MCP Tool 同样进入 OpenCode 的 Permission 模型。官方文档明确说明 MCP 工具与内置工具一样受到权限控制。citation:turn0search2turn0search4
这非常重要:
Harness 不应该因为 Tool 来自 MCP,就绕过自己的安全边界。
10. 第八核心:Context Engineering
这是 Coding Agent 非常重要的一层。
OpenCode 需要不断处理:
text
用户需求
+
System Prompt
+
AGENTS.md
+
当前代码
+
Tool Result
+
Git Diff
+
历史对话
+
Skill
+
错误信息
最终形成:
text
Context
↓
LLM
例如 /init 会分析项目并生成 AGENTS.md,用于帮助 Agent 理解项目结构和编码规范。citation:turn0search11
这其实就是 Harness 的:
Context Runtime / Context Engineering
不是简单的 Memory。
11. AGENTS.md 是什么?
你可以把:
text
AGENTS.md
理解成:
text
项目级 Agent System Prompt
例如:
markdown
# Project Rules
- 使用 Java 21
- 使用 Spring Boot 3
- 不允许修改数据库 Schema
- 所有接口必须增加单元测试
- 禁止直接修改 generated 目录
然后:
text
User
↓
OpenCode
↓
加载 AGENTS.md
↓
形成 Agent Context
↓
LLM
这就是 Harness 中:
text
Instruction Layer
12. 第九核心:Context Compression
Coding Agent 有一个非常严重的问题:
text
任务越复杂
↓
Tool Call 越多
↓
Context 越来越长
↓
Token 爆炸
OpenCode 有 Auto Compact。
官方实现是在上下文接近模型限制时自动总结当前会话,然后基于摘要继续工作。citation:turn0search4
所以:
text
Context
↓
接近窗口上限
↓
Summarization
↓
Compressed Context
↓
继续 Agent Loop
这就是 Harness 中非常重要的:
Context Management
也是为什么 Coding Agent 如果没有 Harness,单纯拿 LLM API 很难长期运行。
13. 第十核心:Loop Control
这是 OpenCode 非常有代表性的 Harness 能力。
Agent 经常可能:
text
Tool
↓
报错
↓
LLM
↓
重新调用
↓
报错
↓
LLM
↓
重新调用
↓
...
如果没有控制,就会:
text
无限循环
Token 爆炸
费用爆炸
OpenCode 有 doom_loop 权限机制,用于检测相同 Tool Call 重复执行的情况。当前文档说明,该机制针对 Agent 似乎陷入重复调用的情况进行恢复提示。citation:turn0search1turn0search5
这就是 Harness 的:
text
Loop Detection
Retry
Timeout
Budget
Circuit Breaker
14. 把 OpenCode 映射到我们前面讲的 Harness
这张表最值得记:
| Harness 核心模块 | OpenCode 对应 |
|---|---|
| Agent Runtime | Build / Plan / Subagent |
| LLM Runtime | 各种 Model Provider |
| Tool Runtime | read/edit/bash/LSP/MCP 等 |
| Agent Loop | LLM ↔ Tool 循环 |
| Planner | Plan Agent / Agent 内部规划 |
| Delegation | Primary Agent → Subagent |
| Skill Runtime | Skills |
| Tool Gateway | Tool + MCP |
| Guardrail | Permission / Rule |
| Policy Engine | Permission Rules |
| HITL | ask / 用户审批 |
| Context Runtime | Prompt + AGENTS.md + Tool Result |
| Context Compression | Auto Compact |
| State/Session | Session 管理 |
| Loop Control | doom_loop |
| Code Intelligence | LSP |
| External Capability | MCP |
| Agent Configuration | Agents |
| Observability | Session/Tool execution/UI 等 |
因此 OpenCode 不是"一个带工具的 LLM"。
更准确地说:
text
OpenCode
│
┌─────────────┼─────────────┐
│ │ │
Reasoning Execution Control
│ │ │
▼ ▼ ▼
LLM Tools Permission
│ │ Guardrail
│ │ HITL
│ │ Loop Control
└──────┬──────┘
▼
Agent Runtime
│
┌──────┼──────┐
▼ ▼ ▼
Context Skills MCP
│
▼
Session/State
15. OpenCode 最值得你借鉴的 Harness 思想
如果你以后自己用 LangGraph 开发 DBA Agent,不要照着 OpenCode 的 UI 去模仿,而应该照着它的 Runtime 思想去设计。
OpenCode 的核心不是:
text
"我有一个很强的模型"
而是:
text
模型
↓
Agent Runtime
↓
Context
↓
Tool
↓
Permission
↓
Execution
↓
Observation
↓
再次推理
↓
直到任务完成
映射到你的 DBA Agent:
text
DBA Harness
│
┌────────────┼────────────┐
▼ ▼ ▼
Coordinator Agents Context
│ │ │
│ ┌────┼────┐ │
│ ▼ ▼ ▼ │
│ MySQL K8s Prom │
│ │ │ │ │
└───────┼────┼────┼───────┘
▼
Tools
│
┌──────┼──────┐
▼ ▼ ▼
MySQL Prometheus SSH
│ │ │
└──────┼──────┘
▼
Guardrail
│
┌─────────┼─────────┐
▼ ▼ ▼
Allow Approval Deny
│ │
│ Human
└────┬────┘
▼
Execute
│
▼
Result
│
▼
Verify
│
┌────┴────┐
▼ ▼
Success Retry
这其实就是你前面一直在研究的:
Harness = Agent Runtime + Tool Runtime + Context Runtime + Control/Safety + State + Observability。
而 LangGraph 的价值就在于,它可以帮助你把这套 Runtime 的"状态、节点、路由、循环、并发、interrupt、checkpoint"显式建模出来。
所以,如果把 OpenCode 当成一个成熟的 Harness 案例来看,最值得你研究的不是"它用了哪个 LLM",而是:
它如何把一个 LLM 变成一个可持续运行、可以调用工具、可以被授权/拒绝、可以调用 Subagent、可以加载 Skill、可以管理 Context、可以处理异常和循环的 Agent Runtime。
这才是 Harness 的核心。