Hindsight 多仓库记忆银行实战:Codex 动态银行 ID 配置、源码机制与验证闭环
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
让 Codex CLI 在订单服务里修一个查询 bug,注入进上下文却冒出隔壁前端项目的 pnpm lint 约定——每条记忆都真实,但全部来自错误的仓库。这就是多仓库共用一个 Hindsight 记忆银行时最典型的翻车现场。Hindsight 是面向 Agent 的长期记忆系统(记忆银行 Bank 是其核心隔离单元),本文从 Codex 集成插件的源码出发,讲清如何用动态银行 ID 实现「一仓库一银行」,团队规范又该放哪,以及隔离是否生效的验证方法。
1. 🧠 心智模型:银行是一道数据隔离墙
Hindsight 的所有写入(retain)与读取(recall)都限定在单个银行内部,数据不会跨银行流动——这是整套布局策略成立的前提。默认配置下所有 Codex 会话共用名为codex的银行;把dynamicBankId打开后,银行 ID 不再由你手写,而是运行时根据「代理名 + 工作目录名」自动派生(如codex::orders),不同仓库自然落进不同银行。布局上只有两种选择:
- 全单银行:所有项目混在一起,召回时无关内容互相竞争预算;
- 多银行:按仓库自动分库,另可加一个固定的共享银行承载跨仓库规范。
本文推荐第二种,且日常开发永远走动态派生。
2. 🚀 三步配置:让每个仓库拥有独立记忆银行
第 1 步:装好 Codex 钩子。按 Codex 集成 README 运行官方一键安装脚本(要求 Codex CLI v0.116.0+ 以支持 hooks,Python 3.9+)。安装器做三件事:把钩子脚本落到~/.hindsight/codex/scripts/、写入~/.codex/hooks.json指向脚本的绝对路径、在~/.codex/config.toml打开codex_hooks = true。
第 2 步:准备后端。接 Hindsight Cloud(填hindsightApiUrl与hindsightApiToken),或自托管:pip install hindsight-api起服务,或用 docker/docker-compose/ 下的编排文件。银行策略与后端无关,两种方式效果一致。
第 3 步:开启按仓库分库。新建~/.hindsight/codex.json(这是官方推荐的落配置的位置,跨插件升级不丢):
{ "dynamicBankId": true, "dynamicBankGranularity": ["agent", "project"] }几个影响体感的默认值,均出自插件安装时写入的 settings.json 与内置 DEFAULTS:bankId缺省"codex"、dynamicBankId缺省false、dynamicBankGranularity缺省["agent", "project"]、retainMode缺省"full-session"、retainEveryNTurns缺省10、recallBudget缺省"mid"、recallTimeout缺省 10 秒。不想碰配置文件时,也可以全部用环境变量切换,如HINDSIGHT_DYNAMIC_BANK_ID=true、HINDSIGHT_AGENT_NAME=myagent、HINDSIGHT_RECALL_TIMEOUT=30(完整映射见 config.py 中的ENV_OVERRIDES)。
3. ⚙️ 机制拆解:银行 ID 是怎么拼出来的
派生逻辑:先静态后动态
从源码 bank.py 的derive_bank_id可以看到两条路径:
- 静态模式(
dynamicBankId: false):直接返回bankId配置值,未配置则回落到"codex";若设置了bankIdPrefix,拼成前缀-bankId。 - 动态模式:取
dynamicBankGranularity列出的字段,逐段求值后用::连接。Codex 支持的字段只有四个(VALID_FIELDS):agent(配置项agentName,缺省"codex")、project(cwd的目录基名,空目录得"unknown")、session(钩子输入的会话 ID)、user(环境变量HINDSIGHT_USER_ID,未设得"anonymous")。注意源码里刻意省略了 channel 维度——Codex 是纯 CLI 工具,不存在 Telegram/Discord 式多通道路由,这个维度没有意义。
对照 test_bank.py 可以确认边界行为:agentName="mybot"且 cwd 为/home/user/hindsight时派生出mybot::hindsight;目录名含空格或 UTF-8(测试里用了西里尔字母目录)时原样保留,不做 URL 编码;cwd 为空时对应段是unknown。写进dynamicBankGranularity的非法字段不会中断流程,只往 stderr 打一条警告。
配置的加载顺序
config.py 的load_config按四层合并、后写覆盖前写:内置默认值 → 安装器写入的~/.hindsight/codex/settings.json→ 用户配置~/.hindsight/codex.json→ 环境变量覆盖。排障时记住这一点:环境变量永远赢,配置文件里改了的值可能被HINDSIGHT_*悄悄盖掉。
三个触发点与失败降级
hooks/hooks.json 注册了三个生命周期钩子,超时各不相同:
| 钩子 | 脚本 | 超时 | 动作 |
|---|---|---|---|
SessionStart | session_start.py | 5s | 探活 Hindsight 服务器,连不上就后台预启动本地 daemon |
UserPromptSubmit | recall.py | 45s | 召回相关记忆并注入上下文 |
Stop | retain.py | 30s | 把会话 transcript 写入长期记忆 |
recall.py 的链路:读 stdin 钩子输入 → prompt 不足 5 字符直接跳过 → 解析 API 地址(注意此处不允许顺带拉起 daemon,服务器没起来就安静退出)→ 派生银行 ID 并补写 mission →recallContextTurns > 1时读 transcript 组装多轮查询 → 按recallMaxQueryChars(默认 800)截断 → 调 recall(默认 10 秒超时)→ 结果过recallMinScores地板过滤(缺失分数放行,即 BM25-only 命中不会被误杀)→ 用<hindsight_memories>包裹,经hookSpecificOutput.additionalContext注入。无论发生什么异常,退出码恒为 0——记忆系统故障永不阻塞你的对话。
retain.py 的链路:读 transcript → 按retainEveryNTurns做门控(用本地 turn 计数器取模,不满 N 轮直接跳过)→chunked模式按N + retainOverlapTurns取重叠窗口 → 组装 transcript → 派生银行 ID → 调 retain。文档 ID 默认取session_id,同一会话重复 retain 是 upsert 而非新增;chunked模式才追加毫秒时间戳区分文档。retainTags/retainMetadata支持{session_id}、{bank_id}、{timestamp}三个模板变量。
另外,bankMission只在银行首次使用时写入一次(本地状态文件bank_missions.json记录已设置名单,超过 1 万条自动裁半),避免每次钩子都发一次写请求。
4. 📥 该往银行里放什么:内容取舍
分库的收益取决于库里存了什么。默认retainMode: "full-session"会在会话收尾时 retain 整份 transcript,由 Hindsight 负责抽取事实——你不需要手动写记忆,只需要让「值得说的内容」在会话里被说出来。回报最高的是四类:
- 仓库约定:这个项目的真实规则。例如「SQL 统一走 sqlc 模板生成,禁止 ORM 层」「前端包管理只用 pnpm + Turborepo,不手写 npm scripts」。每次新会话都要重新解释一遍的东西,就该沉淀。
- 已知脆弱区:以反直觉方式坏掉的地方。例如「staging 重跑迁移前必须手动执行 0042 补丁脚本」「webhook 消费端上游有 3 秒超时,重试逻辑必须幂等」。一条「内有恶龙」的备注,能拦住 Codex 用踩坑的方式重新撞一遍。
- 历史排障:根因故事比修复动作更值钱。例如「网关 502 的根因是空闲连接耗尽,调大 max_idle_conns 后解决」——复发性问题回来时,一次召回就抵得上一轮完整 debug。
- 工程决策:为什么重试要指数退避、为什么消息队列选了 NATS 而不是 Kafka。决策从 diff 反推成本很高,召回几乎零成本。
反面清单同样明确:一次性命令、临时草稿、跑通即弃的实验代码,不值得占用召回预算。这四类取舍的实际用途是帮你识别一次有价值的会话——约定和决策真的被讨论出来的会话,才配得上被整段保留。
5. 🤝 进阶:跨仓库规范用固定共享银行
按仓库隔离是默认,但有些知识天然跨边界:组织级 commit 规范、共享 CI 流水线、安全评审要求、全员依赖的内部 SDK。把这类内容塞进某个仓库的动态银行里,其他仓库永远召回不到;正确做法是给它们一个固定银行。在共享场景的配置里关掉动态派生、写死银行名:
{ "dynamicBankId": false, "bankId": "acme-platform" }指向同一bankId的银行是共享的——一位同事的 Codex 往里 retain 的平台规范,另一位同事的 Codex 会话可以直接召回。实用布局由此变成两层:日常开发走动态派生的按仓库银行,真正跨切的标准走一个具名共享银行。别贪心把动态银行也顺手指向共享名,否则第 1 章讲的隔离墙就没了;全共享的单一银行只适合「个人全局习惯」这种极少数场景,不适合一组异质代码库。
6. ✅ 验证序列与踩坑清单
一套可复现的四步验证,直接检验隔离是否成立:
- 在
orders仓库里让 Codex 明确说出一个决策(比如「为什么订单事件用 NATS」),确保它被讲清楚了; - 结束会话,让 transcript 被 retain(
full-session模式下这一步发生在会话收尾); - 在同一仓库开新会话,问同样的问题——应召回第 1 步的决策;
- 在
dashboard仓库开新会话问同样问题——不应冒出orders的答案。
第 3 步命中、第 4 步干净,说明布局正确。诊断分岔:第 3 步落空时,两次运行大概率派生了不同银行 ID——把HINDSIGHT_DEBUG=true打开,对照 stderr 里Retaining to bank '...'的实际值;第 4 步泄漏时,先确认dynamicBankId真的为true,再检查是否有HINDSIGHT_BANK_ID环境变量在第四层覆盖掉了你的配置。
高频踩坑点,按出现频率排:
- 一直不拆库:
bankId默认"codex",不开动态派生时所有仓库共享它,项目一多必然噪声召回; - 团队规范放错层:跨切约定只存在于某个仓库的银行里等于不存在,该去固定共享银行;
- 反向期望跨库召回:隔离是严格的设计目标,
orders的银行天生看不到dashboard的记忆,不要试图「顺便」召回; - 会话没收尾就验证:
full-session模式下中途去查,transcript 还没落库;retainEveryNTurns缺省是 10,测试期可临时设为 1 让每轮 Stop 都触发 retain,测完记得改回。
7. ❓ FAQ
必须用 Hindsight Cloud 吗?不用。自托管hindsight-api或本地hindsight-embeddaemon 行为一致,银行策略与后端解耦。自托管入口见 docker/docker-compose/ 与官方文档 hindsight-docs/docs/。
按仓库银行和共享银行怎么选?按用途分层:项目私有的约定、排障、决策进动态派生的仓库银行;必须跟着你走进每个仓库的平台规范进固定共享银行。两者不冲突,可以并存于不同集成配置里。
仓库银行的命名规则是什么?开启dynamicBankId后由dynamicBankGranularity派生,默认「代理名::目录基名」,如codex::orders。想区分多个人在同一仓库的记忆,把user加进粒度并设HINDSIGHT_USER_ID即可。
哪些内容不该 retain?临时草稿、一次性命令、跑完即弃的探索。它们不产生复利,却会持续稀释召回精度。
结语
把dynamicBankId打开,Codex 的每个仓库自动拥有私有记忆;再为跨仓库规范配一个具名共享银行,就是多仓库工作下最稳的记忆布局。隔离、沉淀、验证三步做完,记忆系统才从「能跑」变成「可信」。
延伸阅读:
- hindsight-integrations/codex/README.md——完整配置表、默认值与排障
- hindsight-integrations/codex/scripts/lib/bank.py 与 tests/test_bank.py——银行 ID 派生逻辑及行为断言
- hindsight-integrations/codex/scripts/recall.py 与 hindsight-integrations/codex/scripts/retain.py——召回与保留钩子的完整链路
- hindsight-integrations/codex/scripts/lib/config.py——配置加载顺序与环境变量映射
- 需要通读全部代码时,可克隆仓库:
git clone https://gitcode.com/GitHub_Trending/hindsight2/hindsight
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考