第 2 课

接上本地 Embedding,把笔记建成知识库

用 llama serve 起 Qwen3-Embedding-0.6B 并确认 1024 维,在 setup.json 里加 vllm 类型 Embedding 和关闭搜索,用 kb create 把导数笔记建库,用 kb list、kb info、kb search --format json 检查索引和检索结果,再用 run chat --kb 让回答引用笔记原文并列出来源。

图文20 分钟

课程目录第 2 / 3 课

学习位置仅保存在当前浏览器,有效期 180 天。

01 / 图文教材

图文教材

本课对照的官方页面:知识空间、Provider 配置、命令参考。命令与输出均为实测(DeepTutor 1.7.0,本地 llama.cpp),输出为节选。

上一课的小模型把 v'(t) 说成了速度。这一课给 DeepTutor 配上 Embedding 模型,把一份自己的笔记建成知识库(KB),再让它按笔记作答并标出来源。用到的仍然全是本地模型。

第 1 步:再起一个本地 Embedding 服务

知识库检索需要 Embedding 模型。这里用 llama.cpp 再开一个端口,加载 Qwen3-Embedding-0.6B:

llama serve -hf Qwen/Qwen3-Embedding-0.6B-GGUF:Q8_0 \
  --port 8081 --embedding --pooling last \
  --alias qwen3-embedding-0.6b

确认服务可用,并查看向量维度:

curl -s http://localhost:8081/v1/embeddings \
  -H 'Content-Type: application/json' \
  -d '{"model":"qwen3-embedding-0.6b","input":"你好"}' \
  | python3 -c "import json,sys; \
print(len(json.load(sys.stdin)['data'][0]['embedding']))"

对照结果:

1024

记下这个 1024,下一步的 dimension 必须和它一致。

第 2 步:把 Embedding 写进 setup.json

deeptutor config providers 的 embedding 一栏里有 vllm(默认地址 http://localhost:8000/v1/embeddings),它接的是 OpenAI 兼容的 /v1/embeddings 接口,llama.cpp 同样适用。注意这里的 base_url 要写完整的 endpoint,不能只写到 /v1。更新后的 setup.json 如下:

{
  "llm": {
    "provider": "llama_cpp",
    "model": "gemma-4-e2b",
    "base_url": "http://localhost:8080/v1"
  },
  "embedding": {
    "provider": "vllm",
    "model": "qwen3-embedding-0.6b",
    "base_url": "http://localhost:8081/v1/embeddings",
    "dimension": 1024
  },
  "search": {
    "provider": "none"
  }
}

search 设为 none 表示关闭联网搜索,只使用本地资料。DeepTutor 默认的搜索服务是 duckduckgo。写入配置:

deeptutor config apply setup.json
deeptutor config show

对照结果(config show 的 embedding 段,节选):

"embedding": {
  "status": "configured",
  "provider": "vllm",
  "provider_mode": "local",
  "model": "qwen3-embedding-0.6b",
  "base_url": "http://localhost:8081/v1/embeddings",

第 3 步:准备一份笔记并建库

新建 docs/derivative-notes.md,内容可以直接复制:

# 导数学习笔记

## 定义
函数 f(x) 在点 x0 处的导数,是当 h 趋近于 0 时
[f(x0 + h) - f(x0)] / h 的极限,记作 f'(x0)。
几何意义:曲线 y = f(x) 在点 (x0, f(x0)) 处切线的斜率。

## 物理意义
位移 s(t) 对时间求导得到速度 v(t) = s'(t);
速度 v(t) 再对时间求导得到加速度 a(t) = v'(t)。

## 常用公式
(x^n)' = n * x^(n-1)
(sin x)' = cos x
(e^x)' = e^x
乘积法则:(uv)' = u'v + uv'

## 易错点
1. 把 v'(t) 当成速度——其实 v'(t) 是加速度。
2. 求 (x^3)' 时忘记把指数 3 乘到前面,正确结果是 3x^2。

建库。--doc 用来指定单个文件,换成 --docs-dir 可以导入整个目录:

deeptutor kb create calculus --doc docs/derivative-notes.md

对照结果(节选,约 3 秒):

Creating KB calculus with 1 document(s) via LlamaIndex...
Knowledge base created successfully.

过程中会出现一条 bm25s ... Overriding the value of similarity_top_k 的 WARNING,原因是文档太少,可以忽略。

第 4 步:查看与检索知识库

deeptutor kb list
deeptutor kb info calculus

对照结果:kb list 显示 calculus ready 1 llamaindex yes,最后一列表示它已经是默认库;kb info 的 JSON 中可以看到 "embedding_model": "qwen3-embedding-0.6b"、"embedding_dim": 1024、"status": "ready"。

直接检索(默认为 hybrid 模式):

deeptutor kb search calculus "x^3 的导数" --format json

建议加上 --format json。实测默认的 rich 输出会把 [f(x0 + h) - f(x0)] 这类方括号当成排版标记吞掉,JSON 输出则完整保留了原文。JSON 里的 sources[].title 是 derivative-notes.md。

第 5 步:让对话按笔记作答

加上 --kb 就能把知识库挂到这一轮对话上:

deeptutor run chat "根据我的笔记:v'(t) 是速度还是加速度?请引用笔记原文。" \
  --kb calculus -l zh

实测输出(节选,约 26 秒,公式两侧的 $ 已省略):

Retrieving from knowledge base 'calculus'...
Retrieved 362 characters of grounded context.
根据您提供的笔记,v'(t) 是加速度。
笔记中明确指出:
▌ 1 把 v'(t) 当成速度——其实 v'(t) 是加速度。
……
sources (1):
  [1] derivative-notes.md

同一个模型,第 1 课答错的问题,挂上知识库后答对了,还给出了原文和来源。日志里几行 Could not load library with AVX512 support 只是 faiss 在自动选择 CPU 指令集,最终显示 Successfully loaded faiss 即为正常。

以后要追加资料,用 deeptutor kb add calculus --doc chapter2.md。官方文档还提醒:更换 Embedding 模型后必须重建索引(re-index),不能把不同模型的向量混在同一个库里。

小结

  • Embedding 的 base_url 要写完整的 /v1/embeddings 地址,dimension 必须与模型实际输出一致。
  • 常用的建库与检索命令:kb create、kb list、kb info、kb search;需要看原文时加 --format json。
  • run chat ... --kb 库名 让回答有据可查,输出末尾会列出 sources。