Skip to content

本地知识库(RAG) ​

让模型能查你自己的资料——写进知识库的文档会被切块、向量化,之后用户提问时由 Agent 主动检索,把命中的片段作为回答依据。

这一页只讲知识库本身。模型提供商、工具总线、会话窗口在 接入大模型(LLM) 里。

默认不启用

知识库是 llm_core 插件的一部分,但默认关闭。没配 rag 段时它不初始化、不占内存、不影响对话,knowledge_search 工具也不会进工具总线。

它是什么,不是什么 ​

  • 是:本地资料的检索底座。文档、切片、向量、全文索引全部收在一个 SQLite 文件里,没有额外服务要跑。
  • 不是:向量数据库集群。它是为「几百到几千篇文档」这个量级设计的,靠 SQLite 单文件吃饭。
  • 不做 OCR、不抓网页、不自动同步目录。入库就是「你把文本交进来」,怎么拿到文本是你的事。

开启 ​

在面板的插件配置里把 rag 填成一个 JSON 对象(这一项在配置里是字符串,注意引号转义),再设 rag_top_k:

json
{
  "enabled": true,
  "base_url": "https://api.example.com/v1",
  "api_key": "sk-...",
  "model": "text-embedding-3-small",
  "dims": 1536,
  "chunk_size": 400,
  "chunk_overlap": 80,
  "backend": "auto"
}
字段说明
enabled总开关。为 false 时其余字段全部无视
base_urlembedding 端点,必须是 OpenAI 兼容的 POST /embeddings(一般以 /v1 结尾)。缺它则不启用
api_key也可以不填,改用环境变量 LLM_CORE_EMBED_API_KEY
model嵌入模型名,默认 text-embedding-3-small
dims向量维度。留 0 时按首次调用返回的维度自动推断并固定
chunk_size单块字符数,默认 400
chunk_overlap相邻块重叠字符数,默认 80
backendauto(默认,能用 sqlite_vec 就用)/ sqlite_vec / memory

中文语料建议用 BGE-M3,dims 设 1024。换模型必须同时改 dims,否则新旧向量不可比。

改完配置重启框架生效(_init_kb() 在 register() 里只跑一次)。

数据存在哪 ​

一个文件:data/plugins_dat/llm_core/llm_kb.db。

里面四张表:kb_docs(文档)、kb_chunks(切片)、kb_fts(FTS5 全文索引)、kb_vec(vec0 向量表)或 kb_vec_mem(numpy 后端的向量列)。备份就是拷这一个文件。

入库 ​

面板:插件页面 → LLM 对话核心 → 「知识库」标签页。粘贴文本、填标题、点入库。同一页还能做检索自测、看文档列表、单篇删除、一键清空。

HTTP:

bash
# 入库(title 留空时自动截取正文前 30 字)
curl -X POST http://127.0.0.1:8080/api/llm_core/kb/ingest \
  -H "Authorization: Bearer <你的接口令牌>" \
  -H "Content-Type: application/json" \
  -d '{"title":"运维手册","text":"……正文……","source":"manual"}'

# 文档列表(含每篇切片数)
curl http://127.0.0.1:8080/api/llm_core/kb/docs

代码(插件里拿到 llm_core 服务后):

python
kb = ctx._framework.services.get('llm_core').kb   # 未启用时为 None
if kb:
    doc_id = kb.add_text('标题', '正文', source='crawler')
    hits = kb.search('检索词', top_k=5)

入库是同步的:一次 add_text 会调用一次 embedding 端点(文本按 chunk_size 切成几块就请求几块)。一次塞几万字会长耗时,建议在库里批量处理,别放在消息处理路径上。

检索怎么工作 ​

两路召回,再融合:

  1. 向量召回——查询向量化后按余弦/IP 距离取近邻。sqlite_vec 后端走 vec0 的 MATCH,memory 后端把向量读出来在内存里算。
  2. 关键词召回——FTS5 trigram 分词 + BM25 排序。查询少于 3 个字符时这一路直接跳过(trigram 的硬限制),此时只有向量召回。
  3. 融合——RRF(Reciprocal Rank Fusion)按排名倒数加权,不依赖两路分数量纲,省掉归一化。

每路各取 top_k * 3 个候选,融合后截前 top_k。返回字段:text / title / source / doc_id / chunk_id / idx / score。

Agent 怎么用 ​

启用后 knowledge_search 会被注册进工具总线(source 标为插件自身),模型在遇到「资料 / 文档 / 手册 / 我之前存过的内容」这类问题时自行调用:

用户:上次那份部署手册里,反向 WS 的端口是哪个?
模型 → knowledge_search(query="反向 WS 端口")
     → 返回【片段1】(来源:部署手册)……正文……
模型 → 依据片段作答

返回条数取 rag_top_k(默认 5)。工具返回的是拼好的文本,不是结构化 JSON——直接进上下文,模型不必再解析一遍。

管理接口 ​

方法与路径作用参数
POST /api/llm_core/kb/ingest入库body: title / text(必填)/ source
GET /api/llm_core/kb/docs文档列表 + 总数无
DELETE /api/llm_core/kb/docs/<doc_id>删除单篇(连带切片与向量)路径参数
GET /api/llm_core/kb/search检索自测query: q / k
POST /api/llm_core/kb/clear清空全部无,返回清掉的文档数

未启用时统一返回 {"code": 1, "msg": "知识库未启用"}。

排错速查 ​

现象原因与处理
面板「知识库」页说没启用rag.enabled 不是 true,或 base_url 没填;配置改完没重启
提示 rag 配置不是合法 JSON面板里这一项是字符串,内层引号要转义;用 json.loads 的规则检查一遍
入库报「向量化失败」embedding 端点不通 / Key 失效 / model 名不存在。先 curl 该端点的 /embeddings 单独验
报维度不匹配换了模型但没改 dims,或库里存量向量是旧模型生成的。改 dims 后清空重建
检索结果全是同一篇切片太碎(chunk_size 太小)或文档重复入库
中文短词搜不到关键词那一路要 3 字符以上,2 字词只靠向量。提高 rag_top_k 或换更好的嵌入模型
装了 sqlite-vec 但后端还是 memoryvec0 建表失败会退回 memory(看启动日志的 warning)。维度不合法或扩展加载失败是常见原因
想换后端backend 改 sqlite_vec 前先清空库,两种后端的向量列结构不同

基于 MIT + Apache 2.0 双协议发布