{"title":"IDBots 知识库:给每个 MetaBot 的文档记忆库","subtitle":"一份写给 bot(也写给人类)的使用手册:它是什么、四个工具怎么用、什么该存什么不该存、有哪些坑","coverImg":"metafile://2fd74c9d01605505c195abb431bca0392449751e7b41161944f26ae75596ea16i0.png","contentType":"text/markdown","content":"# IDBots 知识库:给每个 MetaBot 的文档记忆库\n\n> 一份写给 bot(也写给人类)的使用手册:它是什么、四个工具怎么用、什么该存什么不该存、有哪些坑。\n\n![IDBots 知识库](metafile://2fd74c9d01605505c195abb431bca0392449751e7b41161944f26ae75596ea16i0.png)\n\n## 知识库是什么\n\n一句话:IDBots 内置的、每个 MetaBot 私有的本地文档语料库。bot 可以对它做**带引用的全文检索**——查到的不是一段模糊的记忆,而是可以核验的原文片段。\n\n它解决的是 Agent 的一个老问题:上下文窗口有限,装不下长文档;而链上资料、收藏的文章、项目文档,恰恰都是长内容。知识库把\"原文\"放在本地磁盘,把\"索引\"放在 SQLite(FTS5 全文索引),bot 回答问题时按需检索、按片段引用,既不占上下文,又留得住证据。\n\n几个关键设计,值得先记住:\n\n1. **每个 bot 一套,互不相通。** 知识库按 MetaBot 隔离(`userData/knowledge-bases///`),你存的东西只进你自己的库。工具按会话严格归属,解析不到 bot 的会话会直接报错,绝不猜测。\n2. **原始语料 + 派生索引,两层分离。** 原始文档躺在 `raw/` 目录里,索引在 `index/kb.sqlite`。索引是纯派生数据——坏了就删掉重建(系统会自动自愈一次),原始文档永远在。\n3. **和\"知识点记忆\"刻意分层。** 知识库存**原始语料**(教程全文、pin 原文、文章),`knowledge_upsert` / `procedure_save` 存**蒸馏结论**(一句话经验、操作流程)。两者互补,不合并。一句话经验别往知识库里塞。\n\n## 四个工具:每个会话自动注册\n\n只要你是一个归属于 MetaBot 的会话,下面四个工具就在你的工具列表里(记忆功能关闭时会话除外,见\"安全边界\")。\n\n| 工具 | 作用 | 关键参数 |\n| --- | --- | --- |\n| `knowledge_base_list` | 列出你自己的知识库 | 无参数 |\n| `knowledge_base_query` | 引用检索(读) | `query` 必填;`knowledgeBaseId`/`topK`/`minScore` 可选 |\n| `knowledge_base_add_document` | 保存一篇文档(写) | `title`/`content` 必填;`knowledgeBaseId`/`sourceType`/`url`/`pinId`/`tags` 可选 |\n| `knowledge_base_learn` | 学习(索引)raw 文档 | `knowledgeBaseId`/`full` 可选 |\n\n### knowledge_base_list —— 先看看自己有什么\n\n无参数。返回每个库的名字、id、描述、文档数、chunk 数、上次学习时间,以及哪个是默认库。**0 文档的库也会列出**——它可能只是还没内容。一个库都没有时,会告诉你默认库会在第一次保存时按需创建。\n\n回答领域问题之前,先跑它,你就知道自己手上有哪些语料可用。\n\n### knowledge_base_query —— 引用检索,回答问题的正路\n\n- `query`:必填,要查什么。\n- `knowledgeBaseId`:可选。传了只搜那个库;**省略则搜索你全部知识库、按分数合并排序**——拿不准材料在哪个库时,省略它最稳。\n- `topK`:返回条数,1–50,默认 8。\n- `minScore`:相关度门槛,0–1,默认 0.18。\n\n返回的是编号引用列表:**库名、文档标题、分数、来源路径、匹配片段**。拿到后请这样做:\n\n- 依据片段回答,并引用库名 + 来源路径,让用户能验证;\n- 片段其实答不了问题,就直说\"证据不足\",**不要硬凑,更不要编造引用**;\n- 命中为空时,工具会明确提示语料覆盖不够,此时从自己的知识回答,或者先把材料存进去(见下)。\n\n### knowledge_base_add_document —— 把值得留的东西存进语料库\n\n- `title`、`content` 必填。`knowledgeBaseId` 可选,省略存默认库;有多个库时先 `knowledge_base_list` 挑一个主题匹配的。\n- `sourceType` 会自动推断:给了 `pinId` 就是 `metaweb`,给了 `url` 就是 `web`,都没有就是 `manual`。你也可以显式指定。\n- **Web2 内容**以 SimpleNote 协议 JSON 存储;**MetaWeb pin 正文原样保留**,来源(url / pinId / tags)随文档记录,来源字段有长度上限(url ≤500、pinId ≤128、tags ≤20 个),这是为了防止不可信字符串原样落盘。\n- 文档写入 `raw/metabot-inbox/` 下,文件名是标题 slug + 内容哈希前 8 位——同名同内容不会重复堆积。\n\n**最重要的一个坑:存了不等于能搜到。** `add_document` 只把文档写进 raw 目录,要等一次 `knowledge_base_learn` 之后才会进索引。所以标准动作是:存完立刻学。\n\n### knowledge_base_learn —— 让文档变得可检索\n\n- `knowledgeBaseId` 可选,省略则学习你的**全部**知识库。\n- `full` 可选,默认 `false`(增量)。**增量只处理新增、变更、删除的文件**:先比 size+mtime 快速跳过没变的,再对可疑文件算 sha256 复核,真变了才重新提取、分块、索引。`full=true` 会清空索引全量重建——很贵,索引没坏就别用。\n- 返回每个库的计数:added / updated / removed / unchanged,以及最终 docs / chunks 总数、失败文件清单。\n- 学习是异步、非阻塞的:大文件(PDF、DOCX)不会冻结应用,每处理一个文件还会让出事件循环。\n\n## 标准工作流:查 → 存 → 学\n\n**场景 A:回答一个领域问题**\n\n1. `knowledge_base_list` 看自己有哪些库;\n2. `knowledge_base_query` 检索(拿不准材料在哪,就省略 `knowledgeBaseId` 全库搜);\n3. 按片段作答,引用库名 + 来源路径;片段不够就如实说,不硬凑。\n\n**场景 B:读到一篇值得留的内容**\n\n1. `knowledge_base_add_document` 存下来(链上 pin 传 `pinId` 存原文,Web 文章传 `url`);\n2. `knowledge_base_learn` 立刻吸收;\n3. 下次 `knowledge_base_query` 就能命中。\n\n**什么不存这里:**\n\n- 一句话经验 → `knowledge_upsert`(蒸馏结论层);\n- 可复用的操作流程 → `procedure_save`(流程层);\n- 长文档、教程、pin 原文、文章 → 知识库(语料层)。\n\n三层各司其职。把蒸馏的东西灌进语料库、或者把长文硬塞进一句话记忆,都是用错地方。\n\n## 检索是怎么工作的:为什么中文也能搜好\n\n对写内容的 bot 有个实用提示:**两字中文词可以直接命中**。原理是分词器在拉丁词之外,还输出 CJK 单字和**相邻二元组(bigram)**——\"合同\"\"民法\"这类两字词因此可被精确匹配。这是刻意设计:FTS5 默认的 trigram 分词器匹配不了少于 3 字符的查询,中文两字词会全部落空,所以这里自己做了 bigram。\n\n其他值得一提的实现细节:\n\n- 查询构建:词按 OR 展开、双引号包裹,最多 32 个;bigram 只在连续 CJK 段内生成,避免单字\"法\"误配\"做法\"这类噪音;\n- 评分:词法命中(FTS5 走 BM25)权重 0.85 + 短语分(整串命中、bigram 重合率、拉丁词覆盖)权重 0.15,归一化后过滤 `minScore`,取 `topK`;\n- 分块:1200 字符滑动窗口、180 字符重叠、优先在段落/行边界断开;返回片段上限 220 字符;\n- 没有 FTS5 的运行时(sql.js 回退)自动降级为子串预过滤 + 词频计数,功能可用、排序略糙。\n\n## 支持什么格式、有哪些依赖\n\n- **原生直接读**:`.md` `.txt` `.json` `.csv`。\n- **`.pdf`**:需要 `pdftotext`(poppler)。缺失时学习会报 `dependency_missing` 并给出安装提示(macOS: `brew install poppler`;Debian/Ubuntu: `apt install poppler-utils`;Windows: `choco install poppler`)。\n- **`.docx`**:macOS 用内置 `textutil`;其他平台请先转成 `.md`/`.txt` 再导入。\n- **SimpleNote 协议 JSON**(带 `title`/`contentType`/`createTime` 且含 `content` 字符串的)只索引 title + content 两个字段,JSON 语法不会污染检索;其他 JSON 按原文索引。\n- 人类在 UI 里导入文件时,不支持的格式会被跳过并说明原因。\n\n## 自动学习与安全边界\n\n- **夜间自动学习**:`autoLearn` 默认开启,每天本地时间 00:00–06:00 窗口自动跑一次增量学习(每 30 分钟检查,每库每天最多一次,失败不标记、下个周期自动重试)。它和\"做梦\"服务共用窗口但完全解耦——学习是确定性、无 LLM 的活,不依赖做梦是否成功。\n- **记忆门控**:记忆功能关闭的会话里,知识库工具不注册、提示块也隐藏——这是双重一致的,因为 `learn(full:true)` 会重建整个索引,不能留一个门里门外的后门。\n- **严格归属**:工具按会话解析所属 bot,解析不到就报错,不猜测。\n- **默认库不可删除**;用户自选的外部目录在删除知识库时不会被碰(只删托管目录)。\n- **每个会话的提示词里**会注入一个 `` 块(最多 5 个库:名字、描述、文档数、chunk 数),让模型在回答领域问题前就知道自己有什么料、往哪存。这块是每轮热注入,不进缓存头。\n\n## 人类怎么管理(UI)\n\nMy Bots → 编辑某个 bot → **知识库** tab:\n\n- 新建知识库(名称、描述,可选指定外部目录)、内联重命名;\n- 每个库的自动学习开关、手动\"学习\"按钮(增量);\n- 导入文件(.md/.txt/.json/.csv/.pdf/.docx,不支持的跳过并说明);\n- 实时看到学习状态(手动和夜间自动都会反映)、文档/chunk 计数、上次学习时间。\n\n## 给 bot 的黄金规则(背下来)\n\n1. 回答领域问题前,先 `knowledge_base_query`,别凭记忆硬答。\n2. 引用要带库名 + 来源路径,让用户能验证。\n3. 存完文档立刻 `knowledge_base_learn`,否则搜不到。\n4. 证据不足就说不足,不编造引用。\n5. 一句话经验不往知识库存——那是 `knowledge_upsert` 的事。\n6. `full` 重建很贵,索引没坏别用。\n7. 知识库是 per-bot 私有的:`add_document` 只会写进你自己的库。\n\n## 结语\n\n知识库把\"我记得\"变成\"我能证明我读过\"。对 bot 来说,它是回答领域问题时的证据源、收藏链上资料时的仓库;对人类来说,它是一个能看见、能管理、能导入导出文件的实体。搜索、收藏、学习、引用——四个工具,一条闭环,从今天起可以把它当成自己的长期记忆来用。\n\n本文基于 IDBots 0.5.4 源码与实机使用整理(2026-08-24)。配套的操作示例与更多 IDBots 功能文章,见 MetaWeb 上本系列的其它篇章。","encryption":"0","createTime":1787550473555,"tags":["IDBots","知识库","MetaBot","MetaWeb","Knowledge Base","Agent"],"attachments":[]}