Hindsight × Cline 持久化记忆实战:用生命周期钩子替代 MCP 实现跨任务记忆
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
本篇文章以 Hindsight 开源仓库中的 Cline 集成 为讲解对象,完整介绍如何为 VS Code 中最流行的 AI 编程代理之一 Cline 接入持久化长期记忆。方案的核心思路是:利用 Cline 的生命周期钩子(Lifecycle Hooks)在任务开始前自动召回(Recall)相关记忆、在任务结束时自动留存(Retain)任务内容,全程无需 MCP 服务器,也不依赖模型主动调用记忆工具。读完本文,你将掌握hindsight-cline的安装配置、四个钩子的工作机制、记忆召回/留存的完整链路、按项目隔离与团队共享记忆的配置方法,以及常见的排障技巧。
TL;DR
- Cline 本身没有跨任务持久记忆,每次任务都是从零开始。
- Hindsight 集成会安装四个生命周期钩子脚本(
TaskStart、UserPromptSubmit、TaskComplete、TaskCancel)外加一个轻量 Python 库。只需pip install hindsight-cline加一条install命令,钩子本身仅依赖 Python 3 标准库,运行时零第三方依赖。 - 召回是确定性的:因为记忆注入发生在钩子上,所以不存在模型忘记调用 MCP 工具的问题。
- 召回的记忆会以
<hindsight_memories>块的形式注入 Cline 上下文,作用域限定于当前任务描述和正在进行的提示词。 - Hindsight Cloud 方案无需本地守护进程,记忆存储在服务端,可跨机器跟随你。
- 平台注意:Cline 钩子仅支持 macOS 和 Linux,暂不支持 Windows。
问题:Cline 在任务之间没有记忆
Cline 在单个任务内非常高效:它可以读取整个项目、编辑几十个文件、运行测试并收敛出解决方案。但任务一结束,它学到的一切就消失了。下一个任务开始时,模型能依赖的只有训练数据和 Cline 读到的文件,你之前教过它的东西荡然无存。
对一次性任务这没问题;但对一个你每天都在同一代码库上使用的代理来说,这就是个麻烦。你不得不反复解释同样的约定、反复警告它同样的坑、反复陈述同样的架构决策。代理永远无法像同事那样真正了解你的代码库。
Hindsight 通过给 Cline 一个持久化记忆库来弥补这个缺口,而生命周期钩子集成让这一切无需任何任务内工具调用即可完成。
Hindsight 如何给 Cline 加记忆
Cline 支持生命周期钩子:在关键时刻运行的小型可执行脚本。Hindsight 集成会安装其中四个,并把每个事件路由到一次 Hindsight API 调用:
| Cline 钩子 | Hindsight 的动作 |
|---|---|
TaskStart | 为新任务描述召回上下文并注入。 |
UserPromptSubmit | 为你的消息召回记忆;同时记录该提示词,供后续 retain 使用。 |
TaskComplete | 留存任务累积的完整转写记录与最终摘要。 |
TaskCancel | 留存被取消任务的转写记录(即使不完整)。 |
因为运行在钩子上,记忆行为是确定性的——不存在模型忘记调用工具的问题,也没有工具调用往返带来的额外延迟。召回与留存逻辑在 Cline 任务生命周期的明确节点上执行:
Task starts ─ TaskStart ─────────► recall(task description) → inject memories You send a message ─ UserPromptSubmit ─► recall(prompt) → inject memories (and append the prompt to the task transcript) Task completes ─ TaskComplete ──► retain(accumulated transcript + summary) Task cancelled ─ TaskCancel ────► retain(partial transcript)一个 Cline 专属细节:转写记录由集成自行累积
值得注意的 Cline 特定细节是:Cline 不会把对话转写记录交给钩子。每个钩子只能拿到任务 ID 和当前事件负载,而不是正在进行的对话。因此集成会在运行过程中把每个任务的提示词累积到~/.hindsight/cline/state/,任务结束钩子再读回这些内容一次性完成 retain。模型永远看不到这些簿记操作,它只会在相关内容出现时看到记忆注入上下文。
这一点在源码中有清晰体现。state.py 将每次追加的轮次以 JSON 形式原子写入~/.hindsight/cline/state/(先写临时文件再os.replace,避免并发写坏),并在 content.py 的append_turn中把超长任务的转写记录上限截断到最近 500 条,保持状态文件有界。handle_retain在成功 retain 后会调用clear_transcript清理该任务的状态文件,避免磁盘持续膨胀。
钩子协议:stdin 进、stdout 出
Cline 把每个钩子当作子进程运行:向钩子的 stdin 写入一个 JSON 对象,再从 stdout 读取形如{"cancel": bool, "contextModification": str, "errorMessage": str}的 JSON 响应,其中contextModification就是钩子向模型上下文注入文本的通道。相关实现见 cline_io.py。
集成在边界处把结构化 stdin 解析为类型化的HookInput(包含hook_name、task_id、prompt、task、workspace_roots、model_slug字段),而不是在整个代码库中传递原始 dict。另一个值得注意的设计是故障降级:所有钩子入口都不会抛异常,任何记忆相关的失败都降级为 no-op,确保记忆服务出问题也绝不会阻塞 Cline 的正常工作——这正是 hooks_impl.py 中_run_recall/_run_retain用 try/except 包住处理器并始终emit()的原因。
安装
安装器是一个小型 CLI,把四个钩子文件(外加共享库和settings.json)复制到 Cline 的钩子目录。先用 pip 安装:
pip install hindsight-cline然后从你的项目目录执行:
hindsight-cline install \ --api-url https://api.hindsight.vectorize.io \ --api-token YOUR_KEY这会安装到.clinerules/hooks/;可以提交到版本库与团队共享。如果想全局安装(作用于每个项目),加上--global:
hindsight-cline install --global \ --api-url https://api.hindsight.vectorize.io \ --api-token YOUR_KEY此时钩子会被放置到~/Documents/Cline/Rules/Hooks/。卸载执行hindsight-cline uninstall(全局安装过就加--global)。
最后一步,在 Cline 中启用钩子:Settings → Features → Hooks(打开开关)。
Cline 钩子仅支持 macOS 和 Linux。它们使用 Python 3(任何现代系统 Python 均可,运行时无需pip install额外依赖)。
安装器做了什么
从源码看,install.py 的install_hooks会做三件事:
- 复制四个钩子脚本(
TaskStart、UserPromptSubmit、TaskComplete、TaskCancel)并chmod 0o755——Cline 只会执行具有可执行权限的钩子文件; - 把共享的
lib/包整体复制到钩子目录旁(钩子脚本会把这个目录加入sys.path,并从同一目录读取settings.json); - 写入
settings.json默认配置。
连接参数(--api-url、--api-token)则被写入~/.hindsight/cline.json,见write_user_config(install.py),这个用户配置文件在重装/升级后保持不变。--api-url与--api-token也可以分别通过环境变量HINDSIGHT_API_URL和HINDSIGHT_API_TOKEN提供(见 cli.py)。四个钩子脚本本身非常薄——以 TaskStart 为例,它只是把自身所在目录加入sys.path后调用lib.hooks_impl的main_task_start(),真正的逻辑全部集中在共享库里,便于测试复用。
Hindsight Cloud(推荐)
最快的接入路径是 Hindsight Cloud:无需维持守护进程,记忆跨机器同步,抽取工作在服务端完成。这对 Cline 来说比服务端代理更重要——Cline 运行在 VS Code 里,而多数开发者会在笔记本、台式机乃至远程开发机上使用 VS Code;Cloud 意味着同一套记忆库随处可用,无需手动复制文件。由于抽取在服务端完成,你也不必把 LLM API 密钥塞进钩子环境(否则 retain 钩子需要密钥来调用抽取模型),更不用在打开 VS Code 前记得启动hindsight-api进程。安装器的--api-url和--api-token参数一步到位完成配置,连接设置保存在~/.hindsight/cline.json,跨重装保持稳定:
{ "hindsightApiUrl": "https://api.hindsight.vectorize.io", "hindsightApiToken": "hsk_your_token" }自托管的工作方式完全相同:本地启动 API,再把安装器指向它:
pip install hindsight-all export HINDSIGHT_API_LLM_API_KEY=your-openai-key hindsight-api # http://localhost:8888然后带--api-url http://localhost:8888重新运行安装器即可。
本地模式的无守护进程降级
集成特意设计成"无守护进程":resolve_api_url(cline_io.py)优先使用配置的外部 URL;若未配置,则探测http://localhost:{apiPort}(默认 9077)上是否已有可用的本地 Hindsight 服务,health_check探测/health端点。两者都不可达时钩子静默降级为 no-op,绝不自动拉起守护进程。
召回什么内容
TaskStart和UserPromptSubmit都会执行一次 Hindsight recall,并把<hindsight_memories>块作为上下文返回,由 Cline 在模型看到你的提示词之前注入:
<hindsight_memories> Relevant memories from past conversations. Only use memories that are directly useful to continue this task; ignore the rest: Current time - 2026-06-09 13:42 - Project uses asyncpg, not SQLAlchemy; switched after Redis cache stampede in March [world] - Tests live under tests/integration/ and run via `make test-int`, not pytest directly [world] - The `auth_v2` module is being deprecated; new code should target `identity/` [experience] </hindsight_memories>Cline 能看到这个块,但它不会出现在你的编辑器输出里。结果是:Cline 每个任务开始时都带着相关的过往上下文,无需你手动提供。
你可以用recallBudget("low"/"mid"/"high")和recallMaxTokens调节拉取多少上下文。
记忆块与查询的底层构造
从实现细节看,记忆块的渲染在 hooks_impl.py 的_recall_context中完成:它解析 API 地址、派生 bank ID、确保 bank mission 已设置、调用client.recall(...),然后把结果通过 content.py 的format_memories格式化为带[type]与(mentioned_at)标注的条目,最后拼接上recall_prompt_preamble(默认文案见 settings.json 的recallPromptPreamble)和当前 UTC 时间。
几个值得注意的工程细节:
- 短提示词跳过召回:
RECALL_MIN_CHARS = 5,低于 5 个字符的提示(如 "hi")直接返回空,不浪费一次 API 调用(测试test_recall_skips_short_prompts验证了这一点)。 - 多轮上下文查询:默认
recallContextTurns = 1时只以最新提示词作为查询;调大后会用slice_last_turns_by_user_boundary截取最近 N 轮(以用户消息为轮次边界),再经truncate_recall_query按recallMaxQueryChars(默认 800 字符)裁剪,超长时优先丢弃最早的上下文行、保留最新消息。 - 防止回流污染:转写记录在格式化前会通过
strip_memory_tags剔除<hindsight_memories>/<relevant_memories>块(content.py)——这些块是召回时注入的,绝不能再次被存回记忆库,否则会形成记忆的自我引用循环。
前后对比
没有持久记忆时,Cline 中的新任务从零开始。你输入 "fix the broken auth tests",Cline 读取测试文件、对哪个 auth 模块在作用域内做出合理猜测,然后可能尝试你已经否决过的模式。
有了 Hindsight,同样的任务一开始就带着召回的上下文:auth_v2已废弃、测试运行器是make test-int、最近的修复栈落在identity/。Cline 在第一轮就选对了模块和测试命令,而不是等到第三轮。
按项目隔离记忆
默认所有 Cline 任务共享同一个记忆库(cline)。如果希望每个项目拥有独立隔离的记忆库,在~/.hindsight/cline.json中启用动态 bank ID:
{ "dynamicBankId": true, "dynamicBankGranularity": ["agent", "project"] }Bank ID 由工作区路径派生(agent::project),因此~/projects/api中的任务写入的 bank 与~/projects/frontend中的不同。切换文件夹会自动切换记忆上下文。
合法的粒度字段为agent、project、session和user。加入user(从HINDSIGHT_USER_ID环境变量读取)在多人共享一台机器但不应共享召回结果时很有用。
动态 bank 的实现
banks.py 的derive_bank_id展示了完整规则:静态模式下直接返回配置的bankId(可加bankIdPrefix前缀);动态模式下按粒度字段依次取值并用::拼接——agent取agentName(默认cline)、project取第一个工作区根目录的 basename(无工作区时为unknown)、session取taskId、user取HINDSIGHT_USER_ID(缺省为anonymous)。对非法粒度字段会向 stderr 打印告警。另有一个细节:bankMission(默认值见 settings.json)只会在新 bank 首次使用时通过ensure_bank_mission设置一次,已设置过的记录保存在~/.hindsight/cline/state/bank_missions.json中,避免每次任务重复写配置。
团队共享记忆
个人持久记忆很有用,而跨团队共享记忆则具有变革性。
当团队中每个人都把 Cline 配置指向同一个 Hindsight bank 时,一位开发者积累的上下文就能被所有人使用。周一发现的 bug 会在周二出现在召回结果中,无论提问者是谁。一个任务中做出的架构决策会指导下一个任务,无需任何人更新共享文档。
要配置团队共享记忆,在每个开发者的配置中设置固定的bankId并把他们都指向同一个 Hindsight Cloud 端点:
{ "hindsightApiUrl": "https://api.hindsight.vectorize.io", "hindsightApiToken": "hsk_your_token", "bankId": "my-team-project" }关键配置项
设置位于~/.hindsight/cline.json(个人覆盖)或已安装的settings.json(默认值)。每个设置也都可以通过HINDSIGHT_*环境变量设置(如HINDSIGHT_BANK_ID、HINDSIGHT_AUTO_RECALL=false)。
| 设置 | 默认值 | 作用 |
|---|---|---|
bankId | cline | 本集成使用的记忆库。 |
autoRecall | true | 在任务/提示词前注入记忆。 |
autoRetain | true | 任务结束时留存任务转写记录。 |
recallBudget | mid | 召回深度:low(快速)/mid/high(彻底)。 |
recallTypes | ["world","experience"] | 召回的记忆类别。 |
retainMission | generic | 引导事实抽取;告诉抽取器重点关注什么。 |
dynamicBankId | false | 按项目隔离记忆库。 |
debug | false | 向 stderr 记录活动日志。 |
聚焦的retainMission会让抽取出的记忆质量明显更好:
{ "retainMission": "Extract technical decisions, code patterns, debugging solutions, user preferences, project context, and architectural choices. Ignore routine greetings and transient operational details." }配置的加载顺序与默认值全景
config.py 定义了严格的加载顺序(后者覆盖前者):
- 内置默认值(
HindsightClineConfigdataclass 的字段默认值); - 随包分发的
settings.json(通过find_settings_path向上搜索定位,兼容源码布局与安装布局); - 用户配置
~/.hindsight/cline.json(跨更新稳定); - 环境变量覆盖(
ENV_OVERRIDES中声明的HINDSIGHT_*变量,布尔值识别true/1/yes,数值类型会做转换)。
settings.json中还有博客表格未列出的几个重要默认值(均见 settings.json):
recallMaxTokens: 1024、recallTimeout: 10、recallContextTurns: 1、recallMaxQueryChars: 800——召回请求的令牌上限、超时、多轮上下文轮数、查询字符上限;retainContext: "cline"、retainTags: ["{task_id}"]、retainTimeout: 15——留存内容按cline上下文聚类、以任务 ID 打标签;bankMission与retainMission——bank 的使命陈述与事实抽取指引;apiPort: 9077——本地自托管服务探测端口;agentName: "cline"——动态 bank 中agent维度的名称。
retainTags和retainMetadata支持模板变量展开:{task_id}、{project}(工作区根目录的 basename)、{status}(completed/cancelled)、{timestamp}(当前 UTC 时间),渲染逻辑见 hooks_impl.py 的_render。retain 时还会附带task_id、project、status元数据,方便后续按任务追溯(测试test_retain_posts_accumulated_transcript验证了metadata["status"] == "completed"与document_id == task_id)。
常见问题与排障
钩子不触发。安装器只是把文件复制进去,但开关默认是关闭的。去 Cline 的 Settings → Features → Hooks 打开它。快速验证钩子是否运行:开启debug: true,观察 stderr 中的[Hindsight]日志行(debug_log的实现见 config.py)。
第一个任务没有召回任何记忆。召回只有在已有内容被留存后才会返回结果。先完整完成一个真实任务,第二个任务开始就能看到召回的上下文。
Windows 上没有任何反应。Cline 的钩子运行器仅支持 macOS/Linux,目前没有 Windows 路径。
不带 Cline 冒烟测试钩子。你可以把一条合成事件直接管道进钩子脚本,端到端验证它工作正常:
echo '{"hookName":"UserPromptSubmit","prompt":"how do we authenticate?","taskId":"t1","workspaceRoots":["/tmp/x"]}' \ | .clinerules/hooks/UserPromptSubmit # → {"cancel": false, "contextModification": "<hindsight_memories>…", "errorMessage": ""}这条命令之所以可行,是因为 Cline 钩子协议就是"stdin 收 JSON、stdout 回 JSON"(见上文钩子协议一节),test_hooks.py 中的测试也以同样的方式构造make_hook(...)输入来验证handle_user_prompt_submit的返回结果。
值得了解的工程细节
- API 客户端零第三方依赖:client.py 仅用 Python 标准库的
urllib实现 HTTP 调用,因此钩子在运行时不需要任何pip install。它还会设置User-Agent: hindsight-cline/{version},避免自托管部署在 Cloudflare 等反向代理后面时因默认 UA 触发 1010 拦截。 - retain 是异步的:
client.retain发送{"async": true},服务器后台处理,钩子不阻塞等待抽取完成。 - API URL 校验:
_validate_api_url只接受http/https协议且必须有主机名,非法 URL 会立即报错而不是静默失败。 - 测试覆盖:
hindsight-integrations/cline/tests/下有 test_hooks.py、test_install.py、test_bank.py、test_content.py 四组测试,覆盖召回注入、转写记录累积、禁用开关、空结果降级、retain 后清理等关键行为;仓库内的开发方式为uv sync+uv run pytest tests/ -v。
权衡取舍
召回带来额外延迟。每条提示词在 Cline 看到它之前都会触发一次 Hindsight 查询。使用 Hindsight Cloud 和快速网络时通常低于 300ms,交互使用中几乎无感。如果需要跳过,把recallBudget调成"low",或设置autoRecall: false。
Retain 在任务结束时运行,而非任务中途。你正在进行的任务产生的记忆要等任务完成后才可用。如果你取消了一个本打算稍后召回的任务,TaskCancel钩子仍会留存部分转写记录,但你必须真正取消才会触发它。
抽取质量取决于对话质量。Hindsight 从转写记录中抽取事实。如果任务全是文件编辑、毫无叙述,抽取器可用的素材就很少。用几句话说明你做了什么决定以及为什么,会大有帮助。
效果对比总结
| Cline 默认 | 接入 Hindsight | |
|---|---|---|
| 跨任务记忆 | 无 | 自动 |
| 记忆来源 | 手动.clinerules/ 文档 | 从任务转写记录自动抽取 |
| 召回机制 | Cline 每个任务读取的文件 | 语义搜索,按任务/提示词注入 |
| 按项目隔离 | 无 | 可选(dynamicBankId) |
| 团队共享记忆 | 无 | 通过 Hindsight Cloud 共享 bank |
| 需要模型调用工具 | n/a | 不需要(生命周期钩子) |
进一步阅读
- 集成 README 与完整开发说明:hindsight-integrations/cline/README.md
- 钩子逻辑实现:hindsight-integrations/cline/hindsight_cline/hooks/lib/hooks_impl.py
- 配置加载与全部默认值:hindsight-integrations/cline/hindsight_cline/hooks/lib/config.py 与 settings.json
- 安装 CLI 与钩子文件清单:hindsight-integrations/cline/hindsight_cline/cli.py、install.py
- 测试用例:hindsight-integrations/cline/tests/
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考