知识库应用实战
知识库应用实战 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
读完本课你能不碰界面、直接用站内 /api/documents 接口走完资料库的一生:创建资料集 → 上传文档 → 自动索引 → 检索问答 → 删除清理,并用一次真实测试验证分类检索和引用有效性。
问题场景
A19 讲了切分、A21 讲了检索、A22 讲了引用,但都是单点。真到用时你会发现断点都在衔接处:上传后索引到底完成没有?删除文档后引用为什么还能搜到?资料混在一个集合里,检索结果全是无关文档的噪声。这课把整条链路跑通,重点看状态流转和数据一致性。
核心解释
本站资料库的完整数据流(真实实现,app/api/documents/route.ts + lib/documents/parse.ts):
上传(PUT multipart) → 解析提取文本 → 切分成片段 → 写 doc_chunk + fts_doc → status='indexed'
↘ 失败 → status='failed' + error 原因可查
检索(search_documents 工具) → FTS5 MATCH → 空则 LIKE 兜底 → 仍空则「没有命中」提示
删除(DELETE ?id=) → 删 document(级联清 chunk/job)→ 删 fts_doc → 删磁盘文件
对应三张表一条链:document(文档元数据与状态)→ doc_chunk(片段,检索兜底与展示用)→ fts_doc(FTS5 索引虚表)。index_job 记录每次索引任务的成败与块数。
关键流程:上传用 PUT + multipart 表单(字段 file 和 collection),支持 .txt/.md/.markdown/.pdf,单文件上限 10MB;collection 传 default 时会懒创建默认资料集。删除走 DELETE /api/documents?id=<文档id>,级联清理三处数据加磁盘文件——少删任何一处,就会出现「搜得到、打不开」的幽灵引用。
用 curl 走一遍全流程:
# 1. 创建资料集
curl -X POST http://localhost:3000/api/documents \
-H "Content-Type: application/json" -d '{"name":"课程笔记"}'
# 2. 上传文档(collection 用第 1 步返回的 slug)
curl -X PUT http://localhost:3000/api/documents \
-F "file=@./notes.md" -F "collection=<上一步的slug>"
# 3. 查看列表:确认 status=indexed、chunks 数量
curl http://localhost:3000/api/documents
# 4. 删除文档(级联清理索引与文件)
curl -X "DELETE http://localhost:3000/api/documents?id=<文档id>"
资料集(collection)是检索的范围开关:search_documents 工具有可选的 collection 参数,传了就只在该资料集内查(SQL 里加 AND collection_slug = ?)。分类的价值在检索质量:把「接口规范」和「学习笔记」分开,问接口问题时就不会被笔记里的同词段落干扰。
示例拆解
验证「引用有效性」的固定测试(每导入一批资料都跑一遍):
{
"case": "删除接口幂等要求",
"expect_document": "团队接口规范.md",
"expect_heading": "删除接口",
"steps": [
"问:删除接口要求幂等吗?",
"检查 1:回答是否基于命中片段而非编造",
"检查 2:引用能否定位到 expect_document + expect_heading",
"检查 3:点开片段原文,结论是否被原文支持(A22 三问)"
]
}
关键点:
- 索引是同步的但状态是显式的:本站上传后立即解析索引(本地小文件),成功
indexed、失败failed且error存人话原因(如「PDF 没有文字层」)。判断「能不能搜」看状态,不看接口返回 200。 - 删除的一致性靠「同事务清理四处」:document 行、doc_chunk、fts_doc、磁盘文件。测试方法:删完后把「被删文档里的原句」拿去检索,必须零命中。
- 分类是检索质量手段,不是文件夹审美:分多少个集合,取决于「你会不会按它限定检索范围」,而不是「它们像不像一类」。
- fail 的资料要可诊断:
document.error和index_job.error都存原因——「为什么我传的文件搜不到」这个问题,答案永远在状态和错误字段里。
动手任务
- 用上面的 curl 命令走完「创建 → 上传 → 查列表」三步,记录返回的 slug、文档 id 和 chunks 数。
- 建两个资料集各传一份文档,问一个两份资料里都有同义词的问题,分别用
collection限定检索,对比命中差异。 - 删除其中一份文档,再用它原文里的句子检索,确认零命中;查列表确认状态——验证「幽灵引用」没有发生。
常见错误
- 上传成功当索引成功:HTTP 201 只代表文件收下了,索引成败看
status字段——failed的文档照样躺在列表里。 - 删除只删文件不删索引:磁盘上文件没了,
doc_chunk/fts_doc还在,检索照样命中、引用点开是空的。 - 所有资料堆一个 default 集合:短期方便,长期检索全是跨主题噪声,限定范围的价值没兑现。
- 重复上传不检查旧版本:同一文档传三次出三份片段,检索结果重复,引用顺序错乱。先删旧的再传新的。
检查与复盘
自查清单:
- 能画出「上传 → 索引 → 检索 → 删除」的状态流转图,标出每个环节落在哪张表
- 删除后能用「原文检索零命中」验证清理彻底
- 能说出 collection 分类如何影响检索质量,并举一个自己资料的分类方案
参考资料
- Next.js 文档:Route Handlers —— 本站 /api/documents 的实现形态
- MDN:FormData —— multipart 上传的数据结构
- SQLite 官方文档:FTS5 —— fts_doc 虚表的检索能力
- 下一课 A25 转向新主题:任务该交给固定流程还是模型自主决策。
读完这一课了?
标记完成后,工作台会安排接下来的学习。