把个人知识库做成了可"对话检索"的 MCP 服务

五一花了 1 天,我把个人知识库做成了可"对话检索"的 MCP 服务

一句话:pip install 一个包,你的 Markdown 笔记就能被 AI 助手自动检索并引用。

起因

我平时在本地写了大量 Markdown 笔记------前端面试题、CSS 知识、Python 性能优化、学习计划......但每次和 AI 助手(Claude Code)对话时,它根本不知道我有这些笔记。我想问"我笔记里的 CSS 第一题是什么",它只能瞎猜。

于是我给自己定了个五一假期的目标:做一个能把自己的私有笔记喂给 AI 助手的 RAG 系统。而且要简单------装个包、配一行配置就能用。

总体设计思路

整个系统的核心链路只有 7 步:

bash 复制代码
本地 .md/.txt 文件
  → Markdown 解析器(markdown-it-py)
  → 按标题分块(Chunker)
  → 文本向量化(BGE-small-zh-v1.5)
  → 存入向量数据库(LanceDB)
  → 封装成 MCP 服务(FastMCP)
  → Claude Code 自动调用
  → 检索结果注入上下文,生成回答

其中,MCP(Model Context Protocol)是 AI 助手和外部工具之间的标准通信协议------想象一下,它就像 USB 接口,你的工具只要实现这个协议,任何 AI 助手都能"即插即用"。这就是为什么 Claude Code、Cursor 都能直接调用我的知识库。

为什么选这些技术

环节 选型 理由
Embedding BGE-small-zh-v1.5 本地运行,512 维向量,中英文检索效果好
向量库 LanceDB 嵌入式数据库,无需额外部署,像 SQLite 一样简单
MD 解析 markdown-it-py Token Stream 解析,正确处理嵌套标题和代码块
分块 标题感知 + 代码块原子保护 按 h2/h3 切分,代码块绝对不切割
集成框架 FastMCP MCP 官方 Python SDK,三行代码注册一个 Tool

这些选型有一个共同的考量:零外部依赖部署。除了 Python 本身,用户不需要装 Docker、不需要起数据库、不需要配云服务。

把一篇 Markdown 变成可检索的知识------核心实现

1. 解析(你猜我绕过了哪个坑)

最初我用 markdown-it-py 的 SyntaxTreeNode 构建文档树,调试了好久一直返回 token=None。后来才搞清楚:markdown-it-py 的树形节点会在非叶子节点上把 token 设为 None------所以你直接读 token 属性就崩了。

解决方案是放弃高层 API,直接遍历底层 Token Stream:

python 复制代码
# 不靠谱的高层 API
tokens = md.parse(content)
node = SyntaxTreeNode(tokens)  # parent nodes 的 .token 是 None!

# 靠谱的底层实现
for token in md.parse(content):
    if token.type == "heading_open":
        # 手动追踪标题层级,构建 Section 树

踩过这个坑之后,"别信框架给你包装好的结构"成了我写解析器的一条原则。

2. 分块(别把代码块切碎了)

分块的核心矛盾:块太小则丢失上下文,块太大则检索精度下降

我的策略:

  • 按 h2/h3 标题边界切分:一个标题及其内容尽量在同一个 chunk 里
  • 代码块原子保护 :用正则 (\``[\s\S]*?```)` 识别代码块,分块时绕开它们,绝不切割
python 复制代码
# 核心逻辑
if len(section_content) <= 1000:
    chunks.append(section_content)  # 整个 Section 作为一个 chunk
else:
    # 按段落切分,但代码块保持完整
    parts = re.split(r'(\`\`\`[\s\S]*?\`\`\`)', section_content)
    for part in parts:
        if part.startswith('```'):
            chunks.append(part)  # 代码块原封不动
        else:
            # 长文本按段落补充切分

3. 向量化与增量索引

BGE 模型有一个设计细节很多人不知道:文档向量和查询向量应该用不同的方式生成

  • 文档文本:直接 model.encode(text)
  • 查询文本:加一个指令前缀 "为这个句子生成表示以用于检索相关文章:" 再编码

这个前缀告诉 BGE 模型"接下来的是查询,不是文档",能显著提升中文检索质量。

增量索引的实现很简单------算文件 SHA256,跟库里存的 content_hash 比对,一样就跳过:

python 复制代码
file_hash = hashlib.sha256(file_bytes).hexdigest()
if db.has_hash(file_hash):
    return "skipped"  # 文件没变,跳过

MCP 协议------让 AI 助手"看懂"你的工具

我注册了 5 个 Tool:

Tool 功能 标签
knowledge_search 搜索知识库 readOnly
knowledge_index 索引文件/目录 destructive, idempotent
knowledge_list 列出已索引文档 readOnly
knowledge_remove 移除索引 destructive
knowledge_stats 全局统计 readOnly

标签系统是 FastMCP 内置的------readOnlyHint 告诉 AI "这个操作是安全的";destructiveHint 告诉 AI "这个会改数据"。Claude Code 会根据这些标签决定要不要弹出确认框。

一个 MCP Server 注册多个 Tool 的概念,类似于一个 HTTP 服务暴露多个 API 端点------启动的是同一个进程,通过同一根 stdio 管道通信,但 5 个 Tool 各自独立可调用。

为什么装好了 MCP,问问题却不自动检索?

这是上线后遇到的一个有意思的问题。我在新环境装好包后,问了一个知识库相关的问题,Claude Code 直接用自己的训练数据回答了------完全没有调用 knowledge_search

原因有二:

  1. 没索引就没有内容可搜------向量库是空的
  2. AI 不知道什么时候该用你的工具------Tool 描述告诉它"我能做什么",但没告诉它"什么时候该用我"

解决方案是创建一个 CLAUDE.md

markdown 复制代码
当用户询问与个人笔记、学习记录相关的问题时:
1. 优先使用 knowledge_search 检索知识库
2. 即使用户提到了具体文件名,也先用 knowledge_search 搜索

这个规则文件是给 Claude Code 看的"行为指南",告诉它遇到哪类问题该走知识库路线。

发布到 PyPI------踩过的坑

  1. license = {text = "MIT"} 是新版 setuptools 不支持的旧写法 ,必须改成 SPDX 表达式 license = "MIT",同时删除旧的 License :: OSI Approved :: MIT License classifier------两者共存直接报 InvalidConfigError

  2. torch/torchvision 版本不匹配 ------sentence-transformers 会拉 torch 2.11.0,但旧版 torchvision 0.22.1 不兼容,报 RuntimeError: operator torchvision::nms does not existpip install torch torchvision --force-reinstall 解决

  3. 包名和模块名是两回事 ------改 pyproject.tomlname 字段改了 pip install 的名字,但 Python 模块名永远是 src/ 下的目录名 knowledge_mcp

成果

  • 总代码量:约 640 行 Python(9 个源文件)
  • 安装方式pip install lxd-knowledge-test-mcp
  • 发布在 PyPIlxd-knowledge-test-mcp
  • 支持格式:Markdown + 纯文本(后续可扩展 PDF、DOCX)

从零到发布,五一假期 3 天搞定。核心体感是:MCP 协议把"AI 调用工具"这件事做得极其丝滑------你写完 Tool 的定义,AI 就能自动发现并调用,不用写任何对接代码。

后续方向

  • 支持 PDF、DOCX 文档格式
  • 文件监听自动增量索引
  • 混合检索(向量 + BM25 关键词)
  • 查询重写(HyDE 等策略提升召回率)
相关推荐
AAI机器之心2 小时前
在 macOS 上本地部署 Ollama + LLaMA3(附教程)
人工智能·macos·langchain·llm·知识库·大模型部署
new【一个】对象2 小时前
RAG详解
python·llm·agent·rag
薛定谔的猫3692 小时前
深入浅出 Model Context Protocol (MCP):连接 AI 与外部数据的桥梁
ai·llm·agent·mcp·modelcontextprotocol
独断万古他化12 小时前
大模型接入指南:API、本地部署与 SDK 三种接入
大模型·llm·api·sdk
qcx2314 小时前
【AI Agent通识九课】02 · Agent 的“思考回路“长啥样?
人工智能·ai·llm·agent
码农小旋风15 小时前
2026 终端 AI 编程工具深度横评:Claude Code、Codex CLI、Gemini CLI、Aider 怎么选
人工智能·gpt·claude
LemonSmile_15 小时前
CC Switch 配置 Claude Code 接入 阿里云百炼
阿里云·云计算·claude·百炼
Techlin16 小时前
Claude Opus 4.7 编程实战:怎么用最新旗舰模型写复杂业务代码?完整配置 + 踩坑记录
ai编程·claude
MLVector18 小时前
Claude Code使用教程 第3篇:从开发功能到修复Bug
claude