目录
本地 RAG 知识库从 0 到 1 部署教程
让你的 AI 真正读懂你的笔记、文章、项目记录和历史经验。
这篇教程适合普通用户照着做,目标是搭建一套可以被 Claude Code 调用的本地知识库系统:
Obsidian 笔记
↓
AnythingLLM 知识库
↓
bge-m3 向量检索
↓
Qwen3.6 本地问答
↓
Claude Code MCP 调用
搭好之后,你可以在 Claude Code 里直接说:
先查询我的 Obsidian 知识库,了解我之前关于 llama.cpp 和 Qwen3.6 的部署记录,然后帮我写 README。
Claude Code 就能先查你的本地资料,再结合当前项目继续工作。
一、这套方案解决什么问题?
普通 AI 最大的问题不是不聪明,而是不了解你。
它不知道:
- 你以前写过什么文章
- 你的项目结构是什么
- 你的 Obsidian 笔记里有哪些资料
- 你之前踩过哪些坑
- 你的公众号或教程是什么风格
所以每次都要重新解释一遍。
RAG 的作用,就是把你的资料变成 AI 可以检索的长期上下文。
简单理解:
大模型负责推理和生成
RAG 负责从你的资料里找依据
没有 RAG,AI 只能猜。
有了 RAG,AI 会先查你的资料,再回答。
二、最终效果和端口规划
这套方案里会有几个本地服务:
Qwen3.6 聊天模型:
http://127.0.0.1:8080/v1
bge-m3 嵌入模型:
http://127.0.0.1:8081/v1
AnythingLLM:
http://127.0.0.1:3001
AnythingLLM Workspace slug:
obsidian
Claude Code MCP 名称:
anythingllm-kb
MCP 工具名称:
query_obsidian_kb
这里最重要的一点是:
Qwen3.6 和 bge-m3 要分开跑。
Qwen3.6 负责聊天回答,bge-m3 负责把文档变成向量。两个模型建议使用两个 llama-server、两个端口。
三、准备条件
开始之前,你需要先准备好:
- 一台 Mac 或 Linux 电脑
- 已经编译好的
llama.cpp - 已经可以运行的 Qwen3.6 GGUF 模型
- Obsidian 笔记库
- AnythingLLM
- Node.js
- Claude Code
本文假设:
llama.cpp 路径:
~/llama.cpp
Obsidian 笔记库路径:
/Users/tianxi/Obsidian-Vault
如果你的路径不一样,后面的命令记得改成自己的路径。
四、启动 Qwen3.6 聊天模型
进入 llama.cpp 目录:
cd ~/llama.cpp
启动 Qwen3.6:
./build/bin/llama-server \
-m ./models/Qwen3.6-35B-A3B-Q4_K_M.gguf \
--host 0.0.0.0 \
--port 8080 \
-c 32768 \
-ngl 99
启动后测试:
curl http://127.0.0.1:8080/v1/models
如果能返回模型列表,说明聊天模型已经正常运行。
后面 AnythingLLM 会把这个服务当成大语言模型使用。
五、部署 bge-m3 嵌入模型
AnythingLLM 内置 Embedder 里不一定能直接选择 bge-m3,所以这里单独用 llama.cpp 启动一个 embedding 服务。
1. 安装 Hugging Face 下载工具
如果你执行 huggingface-cli 提示:
zsh: command not found: huggingface-cli
可以用下面方式安装:
cd ~/llama.cpp
python3 -m venv ~/.venvs/hf
source ~/.venvs/hf/bin/activate
python -m pip install -U pip
python -m pip install -U huggingface_hub hf_xet
2. 下载 bge-m3 GGUF 模型
mkdir -p models/bge-m3
hf download groonga/bge-m3-Q4_K_M-GGUF \
bge-m3-q4_k_m.gguf \
--local-dir ./models/bge-m3
检查文件:
ls -lh models/bge-m3
看到下面文件就说明下载成功:
bge-m3-q4_k_m.gguf
3. 启动 bge-m3 embedding 服务
Qwen3.6 已经用了 8080,所以 bge-m3 用 8081:
cd ~/llama.cpp
./build/bin/llama-server \
-m ./models/bge-m3/bge-m3-q4_k_m.gguf \
--host 0.0.0.0 \
--port 8081 \
-c 8192 \
-ngl 99 \
--embedding \
--pooling cls \
--alias bge-m3
关键参数说明:
--port 8081
避免和 Qwen3.6 的 8080 冲突
--embedding
让 llama-server 作为嵌入模型服务
--pooling cls
BGE 类模型常用的 pooling 方式
--alias bge-m3
让 AnythingLLM 后面可以用 bge-m3 这个模型名调用
4. 测试 bge-m3
测试模型列表:
curl http://127.0.0.1:8081/v1/models
测试 embedding:
curl http://127.0.0.1:8081/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer no-key" \
-d '{
"model": "bge-m3",
"input": "这是一个中文知识库检索测试"
}'
如果返回一大串向量数字,说明 bge-m3 已经跑通。
六、配置 AnythingLLM
打开 AnythingLLM:
http://127.0.0.1:3001
1. 配置 LLM
进入:
设置
→ 人工智能提供商
→ 大语言模型 LLM
选择:
Generic OpenAI
填写:
Base URL:
http://127.0.0.1:8080/v1
Model:
填写 Qwen3.6 的模型名
API Key:
no-key
模型名可以用这个命令查看:
curl http://127.0.0.1:8080/v1/models
2. 配置 Embedder
进入:
设置
→ 人工智能提供商
→ 嵌入器 Embedder
选择:
Generic OpenAI
填写:
Base URL:
http://127.0.0.1:8081/v1
Embedding Model:
bge-m3
API Key:
no-key
Max embedding chunk length:
512
Max concurrent Chunks:
1
这里最容易踩坑的是 Max concurrent Chunks。
不要一开始用默认的 500。本地 llama.cpp embedding 服务不是云端高并发 API,一次丢太多 chunk 容易卡住或失败。
建议先用:
Max concurrent Chunks:1
跑通后再试:
2 或 4
七、整理并导入 Obsidian 笔记
不建议直接把整个 Obsidian Vault 导进 AnythingLLM。
因为 Vault 里通常有很多不适合进入 RAG 的内容:
.obsidian配置目录- 插件缓存
- 图片附件
- Canvas 文件
- 临时草稿
- 重复网页剪藏
推荐先复制一份干净的 Markdown 导入目录。
1. 生成干净导入目录
mkdir -p ~/rag-import/obsidian
rsync -av \
--include='*/' \
--include='*.md' \
--exclude='.obsidian/***' \
--exclude='*.canvas' \
--exclude='*.png' \
--exclude='*.jpg' \
--exclude='*.jpeg' \
--exclude='*.gif' \
--exclude='*.webp' \
--exclude='*.pdf' \
--exclude='*' \
/Users/tianxi/Obsidian-Vault/ \
~/rag-import/obsidian/
检查:
find ~/rag-import/obsidian -name "*.md" | head
2. 在 AnythingLLM 里创建 Workspace
进入 AnythingLLM 后:
创建 Workspace
→ 命名为 Obsidian 知识库
→ 上传 Markdown 文件
→ Move to Workspace
→ Save & Embed
保存并嵌入时,AnythingLLM 会调用 bge-m3,把 Markdown 文档变成向量。
八、生成文章目录索引
导入完成后,如果你问:
当前工作区有哪些文章?
AnythingLLM 可能只回答两三篇。
这不一定是导入失败。
RAG 的逻辑不是列出所有文件,而是根据问题召回最相关的片段。
如果你希望 AI 能稳定列出全部文章,建议生成一个目录索引文件。
cd ~/rag-import/obsidian
echo "# Obsidian 知识库文章目录" > _Obsidian文章目录.md
echo "" >> _Obsidian文章目录.md
echo "以下是当前导入 AnythingLLM 的 Obsidian Markdown 文件列表:" >> _Obsidian文章目录.md
echo "" >> _Obsidian文章目录.md
find . -name "*.md" \
! -name "_Obsidian文章目录.md" \
| sed 's#^\./##' \
| sort \
| while read file; do
title=$(grep -m 1 '^# ' "$file" | sed 's/^# //')
if [ -z "$title" ]; then
title="$file"
fi
echo "- 文件:$file" >> _Obsidian文章目录.md
echo " 标题:$title" >> _Obsidian文章目录.md
echo "" >> _Obsidian文章目录.md
done
然后把这个文件也上传到 AnythingLLM:
_Obsidian文章目录.md
以后可以这样问:
根据 Obsidian 文章目录,列出当前知识库中的全部文章。
九、开启 AnythingLLM API
Claude Code 要调用 AnythingLLM,需要先打开 API。
进入:
设置
→ Developer API / API Keys
→ Generate API Key
生成后保存好 API Key,不要截图公开。
打开 API 文档:
http://127.0.0.1:3001/api/docs
找到:
GET /v1/workspaces
如果返回:
{
"error": "No valid api key found."
}
说明还没有授权。
在 Swagger 页面点:
Authorize
填入:
Bearer 你的_API_KEY
重新测试,如果返回 200,说明 API 正常。
也可以用 curl 测试:
curl -X GET "http://127.0.0.1:3001/api/v1/workspaces" \
-H "Authorization: Bearer 你的_API_KEY" \
-H "Accept: application/json"
确认你的 Workspace slug 是:
obsidian
再测试知识库问答:
curl -X POST "http://127.0.0.1:3001/api/v1/workspace/obsidian/chat" \
-H "Authorization: Bearer 你的_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "根据知识库,总结和 llama.cpp 相关的内容",
"mode": "query"
}'
如果能返回知识库回答,说明 AnythingLLM API 已经打通。
十、创建 Claude Code MCP Server
下一步是创建一个 MCP Server,让 Claude Code 多一个查询知识库的工具。
1. 创建项目
mkdir -p ~/mcp-anythingllm-kb
cd ~/mcp-anythingllm-kb
npm init -y
npm install @modelcontextprotocol/sdk zod
2. 创建 server.mjs
创建文件:
nano server.mjs
写入:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const ANYTHINGLLM_BASE_URL =
process.env.ANYTHINGLLM_BASE_URL || "http://127.0.0.1:3001";
const ANYTHINGLLM_API_KEY = process.env.ANYTHINGLLM_API_KEY;
const ANYTHINGLLM_WORKSPACE =
process.env.ANYTHINGLLM_WORKSPACE || "obsidian";
if (!ANYTHINGLLM_API_KEY) {
console.error("Missing ANYTHINGLLM_API_KEY environment variable.");
process.exit(1);
}
const server = new McpServer({
name: "anythingllm-obsidian-kb",
version: "1.0.0",
});
server.registerTool(
"query_obsidian_kb",
{
title: "Query Obsidian Knowledge Base",
description:
"查询 AnythingLLM 中的 Obsidian 知识库,用于获取用户的历史笔记、文章、部署记录、项目文档等上下文。",
inputSchema: {
question: z.string().describe("要查询 Obsidian 知识库的问题"),
},
},
async ({ question }) => {
const url = `${ANYTHINGLLM_BASE_URL}/api/v1/workspace/${ANYTHINGLLM_WORKSPACE}/chat`;
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${ANYTHINGLLM_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
message: question,
mode: "query",
}),
});
if (!response.ok) {
const errorText = await response.text();
return {
content: [
{
type: "text",
text: `AnythingLLM API 调用失败:HTTP ${response.status}\n${errorText}`,
},
],
};
}
const data = await response.json();
const answer =
data.textResponse ||
data.response ||
data.message ||
data.answer ||
JSON.stringify(data, null, 2);
return {
content: [
{
type: "text",
text: answer,
},
],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
检查文件:
ls -lh /Users/tianxi/mcp-anythingllm-kb/server.mjs
十一、把 MCP 注册到 Claude Code
先准备 API Key:
export ANYTHINGLLM_API_KEY="你的_API_KEY"
找到 node 路径:
NODE_BIN="$(which node)"
注册 MCP:
claude mcp add anythingllm-kb \
--transport stdio \
--scope user \
-e ANYTHINGLLM_BASE_URL=http://127.0.0.1:3001 \
-e ANYTHINGLLM_API_KEY="$ANYTHINGLLM_API_KEY" \
-e ANYTHINGLLM_WORKSPACE=obsidian \
-- "$NODE_BIN" /Users/tianxi/mcp-anythingllm-kb/server.mjs
检查:
claude mcp list
如果能看到:
anythingllm-kb
说明已经添加成功。
进入 Claude Code:
claude
输入:
/mcp
如果看到类似:
Status: connected
Tools: 1
说明 Claude Code 已经可以调用 AnythingLLM 知识库。
十二、在 Claude Code 里怎么用?
可以直接这样说:
请调用 query_obsidian_kb,查询我的 Obsidian 知识库:我之前关于 llama.cpp 和 Qwen3.6 的部署记录有哪些?
也可以这样:
先调用 query_obsidian_kb 查询我的 Obsidian 知识库,了解我之前关于 AnythingLLM、本地 RAG、bge-m3、Qwen3.6 的内容,然后帮我生成一份 README 大纲。
或者:
查询我的 Obsidian 知识库,找出我过去写本地 AI 部署文章的结构和风格,然后根据当前项目生成一篇适合“玩客笔记”发布的公众号文章大纲。
这样 Claude Code 就会先查你的历史资料,再结合当前任务工作。
十三、建议添加 AGENTS.md 或 CLAUDE.md
为了让 Claude Code 更主动使用知识库,可以在常用项目根目录创建:
AGENTS.md
或:
CLAUDE.md
写入:
# 工作规则
你可以使用 MCP 工具 `query_obsidian_kb` 查询我的 Obsidian 知识库。
当任务涉及以下内容时,请优先调用该工具:
- 本地大模型部署
- llama.cpp
- Qwen3.6
- AnythingLLM
- Obsidian
- bge-m3
- RAG 知识库
- Claude Code 工作流
- 玩客笔记公众号写作风格
- 技术教程写作
- 项目历史部署记录
调用知识库后,再结合当前代码仓库内容进行分析、修改或写作。
不要凭空假设我的历史方案;如果知识库里有相关资料,优先参考知识库内容。
十四、常见问题和解决办法
1. AnythingLLM 里找不到 bge-m3
不要选内置 Embedder。
改选:
Generic OpenAI Embedder
然后填写:
http://127.0.0.1:8081/v1
模型名填:
bge-m3
2. bge-m3 和 Qwen3.6 不要用同一个端口
推荐:
Qwen3.6:8080
bge-m3:8081
两个模型分别启动。
3. Max concurrent Chunks 不要一开始设 500
本地 embedding 服务建议:
Max concurrent Chunks:1
稳定后再试 2 或 4。
4. 换 Embedding 模型后要重新嵌入文档
如果之前用 all-MiniLM 导入过文档,后来换成 bge-m3,需要重新嵌入。
否则新旧向量空间不同,检索效果会变差。
5. 聊天里不显示全部文件,不代表没导入
RAG 不是文件管理器。
它只会召回和问题相关的内容。
如果想让它列出全部文章,导入 _Obsidian文章目录.md。
6. API Key 不要公开
AnythingLLM API Key 泄露后,别人可能调用你的知识库。
如果不小心暴露,立刻删除旧 Key,重新生成。
7. Claude Code MCP 命令可能因版本不同而变化
如果这个写法失败:
claude mcp add anythingllm-kb ...
可以先查看帮助:
claude mcp add --help
重点确认:
- server 名字放在哪里
- 环境变量是不是用
-e KEY=value - 是否需要
--transport stdio - 命令前是否需要
--
十五、最终配置清单
笔记系统:
Obsidian
知识库管理:
AnythingLLM
Workspace:
Obsidian 知识库
Workspace slug:
obsidian
聊天模型:
Qwen3.6,通过 llama.cpp 部署
Qwen3.6 API:
http://127.0.0.1:8080/v1
嵌入模型:
bge-m3,通过 llama.cpp 部署
bge-m3 API:
http://127.0.0.1:8081/v1
Embedding Provider:
Generic OpenAI
Embedding Model:
bge-m3
Max embedding chunk length:
512
Max concurrent Chunks:
1
向量数据库:
AnythingLLM 默认本地向量库
Claude Code MCP:
anythingllm-kb
MCP 工具:
query_obsidian_kb
十六、总结
这套方案的核心不是炫技,而是让 AI 真正拥有你的长期上下文。
模型本身再强,如果不了解你的文章、项目、笔记和历史经验,每次还是从零开始。
把 Obsidian 接入 AnythingLLM,再通过 bge-m3 做向量检索,最后让 Claude Code 通过 MCP 调用知识库,本地资料就不再只是躺在文件夹里的文档,而是变成 AI 可以随时使用的工作记忆。
对内容创作者、程序员和小团队来说,这比单纯追新模型更有价值。
先把自己的资料整理好。
再让 AI 读懂你过去写过什么、做过什么、踩过什么坑。
当上下文开始沉淀,AI 才会从一个聪明的陌生人,慢慢变成真正懂你的长期搭档。