Curation 知识库检索
1. 技能定位
Curation 是一个可被复用的知识库检索层:输入一个主题或问题,输出带出处的原文片段(ws_id + curation_doc_id + 文档标题 + 匹配片段)。既可由用户直接使用("查一下教材里怎么说"),也可被任何上层技能作为知识获取步骤调用,拿到证据后再做自己的加工——输出一律遵循 §5 的契约。
边界:
- 只做检索和来源整理,不做结论生成、方案评审、教学讲解、文稿撰写——那些属于调用方。
- 不替代 web search。Curation 覆盖的是已入库的教材与文献语料;库外的新知识、时效性内容仍需 web search。反过来,凡是"已入库教材/课程材料/文献"的检索需求,都应先走 Curation,不要用 web search 顶替。
- 只读。不负责语料入库、工作区创建、索引维护。
2. 知识库范围与选库
工作区映射表在 config/workspaces.json:{ "ws_id": ["工作区全名"] }(文件带 UTF-8 BOM,脚本解析用 utf-8-sig 读取)。选库时现读这个文件,用任务关键词在工作区名中匹配;ws_id 前缀提示大类,便于快速定位:
| 前缀 | 内容 |
| --- | --- |
| ky### | 考研真题、讲义、学习资料、大纲 |
| bkzy### | 本科专业类教材(按专业类划分) |
| bkts### | 本科通识课程教材 |
| yjszy### | 研究生学科门类教材 |
| yjsts### | 研究生通识课程教材 |
| yy### | 英语考试 |
| d_ws_999# | 学术文献库(pubmed / arxiv / chemrxiv) |
各工作区实际有多少文档以检索结果为准,不做静态假设;命中为零时按 §6 降级处理。
3. 调用流程
- 选库预检:从任务中抽出检索关键词,在
config/workspaces.json的工作区名中匹配。匹配不上时降级关键词重试:剥掉限定词、向上归到更宽的学科(高等数学 → 数学 → 大学数学 / 数学类),最多重试两轮;仍无匹配 → 不发起请求,直接返回[CURATION MISS: <主题>](§6),不要猜ws_id。调用方已指定工作区时作为首选,但仍需判断它是否覆盖这个主题。 - 解析
ws_id:每次调用时从config/workspaces.json现读解析,不写进提示词、不跨会话记忆。没有解析出ws_id的调用不允许发起。 - 选能力(§4)、调用(§4 标准命令)、按 §5 整理输出。检索零结果时改用
--search-mode EXACT重试一次,仍为零 → 按[CURATION MISS]处理。
4. 能力选择与标准命令
| 能力 | 脚本 | 返回 |
| --- | --- | --- |
| 原文片段检索(要引用原文时首选) | script/smart-chunk.py | 每篇命中文档的多个原文片段,按相似度排序 |
| 文档发现(要先摸清有哪些资料时首选) | script/smart-scan.py | 命中文档列表 + 每篇一段最佳匹配片段 + 元数据 |
| 定点取片段(已有 doc_id 时) | script/chunk.py | 指定文档内与查询相关的原文片段 |
这三个脚本是 Curation 的全部入口,只允许按本文件与 reference/ 记录的参数调用。 禁止尝试调用本技能未提供的 Curation 接口——包括自行拼装未文档化的端点路径、编造脚本没有的命令行参数、调用同名但本技能不含的 MCP 工具或 HTTP API、以及绕过 config/workspaces.json 猜测工作区标识。所需能力不在表内 → 按 §6 声明信息缺口,不要发明接口,也不要伪造调用。
怎么选:
- 要引用原文——定义、定理表述、例题、原句的确切文字 →
smart-chunk。内部把"找文档"和"取片段"两步串好,是可引用、可回溯的最强形态。 - 要先摸清库里有什么 →
smart-scan。每篇只给一段best_content,轻量,适合选材;选定文档后再用smart-chunk取片段深入。 - 已有确定的
doc_id,要在该文档内继续挖 →chunk。跳过文档发现一步,对一篇已知文档换不同query反复取片段;doc_id一律取自前两者的返回,不要手工拼造。
三个脚本均只依赖 Python 3 标准库;服务地址已由脚本内部处理,调用时无需关心。对外参数:smart-chunk / smart-scan 只有四个——--query、--ws-id、--search-mode、--num;chunk 只有三个——--ws-id、--doc-id、--query。其余请求细节(片段数量、分数阈值、并发、超时等)全部由脚本内部固定,不接受调整。--ws-id 三个脚本都是必填、无默认值,一律从 config/workspaces.json 解析后显式传入——脚本会拿它与映射表比对,写错的 ws_id 在发请求前就被挡下(服务端对不存在的工作区只回空结果、不报错,光看响应分不清是写错还是没命中)。
--search-mode(smart-chunk / smart-scan):默认 KEYWORD,常规检索一律用默认值、命令里不显式传。只有 KEYWORD 零命中时才补一次 --search-mode EXACT(具名定理、定义、术语的精确匹配);仍为零 → §6 的 [CURATION MISS]。
统一退出码:0 有结果、1 参数错/工作区不存在/请求失败、2 请求成功但零结果、130 中断。错误和提示都在 stderr(中文),stdout 只放数据。判成败看退出码,别只看 stdout 是不是 JSON——2 对应 §6 的 [CURATION MISS],1 对应 [CURATION UNAVAILABLE]。
完整参数与输出结构见 reference/ 下与脚本同名的文档:reference/smart-chunk.md、reference/smart-scan.md、reference/chunk.md,需要细节时再读。
脚本入口已调用 force_utf8_output(),把 stdout/stderr 固定为 UTF-8,避免 Windows 默认 GBK 在打印 IPA/中文时 UnicodeEncodeError。
★ Windows 下捕获 JSON:禁止用 PowerShell > / Out-File
在 Windows PowerShell 里写:
python script/smart-chunk.py ... 1> out.json
会把 UTF-8 控制台输出转成 UTF-16 文件,并可能在片段正文里留下非法控制字符;随后 json.loads 报 Invalid control character。这不是知识库返回坏了,是重定向弄坏了 JSON。
正确做法(任选其一):
- 推荐:用 Python
subprocess收stdout字节再decode("utf-8")+json.loads(不要经过 PowerShell 文件重定向)。 - 在脚本同进程内直接解析,或由 Python 自己
Path.write_text(..., encoding="utf-8")落盘。 - 若必须用 shell 重定向,用
cmd.exe且保证无 UTF-16 包装;不要用 PowerShell 的>/Out-File保存这三个脚本输出的 JSON。
解析时也不要用“先按 utf-8 读 PowerShell 重定向文件”来补救——文件往往已是损坏的 UTF-16/混编码,应重新跑检索并用上面的安全捕获方式。
smart-chunk(要原文片段时首选)
python script/smart-chunk.py \
--ws-id "<workspaces.json 解析出的 ws_id>" \
--query "<检索关键词>"
- 片段返回量由脚本内部固定:每个查询最多 3 篇文档、每篇最多 5 个片段,不会撑爆上下文。
- 命中太少时改用
--search-mode EXACT或换更宽的关键词重试。 - 输出会保留兼容字段
doc_ids,同时新增docs[].title、docs[].authors、docs[].doi以及chunks[].title、chunks[].authors、chunks[].doi。这些字段从smart_scan返回的文档顶层字段提取,缺失时再取docs[].metadata中的同名字段或文件名类可读字段;上层技能整理书籍名/资料名、作者和 DOI 时优先使用chunks[]中的同名字段。
smart-scan(只要文档清单时)
python script/smart-scan.py \
--ws-id "<workspaces.json 解析出的 ws_id>" \
--query "<检索关键词>" \
--num 5
- 返回的
docs[].curation_doc_id用于引用溯源;metadata.best_content是引用与判断的主要依据(结构详见reference/smart-scan.md)。
chunk(已有 doc_id 时定点取片段)
python script/chunk.py \
--ws-id "<workspaces.json 解析出的 ws_id>" \
--doc-id "<smart-scan / smart-chunk 返回的 doc_id>" \
--query "<检索关键词>"
- 返回数量与相似度过滤由服务端默认值决定;
results[].content即可引用的原文片段。 - 零结果时换更宽的关键词重试,仍为零则回到
smart-scan确认该文档是否切题。
smart-chunk / smart-scan 的 --query 都可重复传入,脚本内部并发执行;chunk 单次只查一篇文档、一个查询。
5. 输出契约
无论谁调用,Curation 的返回都应包含三部分:
- 结果摘要:检索到什么,够不够回答问题。
- 证据条目(逐条):
ws_id、curation_doc_id、文档标题、作者、DOI、片段文本、使用的query与search_mode(smart-scan结果另有文档级score可用于取舍)。片段文本来自smart-chunk的chunks[].response.results[].content、chunk的results[].content或smart-scan的metadata.best_content;文档标题、作者和 DOI 来自smart-chunk的chunks[]/docs[]同名字段,或smart-scan的docs[]顶层字段 /docs[].metadata同名字段。 - 状态标记:命中、部分命中,或 §6 中的降级标记。
给上层技能时,把证据条目作为 document_context / references 传递,来源信息必须随内容一起传,不得剥离;传原文片段而非全文,条目数量够用即可。面向用户输出时先给结果摘要,再列来源;脚本输出的原始 JSON 是内部数据,整理后再呈现,不要直接贴给用户。
调用方须遵守的三条:
- 未检索到的内容不得当作事实陈述。
- 引用检索内容时必须带上
curation_doc_id与文档标题,让读者能回到原文。 - 检索失败或未命中时,必须在自己的输出中说明信息缺口,并相应降低结论的确定性——不能装作检索过。
6. 降级处理
| 情况 | 标记 | 行为 |
| --- | --- | --- |
| 服务不可达、连接被拒、超时 | [CURATION UNAVAILABLE: connection] | 最多重试一次,然后回落到内部知识,并记录降级 |
| 接口返回 HTTP 4xx / 5xx | [CURATION UNAVAILABLE: endpoint] | 该入口暂不可用:能换 smart-scan 就换,不能则回落;不要反复重试 |
| 工作区名解析不出 ws_id,或脚本报「工作区不存在」(退出码 1) | [CURATION UNAVAILABLE: workspace] | 回到 config/workspaces.json 重新解析;仍无匹配则回落,不猜 id |
| 响应不是合法 JSON 或缺字段 | [CURATION UNAVAILABLE: response] | 同上回落 |
| 服务可达但库里没有该主题(按 §3 重试后仍零命中,脚本退出码 2) | [CURATION MISS: <主题>] | 不静默跳过:说明该主题不在已入库材料范围内,再询问是否继续 |
| 没有 Python 3 解释器 | 无标记,不算降级 | 换传输方式:这些入口本质都是 JSON POST,用 curl 等直接请求即可,但只能请求 reference/ 中已记录的端点。端点路径与请求体结构见 reference/ 各文档;服务地址取脚本内 DEFAULT_BASE_URL 常量。本部署的 URL 没有 user 路径段,不要自行添加 |
| 完全没有 HTTP 能力 | [CURATION UNAVAILABLE: runtime] | 真正不可用;回落到内部知识,不猜未文档化的接口 |
三条禁令:不得用 web search 悄悄顶替失败的 Curation 检索(可以补充,但必须声明这不是知识库来源);不得伪造工具调用——没有能力就说没有,不要用假命令或"检索中…"的表演代替;不得越出 §4 的三个脚本去试探本技能未提供的 Curation 接口——某条路走不通就按上表降级,不要换着花样猜端点、猜参数、猜工作区。
微信扫一扫