给 DeepSeek Harness 装上代码库的持久记忆:Hindsight Coding Agents 集成实战与源码解析
2026/9/13 19:51:48 网站建设 项目流程

给 DeepSeek Harness 装上代码库的持久记忆:Hindsight Coding Agents 集成实战与源码解析

【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight

本篇文章讲解如何为 DeepSeek Harness(dsh,一个基于 Cordis 插件框架的编码智能体)接入 Hindsight 的长期记忆能力:一条命令完成原生 Cordis 插件安装,让仓库的 git 历史与对话在后台自动沉淀为记忆库,并在下一次会话开始时被自动召回。读完本文,你将掌握安装、内存后端选择、配置分层、按仓库路由记忆库的原理,以及hindsight_*工具集在 dsh 生命周期事件中的真实接线方式。

为什么编码智能体最需要记忆

以离散会话工作的智能体擅长专注,却天然缺乏连续性——每一次新会话都要重新理解你的技术栈、重新踩一遍同样的坑、重新问一遍你已经回答过的问题。正如 hindsight-docs/blog/2026-08-14-deepseek-harness-memory.md 指出的:大部分真实修复可以从代码推导出来,但"最后一公里"往往取决于完全不在代码里的项目级决策——一个舍入规则、一份重试白名单、一条命名约定、一个平局裁决标准。这些决策存在于 git 历史和过往对话中,记忆的作用就是把它们放回智能体开始工作时的面前。

DeepSeek Harness 的插件优先设计("everything is a plugin")恰好给了解决途径:既然一切皆插件,那么给 Harness 补上记忆这件事,也可以用一个插件完成,而不是引入额外的 MCP 服务器或外部进程。本项目通过 hindsight-integrations/coding-agents 包实现这一点——一个共享的"反射 + 注入"核心,为每个智能体提供极薄的接入入口。

安装:一条命令

Harness 把一切视为插件,因此集成本身也是一个插件。安装并接线dsh只需:

npx @vectorize-io/hindsight-coding-agents install dsh

该命令会在$DSH_HOME/cordis.patch.yml(默认~/.dsh)中注册一行 Cordis 插件记录,被每个dshprofile 组合加载,使用原生工具而非 MCP。安装时终端会询问记忆存放在哪里——Hindsight Cloud、你自建的服务端,或本机本地守护进程——只需选择一次。脚本化安装可改用--server cloud|self-hosted|daemon参数:

npx @vectorize-io/hindsight-coding-agents install dsh --server cloud --api-token <token> npx @vectorize-io/hindsight-coding-agents install dsh --server self-hosted --api-url http://localhost:8888 npx @vectorize-io/hindsight-coding-agents install dsh --server daemon

安装器把运行时复制到~/.hindsight/coding-agents,再指向各智能体的接线,因此与你在哪里执行命令无关;它是幂等的(重复执行安全),会为触碰过的文件保留.hindsight-backup备份,uninstall只移除自己的条目。日常更新也无需额外操作:默认开启的autoUpdate会让每次会话启动时在后台检查 npm 并重新暂存较新版本;想固定版本可设"autoUpdate": false

如果偏好从已发布包安装,官方还提供了dsh plugin --profile web add @vectorize-io/hindsight-coding-agents这条等价路线——包内自带 profile 补丁层(见 cordis.patch.yml),无需再手工编辑任何配置。

版本前提:Harness 把会话日志写为 Zstandard 帧格式的 JSONL,读取它需要 Node 22.15+。这也影响历史会话的导入(--import-conversations)——旧版 Node 会跳过导入并说明原因,而不是静默导入空数据。

安装后没有"capture"命令需要记忆。从下一个会话开始,记忆是自动的。

源码级原理:Cordis 插件如何接线记忆生命周期

集成不是通过 hook 二进制桥接,而是直接绑定 dsh 的 Cordis 生命周期事件。src/dsh.ts 的注释解释了原因:dsh 的 Claude Code / Codex hook 桥只是同一套类型化生命周期事件的翻译器,直接绑定事件能保留 transcript、session id 与 awaited 的停止边界。四个事件的映射如下:

Cordis 事件对应行为代码入口
agent/session-start冷检查 + 后台 git/代码库种子(seedIfColdhooks.sessionStart
agent/pre-step召回(onPrompt)+ 以带来源的消息注入记忆hooks.preStep
agent/turn-stopping完成回合的写回(onSessionIdlehooks.turnStopping
agent/disposed释放该 session 的实时引用hooks.disposed

三个值得注意的实现细节:

  1. 一个 dsh 进程服务多个仓库。与 opencode/Kilo/Cline 的"一进程一项目"不同,dsh 的 Web UI 可以在任意目录为每个会话创建工作区,session.header.cwd各不相同。因此workspacesMap 按工作区根目录缓存RuntimeCore(bank、client、seed),而不是每进程一份;记忆按仓库解析,与进程无关。
  2. 注入消息带显式来源preStepnext()返回enter决策且用户确有新输入时,才调用onPrompt并追加一条注入消息——source: { kind: "plugin", plugin: "hindsight", form: "recall" }form: "recall"是 dsh 自己的"已检索上下文"词汇,UI 会将其渲染为召回材料而非用户输入;prepend: true让本监听器置于最外层,保证记忆块排在所有其他插件的消息之后、最接近模型的回合。
  3. 子代理会话被跳过workspaceForAgentorigin === "subagent"的会话直接返回空——为其注入会为每次委派多付一次召回,为其保留则会把父会话已完整存储的片段重复归档。

所有监听器都是 fail-open 的:RuntimeCore从不抛出异常,无法解析工作区只会让该会话不获得记忆,而不会破坏智能体本身的运行。

教一次:项目规则如何被保留

在一个正常的工作会话中,告诉 Harness 这个仓库的规则即可。例如记录两条项目约定(包管理用pgm而非npm、PR 标题必须遵循 Conventional Commits),Hindsight 会将其保留为持久记忆:

这些保留内容落在作用域限定为该仓库的 Hindsight bank 中,并带有产生它们的 harness 标签。可以在 Control Plane 中实时观察它们到达:

整个过程无需手动导出。会话写回依赖 src/core/transcript-dsh.ts 对 dsh 会话日志的规范化:dsh 把会话存为追加式SessionEvent类型化日志(而非聊天数组),插件通过session.snapshotEvents()(alpha.4+ 的公开访问器)或旧版events属性直接读取实时日志。在约 30 种事件类型中,只有三种携带对话内容:

  • user/message——人类提示词或注入的插件上下文,只有source.kind === "user"的真实人类消息会被保留
  • assistant/message——单步回复;
  • tool/call——模型的工具调用,渲染为紧凑的 action 回合。

tool/result被刻意跳过:其载荷是原始工具输出,actionLine约定会把这类内容挡在记忆库之外。注入的召回块(source.kind === "plugin")同样会被过滤掉,避免"把机器脚手架当成用户的话",也避免把召回的记忆再喂回下一次抽取。

下一个会话:它记得

稍后开启全新会话,询问项目约定。Harness 不再猜测,而是从记忆库中召回被教过的规则:

包管理规则与 Conventional Commits 要求得以逐字返回,因为它们被存储为"已核对一致的记忆"(reconciled memory),而不是依赖每个会话都会重置的上下文窗口。第一节课的学习成果成为第五十节课的起始上下文。从实现上看,这是preStep在用户提示到达时调用onPrompt触发召回、再把getInjection生成的记忆块以带来源消息追加进消息列表的结果;测试 src/dsh.test.ts 精确断言了这一行为——召回只针对人类提示("why did we roll back?"),工具续回合(只有 plugin 消息)不触发第二次召回,被拒绝或被中止的步骤原样通过。

超越召回:自愈的 Knowledge Pages

集成做的远不止保留和召回单个事实。在冷仓库上,它会运行一次只读调查(codebase survey),为架构、约定与进行中的计划(in-flight initiatives)播种 Knowledge Pages,并在你持续工作的过程中保持它们的最新状态。Harness 在开始任务前会阅读这些页面,并把新工作记录为被追踪的页面——文档因此实现了自我书写与自我修复。

这些页面由服务端从 bank 的记忆中合成(见 src/core/survey.ts 的注释),并使用delta refresh:每次刷新编辑页面而非重建。刷新时机由配置决定——默认pageTriggerCron: "H * * * *"每小时错峰刷新一次(每个页面通过 bank id 与页面名哈希出自己的分钟槽,参见 README 中 JenkinsH语法的说明),pageTriggerType: "auto-refresh"则回到每次整合后刷新(成本更高:每次整合每个页面一次 LLM 合成)。冷仓库调查由当前 harness 自己的 CLI 无头运行(Claude 配方下可用surveyModelsurveyBudgetUsd控制模型与预算),surveyRefreshCommits: 20控制架构持续变动时每隔多少提交重跑一次。

共享记忆库:教一个,全队皆知

因为记忆存放在 Hindsight bank 中而非 Harness 内部,它是可移植的。同一个 bank 既被 Harness 填充,也会被 Claude Code、Codex、Cursor 以及其他十余个编码智能体(本项目支持的完整名单见 hindsight-integrations/coding-agents/README.md)召回。教一个,其余整个工具舰队都知道。

这背后的机制是按仓库解析 bank。默认模板"coding-agent::{gitProject}"对 harness 中立——opencode、Claude Code、Codex、dsh 共享同一仓库的记忆;改用"{harness}-{gitProject}"则按智能体拆分。解析顺序为:

  1. mapPathToBank——最长匹配的绝对路径前缀(映射仓库根目录即覆盖其下所有子目录;覆盖任何显式bankId);
  2. 静态——设置了bankId(或dynamicBankId: false);
  3. 动态——bankIdTemplate占位符展开:{gitProject}是 worktree 感知的仓库名(git rev-parse --git-common-dir把所有 linked worktree 解析为主 worktree 的 basename),{project}是工作目录 basename,{harness}是接入入口,{channel}/{user}来自环境变量。

gitIngest控制 git 深度:"message"只取提交消息(HEAD 移动时重 upsert 一条文档),"full"额外按"最新优先、渐进"抓取逐提交 diff,"none"关闭 git 摄入。

配置:一个 JSON 文件的分层覆盖

所有配置集中在一个文件:~/.hindsight/coding-agent.json。分层按字段覆盖,后者胜出:

  1. 内置默认值;
  2. 环境变量(HINDSIGHT_API_URLHINDSIGHT_API_TOKEN及每个标量设置对应的HINDSIGHT_<FIELD_IN_CAPS>,用于容器/CI);
  3. 文件顶层;
  4. harnesses.<name>段——按智能体覆盖;
  5. banks.<resolvedBankId>段——按仓库覆盖(bank 解析后应用,因此与仓库位置无关、目录移动后依然有效)。

环境变量只是回退:文件设置了值就以文件为准。retainTagsoptInPaths等列表型设置接受逗号分隔值;mapPathToBankharnessesbanksretainMetadata等映射型设置为文件专用。配置在进程启动时读取(文件不被监听):hook 型 harness 每个 hook 调用读一次(下次提示即生效),插件型 harness(含 dsh)每次加载插件时读一次(重启智能体后生效)。唯一例外是apiToken——服务端拒绝请求时每个 host 都会重读它,因此轮换密钥无需重启。

字段默认值含义
apiUrlhttps://api.hindsight.vectorize.ioHindsight API 基址(本地服务端设为http://localhost:8888
apiTokenBearer 令牌(Cloud 模式)
bankIdTemplate"coding-agent::{gitProject}"动态 bank id 格式
mapPathToBank绝对路径 → bank,最长前缀胜出
optInOnly/optInPathsfalse/ —仅白名单项目启用记忆,其余完全惰性(不建 bank、不保留、不播种)
retainTags/retainMetadata— / —给每份文档加盖来源标签/元数据,支持{gitProject}等占位符
observationScopes"shared"观测整合的作用域:每个 bank 一个全局无标签作用域;也可用"per_source"把"提交说的"与"对话决定的"分开整合
autoSeed/seedLimittrue/300冷仓库从 git 历史自动播种 / 最近 N 条提交上限
codebaseSurvey/surveyRefreshCommitstrue/20冷仓库结构调查 / 每积累多少提交重跑调查
retainSessionstrue会话写回总开关
gitIngest"message"git 摄入深度:message/full/none
manageBankConfigtrue让插件塑造 bank 自身配置(retain 策略、knowledge实体标签组、缺失时的 missions);只做增量添加,绝不覆盖既有内容
disabledfalse硬关闭开关(惰性插件/hook)
autoUpdatetrue每日后台检查并重暂存运行时代

按仓库精细控制同样在这个文件里,以解析后的 bank id 为键。例如把coding-agent::secret-client加入黑名单、把旧 bank 收敛到共享 bank、对大型 monorepo 开启完整 git 摄入,都只需在banks段声明;"两个仓库共享一个 bank"既可按 id 收敛(banks映射到同一字面目标),也可按路径前缀(一条mapPathToBank覆盖目录下所有仓库)。

验证与排障

集成在仓库内配有完整的验证链路:

  • 单元测试src/dsh.test.ts 覆盖 pre-step 注入、写回、session-start 恰好一次播种、alpha.4+ 的snapshotEvents回退,以及toDshParameters把 Zod 原始 schema 投影为 dsh 参数 JSON Schema(仅支持字符串参数,非字符串会显式报错);
  • 端到端测试e2e/Dockerfile.dsh 与 e2e/dsh-stub-model.cordis.yml 用一个本地 echo 模型(hindsight-stubopenai-completions协议)替代 DeepSeek API,使 E2E 无需真实账户即可验证完整的生命周期接线,e2e/run-harness.sh负责在容器中执行安装命令并驱动会话。

日常排障时注意:失败永不破坏智能体——一次失败的反射、页面抓取或保留会退化为一次普通的无记忆回合并记入日志。所以"没有记忆"是一个日志问题:检查结构化诊断文件($TMPDIR/hindsight-plugin.log,可用HINDSIGHT_DIAG_FILE覆盖)中session_startdeepen_started是否为该 bank 触发过;reflect_failed/pages_failed表示一次无记忆的运行。hindsight_sync_status工具(脚本用dist/status.js)直接回答"记忆就绪了吗":"synced": true表示播种的记忆可查询。要重置某个仓库的记忆,只需删除服务端上对应的 bank——bank 是这个集成保持的唯一状态,删除后下一次会话就是真正的首次打开,种子与调查会从头再来。

小结

从一条npx命令到原生 Cordis 插件,从agent/session-start的冷启动播种到agent/pre-step的按需召回,再到agent/turn-stopping的会话写回,DeepSeek Harness 通过 Hindsight 获得了真正跨会话的代码库记忆:git 历史与对话在后台沉淀,约定与决策在下一次会话被自动摆在智能体面前,Knowledge Pages 让架构文档自我维护,而共享 bank 让记忆在所有编码智能体之间流动。相关实现细节可继续深入 hindsight-integrations/coding-agents/README.md 与 src/dsh.ts。

【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询