
Hindsight 与 RAG从单路语义检索到四路并行召回的结构化记忆引擎【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight本文基于 Hindsight 仓库的开发者文档 rag-vs-hindsight.md 展开对比传统 RAGRetrieval-Augmented Generation与 Hindsight 结构化记忆在检索策略、多跳推理、时间查询、实体理解、知识固化与行为特质disposition六个维度上的能力差异并结合 memory_engine.py、fusion.py 等源码拆解 Hindsight「解析查询 → 四路并行召回 → RRF 融合 → 交叉编码器重排 → 特质注入」这条 recall 管线的真实实现。读完你可以掌握如何在架构选型上判断该用 RAG 还是记忆系统以及如何理解 Hindsight 每条召回臂arm的底层代码与配置开关。核心区别检索相似文档 vs 维护有状态的信念文档开篇给出的定位是一句话传统 RAG 只检索与查询相似的文档Hindsight 提供具备时间推理、实体理解和信念形成belief formation能力的结构化记忆。这句话对应两类系统的本质差异RAG 是无状态的每次查询独立执行「嵌入 → 向量检索 → 取 top-k → 生成」查询之间不共享任何信息。Hindsight 是有状态的它把写入的事实固化为观察observation、实体关系、心智模型mental model跨会话持久存在并随新证据演化。能力对比六个维度逐项拆解原文档的能力对比表是理解两者边界的核心完整继承如下能力RAGHindsight检索策略仅语义相似度语义 关键词 图 时间多跳推理局限于检索到的文本块沿实体关系做图遍历时间查询关键词匹配如 spring 只能按字面词匹配日期解析与区间过滤实体理解无实体消解entity resolution与共现跟踪知识固化无状态心智模型综合并持续演化行为特质Disposition无3 项特质scepticism、literalism、empathy影响解释方式下面结合源码说明这些能力在 Hindsight 中分别落在哪里。检索策略四路并行召回臂recall_async的 docstring 直接给出了管线总览memory_engine.pyRetrieval: 对每种 fact type 运行 4 路并行检索semantic vector、BM25 keyword、graph activation、temporal graphMerge: 用 Reciprocal Rank Fusion (RRF) 合并Rerank: 用选定的 rerankerheuristic 或 cross-encoder打分Diversify: 应用 MMR 做多样性Token Filter: 按max_tokens预算截断返回从源码结构看这四路检索臂在 search/ 目录中各有实现语义臂查询向量在向量索引中做相似度检索RetrievalResult.similarity字段承载得分关键词臂BM25RetrievalResult.bm25_score承载得分配套 bm25_term_selection.py 做词项选择图臂graph_retrieval.py 中的GraphRetriever抽象基类负责「遍历记忆图entity links、temporal links、causal links」——这正是能力表中「多跳推理沿实体关系做图遍历」的实现载体时间臂由查询中的自然语言时间表达式驱动细节见下节。每条臂都可以按银行bank即独立记忆空间粒度关闭recall_async中会读取预算配置里的enable_temporal_retrieval与enable_graph_retrieval开关memory_engine.py关闭时间臂时也会跳过基于日期的相关度处理search/retrieval.py 的注释进一步说明enable_graph_retrievalFalse会直接跳过图查询。RRF 融合文档说「Fuse results with RRF」代码里是这样做的RRF 的完整实现在 fusion.py 中# 公式: score(d) sum_over_lists(1 / (k rank(d)))默认 k60 def reciprocal_rank_fusion(result_lists: list[list[RetrievalResult]], k: int 60) - list[MergedCandidate]: ... source_names [semantic, bm25, graph, temporal]几个值得注意的实现细节臂的顺序是固定的source_names按 semantic、bm25、graph、temporal 的索引顺序命名各臂结果与文档架构表中「执行 4 路并行检索」的顺序一致每个臂的结果先被截断再融合cap_per_source函数按源截断「在融合前对单路检索结果截断到 top-cap避免某一膨胀的后端挤占其他臂」防止某一路产出过多候选时把候选池占满融合会保留各臂的原始得分ArmScores结构记录每个候选在语义臂的similarity与 BM25 臂的bm25_score供后续重排阶段使用而MergedCandidate则携带source_ranks该候选在每个臂内的名次用于调试与溯源存在一种替代融合策略interleave_fusion采用轮询round-robin融合——按「各臂第 1 名 → 各臂第 2 名……」的顺序轮流取结果并去重。其 docstring 说明了动机RRF 按各臂倒数排名求和打分一条「在语义臂排第 1 但在其他臂缺席」的结果会被平均拉低这恰恰是知识固化consolidation去重场景的失败模式轮询融合则保证每个臂的头部命中都有位置。这说明文档中「RRF 融合」并非唯一实现而是 recall 主链路的默认策略。时间查询从「关键词匹配」到「日期解析 区间过滤」文档用 spring 举例RAG 只能把 spring 当普通词去匹配而 Hindsight 能解析 last spring → 3–5 月并过滤到该区间。源码侧这条能力由 temporal_extraction.py 承担其文件注释写明它「使用基于 transformer 的查询分析处理自然语言时间表达式」默认分析器是DateparserQueryAnalyzer定义于 query_analyzer.py。一个工程细节值得展开该模块把纯 CPU 的时间表达式抽取刻意放到单 worker 的线程池中执行而不是内联在事件循环里。模块注释给出了实测数据16 个并发抽取场景下内联执行会让事件循环卡住 1.3 秒期间所有在途请求全部停摆而单 worker 线程方案下循环卡顿最大值降到 2.8ms。注释同时解释了为什么是 1 个而不是多个 worker——工作是纯 Python 且持有 GIL扩大线程池只会加剧 GIL 竞争。这体现了时间臂作为 recall 管线一环时对整体服务响应性的约束。此外调用方也可以不依赖查询文本中的时间词recall_async提供temporal_window参数「用于替代从 query 中提取日期它把落在窗口内的记忆排得更靠前但不会排除窗口外的记忆」memory_engine.py。重排阶段交叉编码器 时间信号文档架构表的第 4 步「Rerank with cross-encoder」对应 search/reranking.py。从源码结构看重排并不是单纯的神经打分而是在交叉编码器CE基础分之上叠加了乘性时间 boost# 每个信号对基础 CE 分数的相对调整至多 ±(alpha/2) _RECENCY_ALPHA: float 0.2 # 新鲜度recency _TEMPORAL_ALPHA: float 0.2 # 时间邻近度 _PROOF_COUNT_ALPHA: float 0.1 # 证据强度保守取 ±5%新鲜度信号由compute_recency_decay计算支持三种衰减函数代码注释linear默认从 1.0当天线性降到 0.1 的下限在linear_window_days默认 365 天内完成衰减exponential0.5 ** (days_ago / halflife_days)半衰期即信号恰好中性的记忆年龄默认 90 天无硬截断none恒为中性 0.5完全关闭新鲜度 boost。这解释了能力表中 Hindsight 与 RAG 的另一个隐性差异RAG 的 top-k 完全由向量距离决定而 Hindsight 的重排同时感知「记忆的新鲜程度」和「记忆日期与查询时间窗的邻近程度」且未来日期的记忆会被钳制到最高新鲜度、永远不受惩罚。实体理解与多跳推理文档中 Alice → Project Atlas → Kubernetes → outage 的多跳示例对应源码中的两个支撑点图遍历GraphRetriever的retrieve方法接收query_embedding_str用于找图的入口点、budget最多探索/返回的节点数recall接口注释给出 low100 / mid300 / high600 units 三档预算以及可选的预加载邻接表adjacencygraph_retrieval.py实体消解entity_resolver.py 负责把自由文本中的实体指称归一到同一实体仓库测试 test_entity_resolver.py 覆盖其行为这对应能力表中的「entity resolution, co-occurrence tracking」。recall_async还暴露了include_entities/max_entity_tokens参数可以在召回结果中附带实体状态默认 500 token 预算让上层直接拿到「与本次查询相关的实体图快照」而不只是孤立的 fact 列表。行为特质disposition 如何影响解释能力表最后一行「Disposition3 项特质scepticism、literalism、empathy影响解释」在代码中落地为三个整数配置项。config.py 定义了disposition_skepticism: int | None disposition_literalism: int | None disposition_empathy: int | None它们支持环境变量注入同文件 L4807–L4813 从ENV_DISPOSITION_*读取并转为int。这些值在生成阶段被写进提示词reflect/prompts.py 会把特质拼成skepticism…、literalism…形式的标记附加到 prompt 中从而影响回答的语气与解释风格。仓库中的迁移脚本disposition_to_3_traits.py、rename_personality_to_disposition.py也印证了这一概念经历过「personality → disposition → 3 traits」的演进。知识固化心智模型如何演化文档「知识演化」场景描述的行为——从「用户偏好同步编程」固化为「用户对异步渐入渐出」——对应 Hindsight 的固化链路consolidation/ 目录实现把原始 fact 折叠为 observation 的批处理逻辑mental_model_refresh.py 负责心智模型按窗口watermark 跟踪updated_at增量刷新。从recall_async的prefer_observations参数注释「当一个 observation 已固化自某些原始 fact 时把那些原始 fact 从结果中剔除按来源去重」可以推断召回层会主动让「演化后的结论」替代「演化前的碎片」这正是 RAG 做不到的「跨查询持久状态」。架构对比两套管线的步骤级差异完整继承文档的架构对比表RAG步骤操作1嵌入查询2向量相似度检索3返回 top-k 文本块4生成回答单一检索策略查询之间无状态。Hindsight步骤操作1解析查询提取时间表达式、实体2执行 4 路并行检索semantic、BM25、graph、temporal3用 RRF 融合结果4用交叉编码器重排5应用 disposition 特质6生成回答多检索策略跨会话持久状态。对照源码文档的 6 步与recall_async的 5 阶段一一对应步骤 1 由 temporal_extraction.py 的查询解析完成时间表达式抽取被异步化到线程池不阻塞事件循环步骤 2–3 由四臂检索 cap_per_source截断 reciprocal_rank_fusion完成步骤 4 由 cross-encoder 重排完成注意recall_async的reranking参数默认取cross_encoder见 memory_engine.py步骤 5 体现在 reflect/生成阶段的 prompt 注入步骤 6 之后还有文档未列出的第 5 阶段——MMR 多样性选择与max_tokenstoken 预算过滤。示例场景四类典型查询的表现差异完整继承文档的四个对比场景。多跳推理Multi-Hop Reasoning存储的事实Alice is the tech lead on Project AtlasProject Atlas uses KubernetesKubernetes cluster had an outage Tuesday查询Was Alice affected by recent issues?系统结果RAG只检索到关于 Alice 的事实与 issues 无语义相似度Hindsight沿实体链接遍历 Alice → Project Atlas → Kubernetes → outage源码印证图臂的GraphRetriever就是为此设计的——它以语义检索结果作为「独立阈值筛选后的图入口点」preselected_semantic_seeds参数进入记忆图沿着实体/时间/因果链接扩展从而检索到「语义或关键词搜索单独找不到」的事实graph_retrieval.py 的模块 docstring。时间查询Temporal Queries带时间戳的存储事实3 月Alice started microservices migration4 月Alice completed auth service10 月Alice focusing on performance查询What did Alice do last spring?系统结果RAG不分日期地返回所有 Alice 相关事实Hindsight解析 last spring → 3–5 月并过滤到该区间源码印证时间臂的驱动来自extract_temporal_constraint对查询的自然语言时间解析temporal_extraction.py而重排阶段的时间邻近度 boost_TEMPORAL_ALPHA 0.2会进一步把日期落在查询时间窗附近的记忆排上去调用方也可以显式传temporal_window直接指定窗口绕过文本解析。实体理解Entity Understanding跨会话存储的用户事实Pro subscriptionMobile app crashes in settingsSwitched to annual billingDesktop app working fine查询What do you know about my account?系统结果RAG罗列互不相连的事实Hindsight通过实体图返回关联事实订阅状态、计费、已知问题源码印证entity_resolver.py 负责把多条会话中的指称归一到同一实体recall_async的include_entitiesTrue则能在返回结果中附带相关实体的观察集合默认max_entity_tokens500让上层直接获得「以实体为中心的关联事实簇」而非松散列表。知识演化Knowledge Evolution第 1 周用户在 async Python 上挣扎用 threads 才成功第 3 周用户询问 asyncio实现了异步数据库调用系统行为RAG没有关于进步轨迹的记忆Hindsight固化出心智模型「用户偏好同步」→ 精化为「用户对异步渐入渐出」源码印证该行为由固化管线驱动——consolidation/ 将原始 fact 折叠成 observationmental_model_refresh.py 按水位watermark增量刷新心智模型recall_async的prefer_observations机制则保证召回层优先展示「演化后的结论」并剔除其已被吸收的原始碎片。选型指南什么时候用哪个完整继承文档的选型表使用场景推荐静态语料库上的文档问答RAG无时间需求的一般检索RAG需要持久记忆的 AI 助手Hindsight需要实体跟踪的应用Hindsight需要一致行为特质disposition的系统Hindsight时间查询last month、in 2023Hindsight选型时可以把握一条简化判据你的应用是否需要「跨查询的状态」。如果每次请求都是独立的「语料 → 问答」RAG 的嵌入 top-k 已经足够且链路更短、成本更低一旦需要实体在多次会话中保持一致、按时间窗回答「上次/去年」类问题、或让系统对同一用户形成并持续修正的理解心智模型 dispositionHindsight 这类带四臂召回、RRF 融合、时间感知重排与固化管线的记忆引擎才有用武之地。延伸阅读仓库中的关键路径rag-vs-hindsight.md本文对应的原始开发者文档RAG vs Memorymemory_engine.pyrecall_async四臂召回管线的入口与参数全集fusion.pyRRF 与轮询融合的具体实现temporal_extraction.py自然语言时间表达式抽取与线程池调度的实测注释graph_retrieval.py图检索抽象基类实体/时间/因果链接遍历reranking.pycross-encoder 重排与新鲜度/时间邻近度 boostentity_resolver.py实体消解mental_model_refresh.py心智模型增量刷新config.pydisposition 三特质配置项适用前提以上源码分析基于当前仓库快照Python 服务端位于hindsight-api-slim/参数默认值如 RRFk60、重排 boost α0.2、max_tokens4096、图预算 low/mid/high100/300/600以该版本 memory_engine.py 与 fusion.py 的实际定义为准升级版本后请核对源码。【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考