从 RAG 到知识图谱:个人知识管理的演进

0 阅读9分钟

本文面向:关注信息检索演进、想理解语义搜索与知识图谱差异的开发者。
预计阅读时间:9 分钟
最终效果:理解从关键词搜索到知识图谱四代技术的权衡,以及为何混合架构是更优解。

你有没有过这样的经历:明明记得上周解决过一个类似的 bug,但死活搜不到那条对话?或者,你知道某个技术方案讨论过,但关键词怎么换都找不到?

这不是你的记忆力出了问题,而是你的知识管理工具还停留在上一个时代。

第一代:关键词搜索

最原始的信息检索方式就是关键词匹配。你在编辑器里 Ctrl+F,输入一个词,找到包含这个词的所有位置。简单、直接、确定。

在对话管理领域,大多数工具也停留在这个阶段。Claude Code 的 JSONL 文件可以用 grep 搜索,Cursor 的对话记录可以通过 SQLite 的 LIKE 查询过滤。关键词搜索的优点是速度快、结果确定——你搜"内存泄漏",就只会返回包含"内存泄漏"这四个字的记录。

但问题也很明显。

同义词是关键词搜索的天敌。 你搜"内存泄漏",但那条对话里写的是"OOM"、"堆溢出"、"对象未释放"——关键词完全不同,但指的是同一件事。你搜"部署",但记录里用的是"deploy"、"发布"、"上线"。每一次搜索,你都在和自己的词汇量博弈。

上下文被忽略。 关键词搜索不理解"这行代码是在讨论 bug 还是在讨论架构设计"。它只做字面匹配,不理解语义。搜"性能"可能返回优化讨论,也可能返回一段无关的代码恰好用了 performance 变量名。

碎片化。 关键词搜索返回的是片段,不是知识。你需要自己把 10 条搜索结果拼凑成一个完整的理解。

第二代:全文搜索

全文搜索在关键词搜索的基础上引入了倒排索引分词。SQLite 的 FTS5 扩展、Elasticsearch、MeiliSearch 都是这个阶段的代表。

全文搜索解决了分词问题。"内存泄漏"会被正确地切成"内存"和"泄漏"两个词,搜索"内存"也能命中这条记录。它还引入了 TF-IDF 等权重算法,让更相关的结果排在前面。

但全文搜索本质上仍然是词袋模型——它把文本拆成词,统计词频,计算相关性。它不理解语义。

"如何优化数据库查询性能"和"SQL 慢查询排查"在语义上高度相关,但在词袋模型看来,这两个句子的重叠词汇很少,相关性得分不高。

更关键的问题是,全文搜索仍然是平铺的。它返回的是文档列表,不揭示文档之间的关系。你搜到了 20 条关于数据库优化的记录,但它们之间的关联——哪些是原因分析、哪些是解决方案、哪些验证了哪些方案——全文搜索无法告诉你。

第三代:RAG 与向量搜索

RAG(Retrieval-Augmented Generation)的出现是一个范式转变。它的核心思想是:用向量表示语义,用距离衡量相似性。

工作流程是这样的:

  1. Embedding: 把文本通过一个 embedding 模型转换为高维向量(通常是 384 维或 1536 维)。这个向量是文本的"语义指纹"——意思相近的文本,向量距离也近。
  2. 索引: 把所有向量存入向量数据库(ChatCrystal 用的是 vectra),建立高效的近似最近邻(ANN)索引。
  3. 检索: 用户查询也转换为向量,在索引中找到最相近的文档。
  4. 增强生成: 把检索到的相关文档作为上下文,交给 LLM 生成回答。

这解决了全文搜索最根本的缺陷——语义理解

你搜"内存泄漏排查",embedding 模型知道"OOM"和"堆溢出"在语义上与"内存泄漏"很近,会把相关记录一并返回。你搜"数据库慢",它能理解"SQL 查询优化"、"索引缺失"、"N+1 问题"都是相关话题。

在 ChatCrystal 中,RAG 是这样工作的:当你的对话被总结成笔记后,笔记的标题、摘要、关键结论会被分块(chunking),每个块计算 embedding 存入 vectra。当你搜索时,查询向量和所有块的向量做相似度计算,返回最相关的笔记。

但 RAG 也有局限。

它仍然是"平铺的"。 向量搜索告诉你"A 和 B 语义相似",但不告诉你它们是什么关系。A 是 B 的前提条件?A 和 B 是同一个问题的不同解法?A 驳斥了 B 的结论?这些结构化的关系,向量距离无法表达。

检索精度受 chunk 策略影响。 如果切块太大,噪声多;切块太小,上下文丢失。这是一门手艺活,没有通用最优解。

它不擅长"关联推理"。 "这个 bug 的修复方案和上周那个性能问题的优化策略有什么共性?"——这类需要跨越多条记录建立连接的查询,纯向量搜索力不从心。

第四代:知识图谱

知识图谱是一种完全不同的思维方式。它不是把文本拍平成向量,而是把知识拆解为实体关系

在 ChatCrystal 的知识图谱中,每条笔记是一个节点,节点之间的关系有类型:

  • CAUSED_BY: 一条笔记记录的问题由另一条笔记记录的原因导致
  • LEADS_TO: 一条笔记的结论引出了另一条笔记的发现
  • RESOLVED_BY: 一条笔记提出的问题被另一条笔记的方案解决
  • SIMILAR_TO: 两条笔记讨论相似的话题或方案
  • CONTRADICTS: 两条笔记的结论存在矛盾
  • DEPENDS_ON: 一条笔记的技术方案依赖于另一条
  • EXTENDS: 一条笔记在另一条的基础上扩展或深化
  • REFERENCES: 一条笔记引用了另一条的内容

这些关系不是人工标注的,而是 LLM 在生成摘要时自动提取的。当一条新笔记被创建时,系统会把它的摘要和已有笔记做比对,由 LLM 判断它们之间是否存在关系以及关系的类型。

知识图谱解决了 RAG 的核心短板——结构化的关系表达

你可以问"这条笔记的相关笔记有哪些",系统不仅返回语义相似的笔记,还告诉你每条关系的类型和强度。你可以沿着关系链发现知识的脉络:"这个 bug 的根因是一个架构缺陷,这个架构缺陷在三个月前的重构讨论中被提出过,当时的结论是暂时不改,因为它和另一个系统的兼容性有关。"

这种沿着关系链的推理,是纯向量搜索做不到的。

ChatCrystal 的混合架构

ChatCrystal 没有选择"RAG 或知识图谱",而是把两者结合在一起。

向量搜索负责"发现"。 当你有一个模糊的需求——"我记得讨论过类似的问题"——向量搜索能快速找到语义相关的笔记。这是第一层召回。

知识图谱负责"连接"。 当你找到了一条相关笔记,知识图谱告诉你它的上下文——它和哪些笔记有关、是什么关系、形成了一条怎样的知识链。这是第二层理解。

LLM 负责"推理"。 在 MCP 集成中,recall_for_task 工具会同时调用向量搜索和知识图谱,把相关笔记及其关系作为上下文交给 LLM,让它基于这些结构化知识做推理和回答。

这种三层架构的搜索流程是:

用户查询
  → Embedding → 向量搜索 → 候选笔记集合
  → 知识图谱遍历 → 笔记 + 关系 + 关联笔记
  → LLM 推理 → 结构化回答

每一层解决不同层次的问题。向量搜索解决"找到",知识图谱解决"关联",LLM 解决"理解"。

从被动搜索到主动记忆

知识管理的演进还有另一个维度:从被动搜索主动记忆

传统的知识管理是"你来找我"——用户输入查询,系统返回结果。但在 AI Agent 时代,更理想的方式是"我来找你"——系统知道你当前在做什么,自动回忆相关的知识。

ChatCrystal 的 MCP 集成中的 recall_for_task 就是这个理念的实践。当你在 Claude Code 中开始一个新任务时,系统自动用任务描述做向量搜索,找到相关的笔记和历史对话,把这些上下文注入到当前的 AI 对话中。

这比传统的"先搜索、再阅读、再应用"的工作流快了一个数量级。知识不再是需要主动查找的资料,而是像肌肉记忆一样自动浮现的上下文。

write_task_memory 则完成了另一个方向:当你完成一个任务并产生有价值的经验时,系统自动把这些经验写回知识库,形成新的笔记和关系。知识的积累从"手动整理"变成了"自动沉淀"。

知识管理的未来

从关键词搜索到全文搜索,从 RAG 到知识图谱,每一次跃迁都在缩小"信息"和"知识"之间的距离。

关键词搜索给你的是"包含这个词的文档"。全文搜索给你的是"最相关的文档"。RAG 给你的是"语义最接近的文档"。知识图谱给你的是"相关的知识及其结构化关系"。

ChatCrystal 的目标是让最后一步——从"结构化关系"到"真正有用的知识"——由 LLM 来完成。人类负责对话和创造,AI 负责记忆和关联。

这不是科幻。它已经在运行了。打开 ChatCrystal,搜索你上周讨论过的问题,看看知识图谱揭示了哪些你已经遗忘的连接。你可能会对自己的知识盲区有全新的认识。


项目地址:github.com/ZengLiangYi…

如有疑问欢迎在 GitHub Issues 或私信交流,很乐意解答。