Harness Agent 研究知识库:Codex、OpenCode 与 grok-build 全解
说明:本文是完整研究笔记。此前发过精简对比版《解剖三个开源 Harness Agent》,这篇是它背后的全部底稿:按主题重组的一手结论,含目录可跳转。
用途:把与 AI 关于三大开源 harness agent(Codex / OpenCode / grok-build)的多轮讨论,
从零散问答重组为按主题的完整复习材料。用于个人复习、面试讲稿、以及”个人 Agent 引擎 MVP”的设计依据。方法:文档优先(读官方开发文档理解设计意图)→ 源码验证(读实现确认)→ 提炼优劣与可借鉴点。
目录
- 0. 总览与项目定位
- 1. 三家 Harness 横向对比
- 2. Agent 循环与会话模型
- 3. 压缩即记忆 与 三层记忆
- 4. 记忆 RAG:检索管线 / dream / 为何代码检索不用向量
- 5. 权限与多层审批漏斗
- 6. 多智能体与子代理三轴
- 7. 工具 / MCP / Skill / Plugin 四层扩展
- 8. 配置层与”结构化/散文分层”设计原则
- 9. 声明式配置为何用 Markdown
- 10. 源文档索引
- 附. 实施方案与协作模式
0. 总览与项目定位
三个参考系统都是 coding agent 的 harness(把 LLM 包装成能读写代码、执行命令、管理长任务的自主体):
- Codex(OpenAI,Rust):引擎-界面分离、事件溯源;最强的安全模型与会话持久化。
- OpenCode(sst,TypeScript):server-first、万物皆声明式配置;扩展体系边界最清晰。
- grok-build(xAI,Rust):库化解耦;压缩、子代理、workflow 的工程化最完整。
本项目定位:自研的是个人 Agent 大脑(对话、记忆、审批、调度、多智能体编排、IM 渠道、轻量工具),
不是 coding agent。编码任务通过统一 delegate 工具的 coding provider 整体委派给 grok-build(专家子代理范式)。
北极星原则:对开源 harness 做一次解剖 → 逐步长出自己的 harness。功能只能多不能少(能力域全覆盖),
实现细腻度可分档(完整自研 / 委派 / 简化 / 占位预留)。
核心洞察(贯穿全库):
- 多智能体的价值在编排,不在自己实现每个子代理——子代理可异构(本地 loop 或外部进程)。
- 压缩即记忆处理:上下文压缩与长期记忆是同一系统的两半(在线蒸馏 vs 离线整理)。
- 代码检索是 agentic(子代理多轮 grep/glob/read + 改写查询),只有”记忆”才用向量/混合 RAG。
- 配置用 frontmatter(结构) + Markdown(散文) 分层,因为”配置的消费者变成了 LLM”。
1. 三家 Harness 横向对比
设计哲学与强弱
| 系统 | 一句话哲学 | 最强 | 最弱 |
|---|---|---|---|
| Codex | 引擎-界面分离 + 事件溯源,一切皆 Op/Event | 安全模型(策略/机制正交的多层审批)、rollout 持久化、两阶段记忆 | 复杂度爆炸;v1/v2/legacy 三代并存;文档滞后于代码 |
| OpenCode | server-first + 万物皆声明式配置 | 扩展边界最清晰(tool/skill/plugin/MCP 各司其职)、权限规则、Skill 惰性加载 | 无长期记忆层(只有有损压缩);绑死 Bun/TS/Effect;单机单用户 |
| grok-build | 库化解耦,每能力抽成无宿主依赖纯库 | 压缩(trait seam + 质量合同 + 三风格)、子代理四维、workflow 断点续跑 | 抽取半途(循环仍在巨型 shell);记忆属实验;协议对单机过重 |
逐能力域”谁最强”
| 能力域 | 最值得抄谁 | 关键点 |
|---|---|---|
| 核心协议/循环 | Codex | SQ/EQ 双队列、thread/turn/item 三原语、事件可回放 |
| 编辑鲁棒性 | Codex | apply-patch 独立 crate,上下文锚点模糊定位(容忍行号漂移) |
| 权限审批 | Codex + OpenCode | Codex 多层漏斗 + amendment 回写;OpenCode 三元组规则 + doom_loop |
| 上下文压缩 | grok-build | 退化检测 + 用户原文保留 + tool 配对安全 + 三风格 |
| 会话持久化 | Codex | rollout jsonl + resume + fork(边界语义严谨) |
| 长期记忆 | Codex(唯一有真长期记忆) | 两阶段管线 + git diff 脏检查;grok 有混合检索但属实验;OpenCode 无 |
| 多智能体 | 三家一致(编排范式) | Codex spawn 工具族 + review rubric;OpenCode task + 子会话;grok 四维解析 |
| 配置层 | OpenCode | 8 层合并、agent/command/skill 全用 markdown+frontmatter |
| 扩展边界 | OpenCode | MCP=工具/数据、Skill=知识、Plugin=行为改写,职责不重叠 |
| 独有能力 | grok-build workflow / Codex Guardian | Rhai 编排+journal 续跑 / AI 审 AI |
2. Agent 循环与会话模型
核心循环
Codex 的 SQ/EQ 模型(sources/codex-protocol_v1.md):客户端与引擎经 提交队列(SQ)/事件队列(EQ) 异步通信。
- 客户端提交
Op(UserTurn / Interrupt / ExecApproval / PatchApproval / Shutdown…);引擎回推EventMsg(AgentMessage / delta / ExecApprovalRequest / TurnComplete…)。 - 审批本身就是队列里的一条异步消息(Op),不是阻塞回调——这是流式体验的关键。
- 分层:
Session(配置+状态)→Task(一次用户输入触发的工作,同时至多一个)→Turn(一轮”请求模型→执行工具→产出”)。一个 Turn 无输出则 Task 结束。 response_id作为书签:既可 resume 线程,也可从早期点 fork。
通用单 turn 流程(我们要自研的):组装消息(system + 记忆注入 + 历史) → LLM 流式 → 逐个执行 tool_calls(每个先过权限)→ tool 结果回填 → 循环直到无 tool_call 或触达 max_turns。
对外抽象:thread / turn / item
Codex app-server(sources/codex-app-server-README.md)把引擎抽象成三原语,是 IDE/多客户端接入的事实标准:
- Thread:一次会话;Turn:一问一答;Item:消息/推理/命令/文件编辑等。
- 客户端
thread/start|resume|fork→turn/start(立即返回)→ 持续读item/started、item/agentMessage/delta、turn/completed通知流。 - 背压:有界队列,过载回
-32001可重试错误。
会话状态管理
- grok-build:Actor 模式(
sources/grok-build-user-guide/17-sessions.md+ chat-state crate)——会话状态跑在独立 tokio task,无锁,经 Command+oneshot 查询、事件流回推。 - OpenCode:session/message/part 三级模型,一切事件化,天然支持多客户端与回放。
可借鉴到本项目
会话模型用 thread/turn/item 三级;持久化 = SQLite 元数据 + 每会话 jsonl 事件日志(无损事实源),重启后从 jsonl 重建历史 → 长对话能力的根基。
3. 压缩即记忆 与 三层记忆
核心观点:压缩不是省 token,是记忆处理的中间环节
在线压缩和离线记忆整理是同一个操作(LLM 蒸馏历史),区别只在触发时机、存放位置、生命周期。
1 | ┌─ 工作记忆(上下文窗口 = 容器)─────────────────────┐ |
短期记忆的三条硬规则(不是”最近几条”)
- 单位是轮(turn)不是消息条数:OpenCode 用
tail_start_id标记边界;grok-buildselect_turns_to_compact按轮切分。 - tool call/result 配对不可拆散:尾部若保留了孤儿工具结果会让模型错乱 → 保留轮数为配对完整性动态调整。
- 分级遗忘:正式压缩前先忘”体积大、复述价值低”的——grok-build 顺序为 图片 → 旧工具输出(>50%利用率) → 最后才蒸馏对话原文。用户原话最不可蒸馏(
wrap_user_query强制保留)。
尾部为何必须原文
细节保真(路径/行号/报错)、行为连续性(隐式 few-shot)、KV cache 经济学(重写历史会打爆前缀缓存,故压缩策略都是”尽量少发生、一发生就一次到位”,两次压缩间只追加不改写)。
三家压缩实现
- grok-build(最完整,
sources/grok-build-user-guide/13-memory.md+ compaction crate):三风格(code 全替换 / intra 尾部保留 / inter 分块轮间);质量合同:select保 tool 配对、wrap_user_query保原诉求、is_degenerate_summary退化检测 + 重试。 - OpenCode:隐藏 compaction 子代理生成 summary;
tail_start_id保尾部;工具输出截 2000 字符、保护 skill 输出、保留最近 2 轮。 - Codex:
compact.rs多策略 + pre/post compact 钩子;且 rollout 始终保留全量历史,记忆管线从完整 rollout 提取而非压缩后上下文(避免二次失真)。
落到本项目的准则
- 编排层要感知压缩事件,压缩摘要落盘成为记忆写入源。
- 记忆管线输入用全量 jsonl,不从压缩后上下文二次蒸馏(学 Codex)。
- growth-log 本质是手动 dream,可升级为自动提取+整理。
4. 记忆 RAG
先纠正一个行业事实:代码检索不用向量
三家没有一家对代码做向量 RAG。 代码检索是 agentic:
- explore 子代理循环 grep 关键词 → 没命中就换同义词/换命名约定再 grep → glob 换路径 → read 确认。
- “没查到就改写重查、多烧点 token 换召回”这个行为是 LLM 在子会话里自主完成,外层只给它只读工具集和检索力度指令(quick/medium/very thorough)。
- 外层 loop 校验:父代理拿到结论后自己验证(读关键文件),Codex 更用 ReviewTask/Guardian 做结构化 JSON 校验。
- 查询改写(同义词)放在 agentic 层做,不放管线里——管线要快且确定,改写交给会烧 token 的小 agent。
记忆检索才是混合 RAG 管线(grok-build,值得整条抄)
1 | 查询 → FTS5 BM25(候选=3×max_results,另补 evergreen 来源查询防被会话记忆挤出) |
query_expansion.rs不是 LLM 同义词改写,只是 130 个停用词的关键词提取(FTS-only 降级路径用)。- MMR 是 ~60 行纯函数(无需 embedding,Jaccard 相似度),可直接移植 Python。
离线整理两流派
- grok-build dream:门槛(≥N 小时 + ≥N 个新会话);LLM 五规则整理(合并同主题 / 新事实覆盖旧 / 相对日期转绝对 / 丢弃寒暄噪音 / 保留决策与问题-方案对);处理完删源日志清索引。
- Codex 两阶段(
sources/codex-memories.md):Phase1 并发从每个 rollout 抽取raw_memory/rollout_summary(DB 租约防重、退避重试、密钥脱敏);Phase2 全局锁 + git 基线工作区 + spawn 无网络无审批的 consolidation 子代理,用 git diff 让子代理只看增量。
落到本项目
记忆源 = 巡检历史 / Finding / 成长日志 / 仓库上下文 / “记住”条目 / 导入的工作经验。
MVP:markdown 文件 + SQLite FTS5(jieba 中文分词)+ 时间衰减 + MMR;向量为可选增强。代码检索交给 explore 子代理 + codegraph MCP。
5. 权限与多层审批漏斗
Codex 的三层漏斗(全场最精华)
1 | 命令要执行 |
amendment 机制(最妙):人审的”总是允许”不是内存开关,而是回写成第 1 层静态规则(同时更新内存 + 磁盘),审批系统越用越少打扰。见 sources/codex-approval-on_request.md、sources/codex-execpolicy.md。
审批与沙箱正交:AskForApproval(untrusted/on-request/granular/never)× SandboxPolicy(danger-full-access / read-only / external-sandbox / workspace-write)两轴组合。
OpenCode 的规则模型(最好落地,sources/opencode-permissions.mdx)
- 规则 =
(permission, pattern, action=allow/ask/deny)三元组,通配匹配,findLast 后者覆盖前者。 - 挂起模型:ask → 发事件 + 挂起 Deferred → 客户端回 once/always/reject;reject 级联拒绝该会话全部挂起项;always 追加规则并自动放行同会话同类挂起。
- doom_loop:同名工具 + 完全相同输入连续 3 次 → 强制审批(防 agent 烧 token 死循环;IM 场景尤其需要)。
- 默认:多数 allow,
doom_loop/external_directory默认 ask,.env默认拒读。 - 子代理权限收窄铁律:子代理只继承父的 deny 规则,父的允许不放大子的能力。
落到本项目
规则层抄 OpenCode(三元组 + doom_loop);交互层抄 Codex(挂起 → 飞书审批卡片 → amendment 回写 policy.json)。三层齐后 --always-approve 才能退役。
6. 多智能体与子代理三轴
核心认知:多智能体 = 编排,不是自己实现每个子代理
子代理 = 主 agent 通过 spawn/task/delegate 工具,把专业活委派给带独立配置的子代理,收结构化结果。
子代理实现允许异构(本地 loop / 外部进程均可)。编排权(何时 spawn、spawn 哪个、给什么上下文、结果聚合、血缘)在大脑手里——这就是多智能体架构,与子代理是否自研无关。所以”编码委派 grok”本身就是多智能体架构的第一个实例。
三家 spawn 机制
| 维度 | Codex | OpenCode | grok-build |
|---|---|---|---|
| 触发 | spawn_agent 工具族(spawn/wait/send_message/interrupt/list) | task 工具(sources/opencode-agents.mdx) |
Task 工具(sources/grok-build-user-guide/16-subagents.md) |
| 上下文继承 | fork_turns: none/all/N | 全新会话,只带 prompt | 可 resume 已完成同类子代理(继承 transcript+worktree snapshot) |
| 角色/隔离 | agent_type(role) | mode=primary/subagent/all | role/persona/capability/isolation 四维 |
| 深度防失控 | thread_spawn_depth 限制 | subagent_depth 默认 1 | 达 MAX_DEPTH 剥掉 task 工具 |
| 结果回传 | 事件流 + wait | 同步文本标签 / 后台 synthetic 消息注入父会话 | 阻塞等待预算(600s)超时转后台 |
“外层 loop 校验 + 内嵌小 agent 检查” 的教科书实现:
- Codex ReviewTask:一次性 sub-codex 会话,换 REVIEW_PROMPT、审批强制 Never、禁 web/collab 防递归、可用独立 review_model、输出强制 JSON(
sources/codex-review-rubric.md有 8 条判 bug 准则 + P0-P3 + JSON schema)。 - Codex Guardian:常驻安全审查子代理(见第 5 节)。
- OpenCode explore:纯只读工具集子代理。
子代理三轴(本项目 SubagentProvider 接口的一等公民)
| 轴 | 源码对应 | 说明 |
|---|---|---|
| 角色 | agent_type / SubagentRole / persona | 由谁定义职责与 prompt |
| 权限 | grok capability_mode(read-only/read-write/execute/all)、OpenCode deriveSubagentSessionPermission | 能用哪些工具 |
| 上下文分配 | Codex fork_turns、persona inputs/outputs | 注入哪些记忆/文件/历史片段 |
关键设计边界(两类 provider 控制粒度不同):
- 自研 provider(跑我方 loop+权限漏斗)→ 三轴全控(逐工具权限、精确 fork 历史)。
- 外部黑盒 provider(grok)→ 三轴粗粒度(角色固定、权限只能外层审批一次、上下文只能单向注入 prompt)。框架不得假装黑盒可被细粒度管控。
7. 工具 / MCP / Skill / Plugin 四层扩展
四层工具栈
1 | ① 内置工具 Tool trait/接口 + 流式输出契约(Progress* + Terminal) |
扩展机制职责边界(OpenCode 讲得最清楚,直接采用其心智模型)
- MCP = 外部工具/数据(
sources/opencode-mcp-servers.mdx;文档明确警告”吞噬上下文”,要节制)。 - Skill = 纯知识/指令,惰性加载(
sources/opencode-skills.mdx):system prompt 只放<available_skills>名字+描述,模型调skill工具时才返回 SKILL.md 全文 + 目录文件,且过 skill 权限。 - Plugin = 进程内行为改写(
sources/opencode-plugins.mdx):18 个钩子(tool.execute.before/after、permission.ask、chat.params、session.compacting…),output 可变对象改行为。 - 自定义工具(
sources/opencode-custom-tools.mdx):.opencode/tools/*.ts,文件名即工具名,可覆盖内置。
Skill 渐进披露 = 本项目该马上改的点
对比:我们现在 10 个 Skill 全靠 grok 启动扫描,Skill 越多 system prompt 越肥。照 OpenCode 模式(清单常驻 + 正文按需加载)能显著省上下文,Router 分发也因描述更聚焦而更准。
MCP 的现成挂载点
grok ACP session/new 传的 mcpServers 参数支持按会话注入 MCP server(含超时/禁用工具)。即 Python 层可按任务类型给不同会话注入不同工具集(巡检注入 GitHub 只读、交付注入完整),一行参数的事。
8. 配置层与”结构化/散文分层”设计原则
分层原则:按”内容给谁读”决定格式
- 机器/解析器读 → JSON(engine/policy/server/memory 配置、权限规则、MCP 配置)。
- LLM 读的散文 → Markdown 正文(系统提示词、技能指令、角色 prompt)。
- 两者都要 → frontmatter(YAML/JSON 字段) + Markdown 正文(agent/skill/command 定义)。
- frontmatter 严格 schema 校验(name 正则、description 限长、capability 枚举);正文当不透明字符串透传给模型,绝不解析成字段。
结构的产生方式(关键:结构从哪来,杜绝脆弱解析)
结构化数据绝不通过解析模型自由书写的 Markdown 散文得到。 只有三种合法来源:
- 人写的(多数声明式配置):
agents/*.md、SKILL.md的 frontmatter 是人照文档格式手写,模型不参与;加载时 schema/正则/限长校验,不合格拒绝。 - 代码确定性序列化(应用自己拥有的数据):会话元数据、”记住”条目的 source/时间戳、配置写回、amendment——由代码用序列化器写(
yaml.dump/json.dumps),模型不手打这些字节。 - 受约束生成 + 校验 + 重试(运行时必须让模型产出结构):用 JSON Schema / 结构化输出 / tool-call 参数在生成阶段强制模型只吐合法 JSON,再做 schema/正则/退化检测校验,非法则拒绝重试(对齐 Codex review 严格 JSON、记忆 Phase1、grok
is_degenerate_summary)。
一句话:格式化(serialize)由代码做,结构约束(schema)由生成层强制,散文由人或模型自由写但从不被解析。 模型永远不是结构化数据的”事实来源手写者”。
具体例子:
记住 我偏好用 pytest→ frontmatter(source/created_at/kind) 由代码写,正文是用户原文,模型零参与。- 会话摘要提取 → JSON Schema 约束模型返回
{facts:[], decisions:[]},校验后由代码序列化进sessions/*.md。
9. 声明式配置为何用 Markdown
它们没有在”MD vs JSON”里二选一,而是 frontmatter + Markdown 混合;分界线是”这段内容给谁读”。
决定性原因:agent/skill/command 里最重要的字段是系统提示词,读者是模型。Markdown 是模型的母语(训练语料海量、天然理解标题/列表/代码块)。把 300 行 prompt 塞进 JSON 字符串会变成转义 blob,模型读到的也是那坨;Markdown 正文是零摩擦注入(所见即所得)。
附带收益:人类可写(无括号/逗号/转义错)、Git 友好(一文件一 agent、diff 清晰可 review)、渐进披露(标题层级给模型导航)、token 高效。
“不稳定”的正解:担忧只在”试图从散文解析出结构化数据”时成立,而它们恰恰不这么做——只严格解析 frontmatter,正文当不透明字符串透传,不解析 → 无脆弱解析。
一句话:当你的配置里有字段的读者是语言模型时,就用语言模型的母语写那个字段。AI 厂商爱 Markdown,本质是”配置的消费者变了”。
10. 源文档索引
本地离线副本在 sources/(详见 sources/README.md)。关键原始文档:
Codex(github.com/openai/codex)
sources/codex-protocol_v1.md— SQ/EQ、Session/Task/Turn、response_id 书签sources/codex-app-server-README.md— thread/turn/item、审批流程、背压(原文 2411 行,看 Approvals / Core Primitives / API Overview 节)sources/codex-execpolicy.md— Starlark 前缀规则引擎sources/codex-approval-on_request.md— 审批升权与 prefix_rule 设计sources/codex-review-rubric.md— review 子代理判 bug 准则 + JSON schemasources/codex-memories.md— 两阶段记忆管线sources/codex-core-README.md— 各平台沙箱(Seatbelt/Landlock+bwrap/Windows)- 官方:https://developers.openai.com/codex/
OpenCode(github.com/sst/opencode,官方站 https://opencode.ai/docs/)
sources/opencode-agents.mdx— primary/subagent、task、子会话sources/opencode-permissions.mdx— allow/ask/deny 规则、doom_loop、.env 默认拒读sources/opencode-server.mdx— headless server + SSEsources/opencode-config.mdx— 8 层配置合并sources/opencode-skills.mdx— SKILL.md 惰性加载sources/opencode-mcp-servers.mdx、opencode-plugins.mdx、opencode-custom-tools.mdx、opencode-tools.mdx、opencode-acp.mdx、opencode-sdk.mdx
grok-build(grok-build/,官方站 https://docs.x.ai/build/overview)
sources/grok-build-user-guide/(25 篇完整用户指南)——重点:13-memory、16-subagents、17-sessions、18-sandbox、22-permissions-and-safety、10-hooks、14-headless-mode、19-plan-mode、20-background-tasks- 设计意图另见各 crate
src/lib.rs顶部注释(compaction / memory / subagent-resolution / chat-state 等)
附. 实施方案与协作模式
实施方案:见仓库根 个人Agent引擎MVP实施方案.md(14 能力域完备性基线 + M1-M4 里程碑 + 三张架构图 + Test Plan)。
协作模式(学习价值分工):
- 认知黄金(agent loop / 压缩选择算法 / 记忆 RAG 打分 / 权限漏斗求值)→ 用户亲手写 Python,AI 带读源码 + 出实现规格 + code review。
- 样板管道(FastAPI 路由 / SQLite 建表 / jieba 接线 / 渠道适配)→ AI 直接写。
- 每里程碑结束做复盘(对应三家哪个设计、可迁移到什么场景)。
编码路径:先委派 grok(coding provider),原生 coding 作为可逆升级(共享同一 loop,只需补 apply-patch + 编码 prompt + 验证循环,不返工)。
附2. 诚实边界与面试答法(复习前必看)
本 MVP 真实状态分档(面试只能按此表述,说过头即翻车):
- 设计充分可主讲:记忆 RAG、压缩、会话持久化、Server/渠道、配置层、可观测、模型接入。
- 仅架构草图待深化:Agent Loop(流式/工具交错/中断/max_turns 细节未定)。
- 框架+占位勿夸大:多智能体(接口+单一委派 provider)、Hooks(预留钩子)、MCP(首期 1 个)、Skill(渐进披露设计,与
.agents/skills关系待定)。 - 明确降档需主动承认:无 OS 沙箱(靠审批+危险前缀 deny)、无 Guardian AI 审、edit 委派不自研。
5 个面试戳穿点 + 诚实答法:
- 多智能体就一个调外部 CLI?→ 刻意取舍,价值在编排,编码复用成熟引擎当子代理且可逆。
- 没沙箱 prefix-deny 可绕过?→ 承认,MVP 靠审批+deny-list,OS 沙箱是明确下一档。
- 最难的编码没自研?→ 边际成本可控+可逆,能讲清 apply-patch 长尾难点。
- 跑起来了吗?→ 最危险,解法=先做能跑的纵向切片,从”设计”升”作品”。
- 记忆参数怎么来?→ 移植 grok-build 默认值+自建评测集上调过。
面试就绪路径:补完 loop 深设计 → 纵向切片跑通(loop+工具+记忆+CLI)→ 评测数字+demo → 全程档位语言。
- 标题: Harness Agent 研究知识库:Codex、OpenCode 与 grok-build 全解
- 作者: phenix-fledgling
- 创建于 : 2026-07-29 18:00:00
- 更新于 : 2026-07-30 01:00:17
- 链接: https://blog.xugua.xyz//post/Harness Agent 研究知识库:Codex、OpenCode 与 grok-build 全解.html
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。