技术笔记 AI 工程化

本地知识图谱实战:把散落的笔记变成能跨文档问答的"第二大脑"

2026-09-13 子沐 阅读约 10 分钟

写了两年 Obsidian,笔记攒了几百篇。但每次想找"那个 XX 问题当时怎么想的",还是得翻文件夹、靠文件名猜。

向量数据库(RAG)火了之后我试了几轮,发现一个尴尬的事:它能回答"这篇文章讲了什么",但回答不了"A 和 B 之间有什么关系"。你问它"之前那篇提到的方案和这次的冲突在哪",它经常答非所问——因为它只在做文本相似度匹配,根本不知道你笔记里写的实体之间有什么联系。

后来我换了个思路:不做纯向量检索,先让 AI 把你笔记里的人和事抽出来、连成一张图,再基于这张图回答问题。搭完跑了两周,78 篇笔记索引成 3000 多个实体节点,跨文档问答确实比纯向量 RAG 好用。这篇文章讲清楚技术选型、部署步骤、踩过的坑,以及什么情况下值得搭。

系统架构图
图 1:从笔记文件到跨文档问答的完整数据流

普通 RAG 和 GraphRAG 到底差在哪

普通 RAG 的流程:文档切块 → embedding → 存向量库 → 问题来了找最相似的几块 → 塞给大模型回答。

瓶颈在于相似不等于相关。两篇文章用词不同但讲同一件事,向量距离可能很远;反过来,两个词面相似但讲的是完全不同的东西,它又会误召回。它能回答"这篇文章讲了什么",但回答不了"A 和 B 之间有什么关系"。

GraphRAG 在索引阶段多做了一步:让大模型读你的每篇文档,把实体和关系抽出来,存成一张图。查询时除了向量召回,还沿着图遍历。

普通向量 RAGGraphRAG(本文方案)
索引方式文档切块 → 向量抽实体+关系 → 图谱 + 向量
擅长回答"这篇文章讲了什么""X 和 Y 什么关系、有什么冲突"
跨文档关联弱(靠向量相似度)强(沿图遍历)
索引成本低(只 embedding)高(每篇调 LLM)
适合文档量几百到几万几十到几千(LLM 成本可控)
两种方案的能力对比(1-5 分)

技术栈选型

组件选型为什么不选别的
图谱框架LightRAG 1.5.7开源、支持中文、自带 Web UI 和多种查询模式
LLMDeepSeek API便宜,索引 80 篇几块钱;本地模型慢
EmbeddingOllama + bge-m3本地免费,中英混排友好
文件监听20 行 Python5 秒轮询够用,不用装 watchman
编辑器Obsidian双向链接 + 图谱视图
对外接口MCP stdio(100 行)官方不带 MCP,自写透明可控

查询模式怎么选

模式走什么路径适合什么问题
mix向量 + 图遍历默认,最全面
local纯图遍历查具体实体/术语,命中率最高
global全局摘要问宏观策略
hybrid向量 + 图加权介于 mix 和 local 之间
查询模式决策树
图 2:查询模式选择决策树

实测发现:查英文术语时优先用 local 模式。 hybrid 经常首轮答不出来——实体在图里但向量没带出来。切 local(纯图检索绕开向量),命中率明显提高。

两个 AI agent 怎么分工

这套系统不是单个 AI 在用,而是两个独立的 AI agent 共享同一个知识图谱。这是我觉得最有意思的部分:它们不直接对话,而是通过文件系统 + 知识图谱异步协作。

双 AI 协作架构图
图 5:双 AI agent 异步协作架构
Agent A(生产者)Agent B(消费者)
主要工作写笔记、做复盘、沉淀方法论查资料、回答问题、做交叉验证
和图谱的关系写入(自动索引新 md)查询(MCP 协议调用)
技术接口文件系统(md 落盘)MCP stdio(6 个查询工具)
不直接通信两个 agent 不直接对话,靠共享文件系统 + 图谱异步协作

这种设计的好处是解耦:生产者不用关心怎么查询,消费者不用关心怎么索引。新笔记写进去 5 秒就进图,另一个 agent 马上就能查到。

部署步骤

部署步骤流程图
图 3:五步部署流程

1. 装 Ollama 和 embedding 模型

ollama pull bge-m3

2. 装 LightRAG

pip install lightrag-hku

# .env 配置
# LLM_BINDING=openai
# OPENAI_BASE_URL=https://api.deepseek.com/v1
# EMBEDDING_BINDING=ollama
# EMBEDDING_MODEL=baai/bge-m3

3. 启动 Server

lightrag-server --port 9621

4. watchdog 自动索引(20 行)

while True:
    for f in Path(WATCH_DIR).rglob("*.md"):
        h = file_hash(f)
        if f"{f}:{h}" not in seen:
            requests.post("http://localhost:9621/documents/text",
                json={"text": f.read_text(encoding="utf-8"),
                      "file_source": str(f)}, timeout=120)
            seen.add(f"{f}:{h}")
    time.sleep(5)

五个踩过的坑

坑 1:MCP SDK 版本不对。 pip install mcp 默认装 2.x,API 全变了。pin 到 <2

坑 2:COS 源站类型选错。 必须选"静态网站源站",选错了 GET / 返回 403。

坑 3:开机自启别用任务计划程序。 用户权限会被拒,用 Startup 文件夹 VBS。

坑 4:别手改 Electron 配置。 Obsidian 的 vault 配置手写会被覆盖,走 UI。

坑 5:embedding 要匹配内容语言。 纯英文模型中文检索差,换 bge-m3 改善明显。

什么情况下值得搭

是否值得搭的判断流程图
图 4:要不要搭的判断流程
条件不够(别搭)值得搭
笔记量几十篇,搜索够用过百,经常跨文档找关联
笔记结构零散记录、待办项目复盘、方法论、技术调研
成本几万篇,LLM 成本高几百篇以内,成本可忽略

78 篇笔记索引完:3000+ 实体节点、3800+ 关系边、索引约 20 分钟、API 成本几块钱。查询响应 3-8 秒。

现在的日常

新笔记写进文件夹,5 秒内自动进图。想查直接在 AI 对话框里问——背后是 MCP 协议调本地服务。写笔记时 Obsidian 自动关联。整个栈开机自启,重启不用管。

最关键的变化不是"能搜索了",而是笔记不再是孤岛