Harmonist结构化记忆原理:correlation_id与30类密钥扫描如何让记忆不可伪造
【免费下载链接】harmonistPortable AI agent orchestration with mechanical protocol enforcement. 186 agents, zero runtime dependencies.项目地址: https://gitcode.com/gh_mirrors/ha/harmonist
Harmonist 是一个可移植的 AI Agent 编排包,其中"结构化记忆"是它的核心机制之一:每条记忆都带有由钩子(hooks)生成的 correlation_id 任务序列号,写入前还要通过 30 余类密钥模式扫描与严格的 schema 校验。这套设计让 AI 助手"记下的东西"既无法被 LLM 伪造身份,也不会把密钥泄露进记忆文件。
🧠 为什么 AI Agent 的记忆默认不可信
让 AI Agent 把项目状态写进一个自由格式的 markdown 文件,听起来很简单。但问题在于:
- LLM 可能"不诚实"——忘记更新、重复记录、甚至编造时间戳;
- 密钥容易混入——调试记录里随手一贴,
AWS_SECRET_ACCESS_KEY就被永久写进了记忆; - 无法追溯——一条"架构决策"到底属于哪次任务?说不清。
Harmonist 的答案是 memory/SCHEMA.md 中定义的Memory Schema v1:三个固定角色文件 + 机器可读的条目结构 + 强制校验,一条都不能少。
| 文件 | 类型 | 职责 |
|---|---|---|
session-handoff.md | state | 项目状态的滚动快照,最新条目即权威状态 |
decisions.md | decision | 只增不改的架构决策记录 |
patterns.md | pattern | 经验教训——什么有效、什么踩坑 |
每条记忆都包裹在<!-- memory-entry:start -->与<!-- memory-entry:end -->标记之间,内部是一段 YAML 前置元数据(frontmatter)。文件里允许随意写自由文本,但只有结构化块受契约约束,校验器只认契约。
🔒 correlation_id:LLM 无法伪造的"任务序列号"
这是 Harmonist 记忆防伪造的关键设计:correlation_id 不是由 LLM 生成的,而是由强制执行的 hooks 生成的(见 memory/README.md)。
它的格式是<session_id>-<task_seq>:
session_id= 会话启动那一刻的 Unix 秒级时间戳;task_seq从 0 开始,只有当 stop 门(任务完成闸门)判定任务成功结束并放行后,才自增 1。
当前活跃的 correlation_id 存放在.cursor/hooks/.state/session.json的active_correlation_id字段中。记忆 CLI memory/memory.py 在追加条目时会自动读取它,把id、correlation_id、时间戳at全部自动填入。
<!-- memory-entry:start --> --- id: 1745333456-0-state correlation_id: 1745333456-0 at: 2026-04-22T19:30:56Z kind: state status: done author: orchestrator summary: Integrated Stripe webhook handler for checkout flow --- (正文内容) <!-- memory-entry:end -->这一机制带来三重防伪效果:
- 身份绑定:同一次任务中写入的
state快照、decision决策、pattern经验,共享同一个 correlation_id,可以精确追溯"这个决策是在哪次任务中做出的"; - 时间不可撒谎:
task_seq只能被 hooks/scripts/gate-stop.sh 在任务通过校验后递增,LLM 无法"提前"给自己签发未来任务的编号; - 写错即拒收:校验器 memory/validate.py 会检查条目的
correlation_id是否匹配写入时刻的活跃值,不匹配直接报错(人工手写条目在加--allow-manual时才放行)。
此外,条目的id由<correlation_id>-<kind>派生并全局去重——重复的id会被validate.py当作硬性错误报出。换句话说,连"这条记忆叫什么名字"都不由 LLM 说了算。
🔍 30类密钥扫描:秘密信息永远进不了记忆
Harmonist 假设记忆文件"迟早会被误提交进某个仓库",所以在memory.py append时就拦截一切疑似凭据。
打开 memory/memory.py 的_SECRET_PATTERNS可以看到一条精心调校的清单,覆盖 30 余类真实密钥形态:
| 类别 | 涵盖示例 |
|---|---|
| 云厂商 | AWS Access Key / Secret Key、GCP 服务账号、Azure 连接串与 SAS 令牌、Google API Key、DigitalOcean PAT |
| 代码托管 | GitHub PAT / OAuth / 细粒度令牌、GitLab PAT、npm、PyPI、Docker Hub |
| AI 服务 | OpenAIsk-...、Anthropicsk-ant-... |
| 协作/消息 | Slack 令牌与 Webhook、Discord Bot Token、Telegram Bot Token |
| 支付/邮件 | Stripe 密钥、Twilio SID、SendGrid、Mailgun |
| 通用兜底 | JWT(eyJ...)、PEM 私钥块、24 词助记符、带账号密码的数据库 URL |
光靠固定模式还不够,Harmonist 还叠了两层"智能"检测:
- 上下文 UUID 识别:UUID 本身不是密钥,但当它出现在
heroku或postmark字样前后 ±60 字符范围内时,就会被判定为 API 密钥并拦截; - 高熵令牌兜底:对 28 字符以上的裸令牌计算香农熵,超过 4.3 bit/char 即报警——随机生成的 base64/blob 分数远高于人类可读文本。
更妙的是占位符感知:被<PLACEHOLDER>、${VAR}、$(cmd)、{{ template }}这类"围栏"包住的匹配会被跳过,所以文档示例里的假密钥不会误报,而真实密钥躲在哪里都会被逮住。命中后 CLI 会拒绝追加并列出命中的类别,只有显式加上--allow-secrets才能强行写入。
🛡️ 写入即校验:回滚、去重与泄漏审计
最后一道防线在写入路径上:
- 写前验证、失败回滚——渲染好的条目块先过一遍
validate.py,校验不过就把刚写入的内容整块撤销,绝不留半成品; - 去重守卫——新条目的
summary与全文任一条目重复、或正文的 blake2s 哈希与已有条目相同("换了个说法、内容一字未改"),都会被拒收,防止记忆被反复"灌水"; - 跨进程文件锁——并发的两个追加不会抢注同一个 id,也不会交错回滚;
- 事后审计——万一记忆文件真的被误提交,agents/scripts/scan_memory_leaks.py 会遍历 git 历史,列出当前和历史上所有被追踪的
.cursor/memory/文件,并直接生成可复制的git rm --cached/git filter-repo清除方案。
📚 动手看看源码
| 想了解的机制 | 去哪里看 |
|---|---|
| 完整契约(字段约束、correlation_id 规则) | memory/SCHEMA.md |
| 记忆 CLI 与三层密钥扫描 | memory/memory.py |
| 逐条 schema 校验与 id 全局唯一性 | memory/validate.py |
| 任务完成后递增 task_seq 的闸门 | hooks/scripts/gate-stop.sh |
| 记忆文件泄漏审计 | agents/scripts/scan_memory_leaks.py |
隐私约定(.gitignore与.shared.md) | memory/README.md |
小结
Harmonist 的结构化记忆本质上回答了一个问题:如何让你不信任的 LLM 写出可信任的记录。
- 用hooks 生成 correlation_id,让"谁、在哪次任务、何时"由机器说了算,LLM 只能填写内容;
- 用30 余类密钥模式 + 上下文识别 + 高熵兜底,把秘密挡在记忆之外;
- 用写前校验 + 失败回滚 + 全文去重 + 事后泄漏审计,把"写坏了"变成不可能事件。
三层机制叠加,记忆文件就从"AI 随手记的便签"升级成了可验证、可追溯、不可伪造的项目档案。
【免费下载链接】harmonistPortable AI agent orchestration with mechanical protocol enforcement. 186 agents, zero runtime dependencies.项目地址: https://gitcode.com/gh_mirrors/ha/harmonist
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考