Codewhale Workflow 外部记忆(External Memory)设计边界:基于 v0.9.0 Cutline 的层划分、可见性与权限原则
【免费下载链接】CodewhaleOpen-source coding agent for your terminal, built in Rust and on a journey of continuous community improvement. Issues and PRs welcome.项目地址: https://gitcode.com/GitHub_Trending/de/Codewhale
本文解读 CodeWhale 开源仓库中的设计文档 docs/rfcs/WORKFLOW_EXTERNAL_MEMORY.md。该 RFC 回答了一个关键架构问题:当 Workflow(工作流)系统演化到 v0.9.0 之后,跨长时运行的外部记忆(External Memory)应该如何被引入。它是一份设计边界(design boundary)而非运行时实现——先划定"什么该做、什么绝不该做",再谈代码。读完本文,你将理解:外部记忆为何必须保持可选与显式、它与现有 User Memory / Repo Search / RLM Memo / TraceStore / Cached-main 五条记忆与回放层的边界划分、可见性与权限的硬性要求,以及未来实现应遵循的落地路线。
文档定位:原则优先的 Cutline
文档自注为"Principle-only cutline",状态标注日期 2026-07-15,并在 v0.9.0 依然有效。它开宗明义地划清了"已经存在"与"仅被提议"的边界:
- 仓库中已经存在:用户记忆(
/memory命令与remember工具)以及 RLM 会话(见 docs/MEMORY.md、docs/ARCHITECTURE.md); - 仅被提议、尚未进入代码树:层边界表格中出现的 TraceStore、ARMH/RLM memo store、cached-main overlay 等机制名称。
这一点提醒读者:本文引用到的多数分层表格属于未来的演进路线图,真正的落地必须逐个经过设计与评审,而不是一蹴而就。把"原则"与"现状"区分开,是理解该 RFC 的前提。
核心决策:外部记忆必须可选、显式、可审计
RFC 的Decision章节给出 v0.9.0 之后不可动摇的底线:
外部记忆应保持可选(optional)与显式(explicit)。CodeWhale 的正常运行不能依赖它,Workflow 不得为长时运行静默开启外部记忆。
在此基础上,未来版本中外部记忆只能以三种形态出现:
- 显式的工作流节点(explicit workflow node)——其输入、输出、作用域与权限都在类型化的 Workflow IR 中可见;
- 可选的插件或技能(skill)驱动的工具——由用户刻意启用;
- 有文档记录的实验(documented experiment)——其状态可被检查、清空与导出。
同时它被明确排除在三种角色之外:
- 不能是隐藏的上下文基底(hidden context substrate);
- 不能是仓库搜索的替代品;
- 不能是每次工作流运行的默认后备存储。
为什么"显式节点"是一个硬约束:类型化 IR 佐证
"输入、输出、作用域与权限在类型化 Workflow IR 中可见"这一要求并非空话。Workflow 引擎的核心 crate crates/workflow/src/lib.rs 维护着 Rust 侧的类型化 IR 边界,其 crate 注释明确写道:运行时工具暴露、worktree 应用、回放与模型执行,只有在取消与证据(evidence)语义被证明之后,才允许叠加在其上(见crates/workflow/src/lib.rs顶部文档注释)。WorkflowSpec携带nodes: Vec<WorkflowNode>,WorkflowNode枚举统一建模顺序、分支、循环、展开等各类节点,并有专门的校验函数把关节点形态。
也就是说:如果未来要引入外部记忆,就必须先把它提升为一等公民的 IR 节点,让validate_workflow_nodes之类的校验路径能看到它的存在——这与"隐藏检索(hidden retrieval)藏在普通 prompt 背后"的形态针锋相对。同样的思路也体现在实验性搜索模块 crates/workflow/src/experimental_search.rs 中:它自称是"authoring and freeze boundary,而非新的运行时或调度器",并强调 worker 自报结果永远不会被提升为硬门禁证据——防止把不可审计的隐式通道悄悄变成系统默认行为。
层边界:六层记忆与回放如何分工
RFC 的核心是一张层边界表,把外部记忆与既有/规划中的记忆和回放层彻底剥离开。这张表是全文的骨架,逐层说明如下(保留原始英文层名以便对照源码):
| 层 | 作用域 | v0.9.0 之后的规则 |
|---|---|---|
| User memory(用户记忆) | 由/memory呈现的小型持久化用户偏好与事实 | 可选开启、归用户所有、不作为工作流证据 |
| Repo search / codemap(仓库搜索/代码地图) | 从仓库派生的结构与搜索结果 | 可由工作区重建;不是记忆日志 |
| ARMH/RLM memo(会话内记忆) | 会话内工作记忆与精确上下文记忆化 | 命中/未命中遥测可见;不构成持久回放证据 |
| TraceStore | 记录工作流、分支、叶子与控制结果 | 确定性回放的来源;回放期间不做实时模型调用 |
| Cached-main overlay(缓存主分支覆盖层) | 经评审与回放后沉淀的经验 | 可检查、可回退;绝不改写 Git main |
| External memory(外部记忆) | 常规上下文之外的本地或插件支撑的大数据 | 仅限显式节点/插件;必须可见且可清空/导出 |
User memory:今日唯一的记忆实现
表格中的 User memory 是仓库中真实存在的部分。系统文档 docs/MEMORY.md 说明:自 v0.9.4 起,原生记忆存储(native memory store)是唯一的记忆系统——以 Markdown 文件为持久源、由 SQLite FTS5 做全文索引,完全离线,按仓库 git origin 的哈希划分作用域。
- 启用方式:环境变量
DEEPSEEK_MEMORY=on(真值:1/on/true/yes/y/enabled),或在~/.codewhale/config.toml写入[memory] enabled = true; - 目录布局:
~/.codewhale/memory/global/MEMORY.md(全局)+workspace/<id>/MEMORY.md(仓库级)+ 可重建的index.sqlite3FTS5 缓存; - 注入策略:启用后系统提示词携带**有边界、带出处(provenance)**的记忆块(最多 32 条 / 12,000 字符,global + 当前 workspace),并明确标记为"不可信用户数据"而非第二指令层;更深层检索通过
memory_search/memory_get工具完成; - 写入方式:
#前缀的 composer 输入、/memory native remember子命令、以及模型侧自动化的remember工具(JSON schema 见 docs/MEMORY.md)。
这与 RFC 中 User memory 的定位完全一致:"Opt-in、用户所有、不作为工作流证据"。它服务于跨会话的偏好与约定(如"本仓库用 4 空格缩进"),而不是被 Workflow 当作隐含证据源。
ARMH/RLM memo:可见的命中/未命中遥测
表格要求 ARMH/RLM memo(会话内工作记忆与精确上下文记忆化)提供可见的命中/未命中遥测,且不构成持久回放证据。
"可见遥测"在 IR 中已有对应数据结构:crates/workflow/src/lib.rs中的WorkflowMemoUsage携带armh_hits、armh_misses、armh_saved_estimated_tokens以及 provider prompt-cache 的命中/未命中计数(见crates/workflow/src/lib.rs的WorkflowMemoUsage定义与add_assign聚合逻辑)。这些字段随LeafResult一起被记录,使得"某个叶子节点是否真的从记忆化中获益"可以量化——这正是 RFC 反复强调的可解释性在数据结构层面的落地。
另一方面,RLM 会话(persistent Recursive Language Model REPL 会话)今天已经存在于仓库中,docs/ARCHITECTURE.md 将其描述为"沙箱化 Python REPL,支持语义化辅助调用与var_handle输出"。RFC 的 status 注记特意澄清:目前树中只有 user memory 与 RLM 会话,ARMH/RLM memo store 本身仍是提案。
TraceStore:确定性回放的证据源
TraceStore 的规则是"记录工作流、分支、叶子与控制结果,作为确定性回放的来源;回放期间不进行实时模型调用"。
尽管 TraceStore 尚未进入代码树,但其回放契约在 crates/workflow/src/replay.rs 已有扎实的雏形:
WorkflowReplayTrace由trace_id、leaf_records(ReplayLeafRecord:叶子输入哈希 + 结果)与control_records(ReplayControlRecord:控制节点结果与生成节点)组成;WorkflowReplayExecutor以这些记录为输入重放执行;- 关键选项
ReplayOptions { allow_live_replay: bool }默认关闭(见crates/workflow/src/replay.rs),即默认不允许实时(live)回放——与 RFC"回放期间不做实时模型调用"互为表里:回放应当只依据已记录的证据复现结果,而不是重新烧钱调用模型。
Cached-main overlay:可回退、绝不写 main
该层承载"经评审与回放后沉淀的经验/教训",但要求可检查、可回退、绝不改写 Git main。它把"经验沉淀"与"真实仓库状态"彻底隔离:任何从运行中提炼出的改进,都要先落在这个可逆的 overlay 上,经人工/门禁评审后再走正常合入路径。
外部记忆:行尾的"新层"
外部记忆在表中是独立一行:作用域为"常规上下文之外的本地或插件支撑的大数据",v0.9.0 之后的规则是仅限显式节点/插件,必须可见且可清空/导出。把这一行放在表格末尾,语义很清楚:它是将来要加的第七层,而不是对既有六层的暗中替换。
可见性要求:把记忆做成"活动的上下文层"而非"直觉"
RFC 给出任何未来外部记忆实现都必须对外展示的六项信息:
- 何时处于激活状态;
- 由哪个工作流节点或插件拥有它;
- 状态存储在哪里;
- 它能读取哪些仓库或运行作用域;
- 它是否被纳入回放、导出或晋升(promotion)证据;
- 如何检查、清空、固定(pin)与导出它。
原文接着给出了一个判定准则,值得原样保留:
UI 应把外部记忆当作一个活动的上下文层来对待,而不是当作看不见的模型直觉。如果一次运行无法解释某条事实为何来自外部记忆,那么这个功能就没有准备好作为默认使用。
这条"解释性原则"是全文档最具操作性的验收标准:任何记忆引入,只要无法在运行结束时间答"这条事实从哪来",就应视为不成熟。它与前文 IR 中的memo_usage遥测、TraceStore 的ReplayLeafRecord输入哈希是一脉相承的——CodeWhale 的记忆哲学是用出处与可观测性取代"黑盒直觉"。
权限与隐私:继承最严格的相关作用域
外部记忆必须默认采用最严格的适用作用域,RFC 列出四条硬约束:
- 不得跨越仓库/工作区边界,除非获得显式批准——对应 docs/MEMORY.md 中已有实现的隐私设计:workspace 记忆以 git origin 的哈希为 key,一个仓库的笔记不会泄漏进另一个仓库的 prompt;
- 项目本地配置不得静默启用宽泛的外部记忆读取——防止仓库内一个
.toml就把用户本机大范围数据卷进上下文; - 回放必须把外部记忆输入记录为证据,或将回放标记为不可用/已分叉(diverged)——这与 replay.rs 中"依据输入哈希 + 记录结果重放"的模型一致:证据链缺失时宁可声明"回放不可用",也不能用猜测补齐;
- 导出必须让外部记忆的引用可见,但默认不得倾倒私有的原始状态——即"导出引用、遮蔽原始数据"。
推迟的工作与落地顺序
RFC 明确列出 v0.9.0 cutline 范围内不做的五件事,防止范围蔓延:
- 默认开启的 Aleph 风格记忆(对所有 Workflow 运行);
- 从外部记忆自动晋升进 cached-main overlay;
- 在普通 prompt 背后做隐藏检索;
- 托管式或共享式外部记忆服务;
- 把外部记忆当作 TraceStore 回放的替代品。
最后,RFC 给出了明确的未来实施顺序建议:
未来的实现应先从一个只读的类型化工作流节点与一个mock 回放夹具(mock replay fixture)开始,然后再加入任何插件支撑或实时检索路径。
这条路线与 Workflow crate 的现状高度吻合:目前 crates/workflow/src/lib.rs 中已经存在以 mock 叶子结果(leaf_outcomes映射等)驱动执行器的测试脚手架,而 crates/workflow/src/replay.rs 提供了类型化的 trace/record 结构——两者共同构成"先只读节点、先 mock、再谈真实检索"的天然试验台。此外,相关演进在根 CHANGELOG.md 的 v0.9.0 阶段记录中亦可见端倪(例如叶子/控制节点结果记录朝向 TraceStore 契约的方向,以及"外部记忆保持可选、显式、可见、可清空/导出,而不是成为隐藏的默认上下文基底"的表述)。
总结
WORKFLOW_EXTERNAL_MEMORY这份 RFC 的独特价值,在于它用最小的篇幅划定了一条最清晰的架构红线:
- 记忆要分层:User Memory 管用户偏好、Repo Search 管可重建事实、ARMH/RLM Memo 管会话内记忆化(带命中遥测)、TraceStore 管确定性回放、Cached-main 管可逆经验沉淀——各司其职,互不越界;
- 外部记忆要显式:只能是类型化 IR 节点、用户刻意启用的插件/技能工具、或有完整可观测性的实验;
- 一切要可审计:激活状态、属主、存储位置、作用域、证据参与、检查/清空/导出路径缺一不可;
- 数据要守界:跨仓库需批准、本地配置不得静默放权、回放证据链断裂即声明不可用、导出不泄私密原始态。
对于希望参与 CodeWhale 演进(Issues / PRs 欢迎)的开发者,这份文档给出了进入门槛最低的起点:在真实代码库中先建立只读节点与 mock 回放验证,再谈任何插件或实时检索。对使用者而言,它也意味着一个稳定的承诺——无论未来记忆能力如何扩展,默认的、显式的、可解释的 CodeWhale 运行方式不会因为新增记忆层而悄悄改变。
【免费下载链接】CodewhaleOpen-source coding agent for your terminal, built in Rust and on a journey of continuous community improvement. Issues and PRs welcome.项目地址: https://gitcode.com/GitHub_Trending/de/Codewhale
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考