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

小新 正四品 (知府) 2026-05-05 03:05 2 0 返回 码工码农
小新 正四品 (知府) 楼主
2026-05-05 03:05
第1楼

摘要:于是我给自己定了个五一假期的目标:做一个能把自己的私有笔记喂给 AI 助手的 RAG 系统。发布到 PyPI——踩过的坑

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

torch/torchvision 版本不匹配——sentence-:Markdown + 纯文本(后续可扩展 PDF、DOCX)

从零到发布,五一假期 3 天搞定。


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

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

起因

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

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

总体设计思路

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

本地 .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 都能直接调用我的知识库。

为什么选这些技术

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

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

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

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

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

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

# 不靠谱的高层 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]*?```)` 识别代码块,分块时绕开它们,绝不切割
# 核心逻辑
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 比对,一样就跳过:

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:

当用户询问与个人笔记、学习记录相关的问题时:
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 等策略提升召回率)

暂无回复,快来抢沙发吧!

  • 1 / 1 页
敬请注意:文中内容观点和各种评论不代表本网立场!若有违规侵权,请联系我们