人工智能AI AgentAgent 记忆RAGMCP 服务【免费下载链接】agent-memoryMemory 是一款面向 AI 智能体的长期记忆模块为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。项目地址https://gitcode.com/openJiuwen/agent-memory点击查看免费下载本文以 agent-memory 项目特性文档 F06-composite-recaller-assembly.md 为骨架结合jiuwen_memory/storage与jiuwen_memory/retrieval的当前源码实现、默认装配配置与测试基线完整讲解「多路 Recaller 召回路装配从 Retriever 工厂内收到 Storage/StoreManager 工厂」这一设计决策。读完你将掌握七个*_recaller选择键与三个能力开关的配置语义、具名/匿名构建下循环依赖的双预注册破解方案、PipelineRetriever不再持有召回路后的委托模型以及手工接线与构建期 fail-fast 的测试验证方式。背景统一 Storage 落地后的装配错位在 F05-unified-storage-design 统一 Storage 落地之后PipelineRetriever的生产装配仍按旧世界做事retriever 工厂自己组装 keyword/vector/graph/L0/L1 各路 Recaller再通过isinstance(storage, CompositeStorage)判断后调用bind_recallers把召回路塞回 storage。这种装配方式带来三个结构性问题责任错位recall/get/rank 三条首选路径的执行都在 Storage 内唯独召回路的组装留在 Retriever 工厂——CompositeStorage的能力开关如vector_enabled要由别人替它解释能力声明与实际装配脱节。非 Composite 实现被拖进无关概念一体化 Storage 自带检索路径根本不需要 Recaller旧装配却仍先组装一整组 recaller再发现无处可绑白白浪费构建成本并造成概念污染。构造签名被迫膨胀PipelineRetriever构造签名被迫携带recallers参数并在构造期做「无 storage 就用 unit_reader.kv 临时拼一个 CompositeStorage 再绑 recaller」的兼容逻辑把一个装配期问题泄漏进运行期对象。核心决策五条设计主线针对上述问题F06 确立了五条相互咬合的决策其最终形态在当前仓库代码中完整落地。决策 1召回路装配内收到 Storage 工厂StorageProducer.register(composite)的_build按配置组装 recaller。在 F07 拆分后该装配入口位于 composite_store_manager.py 的from_config召回路组装逻辑收敛在 composite_domain_store.py 的_assemble_recallers与for_manager能力开关vector_enabled/graph_enabled/layers_index_enabled经config.get回退 globals属于跨切面意图开关recaller 选择键keyword_recaller/vector_recaller/graph_recaller/keyword_l0_recaller/keyword_l1_recaller/vector_l0_recaller/vector_l1_recaller共七个落在storage.default.paramsF07 后进一步下移到domain_stores.default。这组键相应从defaults.py的retriever.default.params移到了 storage 侧retriever段只保留本算子私有调参over_fetch_factor、recall_max、rerank_max等。默认装配下会同步组装出 7 路 recaller。决策 2构建期同步组装 双预注册打破循环recaller builder 内部会StorageProducer.resolve(config)回取本 Storage 实例而build_named没有「构建中」检测——如果装配期直接同步组装会形成「装配 CompositeStorage → 组装 recaller → recaller 回取 Storage → 再建一个 CompositeStorage」的无限递归。破解方案是_build先把构建中的实例预注册进具名缓存再组装且区分具名/匿名两条路径。决策 3PipelineRetriever 不再持有召回路构造签名删除recallers参数与recallers属性retrieve只按storage.preferred_retrieval_pipeline()委托recall/recall_and_get/retrieve。非 Composite 实现不再被拖进 recaller 概念。storageNone回退保留为CompositeStorage(kvunit_reader.kv)无召回路仅供只走点读/短路路径的调用。决策 4bind_recallers 保留为手工/测试接线口recaller 构造需要 storage 实例如KeywordRecaller(storage)手工接线仍是「先建 storage、再建 recaller、再 bind」绑定后惰性 loader 作废。重绑守卫不变同一实例不允许绑定两套不同 recaller。决策 5模块依赖方向不破composite_storage.py只在_assemble_recallers函数体内惰性from jiuwen_memory.retrieval.recaller import RecallerProducer模块层面 storage 仍不导入 retrieval。F07 E 组把 Recaller 整体移入 storage 数据面后这条延迟导入连同它绕开的循环一起消失——这正是当前代码中Recaller契约与实现已经位于 recaller.py 的原因。配置详解七个选择键与三个能力开关召回路装配的完整默认配置位于 defaults.py。F07 参数归位后数据面的全部装配参数住在store_manager.inst.params.domain_stores.name默认形状如下globals: schema_enabled: false vector_enabled: true graph_enabled: true rerank_enabled: true embedder_dim: 64 chunk_size: 120 store_manager: default # 全局唯一 StoreManager 指名 store_manager: default: target: composite params: domain_stores: default: # 数据面 default 必建命名实例 overlay 在它之上 kv_store: default preferred_retrieval_pipeline: recall_get_rank keyword_recaller: keyword vector_recaller: vector graph_recaller: graph keyword_l0_recaller: keyword_l0 keyword_l1_recaller: keyword_l1 vector_l0_recaller: vector_l0 vector_l1_recaller: vector_l1下表给出全部装配参数的语义参数取值/默认语义kv_store端口名字符串默认default数据面真源 KV 端口名与其余消费方同一套选择键机制运行期不硬编码defaultpreferred_retrieval_pipelinerecall_get_rank/recall_and_get_rank/retrieve数据面实例级稳定的首选检索路径见 retrieval.py 的RetrievalPipeline枚举keyword_recallerkeyword关键词/全文通道L2 content包一个FulltextStorevector_recallervector向量语义通道L2 content chunk包一个VectorStoregraph_recallergraph图遍历通道关键词种子 → 1 跳邻居候选keyword_l0_recallerkeyword_l0预生成概要分表的全文倒排召回keyword_l1_recallerkeyword_l1预生成片段分表的全文倒排召回vector_l0_recallervector_l0概要整段向量分表召回vector_l1_recallervector_l1片段整段向量分表召回recaller 具名实例声明在recaller:顶层命名空间target 与注册名在 F07 迁移后逐字不变YAML 配置零迁移recaller: keyword: { target: keyword } keyword_l0: { target: keyword_l0 } keyword_l1: { target: keyword_l1 } vector: { target: vector, params: { min_similarity: 0.0 } } vector_l0: { target: vector_l0 } vector_l1: { target: vector_l1 } graph: { target: graph }三个能力开关的生效逻辑见_assemble_recallersvector_enabledfalse时不装vector_recaller/vector_l0_recaller/vector_l1_recallergraph_enabledfalse时不装graph_recallerlayers_index_enabledfalse时不装 L0/L1 四路keyword_l0/l1、vector_l0/l1。注意一个易踩的静默退化陷阱RecallerProducer.dep读的是config.params直读不回退 globals因此domain_stores的命名 entry 必须先 overlay 在defaultentry 之上再传入。若命名 entry 漏掉*_recaller键dep会落到cls.build(default, {}, ctx)匿名新建一套不共享、params 为空的 recaller——装配不报错读写悄悄用上两套实例测试 test_named_domain_stores.py 中test_named_entry_shares_recaller_instance_with_default用对象身份is断言而非通道名来锁死该退化。源码级原理循环依赖的具名/匿名双预注册Factory.build_named见 factory.py没有「构建中」检测命中缓存即返回共享实例未命中则新建并入缓存。这意味着装配期直接同步组装 recaller 时recaller builder 内部的StorageProducer.resolve(config)会触发再建一个 CompositeStorage形成递归。_assemble_recallers按构建形态拆成两条分支具名构建config.name非空CompositeStoreManager.from_config先StoreManagerProducer.put(config.name, manager)把构建中的实例预注册进具名缓存recaller 命名空间下声明的具名实例recaller.keyword等带store_manager: name字符串引用RecallerProducer.dep走build_named命中缓存StoreManagerProducer.resolve在 builder 内回取成功打破循环。匿名构建无config.name如IndexBuilderProducer调StorageProducer.resolve落到第三分支构建无缓存键dep缺省会回落cls.build(default, {}, ctx)再次触发 recaller builder 用空 params 走StorageProducer.resolve落第三分支再建一个匿名 CompositeStorage → 递归。破解方案是用合成名__anon_store_manager_{id(storage)}__id保证唯一预注册本实例改走RecallerProducer.build(target, {store_manager: synthetic_name}, ctx)直接注入 storage 引用让 builder 内resolve走第一分支cls.dep命中合成名缓存。当前实现见 composite_domain_store.py_assemble_recallers的synthetic_name分支。装配错误选择键指向未注册实现、必填插件缺失等在构建期 fail-fast 暴露不拖到首次召回。这正是测试 test_storage_factory_wiring.py 中test_recaller_assembly_error_surfaces_at_build_time锁住的行为把vector_recaller指向nonexistent_impl后StoreManagerProducer.build_named(default, context)在构建期直接抛ValidationError。PipelineRetriever 的委托模型当前 pipeline_retriever.py 的构造签名已不含recallers只收parser/fuser/discloser/unit_reader/reranker与检索调参以及 keyword-only 的domain_storeF07 后 Retriever 运行期只持数据面。_build工厂只做两件事经StoreManagerProducer.resolve取全局 manager再用manager.domain_store(resolve_name(config, domain_store))取数据面注入。retrieve的召回段按self._domain.preferred_retrieval_pipeline()三选一首选路径行为RECALL_GET_RANK先recall多路并行召回 ScoredUnit→ 再get物化真源 复核 → fuser 融合RECALL_AND_GET_RANK数据面内一次完成recall_and_getRetriever 侧复核后直接融合RETRIEVE数据面内完成 recall get rank传入 fuserRetriever 只收已融合候选多路并行与结果合并由 composite_domain_store.py 的recall负责按channels过滤已装配 recallerThreadPoolExecutor并行提交逐路捕获异常记入ChannelError全路失败才抛StorageRetrievalError部分成功语义。每个 Recaller 对应一条召回通道互不感知其他通道。手工接线bind_recallers 的测试与定制路径bind_recallers仍是公开的手工/测试接线口F06 决策 4 不变装配路径改由for_manager内部调用。测试夹具 conftest.py 的make_world就是典型手工接线形态storage CompositeStoreManager(kvkv, vectorvector, fulltextfulltext) domain_store CompositeDomainStore( managerstorage, preferred_pipelineRetrievalPipeline.RECALL_GET_RANK ) keyword KeywordRecaller(storage) vector_recaller VectorRecaller(storage) domain_store.bind_recallers([keyword, vector_recaller]) # 先建 storage → 再建 recaller → 再 bind storage.bind_domain_store(domain_store)自定义召回路集成测试如 test_pipeline_retriever.py 的test_default_config_attaches_l0_l1_recallers、test_index_contract.py也走这条路径手工构造CompositeStoreManagerCompositeDomainStorebind_recallers注入故障注入型/固定候选型 recaller 验证通道级降级、并行性与 L0/L1 装配。验证体系F06 的验证覆盖在仓库中完整对应test_storage_factory_wiring.py默认装配下retriever.storage is storage且storage.recallers同步组装出 7 路globals 关闭三个能力开关后只剩 keyword 一路选择键指向未注册实现时构建期抛ValidationError。test_index_builder.pytest_fulltext_factory_*/test_vector_factory_*/test_unified_factory_*覆盖匿名 CompositeStorage 构建经StorageProducer.resolve第三分支合成名预注册打破循环、不触发递归。test_storage_pipelines.py、test_recallers.py、test_pipeline_retriever.py含keyword_recaller覆盖键移到 storage 段的用例、test_index_contract.py 全部适配并通过conftest.py的make_world改为 bind 手工接线。test_named_domain_stores.pydomain_stores段此前全仓零覆盖F07 补上 11 例其中test_named_entry_shares_recaller_instance_with_default锁死「命名 entry 继承 default 的 recaller 实例」这一静默退化。F06 文档记录的测试基线为.venv-wsl/bin/python -m pytest tests/unit tests/integration1318 passed / 82 skipped4 failed 均为 HEAD 既有问题2 个 bge_m3 缺 torch2 个 entity_linker 测试间干扰。F07 演进后基线为pytest tests/unit/1978 passed / 8 skipped、pytest tests/integration/48 passed / 61 skipped。拒绝的方案与取舍理由F06 明确记录了被否定的备选方案理解它们有助于把握内收设计的分寸装配期同步构建仅put预注册具名路径可行但匿名构建仍会经 recaller builder 回取storage.default递归构建默认实例。最终采纳时补上合成名预注册 直接RecallerProducer.build注入 storage 引用覆盖匿名路径。首次召回时惰性物化能彻底回避循环但装配错误推迟到首次召回才暴露违背「配置错误尽早暴露」原则且增加首次召回延迟与状态管理复杂度。保留 retriever 侧装配、仅按isinstance跳过非 Composite责任依然错位开关仍由 retriever 工厂替 storage 解释治标不治本。让 recaller 不再依赖 Storage改注入裸端口可彻底消除循环但要改全部 recaller 的构造契约与测试且违背「上层握共享 Storage 入口、勿构造期握死裸端口」的本地约束RoutingStorage 惰性代理依赖这一点。召回路用命名空间扫描替代显式选择键失去按配置裁剪/替换单路的能力且会把未接线入库的具名实例也拉进来。已知遗留与后续演进F07F06 的已知遗留当前依旧成立recaller 装配的运行时错误如距离型度量向量库被VectorRecaller在首次召回时拒绝、向量库连接不通等仍推迟到首次召回才暴露装配期 fail-fast 只覆盖选择键指向未注册实现、必填插件缺失等配置类错误运行时错误依赖冒烟/健康检查覆盖。注距离型度量的拒绝实际发生在构造期——vector_recaller.py 在__init__中检查score_higher_is_better()并抛ValidationError。匿名构建用id(storage)派生合成名预注册进_instances缓存装配后该缓存条目无人再引用recaller 已持直接引用属无害死条目Factory.reset_all在每次装配前清空。用户配置迁移写在retriever.*.params的*_recaller覆盖键不再生效需迁移到storage.*.paramsF07 后进一步迁至domain_stores.nameglobals 里的能力开关不受影响。后续演进见 F07-storage-manager-domain-store-split.md本文的召回装配链路整体保留仍由 manager 工厂末尾调_assemble_recallers仅符号随拆分更名CompositeStorage→CompositeStoreManager/CompositeDomainStore、StorageProducer.resolve→StoreManagerProducer.resolve、合成名__anon_storage_{id}__→__anon_store_manager_{id}__。F07 E 组进一步把Recaller契约与实现移入storage/domain_store_impl/_assemble_recallers的调用点下沉进CompositeDomainStore.for_manager本文决策 5 的惰性导入随之删除。值得强调的是F06 拒绝方案里「让 recaller 不再依赖 Storage改注入裸端口」始终未被采纳——E 组走的是相反方向不是把 recaller 从 storage 摘出去而是把它收进来。赞分享人工智能AI AgentAgent 记忆RAGMCP 服务【免费下载链接】agent-memoryMemory 是一款面向 AI 智能体的长期记忆模块为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。项目地址https://gitcode.com/openJiuwen/agent-memory点击查看免费下载相关推荐OpenStock 使用指南免费实时行情 价格提醒如何 10 分钟搭好盯盘流程OpenStock 使用指南免费实时行情 价格提醒如何 10 分钟搭好盯盘流程 OpenStock 是一款开源股票工具免费实时行情、板块热力图与自定义金融科技前端后端AI 应用Anki-Android 模块化架构中的 :anki-common打破循环依赖的共享层设计详解Anki Android 模块化架构中的 :anki common 打破循环依赖的共享层设计详解 导读 本文以 Anki AndroidAnkiDroid移动开发教育agent-memory 检索层实现规约深度解析QueryParser / Recaller / Fuser / Discloser / Retriever 的装配、语义与取舍agent memory 检索层实现规约深度解析QueryParser / Recaller / Fuser / Discloser / Retriever人工智能AI AgentAgent 记忆RAGMCP 服务上一篇Aptos Core 二进制发布与 cargo-binstall 集成指南让用户免编译安装预编译二进制下一篇Epic Stack 导入路径方案演进用 package.json 的 imports 字段配置 前缀路径别名创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考