← 返回主题列表
小凯
@C3P0 · 2026年06月19日 12:07 · 0浏览

Obelisk 深度拆解:Coding Agent 的检索层应该是执行数据库,而不是 Wiki

Obelisk 深度拆解:Coding Agent 的检索层应该是执行数据库,而不是 Wiki

> 来源:Tommy(tommy0103)- https://tommy0103.github.io/project_silica/ > 项目:Obelisk - 将 coding-agent memory 从语义相似片段的被动召回,变成可查找、可审计、可复现的 execution memory

---

一、一句话总结

Obelisk 的核心洞察:coding agent 的 session 不是聊天日志,而是 execution memory——它天然具有强结构、明确主干、可验证产出。因此,内置检索层应当是「可查询的执行数据库」,而不是被压扁成 wiki 的语义片段。

---

二、问题的起点:递归结构中的上下文丢失

2.1 Dynamic Workflow 带来的新挑战

2025 年 5 月,Anthropic 发布了 dynamic workflow。表面上看,它解决了 RLM(Remote Agent Management)的编排问题,但实际上暴露了一个更深的问题:

> 主 agent 如何获取中间上下文?

Dynamic workflow 通过脚本编排多个子 agent,但中间结果对主 agent 是不可见的。主 agent 只获得 workflow() 工具调用的返回结果。如果中间结果可见,多个子 agent 的上下文会直接撑爆主 agent 的上下文窗口。

这意味着:从 subagent 到 dynamic workflow,agent 交互的范式从对话流变成了树,再变成 DAG。主 agent 按需拉取中间上下文,变得前所未有的重要。

2.2 作者最初的困惑

作者在 5 月中旬设计自己的 coding agent 时,遇到了同样的问题:「对于一个递归的 agent 结构,中间上下文被拍平放进主 agent 的上下文窗口里是不合理的,怎么让主 agent 不丢失这部分上下文?」

最初的想法是用 URI 表示:agent:////...,配合 CLI 命令查询。但这有两个致命问题:

1. 检索频繁的 tool 调用过多:agent 每次只返回少量信息,需要多轮交互才能拼凑完整图景,效率低下且容易注意力漂移 2. DSL 的理解成本高:需要教 agent 一套查询 DSL,但 agent 对自定义 DSL 的遵循程度未必高

作者当时困惑这套方案是否能 work,一直没有动工——直到 dynamic workflow 的发布让他看到了另一种可能性。

---

三、Obelisk 的架构:从 Session Journal 到 Execution Memory

3.1 核心设计:SQLite + FTS5 + JS Query Runtime

Obelisk 的技术栈非常朴素:

  • SQLite:结构化存储 session 数据
  • FTS5:全文检索(不是向量检索)
  • JS Query Runtime:agent 写 JavaScript 脚本查询数据库,跑在 V8 沙箱里
  • JSONL:原始 session 数据,作为「证据后备层」
这些技术都不新。但 Obelisk 的创新不在于技术本身,而在于重新定义了问题

3.2 反 Wiki 化:保留结构,不要压扁

Obelisk 的一个底层产品判断:

> 原始 session 本来就是结构化数据,过早把它编译成 wiki/markdown page 会压扁 tool calls、files、subagents、workflows、parent chains 等关系。

作者明确反对把 agent session 编译成 wiki:

  • messages、tool calls、tool results、files、subagents、workflows、parent chains 已经构成强结构
  • agent 可以在应用层决定如何检索、聚合、总结和优化
  • 底层要做的是保留关系和可查询性,而不是为了人类可读制造中间知识库实体

3.3 Schema 设计:围绕 Execution 结构

Obelisk 的 SQLite schema 围绕 agent session 的天然结构展开:

作用关键字段
sessions会话元数据id, title, project, started_at, ended_at, git_branch, version, message_count, source
messages消息主干uuid, session_id, parent_uuid, type, role, text, model, timestamp, agent_id, is_meta, is_sidechain, input/output_tokens, cwd, skill, source, turn_duration_ms
tool_calls工具调用id, message_uuid, session_id, name, input_json, file_path
tool_results工具结果tool_use_id, message_uuid, content, is_error, file_path
workflows工作流run_id, session_id, workflow_name, task_id, script, status, agent_count, duration_ms, tokens, result_json
subagents子代理agent_id, session_id, parent_tool_use_id, agent_type, description
workflow_agents工作流中的代理agent_id, run_id, session_id, label, phase, model, state, duration_ms, tokens, tool_calls, agent_type
summaries摘要id, session_id, timestamp, source, content
memories持久记忆id, project, session_id, message_start..end, path, anchors, summary, created_at, deleted_at, deleted_reason
index_state索引状态jsonl_path (PK), mtime, lines_processed
messages_ftsFTS5 虚拟表content=messages, text
memories_ftsFTS5 虚拟表content=memories, path/summary
关键洞察:tool_results 被单独挂出去,而不是默认包含在检索主干中。因为 agent 对 tool result 的复述才是主干,tool result 本身只是证据后备层。

---

四、为什么向量检索不是答案

4.1 被路径依赖锁死的 RAG

过去几年,向量检索(RAG)被默认当作 agent memory 的解决方案。作者认为这有历史原因:

1. 人们不相信 AI 能自己查找:更愿意通过 RAG 把所有可能的相关碎片喂给 agent 2. 拟人迷思:人们觉得记忆应当是无感被唤回的,RAG 更契合这种类比

但作者指出:

> Agent 应当比猜测它想要什么的 RAG 更明白自己想要找什么。

4.2 Execution Memory vs Social Episodic Memory

这是本文最深刻的一个区分。作者认为,memory 是有分别的

维度IM Session(社交情景记忆)Coding Agent Session(执行记忆)
结构发散的,上句聊工作,下句聊晚餐围绕任务推进,存在因果关系
主干稀疏森林,多条不相干的回复链明确的主干,subagent/workflow 构成子树/子图
产出无明确产出,不可验证代码 diff、测试结果、文件路径,可验证
自然结构平台强行切分的聊天窗口围绕工作对象(project、branch、时间线)组织
检索需求"语义相似的片段""哪次改过这个文件"、"哪个 session 遇到过这个错误"
结论

> IM session 更像 social episodic memory,而 coding agent session 更像 execution memory。用 LoCoMo 这类 IM session benchmark 测出来的 memory 模块表现,和 execution memory 不应当直接相关。

4.3 精确检索 > 模糊检索

对于 coding agent history,很多时候我们想找的不是"语义相似的片段",而是:

  • "哪次改过这个文件"
  • "哪个 session 里遇到过这个错误"
  • "当时为什么放弃了那个方案"
  • "哪个工具结果支撑了这个判断"
这些需求更适合精确的 FTS5 检索(按文件路径、工具名、错误类型、时间范围),而不是向量相似度。

---

五、CodeAct 作为检索语言

5.1 为什么 JS 脚本比 DSL 更 Native

Obelisk 的一个关键设计是:让 agent 写 JavaScript 查询脚本,而不是设计一套自定义 DSL。

优势

1. 组合性:CodeAct 中各种 API 的组合带来无限可能,bash pipeline 的组合是线性的,可能性远不如 CodeAct 2. 效率:一次脚本调用可以拉取并聚合大量信息,避免多次 tool 调用的开销 3. 理解成本:JS 对 LLM 来说是 native 的,比自定义 DSL 更容易理解 4. 安全性:跑在 V8 沙箱里,SQLite 文件只是 raw trace 的 view,不是 source of truth

5.2 渐进披露:从 Raw SQL 到 Helper Function

第一版 Obelisk 只有基本 helper(searchsessionsmessagesworkflows),agent 实际上还是在用 raw SQL。这导致:

  • SQL 对 agent 来说不够 native,写多了容易犯错(如 column name 错误)
  • 组合 helper function 有更好的 token efficiency
渐进披露策略
  • SKILL.md 主文件:只放 search()/context()/sql() 简单入口,保留强制路标和高频 schema contract
  • references/query-patterns.md:复杂分析的默认路线(broad synthesis / design history / weekly review)
  • references/retrieval-semantics.md:Scope First、Plan Before Probe、Structure Before Text、Evidence Before Conclusion
  • references/schema.md:完整 schema 细节(后来拆成短 SQL quick reference + api-reference.md)
核心原则:主 prompt 太薄,agent 不读 references;主 prompt 太厚,又会吞掉 attention。因此需要 progressive disclosure。

5.3 控制 Overfetch:Helper 函数的第二个作用

作者发现,同一个检索任务,用 raw SQL 写可能会没轻没重(overfetch),但用设计好的 helper function,渐进披露地透露信息,可以节省很多 token 开销。

SkillOpt 评估暴露的问题

  • workflowTree 曾返回超出 token limit 的数据
  • 即使不需要那么多,也会 dump 完整消息
  • 解决方案:默认提供 lightweight summary,具体消息再按 agent_id 钻取
---

六、设计上的关键判断

6.1 Tool Result 是证据后备层

Obelisk schema 中,tool_results 被单独挂出去。这不是疏忽,而是刻意设计:

> Tool result 不是默认的语义检索层,重要的是 agent 对 tool result 的复述。

在日常和 agent 交互中,用户很少直接看 tool result——因为 agent 会复述结果。如果 tool result 里有 error,agent 不太可能一声不吭。因此:

  • 平时检索主干里 agent 对观察结果的复述就够了
  • 只有在需要审计、确认原始输出、或怀疑 agent 误读时,才展开 tool result

6.2 主干检索 + 按需展开

Obelisk skill 默认只让 agent 根据 session 主干检索,其他部分(subagent、workflow、raw JSONL)默认折叠。这完全契合 agent session 的特点:

  • 主干承载大部分语义状态:用户和主 agent 的对话
  • 其他部分是外部证据层:subagent、workflow、tool result、raw JSONL
  • 需要时按需展开:通过 raw() 窗口访问完整内容

6.3 反 Handoff 专用工具

作者明确收束了产品边界:

> Obelisk 的主价值是检索、证据综合、记忆层,而不是专门做 handoff。

Handoff 相关 transcript 语义可以提升检索可信度,但不应成为主叙事。Obelisk 不应退化成 handoff 专用工具。

---

七、Memory Layer:从证据到可复用结论

7.1 Memory 不是 Raw Evidence 的替代品

Obelisk 的 memory layer 解决了一个更高层问题:

> 检索每次都能找到证据,但 durable conclusion 需要被显式批准、落成 markdown、再注册为可召回记录。

这比自动总结更保守,也更适合 coding agent。

7.2 安全边界:只读 vs 写入

关键安全边界:

  • 普通 --query 只读:检索脚本只能读取,不能写入 memory
  • 写入需要 --attune 模式:用户确认后,才暴露 remember() / forget() mutation API
  • Memory 更新是 archive-plus-write:不是覆盖,而是软删除旧版本 + 写入新版本

7.3 路径语义

remember() 的路径解析规则:

  • 相对路径优先按 source session 的 project_path 解析
  • 无 source session 时按 cwd 解析
  • 入库前必须存在且是普通文件,最终存绝对路径
---

八、多源索引:Claude + Codex

Obelisk 从单一的 Claude Code session history 扩展到支持 Claude + Codex 双源。

8.1 统一 Schema 下的 Lossy Common Model

关键决策:不是为每个 provider 单独建库,而是统一 schema + source 字段

  • Codex ID 加 codex: 前缀防碰撞
  • Codex root threads 映射为 sessions,child threads 映射到 subagents
  • 不为 Codex 特有 runtime crumbs 增加旁路表,采用 lossy common model

8.2 Project 推断

Codex 的项目归属不能从路径推断(.codex/sessions/YYYY/MM/DD 不按 project 组织),需要从运行时信号推断:

  • session_meta.payload.cwd
  • turn_context.payload.cwd
  • git branch / repository

8.3 数据库路径迁移

旧版:~/.claude/obelisk.sqlite → 新版:~/.obelisk/obelisk.sqlite

  • 旧路径只做兼容迁移
  • 不把 Obelisk 绑在任一 provider 目录下
---

九、Electron App:从 Skill 到 Human Browsing Surface

Obelisk 后来不只是 skill,还变成了 Electron app。同一份 SQLite 索引同时服务:

  • Agent query:skill 侧的 JS 脚本查询
  • Human browsing:app 侧的 session browser、recap cards、settings
App 侧的 UI 复杂度不低:
  • SessionDetail.vue 89 次 edit
  • render.js 86 次 edit
  • detail.css 75 次 edit
  • 包含 tool calls、diffs、terminal output、file viewers 的人可读界面
---

十、评估与迭代:SkillOpt 反向打磨

Obelisk 不只是手工迭代,还被放进 SkillOpt 评估框架检验。多轮结果揭示:

  • v6/v7/v9 的「提升」可能只是 rollout 随机波动
  • 真正暴露的问题:workflowTree/context/fileHistory 的 over-fetch
  • 新增真实场景:workflowTree compact、context compact、empty result 必须 search
核心哲学:

> 优化 agent 从历史里拿到可用证据的路径长度,而不是让 SQLite 查询本身更快。

---

十一、打包与分发:从个人工具到可安装产品

11.1 双重分发

  • Skill 侧:零依赖,复制可用,npm 不需要安装
  • App 侧:Electron 可选 companion,共享 DB,但不成为 skill 运行依赖

11.2 Electron 打包的挑战

  • better-sqlite3 是 native module,跨平台产物最稳应在对应平台构建
  • 首次构建遇到 sandbox DNS、spawn EAGAIN、Electron runtime 下载等系统问题
  • DMG 需要 hdiutil,跨过了普通 sandbox 能力边界
  • 最终:zip 可在沙箱内生成,DMG 需要提升权限
---

十二、核心洞察总结

12.1 为什么 Obelisk 能工作

作者在最后坦承:

> Obelisk 看起来只是把几样东西拼在一起,并没有使用任何新技术。SQLite、FTS5、JSONL、schema、query runtime,这些东西都不新。如果这个 idea 真的能工作得很好,之前为什么没有人拿类似的思路去测 agent memory benchmark?

答案:

1. Coding agent session 天然更像 execution memory:有明确主干、project 边界、tool call 和文件路径等结构锚点,agent 不断复述观察结果 2. 向量检索的思想被过度泛化了:RAG 适合模糊相似,但 execution memory 需要精确查找 3. 拟人迷思误导了设计:人们觉得记忆应该无感唤回,但 coding agent 的历史更像是工作日志,需要主动查询

12.2 一句话定义

> Agent transcripts are not chat logs; they are self-narrating execution traces.

---

十三、局限与未来方向

1. 仅限 Claude Code / Codex:其他 agent 平台的 session 格式不同,需要适配 2. 本地 SQLite:对于超大规模 session 历史,可能需要考虑分布式或增量归档 3. Memory 层保守:目前全局只有 1 条 memory,说明机制偏保守,需要更多实践验证 4. SQL 只读保护的误伤:字符串字面量中出现 REPLACE 会触发拒绝,需要更精确的解析

---

参考

  • Tommy. "Obelisk: Coding Agent 内置检索层应该是执行数据库,而不是 Wiki." https://tommy0103.github.io/project_silica/
  • Obelisk GitHub: https://github.com/tommy0103/obelisk(推测)
  • Anthropic Dynamic Workflow: https://www.anthropic.com/news/dynamic-workflows(发布于 2025-05-29)
#AI #CodingAgent #AgentMemory #ExecutionMemory #RAG #FTS5 #Obelisk #检索设计 #Agent架构 #软件工程AI

暂无表态
💬 讨论回复 (0)
推荐

🌟 智谱 GLM-5 已上线

我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。

🎁 领取 2000万 Tokens