会话召回技能
从四层存储查询历史知识,并注入当前会话上下文。
触发场景
场景 1: 用户感到沮丧
用户可能感到烦躁,因为:
- 你似乎忘记了之前学过的东西
- 你在重复之前被纠正过的错误
- 你在走之前已证明行不通的方向
- 你在忽略用户已表达过的偏好
处理方式: 先主动道歉,再展示召回结果。
场景 2: 常规查询
用户只是想查询历史记录:
- "有没有关于 X 的记录?"
- "之前怎么处理的?"
- "我的偏好是什么?"
处理方式: 直接展示召回结果,不假设用户沮丧。
场景 3: 主动刷新
用户调用 /recall 无参数:
- 对话已持续较长时间
- 想刷新上下文中的知识
处理方式: 展示所有四层的简洁摘要。
四层数据源
与 auto-extract 存储层完全对应:
| 层级 | 核心问题 | 特性 | | ------------------- | ---------------------------- | ------------------------ | | Layer 1: 用户配置 | "每个会话都需要知道什么?" | 跨项目、身份性、自动加载 | | Layer 2: 项目根配置 | "这个项目整体需要知道什么?" | 项目级、版本控制 | | Layer 3: 子模块配置 | "这个子模块需要知道什么?" | 子模块特定、就近原则 | | Layer 4: 情境记忆 | "特定情境下需要召回什么?" | 情境性、按需查询 |
硬规则:单条知识唯一归属
- 同一条知识不应同时存在于多层。
- 召回时如果多层都命中同一主题,视为存储不一致:必须显式标注来源并提醒清理,不要静默选择其一。
第零步:探测可用后端(MANDATORY)
查询前必须先探测,不假设任何特定文件、工具或服务存在。
Layer 1 — 用户配置
扫描用户级配置文件,检测是否存在:
~/.claude/CLAUDE.md- 其他用户级 agent 配置文件
检测到哪个查询哪个。不存在则跳过该层。
Layer 2 — 项目根配置
扫描项目根目录,检测以下文件是否存在:
{repo}/AGENTS.md{repo}/CLAUDE.md{repo}/.claude/CLAUDE.md
所有检测到的文件均参与查询。
Layer 3 — 子模块配置
扫描项目中子目录里已存在的配置文件(AGENTS.md 或 CLAUDE.md)。
探测方式: 搜索 {repo}/**/AGENTS.md 和 {repo}/**/CLAUDE.md(排除根目录,排除 node_modules 等)。
如果有相关参数(如 /recall oc-tweaks 发布),优先查询语义最近的子模块配置。
Layer 4 — 情境记忆
按优先级探测可用的记忆后端:
- 记忆相关的工具: 检查当前环境是否有可调用的记忆搜索工具(能按关键词检索知识条目的工具)。有则用。
- 已存在的 memory 目录: 检查项目级(如
{repo}/.opencode/memory/、{repo}/.memory/)或全局是否存在 memory 目录(含*.md文件)。有则用 Read 操作查询。 - 兜底
.memory/目录: 使用项目内的.memory/目录(如果存在)。
原则: 探测到什么用什么。不要求用户安装任何额外依赖。
执行步骤
第一步:理解上下文
分析用户为什么调用 /recall:
- 判断触发场景(沮丧/常规/刷新)
- 提取关键词(用户参数 > 对话上下文)
- 确定查询范围
如果用户提供了参数(如 /recall 代码风格),用它们作为主要关键词。
如果参数类似"我不知道/你看看/refresh",视为场景 3(主动刷新):四层都查,每层展示最相关的 2-3 条。
第二步:查询 Layer 1 用户配置
1. 读取探测到的用户级配置文件
2. 按 section 标题匹配关键词
3. 提取相关段落
第三步:查询 Layer 2 项目根配置
1. 读取探测到的项目根配置文件(可能有多个)
2. 按 section 标题匹配关键词
3. 提取相关段落
第四步:查询 Layer 3 子模块配置
1. 读取探测到的子模块配置文件
2. 优先查询与关键词语义最近的子模块
3. 提取相关段落
第五步:查询 Layer 4 情境记忆
根据探测到的后端类型执行对应查询:
- 工具后端: 使用其提供的搜索 API,传入提取的关键词。中英文都试试;先宽泛搜索,结果太多再缩小范围。
- 文件系统后端: 使用 Read 读取 memory 目录中的 markdown 文件,按文件名和内容匹配关键词。
- 无可用后端: 明确说明"情境记忆层无可用后端",不报错。
第六步:格式化并展示
按层级分组展示结果:
## 召回结果
### L1 用户配置(来自 {探测到的文件名})
找到 X 条相关内容:
- **[Section 标题]**: [相关内容摘要]
### L2 项目根配置(来自 {探测到的文件名})
找到 X 条相关内容:
- **[Section 标题]**: [相关内容摘要]
### L3 子模块配置(来自 {探测到的文件名})
找到 X 条相关内容:
- **[Section 标题]**: [相关内容摘要]
### L4 情境记忆(来自 {探测到的后端描述})
找到 X 条相关记录:
- **[主题]**: [内容摘要]
---
**应用到当前情况**: 基于这些召回,我会...
如果同一主题在多层命中,视为存储不一致:必须显式标注来源并提醒清理。
第七步:确认并调整
根据触发场景调整响应:
| 场景 | 响应开头 | | ---- | --------------------------------------- | | 沮丧 | "抱歉让你重复了。我回顾了之前的记录..." | | 常规 | "我查询了历史记录,找到以下相关内容..." | | 刷新 | "以下是当前相关的知识摘要..." |
查询策略
按主题查询
如果用户提供了主题(如 /recall 代码风格):
- L1: 搜索 "编码风格"、"Coding" 相关 section
- L2: 搜索 "Code Style"、"代码风格" 相关 section
- L3: 搜索语义最近的子模块配置
- L4: 搜索 "code style"、"代码风格"(中英文都试)
无参数查询
如果没有提供主题:
- 从最近的对话中提取关键词
- 每层展示最相关的 2-3 条
按层级优先
如果某层已有足够相关内容:
- 可以跳过后续层级
- 或仅展示后续层级的摘要
边界情况
没有找到结果
我查询了四层数据源,但没有找到与 "[主题]" 相关的记录。
已搜索:
- L1 用户配置 - {文件名或"未检测到"} - 无匹配
- L2 项目根配置 - {文件名或"未检测到"} - 无匹配
- L3 子模块配置 - {文件名或"未检测到"} - 无匹配
- L4 情境记忆 - {后端描述或"无可用后端"} - 无匹配
可能原因:
- 这个话题还没有被学习过
- 尝试使用不同的关键词
你能告诉我具体是什么情况吗?
文件不存在
跳过该层并继续查询下一层,在结果中注明"未检测到"。
情境记忆后端不可用
L4 情境记忆:无可用后端,仅查询了配置文件层。
子模块无配置文件
跳过 Layer 3,不报错。在结果中注明"无子模块配置"。
与 auto-extract 的一致性
| auto-extract 存储层 | knowledge-fetch 查询层 | 核心问题 | | ------------------- | ---------------------- | ---------------------------- | | L1 用户配置 | L1 用户配置 | "每个会话都需要知道什么?" | | L2 项目根配置 | L2 项目根配置 | "这个项目整体需要知道什么?" | | L3 子模块配置 | L3 子模块配置 | "这个子模块需要知道什么?" | | L4 情境记忆 | L4 情境记忆 | "特定情境下需要召回什么?" |
边界原则:
- L1 用户配置 = 身份层 = "What I always need to know"
- L2/L3 配置层 = 项目/模块约定层
- L4 情境记忆 = 经验层 = "What I learned for specific situations"
- 严格唯一:同一知识只应存在于一层;召回发现多层命中时,视为不一致并提醒清理
确保双向一致:学习时分类到哪层,召回时就从哪层查询。
微信扫一扫