2026年10月3日
Gemini_Generated_Image_8xus438xus438xus

目录

本地 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 文件
  • PDF
  • 临时草稿
  • 重复网页剪藏

推荐先复制一份干净的 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 才会从一个聪明的陌生人,慢慢变成真正懂你的长期搭档。

About The Author

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注