news 2026/9/11 23:07:09

oh-my-pi 长期记忆检索工具 recall 完全指南:从查询语义到双后端实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
oh-my-pi 长期记忆检索工具 recall 完全指南:从查询语义到双后端实现原理

oh-my-pi 长期记忆检索工具 recall 完全指南:从查询语义到双后端实现原理

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

本文系统讲解 oh-my-pi(coding-agent)内置的recall工具:它负责在长期记忆中按相关性检索并返回匹配条目,服务于"过去对话、用户偏好、项目决策"等需要历史上下文的场景。读完本文,你将掌握recall的触发时机、输入输出契约、与reflect的分工、Hindsight / Mnemopi 双后端的完整调用链、作用域(bank scoping)配置,以及截断预览与memory://<id>全行读取的配合方式。

recall是 oh-my-pi 记忆子系统中最基础、最常被模型主动调用的工具之一。它本身不做归纳总结,只做"原始检索":把自然语言查询交给长期记忆后端,返回按相关性排序的匹配条目。与其配套的retain(写入记忆)、reflect(跨记忆综合)、memory_edit(编辑记忆)共同构成完整的长期记忆工具集,详见 docs/tools/retain.md 与 docs/tools/recall.md。

recall 工具定位:先检索,再判断

模型提示词(packages/coding-agent/src/prompts/tools/recall.md)对recall的定位非常明确:

Search long-term memory; return raw relevance-ranked matching entries.

即"搜索长期记忆,返回按相关性排序的原始匹配条目"。文档同时给出了两条关键使用纪律:

  • 主动使用:在涉及过去对话、用户偏好、项目决策,或任何"有历史上下文能提升准确度"的话题之前,应当主动调用recall拿不准时,先 recall 再说When in doubt, recall first)。
  • reflect分工recall返回具体事实或条目;reflect则在众多记忆之上综合出一个整体回答(reflect: synthesized answer across many memories)。详见 packages/coding-agent/src/prompts/tools/reflect.md 中 "What do you know about this user?"、"Summarize project decisions." 这类开放式问题的适用场景。

在工具注册层面,recallretainreflectmemory_editlearn被统一定义为"依赖记忆后端的工具集合",见 packages/coding-agent/src/memory-backend/tool-names.ts 中的MEMORY_BACKEND_TOOL_NAMES

工具元数据与注册条件

recall工具的元数据定义在 packages/coding-agent/src/tools/memory-recall.ts 的MemoryRecallTool类中:

属性含义
namerecall工具名
approval"read"只读操作,不需要写权限审批
stricttrue严格模式,参数校验严格
loadMode"discoverable"可发现的内置工具(非显式注册)
summary"Search memory for relevant prior context"供上层 UI 展示的摘要

注册逻辑由createIf(session)实现(memory-recall.ts):

static createIf(session: ToolSession): MemoryRecallTool | null { const backend = session.settings.get("memory.backend"); if (backend !== "hindsight" && backend !== "mnemopi") return null; return new MemoryRecallTool(session); }

这决定了recall可用性前提

  • memory.backend必须为"hindsight""mnemopi"
  • memory.backend = "off"(默认值)或"local"时,recall完全不注册。

从源码结构还可以推断出两点可见性细节:

  • 在未限制工具列表的会话中,只要选择了任一受支持后端,注册时会自动带上recall/retain/reflect这一整套工具;显式指定的受限工具列表不会被自动扩充。
  • 在普通的tools.xdev会话中,可发现的内置工具可能以xd://recall的形式呈现;而显式请求的工具保持顶层形式。

执行方式为单次执行(single-shot):工具不会流式输出参数/结果更新。

输入与输出契约

输入:唯一参数 query

字段类型必填说明
querystring自然语言搜索查询词

工具对query做透传(pass-through),不修改内容——唯一的例外是 Mnemopi 的per-project-tagged模式可能额外运行一次"共享库回落查询"(shared-bank fallback query),见下文作用域章节。参数 schema 定义在 memory-recall.ts:

const memoryRecallSchema = type({ query: type("string").describe("natural language search query"), });

输出:命中时的文本格式

无论哪个后端,有匹配时都返回单条content[0].type = "text"的文本结果,details = {},文本前缀固定为:

Found <n> relevant memory/memories (as of YYYY-MM-DD HH:MM UTC): <bullet list>

前缀中的 UTC 时间戳由 hindsight/content.ts 的formatCurrentTime()生成,格式为YYYY-MM-DD HH:MM。两种后端的条目格式不同:

Hindsight 条目formatMemories,见 hindsight/content.ts):

- <text> [<type>] (<mentioned_at>)

其中[<type>](<mentioned_at>)仅在对应字段存在时出现。

Mnemopi 条目formatScopedRecallWithIds,见 mnemopi/state.ts):

- <content> (id: <id>) [<source>] (<YYYY-MM-DD>) c:<score>

各后缀规则:

  • (id: <id>):携带 id 供后续read memory://<id>memory_edit使用;id 不可用时渲染为(id unavailable)
  • [<source>]:来源标签,缺失时省略;
  • (<YYYY-MM-DD>):日期取时间戳前 10 位,缺失时省略;
  • c:<score>:置信度/相关性得分(scoreimportance,保留一位小数),缺失时省略。

无命中时的输出

无匹配时返回:

No relevant memories found.

同时details = {}useless = true——调用方与渲染层可据此把该结果视为"无贡献上下文",避免污染后续决策。

执行流程:从注册到返回的双后端调用链

execute(...)的整体流程(memory-recall.ts):

  1. MemoryRecallTool.createIf(...)memory.backend"hindsight""mnemopi"时暴露工具;
  2. execute(...)untilAborted(...)包裹整个操作,支持AbortSignal取消;
  3. 根据后端类型走 Mnemopi 或 Hindsight 分支;
  4. 后端失败时以logger.warn("recall failed", ...)记录日志,并按需以Error实例重新抛出。

Mnemopi 分支:本地 scoped recall

memory.backend == "mnemopi"时:

  • 读取session.getMnemopiSessionState(),未初始化则抛出Mnemopi backend is not initialised for this session.
  • 调用state.recallResultsScoped(params.query),其底层实现为collectScopedRecallResults(...)(mnemopi/state.ts):
    • 对每个已解析的 recall bank 调用recallEnhanced(query, recallLimit, { includeFacts: true, channelId: bank })
    • 按 id / content 对结果去重合并(mergeRecallResult),优先保留得分高者;
    • 排序(compareRecallResults:得分降序 → 时间戳降序 → 内容字典序)后截断到recallLimit条;
    • per-project 模式还会扫描安全识别的遗留 bank(legacy banks):只有working_memory中所有行的metadata_json.$.cwd都属于当前绝对 cwd 的 bank 才会被加入 recall 集合,用于救回旧版 bank 派生方案留下的记忆;启动扫描上限为 64 个候选 bank 目录(见 mnemopi/config.ts 的extendRecallWithLegacyBanks);
    • per-project-tagged模式下,共享 bank 可能额外执行一次回落查询:将查询中项目 bank 的字面 token 剥离后再查一遍,保证宽泛的全局记忆仍能命中(见 mnemopi/state.ts 的deriveSharedRecallFallbackQuery);
  • 结果带 id 格式化(formatScopedRecallWithIds),供后续全行读取与memory_edit

Hindsight 分支:远程 HTTP recall

memory.backend == "hindsight"时:

  • 读取session.getHindsightSessionState(),未初始化则抛出Hindsight backend is not initialised for this session.
  • 调用state.client.recall(state.bankId, params.query, {...}),携带配置的budgetmaxTokenstypes以及 bank 作用域下的 tag 过滤器(recallTags/recallTagsMatch);
  • HindsightApi.recall(...)POST /v1/default/banks/{bank_id}/memories/recall发起请求(hindsight/client.ts),请求体包含querytypesmax_tokensbudget(默认"mid")、tagstags_match
  • 结果经formatMemories(...)格式化为纯文本列表。

副作用与取消

  • 网络:Hindsight 产生一次 HTTP POST;Mnemopi 本身无网络调用,除非配置了本地运行时 provider(嵌入/LLM 计算在 recall 期间发生)。
  • 会话状态:显式工具路径成功后不改动会话状态——与后端自动 recall(auto-recall)不同,它不更新lastRecallSnippet,也不刷新系统提示词。
  • 取消:工具调用信号被取消时,通过untilAborted(...)中止。

Bank 作用域(Scoping):三种模式如何决定检索范围

作用域决定recall到底"从哪几个 bank 里找"。两个后端都支持globalper-projectper-project-tagged三种模式。

Hindsight 作用域

Hindsight 使用 tag 过滤器实现(hindsight/config.ts):

模式行为
global单个共享 bank,不加 tag 过滤
per-project每个项目标签一个独立 bank id(git 主检出根目录 basename;仓库外取 cwd basename)
per-project-tagged共享 bank id +project:<项目标签>过滤,tagsMatch = "any",因此项目打标记忆与未打标全局记忆都能同时浮出

Mnemopi 作用域

Mnemopi 没有 tag 过滤式 recall,per-project-tagged通过"项目本地写入 bank + 共享可读 bank"的方式实现(mnemopi/config.ts 的computeMnemopiBankScope):

模式写入 bank(retain)读取 bank(recall)
global共享 bank共享 bank
per-project由绝对 cwd basename + 该绝对 cwd 的 hash 派生的 bank同项目 bank
per-project-taggedcwd 派生项目 bank项目 bank + 共享 bank,结果合并

注意 Mnemopi 项目 bank 的派生刻意不依赖 git:旧版本先解析 git 根再 hash,导致增删.git会让同一目录漂移到不同 bank、碎片化记忆(issue #2412)。现在的派生纯粹基于cwd,稳定合约见projectBankSegment(mnemopi/config.ts):<清洗后basename>-<Bun.hash(projectRoot).toString(36)>,并限制在 64 字符以内。

另外,会话作用域为跨会话读取recall读取的是跨会话的记忆数据,使用当前会话缓存的配置与作用域;子代理(subagent)别名共享父级的后端作用域。

限制与可调参数(Limits & Caps)

recall的默认行为受配置项约束,相关 schema 定义在 packages/coding-agent/src/config/settings-schema.ts。

Hindsight 侧

配置项默认值说明
hindsight.recallBudget"mid"检索预算,枚举low/mid/high
hindsight.recallMaxTokens1024返回结果的最大 token 数
hindsight.recallTypes["world", "experience"]检索的记忆类型
hindsight.recallTimeoutMs30_000请求超时(毫秒)

客户端默认的 raw recall 预算也是"mid",但工具路径会从配置覆盖(hindsight/client.ts)。配置优先级为:内置默认 < 设置项(hindsight.*)<HINDSIGHT_*环境变量(如HINDSIGHT_RECALL_BUDGETHINDSIGHT_RECALL_MAX_TOKENS),环境变量最高,便于 CI/生产环境按 shell 覆盖。

Mnemopi 侧

配置项默认值说明
mnemopi.recallLimit8返回条数上限,运行时至少钳制为 1
mnemopi.scoping"per-project"默认作用域
内容预览上限500字符/条RECALL_CONTENT_PREVIEW_CHARS/RecallOptions.contentPreviewChars控制

关键约束:显式工具路径不应用hindsight.recallContextTurnshindsight.recallMaxQueryCharsmnemopi.recallContextTurnsmnemopi.recallMaxQueryChars——这些上限只作用于后端自动 recall(auto-recall)的查询组合,例如HindsightSessionState.beforeAgentStartPrompt(...)/maybeRecallOnAgentStart(...)MnemopiSessionState.beforeAgentStartPrompt(...)/maybeRecallOnAgentStart(...)composeRecallQuery/truncateRecallQuery的"最近 N 轮上下文 + 字符预算截断"逻辑(见 hindsight/content.ts)。

截断预览与 memory:// :修改前必须读全行

Mnemopi 的 recall 内容默认是预览,每条约 500 字符;被截断的条目以(省略号)结尾。此时:

  • 内部 recall 行携带truncatedfull_length字段(RecallResult.truncated),但工具返回的是格式化文本、details = {}不暴露这两个字段;
  • 因此,在对任何条目执行整体式memory_edit update之前,必须先读取完整行read memory://<id>

这条规则的动机很实际(见 mnemopi/state.ts 的注释):recall 裁剪了内容,若直接用预览文本做整体覆盖式更新,会覆盖掉未见过的字节(issue #4443)。memory://<id>URL 由 packages/coding-agent/src/internal-urls/memory-protocol.ts 提供支持,它对应getScopedMemory(id):按 retain → recall → global 的顺序在所有可 recall 的 bank 中查找,返回完整行(含contentsourcetimestampimportanceveracitysession_idmemory_type等字段)。注意:fact表中的行是只读投影,可解析但不可编辑(issue #4725)。

错误处理与边界情况

  • 后端未初始化memory.backend == "mnemopi"但无状态 →Mnemopi backend is not initialised for this session.;Hindsight 同理抛出对应错误。
  • Hindsight 失败:HTTP、fetch、超时失败统一包装为HindsightError;HTTP 错误携带statusCode与解析出的details(hindsight/client.ts)。超时错误信息形如recall request timed out after 30s
  • Mnemopi 失败:按目标(bank)逐个捕获并记录日志,健康目标仍正常贡献结果;若所有目标全部失败,则抛出原始错误(单目标)或携带各 bank 详情的AggregateError(多目标),而不是把失败静默转成空结果——避免"检索失败被伪装成'没找到'"。
  • Error异常:统一规范化为new Error(String(err))后重新抛出。

注意事项(Notes)

  • Mental models 不在此工具范围recall不拉取 Hindsight 的心理模型(mental models)。这些模型可能已作为<mental_models>块缓存在开发者指令中,独立于 recall 结果(Hindsight 后端在 hindsight/content.ts 中有对应的块剥离正则,用于防止记忆块回流到记忆库形成正反馈回路)。
  • Mnemopi 的<memories>:后端自动 recall 可能把<memories>块注入开发者指令,但显式recall工具不更新该块。
  • recall ≠ reflectrecall只返回命中条目,不做跨记忆综合。需要综合时,Hindsight 用reflect做远端综合;Mnemopi 的reflect变体是"本地 recall + 格式化"。

小结:recall 的正确使用姿势

  1. 时机:涉及历史对话、用户偏好、项目决策等话题时,先recall再作答(When in doubt, recall first)。
  2. 查询:传入自然语言查询(如 "user's preferred editor"、"why did we choose X"),查询原样透传。
  3. 读结果:注意条目后缀——Hindsight 条目带[type](mentioned_at),Mnemopi 条目带(id: ...)[source]、日期与c:score
  4. 追全量:Mnemopi 预览被截断(结尾)时,用read memory://<id>取全行;任何整体式memory_edit update之前必须这样做
  5. 区分 reflect:需要"综合多段记忆给结论"时改用reflect

recall是记忆闭环的"读"入口:retain负责写、recall负责原始检索、reflect负责综合、memory_edit负责修正。理解它的注册条件(仅hindsight/mnemopi后端)、单参数契约、双后端调用链与作用域配置,就能让模型在任何需要历史上下文的场景中准确、高效地取回记忆。

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 23:06:05

蜣螂优化算法DBO工程实践:参数调优、代码修复与实时部署

简介&#xff1a;本资源是面向本科及硕士阶段科研学习者的蜣螂优化算法&#xff08;DBO&#xff09;实践包&#xff0c;聚焦智能优化算法在神经网络预测、信号处理、路径规划等领域的Matlab与Python双平台实现。压缩包共5个文件&#xff0c;含2个核心Python脚本&#xff08;mai…

作者头像 李华
网站建设 2026/9/11 23:06:03

Maestro 移动测试体检:四周补齐稳定的指标

Maestro 移动测试体检&#xff1a;四周补齐稳定的指标 【免费下载链接】Maestro Painless E2E Automation for Mobile and Web 项目地址: https://gitcode.com/GitHub_Trending/ma/Maestro 上周 CI 夜夜飘红&#xff0c;一次发版又让一半脚本集体失效&#xff0c;测试报…

作者头像 李华
网站建设 2026/9/11 23:05:32

HarmonyOS 4刷题APP开发:Stage模型、ArkUI与RDB持久化实践

简介&#xff1a;本代码包是一款基于HarmonyOS 4开发的刷题型鸿蒙应用完整工程&#xff0c;面向正在学习鸿蒙开发或需要完成毕业设计、期末大作业的开发者。项目围绕HarmonyOS基础架构、分布式任务调度、UI框架与组件、DevEco Studio工程配置等核心知识展开&#xff0c;通过真实…

作者头像 李华
网站建设 2026/9/11 23:04:34

YOLOv10快递包装缺陷检测实战指南

简介&#xff1a;本资源面向计算机视觉方向的算法工程师、AI初学者及工业质检场景开发者&#xff0c;提供基于YOLOv10的快递包裹与包装盒缺陷检测完整解决方案。资源包含已训练好的高精度检测权重模型&#xff0c;支持开箱即用的推理部署&#xff1b;同时配套1200余张真实场景采…

作者头像 李华
网站建设 2026/9/11 23:00:15

基于Hadoop的电影推荐系统:MapReduce协同过滤实现与课程设计指南

简介&#xff1a;基于Hadoop的电影推荐系统设计与实现方案&#xff0c;适合大数据、计算机相关专业学生作为小组作业、课程设计或毕业设计参考&#xff0c;也可供初学者了解推荐系统与Hadoop生态的结合方式。方案围绕电影评分数据&#xff0c;实现基于用户或物品的协同过滤推荐…

作者头像 李华