深度拆解 Hy Memory 2.0:chat / working / coding 三类记忆如何在一套框架里共存【免费下载链接】Hy-Memory项目地址: https://gitcode.com/gh_mirrors/hy/Hy-Memory2026 年 10 月,腾讯混元把 Hy Memory 2.0 整体开源:hy-memory==2.0.4上架 PyPI,配套的 Hy-Memory-30B-A3B 记忆写入模型(30B 总参数、仅激活 3B 的 MoE)一并放出,外加桌面/CLI 产品 MemHub 和 OpenClaw 插件,模型、框架、应用三层全开源。社区最感兴趣的一点是:它没有做"大而全"的一把梭记忆系统,而是把记忆按任务切成了chat / working / coding三条管线,却共用同一个HyMemoryClient入口、同一套写入/检索 API。这三类记忆的形态差异极大——聊天记忆是分层摘要与认知结构,生产力记忆是"事实+经验"双层卡片,编码记忆还要能追溯"被回滚的代码改了什么"。它们凭什么能装进一套框架?这篇文章基于仓库源码拆解三件事:三条管线各自的记忆形态与边界、System 1 / System 2 双系统如何分工、以及官方给开发者留了哪些可编程钩子。一、先说结论:三条管线,一个入口,数据完全分轨Hy Memory 把scene作为路由参数贯穿写入与检索,README 中给出的边界定义是:scene典型任务记忆形态chat闲聊、个人信息、偏好、一般问答L0–L7 分层记忆working文档、表格、研究、财经分析、内容创作、电脑操作双层记忆:会话事实 + 可复用经验coding编码、调试、测试、构建、API/SDK、脚本、SQL与 working 同构的双层记忆 + 代码版本演进链关键设计是"分轨"而非"融合":working 与 coding复用同一套生产力 pipeline 和 schema,但使用不同的抽取规范、独立的 SQLite 文件(coding_memory.dbvscoding_memory_cv.db)与向量集合,数据不会混在一起。这个取舍在 docs/scene_coding_usage.md 中写得很直白:两条链共享结构,隔离靠存储与规范,而不是靠一套"万能 prompt"。路由是怎么做的:一个"有界摘要"三分类器写入时如果调用方不显式指定scene,路由逻辑是:输入没有 tool/tool_calls:直接进 chat 管线,零 LLM 调用;输入含 tool 轨迹:调用一次场景分类 LLM,在chat / working / coding三选一中判定。分类器实现在 hy_memory/coding/judge.py,它是一个 single-label 分类器,且刻意只看一个"有界视图"——用户 query + 工具名的摘要,模块顶部用常量把输入框死:_JUDGE_MAX_TURNS = 20 _JUDGE_USER_CONTENT_LIMIT = 1_000 _JUDGE_USER_CONTENT_HEAD = 200 _JUDGE_USER_CONTENT_TAIL = 200分类边界也写进了 prompt:代码或开发产物是"工作对象或实现媒介"判 coding;有明确生产力交付物但代码不是核心媒介判 working;只用了 search/browser 类工具不会自动升格为 working。judge 失败或输出无法解析时回退 chat——这是一个偏保守的失败策略:宁可少进一条结构化管线,也不把噪声写进工作记忆。检索侧同理:search_mode="default"单 query 固定走 chat 轻量检索、零 LLM;search_mode="agentic"才启用 LLM 三分类 + query rewrite + 时间范围解析;而显式传scene时直接选路,跳过一切 judge/rewrite。也就是说,路由成本是可按需付费的,高频低价值调用可以完全绕开 LLM。二、chat 管线:八层记忆与双系统分工L0–L7:原始对话如何被逐层抽象chat 管线是典型的"长期个人记忆"形态。记忆层枚举定义在 hy_memory/models/memory.py 中:class MemoryLayer(str, Enum): L0_BASIC_INFO = "l0_basic_info" # 基本信息 L1_RAW = "l1_raw" # 原始对话 (Append-Only) L2_FACT = "l2_fact" # 原子事实 (版本化不可变记录) L3_SUMMARY = "l3_summary" # 会话摘要 ... L6_SCHEMA = "l6_schema" # 心智模型 (抽象叙事模板, Graph 层) L7_INTENTION = "l7_intention" # 前瞻意图 (带过期时间)从只增不改的 L1 原始对话,到版本化原子事实 L2、会话摘要 L3,再往上到图层的 SCHEMA(心智模型)与 INTENTION(前瞻意图,过期后降级为普通事实)——每一层服务不同的检索粒度。读取侧也对应设计了分层视图:画像摘要(L0,始终返回)、索引视图(~100 tokens)、摘要视图(~500 tokens)、完整内容(按需懒加载),token 预算是显式管理的。System 1 / System 2:即时写入与离线演化的双系统这是 Hy Memory 论文(EMNLP 2026 收录的Memory Beyond Recall: A Dual-Process Cognitive Memory System)的核心主张,也是"双系统认知架构"的落点。代码里的分工非常清晰:System 1 跑在add()路径上,负责即时。hy_memory/agent/mem_agent.py 中的MemAgent统一调度 Extractor(事实/实体提取)与 Reflector(反思)。Reflector 的职责不是简单去重,而是把新信息与已有信息的关系分类为OVERRIDE / SUPPLEMENT / TEMPORAL / NEGATE / CONFLICT五类更新类型,并做冲突检测与隐式信号推断(hy_memory/agent/reflector.py)。L7 的意图抽取也是 System 1 在写入时即时完成的。System 2 跑在evolve()上,负责慢思考。hy_memory/pipelines/system2_agent.py 的头注释说明了它的设计:Phase 1 是硬编码预处理——从 VDB 取未处理事实、DBSCAN 聚类、图正向/反向查找;Phase 2 才是 Agent LLM,且只在聚类非空时触发,散事实冷启动时不烧 LLM。evolve()的 API 语义值得单独看(hy_memory/client.py):def evolve(self, user_id, agent_id="default_agent", max_batches=None): """ 手动触发 System 2 认知加工(ultra 模式专用,同步阻塞直到完成)。 非幂等:每次 evolve 看到的是当前 VDB 全量,连续多次 evolve 有意义 (add 一批 → evolve → 再 add 一批 → 再 evolve)。 触发时机由调用方控制:System 2 不在 add/write 里自动触发,也无进程内队列。 仅 ultra 模式可调用。 """注意两个工程细节:System 2不自动触发,节奏完全交给调用方——这把它从"后台黑盒"变成了可编程的批处理单元;evolve是非幂等的(每次扫 VDB 全量),所以"add 一批 → evolve → 再 add 一批 → 再 evolve"是推荐的迭代模式。另外 Agent 单次处理的候选事实被_S2_MAX_FACTS_PER_BATCH = 24限流,防止 LLM 输出预算耗尽产出不可解析的 JSON。三档模式则把双系统做成了可降级的配置:lite(纯 embedding,零 LLM,scene/layers全忽略)、pro(+ LLM 提取 + reconcile,图谱可选)、ultra(+ System 2 schema 归纳 + cross-domain sweeper,图谱必开)。三、working 管线:事实层保证"记下来",经验层保证"用得上"working 管线的核心是一次会话 trace 同时产出两层记忆(hy_memory/coding/types.py):层记录什么数量策略结构Facts(WorkingFact)本次做了什么:任务、做法、结果每 session 恰好 1 条,无阈值statement,subject,files,detailsExperiences下次遇到同类任务可复用的方法0–N 条,必须过价值门槛task,search_keys,solution,boundary_envs,confidence事实层"无门槛、必落一条",保证干过的事一定有迹可循;经验层"高门槛、宁缺毋滥",boundary_envs记录经验依赖的环境、confidence给出置信度,供消费方判断是否仍适用。两层互相链接:fact.derived_experience_ids↔experience.source_fact_ids由同批全互链回填,被覆盖的事实则通过 task 进展链(fact_chain_summary)保持可追溯。写入协调器 hy_memory/coding/writer.py 把整条链串起来,模块注释本身就是流程文档:extractor.extract(...) ← 一次 LLM 产出双层草稿 reconciler.reconcile(经验草稿) ← ADD/UPDATE/DELETE/SKIP fact_reconciler.reconcile(事实草稿) ← INSERT/SUPERSEDE _crosslink(...) ← 同批全互链回填其中有两处设计哲学值得注意。第一,抽取时故意不给 LLM 看库里已有记忆:writer 的注释解释,把已有 task 摆在 extractor 面前,它会"把一个其实不同的任务往清单里某个措辞上靠",随后被 reconciler 误判为 UPDATE 合并掉——措辞对不上顶多多存一条,措辞被带偏是直接写错。去重/合并的判定权完全交给 reconcile 阶段,抽取只负责忠实记录"这一段发生了什么"。第二,历史窗口与本次输入严格分离:store 回读最近 5 个 user-turn 仅作指代消解上下文(LAST 5 USER TURNS),本次add()的全部消息构成NEW MESSAGES抽取主体,且历史在finally块中回写——即使本次没跨过价值门槛,上下文也不能丢。四、coding 管线:版本演进链,"一个装饰器,不是检索器"coding 与 working 的差异可以精确列成三条:抽取规范不同(subject 必须是代码或决策,记录精确坐标而非粘贴代码)、存储独立(coding_memory_cv.db+*_cv集合)、以及独有版本演进链。而链的设计是整个 2.0 里最"反直觉"的一块,hy_memory/coding/chain_store.py 的模块文档把它说得很透:为什么必须存 diff,而不是把 fact 写详细点?因为抽取 prompt 是明文要求砍代码的——"EXACT COORDINATES, NOT PASTED CODE",硬上限约 200 汉字。这个取舍在通用场景下是对的:200 字预算里一个feat/x分支 token 的价值远超 30 行 diff,而且代码"可以回去读"。但前提有个洞:被撤掉那版的代码读不回来——它不在工作区、不在 HEAD,只在某次中间提交里。所以 chain_store 不改抽取 prompt 一个字,而是零 LLM 地把每一版的真实 patch 存下来,"补的不是抽取质量,是 LLM 摘要必然丢掉的那一类信息"。它是装饰器,不是检索器。向量层决定"给哪几条 fact"(top-k、阈值、排序全归它),chain 只负责"每条 fact 后面跟什么":把那条 fact 涉及的代码在这条分支上的全部改动版本(每版的用户原话 + 每版真实 diff)按顺序挂上去。不做相似度、不选版本、不猜哪版是最终答案——"判定权交给指令本身"。数据模型是两张表加一张辅助索引:thread(id, owner, branch, file, symbol, lo, hi, n_rounds, updated_at) 一条 thread = 某分支某文件某函数的某一块被反复改的历史 owner = 隔离键 "<user_id>|<workspace_id>" round(id, thread_id, seq, said, patch, adds, created_at) 一条 round = 一次改动,seq = 第几版 repo_symbol(name, path, line, kind) 全仓 AST 索引,只用于定位,不参与分链几个值得细看的工程决定:seq是 observe() 的第几次调用,纯计数。不做 diff 间比对、不推断谁覆盖谁,"第 1 版就是第一次调用,物理事实"——不存在猜错的可能。thread 键三级降级:hunk header 带函数名 →(owner, branch, file, symbol, 行区间);只有上下文文字 → 降到文件+行区间聚类(而不是直接降到文件粒度,否则同文件所有改动会挤成一条十几版的长链);裸 hunk → 文件粒度。且明确不用AST 索引按行号反查补符号,因为"patch 里的行号是改后的、索引是改前建的",会系统性偏一个符号。失败闸门:从对话里合成path/old/new替换操作时,必须检查编辑是否真的成功(AssertionError、old not in、returncode>1等正则判失败,REPLACED = 1等判成功),否则"agent 只是提议改法但用户拒绝了"的失败版本也会进链——"链是'哪一版赢了'的唯一依据,掺一个没生效的版本进去,agent 可能照着写"。注入预算全是显式常量:MAX_SAID_CHARS=800(每版原话)、MAX_BLOCK_CHARS=14000(整块)、TOPN_THREADS=3、TOPN_FACTS=1……注释反复强调一个原则:原话是这个机制的核心信息,宁可少挂一条链也不把它压短,因为"同一条链上各版原话的开头往往相同,真正区分版本的词常在后段"。改动来源只有两个确定性入口:本地 Git diff(配置MEMORY_CODING_CHAIN_REPO_ROOT),或工具 trace 里带path/old/new的确定性替换动作。检索时返回结构里,scene="coding"会额外带出chain_block(与已召回 fact 对齐的版本演进上下文,无法挂链时为空串)和chain_used字段。五、开发者钩子:官方把哪些旋钮留给了你抛开单条管线,"可编程记忆"真正体现在 API 与配置面上。梳理 hy_memory/client.py 的公开接口:写入面。add()的参数就是一组正交的隔离/路由维度:user_id / agent_id / session_id三级隔离键,source(如openclaw / cursor / codex)与agent_id正交,用于隔离不同调用方应用——这是"10 款 AI 工具共享同一份记忆但可分源治理"的底层支撑,检索端用include_sources / exclude_sources过滤;scene / workspace_id / branch控制管线路由与 coding 作用域;memory_at支持导入历史记忆并指定时间戳;meta是业务透传字段:不 embed、不参与召回、不作过滤,写入时存为 list(同一节点多次写入会追加而非覆盖),查询时原样返回;embed_override支持单次调用级别切换 embedding 端点(或用with embed_endpoint_override(...)上下文并发安全切换)。读与治理面。search()返回结构按场景分形:chat 返回memories(profile/normal/proactive 通道 +schema_min_score、intention_limit等分层预算),working/coding 返回facts/experiences双层 + coding 专属chain_block,且两层可分别用working_fact_min_score/working_experience_min_score设阈值。get / update / delete / list_memories构成 CRUD,evolve()与sweep()(仅 ultra 模式可用)是显式的 System 2 触发器,finalize_session()可以把一个会话固化为一等公民的 episode 叙事(opt-in)。存储与模型面。向量层兼容 ChromaDB(默认)/ Qdrant / FAISS,图层 Kuzu(默认)/ Neo4j,缓存可换 MySQL,全部通过 pip extras 安装(hy-memory[qdrant]、hy-memory[graph]……),配置只需一对 OpenAI 兼容的 LLM + embedding 端点。所有行为细节(历史轮数、tool 结果截断字节数、chain 预算等)都是环境变量,见 docs/env_reference.md 与 docs/scene_coding_usage.md。集成面。仓库里的 plugins/openclaw/ 插件暴露memory_search / memory_add / memory_get / memory_update / memory_delete五个工具,并提供 Auto-Recall(每轮 agent 前自动注入相关记忆)、Auto-Capture(每轮后自动存关键事实)、自动拉起本地 Python 服务三种托管能力;memhub/ 则把 Claude Code、Cursor、Codex、OpenCode、Qwen Code 等应用的会话历史与编码 trace 统一进一个本地数据目录做跨应用受控召回。SDK 内部每个阶段(judge/extract/reconcile)还有统一的 pipeline log 落库(store_pipeline_log记录 prompt、response、token、耗时),排查"为什么这条记忆没被写进去"时有据可查。六、一点观察:为什么是"分轨"而不是"大一统"把三条管线放在一起看,Hy Memory 2.0 的选择其实很克制:它没有试图用一套 schema 覆盖所有记忆,而是承认三类任务的记忆形态根本不兼容——个人事实要的是演化(分层抽象 + 冲突调和),生产力经验要的是复用(高门槛 + 边界环境),代码决策要的是可追溯(被回滚的版本必须能读回来)。框架层真正统一的是:一个客户端入口、一套 scene 路由协议、一组隔离键(user/agent/session/source/workspace/branch)、以及"路由与加工成本可按需付费"的降级策略(lite 模式零 LLM,judge 失败回退 chat)。这也解释了它论文层面的两个锚点:EMNLP 2026 的双系统认知记忆论文(chat 侧),和已提交 ICLR 2027 的 CMB benchmark(docs/papers/ 目录内有全文,针对长时程交织编码 agent 的记忆评测,coding 侧)。配合 30B-A3B 的记忆写入专用模型(用归因强化学习训练,专注高精度抽取与冲突调和),"框架开源 + 专用模型 + 评测集"算是把这条路线的三块拼图都放出来了。对想给 agent 加长期记忆的开发者来说,值得动手的不是它的宣传口径,而是 docs/usage.md 里那几张路由与返回结构表——它们定义了这个框架真正的能力边界。【免费下载链接】Hy-Memory项目地址: https://gitcode.com/gh_mirrors/hy/Hy-Memory创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
深度拆解 Hy Memory 2.0:chat / working / coding 三类记忆如何在一套框架里共存【免费下载链接】Hy-Memory项目地址: https://gitcode.com/gh_mirrors/hy/Hy-Memory2026 年 10 月,腾讯混元把 Hy Memory 2.0 整体开源:hy-memory==2.0.4上架 PyPI,配套的 Hy-Memory-30B-A3B 记忆写入模型(30B 总参数、仅激活 3B 的 MoE)一并放出,外加桌面/CLI 产品 MemHub 和 OpenClaw 插件,模型、框架、应用三层全开源。社区最感兴趣的一点是:它没有做"大而全"的一把梭记忆系统,而是把记忆按任务切成了chat / working / coding三条管线,却共用同一个HyMemoryClient入口、同一套写入/检索 API。这三类记忆的形态差异极大——聊天记忆是分层摘要与认知结构,生产力记忆是"事实+经验"双层卡片,编码记忆还要能追溯"被回滚的代码改了什么"。它们凭什么能装进一套框架?这篇文章基于仓库源码拆解三件事:三条管线各自的记忆形态与边界、System 1 / System 2 双系统如何分工、以及官方给开发者留了哪些可编程钩子。一、先说结论:三条管线,一个入口,数据完全分轨Hy Memory 把scene作为路由参数贯穿写入与检索,README 中给出的边界定义是:scene典型任务记忆形态chat闲聊、个人信息、偏好、一般问答L0–L7 分层记忆working文档、表格、研究、财经分析、内容创作、电脑操作双层记忆:会话事实 + 可复用经验coding编码、调试、测试、构建、API/SDK、脚本、SQL与 working 同构的双层记忆 + 代码版本演进链关键设计是"分轨"而非"融合":working 与 coding复用同一套生产力 pipeline 和 schema,但使用不同的抽取规范、独立的 SQLite 文件(coding_memory.dbvscoding_memory_cv.db)与向量集合,数据不会混在一起。这个取舍在 docs/scene_coding_usage.md 中写得很直白:两条链共享结构,隔离靠存储与规范,而不是靠一套"万能 prompt"。路由是怎么做的:一个"有界摘要"三分类器写入时如果调用方不显式指定scene,路由逻辑是:输入没有 tool/tool_calls:直接进 chat 管线,零 LLM 调用;输入含 tool 轨迹:调用一次场景分类 LLM,在chat / working / coding三选一中判定。分类器实现在 hy_memory/coding/judge.py,它是一个 single-label 分类器,且刻意只看一个"有界视图"——用户 query + 工具名的摘要,模块顶部用常量把输入框死:_JUDGE_MAX_TURNS = 20 _JUDGE_USER_CONTENT_LIMIT = 1_000 _JUDGE_USER_CONTENT_HEAD = 200 _JUDGE_USER_CONTENT_TAIL = 200分类边界也写进了 prompt:代码或开发产物是"工作对象或实现媒介"判 coding;有明确生产力交付物但代码不是核心媒介判 working;只用了 search/browser 类工具不会自动升格为 working。judge 失败或输出无法解析时回退 chat——这是一个偏保守的失败策略:宁可少进一条结构化管线,也不把噪声写进工作记忆。检索侧同理:search_mode="default"单 query 固定走 chat 轻量检索、零 LLM;search_mode="agentic"才启用 LLM 三分类 + query rewrite + 时间范围解析;而显式传scene时直接选路,跳过一切 judge/rewrite。也就是说,路由成本是可按需付费的,高频低价值调用可以完全绕开 LLM。二、chat 管线:八层记忆与双系统分工L0–L7:原始对话如何被逐层抽象chat 管线是典型的"长期个人记忆"形态。记忆层枚举定义在 hy_memory/models/memory.py 中:class MemoryLayer(str, Enum): L0_BASIC_INFO = "l0_basic_info" # 基本信息 L1_RAW = "l1_raw" # 原始对话 (Append-Only) L2_FACT = "l2_fact" # 原子事实 (版本化不可变记录) L3_SUMMARY = "l3_summary" # 会话摘要 ... L6_SCHEMA = "l6_schema" # 心智模型 (抽象叙事模板, Graph 层) L7_INTENTION = "l7_intention" # 前瞻意图 (带过期时间)从只增不改的 L1 原始对话,到版本化原子事实 L2、会话摘要 L3,再往上到图层的 SCHEMA(心智模型)与 INTENTION(前瞻意图,过期后降级为普通事实)——每一层服务不同的检索粒度。读取侧也对应设计了分层视图:画像摘要(L0,始终返回)、索引视图(~100 tokens)、摘要视图(~500 tokens)、完整内容(按需懒加载),token 预算是显式管理的。System 1 / System 2:即时写入与离线演化的双系统这是 Hy Memory 论文(EMNLP 2026 收录的Memory Beyond Recall: A Dual-Process Cognitive Memory System)的核心主张,也是"双系统认知架构"的落点。代码里的分工非常清晰:System 1 跑在add()路径上,负责即时。hy_memory/agent/mem_agent.py 中的MemAgent统一调度 Extractor(事实/实体提取)与 Reflector(反思)。Reflector 的职责不是简单去重,而是把新信息与已有信息的关系分类为OVERRIDE / SUPPLEMENT / TEMPORAL / NEGATE / CONFLICT五类更新类型,并做冲突检测与隐式信号推断(hy_memory/agent/reflector.py)。L7 的意图抽取也是 System 1 在写入时即时完成的。System 2 跑在evolve()上,负责慢思考。hy_memory/pipelines/system2_agent.py 的头注释说明了它的设计:Phase 1 是硬编码预处理——从 VDB 取未处理事实、DBSCAN 聚类、图正向/反向查找;Phase 2 才是 Agent LLM,且只在聚类非空时触发,散事实冷启动时不烧 LLM。evolve()的 API 语义值得单独看(hy_memory/client.py):def evolve(self, user_id, agent_id="default_agent", max_batches=None): """ 手动触发 System 2 认知加工(ultra 模式专用,同步阻塞直到完成)。 非幂等:每次 evolve 看到的是当前 VDB 全量,连续多次 evolve 有意义 (add 一批 → evolve → 再 add 一批 → 再 evolve)。 触发时机由调用方控制:System 2 不在 add/write 里自动触发,也无进程内队列。 仅 ultra 模式可调用。 """注意两个工程细节:System 2不自动触发,节奏完全交给调用方——这把它从"后台黑盒"变成了可编程的批处理单元;evolve是非幂等的(每次扫 VDB 全量),所以"add 一批 → evolve → 再 add 一批 → 再 evolve"是推荐的迭代模式。另外 Agent 单次处理的候选事实被_S2_MAX_FACTS_PER_BATCH = 24限流,防止 LLM 输出预算耗尽产出不可解析的 JSON。三档模式则把双系统做成了可降级的配置:lite(纯 embedding,零 LLM,scene/layers全忽略)、pro(+ LLM 提取 + reconcile,图谱可选)、ultra(+ System 2 schema 归纳 + cross-domain sweeper,图谱必开)。三、working 管线:事实层保证"记下来",经验层保证"用得上"working 管线的核心是一次会话 trace 同时产出两层记忆(hy_memory/coding/types.py):层记录什么数量策略结构Facts(WorkingFact)本次做了什么:任务、做法、结果每 session 恰好 1 条,无阈值statement,subject,files,detailsExperiences下次遇到同类任务可复用的方法0–N 条,必须过价值门槛task,search_keys,solution,boundary_envs,confidence事实层"无门槛、必落一条",保证干过的事一定有迹可循;经验层"高门槛、宁缺毋滥",boundary_envs记录经验依赖的环境、confidence给出置信度,供消费方判断是否仍适用。两层互相链接:fact.derived_experience_ids↔experience.source_fact_ids由同批全互链回填,被覆盖的事实则通过 task 进展链(fact_chain_summary)保持可追溯。写入协调器 hy_memory/coding/writer.py 把整条链串起来,模块注释本身就是流程文档:extractor.extract(...) ← 一次 LLM 产出双层草稿 reconciler.reconcile(经验草稿) ← ADD/UPDATE/DELETE/SKIP fact_reconciler.reconcile(事实草稿) ← INSERT/SUPERSEDE _crosslink(...) ← 同批全互链回填其中有两处设计哲学值得注意。第一,抽取时故意不给 LLM 看库里已有记忆:writer 的注释解释,把已有 task 摆在 extractor 面前,它会"把一个其实不同的任务往清单里某个措辞上靠",随后被 reconciler 误判为 UPDATE 合并掉——措辞对不上顶多多存一条,措辞被带偏是直接写错。去重/合并的判定权完全交给 reconcile 阶段,抽取只负责忠实记录"这一段发生了什么"。第二,历史窗口与本次输入严格分离:store 回读最近 5 个 user-turn 仅作指代消解上下文(LAST 5 USER TURNS),本次add()的全部消息构成NEW MESSAGES抽取主体,且历史在finally块中回写——即使本次没跨过价值门槛,上下文也不能丢。四、coding 管线:版本演进链,"一个装饰器,不是检索器"coding 与 working 的差异可以精确列成三条:抽取规范不同(subject 必须是代码或决策,记录精确坐标而非粘贴代码)、存储独立(coding_memory_cv.db+*_cv集合)、以及独有版本演进链。而链的设计是整个 2.0 里最"反直觉"的一块,hy_memory/coding/chain_store.py 的模块文档把它说得很透:为什么必须存 diff,而不是把 fact 写详细点?因为抽取 prompt 是明文要求砍代码的——"EXACT COORDINATES, NOT PASTED CODE",硬上限约 200 汉字。这个取舍在通用场景下是对的:200 字预算里一个feat/x分支 token 的价值远超 30 行 diff,而且代码"可以回去读"。但前提有个洞:被撤掉那版的代码读不回来——它不在工作区、不在 HEAD,只在某次中间提交里。所以 chain_store 不改抽取 prompt 一个字,而是零 LLM 地把每一版的真实 patch 存下来,"补的不是抽取质量,是 LLM 摘要必然丢掉的那一类信息"。它是装饰器,不是检索器。向量层决定"给哪几条 fact"(top-k、阈值、排序全归它),chain 只负责"每条 fact 后面跟什么":把那条 fact 涉及的代码在这条分支上的全部改动版本(每版的用户原话 + 每版真实 diff)按顺序挂上去。不做相似度、不选版本、不猜哪版是最终答案——"判定权交给指令本身"。数据模型是两张表加一张辅助索引:thread(id, owner, branch, file, symbol, lo, hi, n_rounds, updated_at) 一条 thread = 某分支某文件某函数的某一块被反复改的历史 owner = 隔离键 "<user_id>|<workspace_id>" round(id, thread_id, seq, said, patch, adds, created_at) 一条 round = 一次改动,seq = 第几版 repo_symbol(name, path, line, kind) 全仓 AST 索引,只用于定位,不参与分链几个值得细看的工程决定:seq是 observe() 的第几次调用,纯计数。不做 diff 间比对、不推断谁覆盖谁,"第 1 版就是第一次调用,物理事实"——不存在猜错的可能。thread 键三级降级:hunk header 带函数名 →(owner, branch, file, symbol, 行区间);只有上下文文字 → 降到文件+行区间聚类(而不是直接降到文件粒度,否则同文件所有改动会挤成一条十几版的长链);裸 hunk → 文件粒度。且明确不用AST 索引按行号反查补符号,因为"patch 里的行号是改后的、索引是改前建的",会系统性偏一个符号。失败闸门:从对话里合成path/old/new替换操作时,必须检查编辑是否真的成功(AssertionError、old not in、returncode>1等正则判失败,REPLACED = 1等判成功),否则"agent 只是提议改法但用户拒绝了"的失败版本也会进链——"链是'哪一版赢了'的唯一依据,掺一个没生效的版本进去,agent 可能照着写"。注入预算全是显式常量:MAX_SAID_CHARS=800(每版原话)、MAX_BLOCK_CHARS=14000(整块)、TOPN_THREADS=3、TOPN_FACTS=1……注释反复强调一个原则:原话是这个机制的核心信息,宁可少挂一条链也不把它压短,因为"同一条链上各版原话的开头往往相同,真正区分版本的词常在后段"。改动来源只有两个确定性入口:本地 Git diff(配置MEMORY_CODING_CHAIN_REPO_ROOT),或工具 trace 里带path/old/new的确定性替换动作。检索时返回结构里,scene="coding"会额外带出chain_block(与已召回 fact 对齐的版本演进上下文,无法挂链时为空串)和chain_used字段。五、开发者钩子:官方把哪些旋钮留给了你抛开单条管线,"可编程记忆"真正体现在 API 与配置面上。梳理 hy_memory/client.py 的公开接口:写入面。add()的参数就是一组正交的隔离/路由维度:user_id / agent_id / session_id三级隔离键,source(如openclaw / cursor / codex)与agent_id正交,用于隔离不同调用方应用——这是"10 款 AI 工具共享同一份记忆但可分源治理"的底层支撑,检索端用include_sources / exclude_sources过滤;scene / workspace_id / branch控制管线路由与 coding 作用域;memory_at支持导入历史记忆并指定时间戳;meta是业务透传字段:不 embed、不参与召回、不作过滤,写入时存为 list(同一节点多次写入会追加而非覆盖),查询时原样返回;embed_override支持单次调用级别切换 embedding 端点(或用with embed_endpoint_override(...)上下文并发安全切换)。读与治理面。search()返回结构按场景分形:chat 返回memories(profile/normal/proactive 通道 +schema_min_score、intention_limit等分层预算),working/coding 返回facts/experiences双层 + coding 专属chain_block,且两层可分别用working_fact_min_score/working_experience_min_score设阈值。get / update / delete / list_memories构成 CRUD,evolve()与sweep()(仅 ultra 模式可用)是显式的 System 2 触发器,finalize_session()可以把一个会话固化为一等公民的 episode 叙事(opt-in)。存储与模型面。向量层兼容 ChromaDB(默认)/ Qdrant / FAISS,图层 Kuzu(默认)/ Neo4j,缓存可换 MySQL,全部通过 pip extras 安装(hy-memory[qdrant]、hy-memory[graph]……),配置只需一对 OpenAI 兼容的 LLM + embedding 端点。所有行为细节(历史轮数、tool 结果截断字节数、chain 预算等)都是环境变量,见 docs/env_reference.md 与 docs/scene_coding_usage.md。集成面。仓库里的 plugins/openclaw/ 插件暴露memory_search / memory_add / memory_get / memory_update / memory_delete五个工具,并提供 Auto-Recall(每轮 agent 前自动注入相关记忆)、Auto-Capture(每轮后自动存关键事实)、自动拉起本地 Python 服务三种托管能力;memhub/ 则把 Claude Code、Cursor、Codex、OpenCode、Qwen Code 等应用的会话历史与编码 trace 统一进一个本地数据目录做跨应用受控召回。SDK 内部每个阶段(judge/extract/reconcile)还有统一的 pipeline log 落库(store_pipeline_log记录 prompt、response、token、耗时),排查"为什么这条记忆没被写进去"时有据可查。六、一点观察:为什么是"分轨"而不是"大一统"把三条管线放在一起看,Hy Memory 2.0 的选择其实很克制:它没有试图用一套 schema 覆盖所有记忆,而是承认三类任务的记忆形态根本不兼容——个人事实要的是演化(分层抽象 + 冲突调和),生产力经验要的是复用(高门槛 + 边界环境),代码决策要的是可追溯(被回滚的版本必须能读回来)。框架层真正统一的是:一个客户端入口、一套 scene 路由协议、一组隔离键(user/agent/session/source/workspace/branch)、以及"路由与加工成本可按需付费"的降级策略(lite 模式零 LLM,judge 失败回退 chat)。这也解释了它论文层面的两个锚点:EMNLP 2026 的双系统认知记忆论文(chat 侧),和已提交 ICLR 2027 的 CMB benchmark(docs/papers/ 目录内有全文,针对长时程交织编码 agent 的记忆评测,coding 侧)。配合 30B-A3B 的记忆写入专用模型(用归因强化学习训练,专注高精度抽取与冲突调和),"框架开源 + 专用模型 + 评测集"算是把这条路线的三块拼图都放出来了。对想给 agent 加长期记忆的开发者来说,值得动手的不是它的宣传口径,而是 docs/usage.md 里那几张路由与返回结构表——它们定义了这个框架真正的能力边界。【免费下载链接】Hy-Memory项目地址: https://gitcode.com/gh_mirrors/hy/Hy-Memory创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考