导读文章给出一套可本地跑通的最小 Graph-RAG 闭环用 Python 清洗笔记/PDF 文本借助 Chroma 做语义检索、Neo4j 存实体关系再用 Agent 串起“先找原文、再查关联、最后生成答案”的问答流程。很多人已经在用 AI 做“知识库问答”把笔记、PDF、会议纪要丢进去靠向量检索召回片段再让模型生成答案。它通常能解决“找得到”却不稳定解决“串得起来”。你也许能搜到一段原文却很难继续追问它和谁有关、是在什么背景下形成的、又和哪些项目或人物连在一起。问题往往不在资料不够多而在系统只有相似片段没有关系结构。所以这篇文章不展开企业级架构只搭一个最小可用闭环本地收集原始文本建立向量检索从文本中抽取实体关系写入图数据库再用一个简单 Agent 把“找原文”和“查关联”串起来。跑通后你会得到一套本地Graph-RAG系统既能回答“这段内容在哪”也能回答“它和哪些人、项目、事件有关”。一、先把最小系统架构说清楚这里先只保留四层够搭闭环也方便排错。原始文本层 - 向量检索层 - 图谱层 - Agent 编排层最小 Graph-RAG 闭环原文、向量检索、图谱关系与 Agent 编排各司其职。对应分工其实很简单原始文本层负责保留 markdown、txt、导出笔记和 PDF 转文本后的原文作为最终引用依据向量检索层用本地 embedding 加Chroma或FAISS召回相关片段图谱层用Neo4j存实体、关系和来源Agent 编排层再把“检索原文”和“查询关系”串起来形成可问答的闭环。如果你只想先搭一个能跑的版本我建议直接用 Python 处理文本向量层用Chroma图谱层用Neo4j聊天模型和向量模型走本地Ollama或 sentence-transformers编排层先用LangGraph或纯 Python 函数式流程。这样依赖少、资料多、本地可跑出了问题也更容易定位。二、环境准备 / 前置条件先把资源和边界讲清楚避免做到一半才发现机器、依赖或模型不满足要求。推荐环境操作系统用 macOS、Linux 或 Windows WSL2 都可以Python 建议 3.10再准备一个 Docker Desktop 用来启动 Neo4j。机器方面至少给到 16GB 内存和 20GB 可用磁盘会更稳32GB 会舒服很多。模型如果只是验证闭环7B~14B 的本地模型通常够用没有独显也能跑只是抽取会慢很多。原始资料量一大首次建索引和抽图会明显变慢所以第一轮最好只拿几十篇文档试跑。推荐工具工具链保持轻一点就够本地模型和 embedding 服务用Ollama图数据库用Neo4j轻量向量库用ChromaPython 侧再装neo4j、chromadb、pydantic、sentence-transformers和langgraph这一组依赖即可。安装示例先安装 Python 依赖pip install chromadb neo4j pydantic sentence-transformers python-dotenv langchain langgraph启动 Neo4jdocker run -d \ --name neo4j-local \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTHneo4j/password123 \ neo4j:5启动后先做两个检查• 浏览器访问http://localhost:7474确认 Neo4j 页面能打开。• 用neo4j / password123登录一次确认数据库实例正常。如果你使用 Ollama本地还需要准备一个聊天模型和一个 embedding 模型。不同机器适合的模型不同这里不写死具体名称只要满足“一个负责抽取 / 问答一个负责向量化”即可。正式开工前建议先单独验证两件事• 聊天模型能正常返回结果• embedding 接口能正常生成向量目录建议second-brain/ data/ raw/ clean/ scripts/ clean.py build_vector.py extract_graph.py ask.py storage/ chroma/ .env config.json建议把连接信息统一放到.env至少写清 Neo4j 地址、用户名、密码以及本地模型服务地址如果你想把向量库存储路径也收进配置再补一个默认向量库路径就够了。做到这里才算环境准备完成。最低完成标准是先确认环境与工具链跑通再开始建索引和抽图能显著降低排错成本。Neo4j 能打开并登录Python 依赖装好你手头有一批原始文本可处理本地模型或 embedding 服务至少能单独跑通一次。三、工具栈选型为什么这样分工这里不做横向评测只说明这条链路里每个组件到底负责什么避免后面把问题归错地方。1原始文本层Markdown / TXT / 清洗后的 PDF 文本不要一开始就直接接飞书、Notion、邮件、微信导出。先把数据统一成文本文件后续清洗、切块、追溯、排错都会简单很多。每篇文档至少保留doc_id、title、source、created_at和content重点不在字段多而在后面能追溯尤其source和doc_id做引用、回查原文、修正抽取错误时都会用到。2向量检索层Chroma为什么不用更重的服务因为在最小闭环阶段Chroma已经够了本地持久化简单开发调试方便也适合个人知识库规模。它负责的事情很明确就是把文本切块并按语义召回片段关系推理和多跳路径查询仍然要交给后面的图谱层。3图谱层Neo4jGraph-RAG的关键不只是“有个图数据库”而是你能把知识组织成三类东西实体例如人物、项目、公司、概念、工具、事件关系例如参与、依赖、提出、发生于、引用、对比、属于还有来源也就是这条关系来自哪篇文档、哪个段落。Neo4j的价值在于你可以查路径而不只是查文档。比如“Graph-RAG 和某个项目之间隔了哪些概念或工具”这就不是向量检索擅长表达的问题了。4Agent 编排层LangGraph / Python为什么还要 Agent因为问答通常不是一步完成的• 用户先提一个问题• 系统先做语义召回• 再识别其中的关键实体• 然后去图谱查关系• 最后把“原文证据 图谱关联”合成答案这就是最小 Agent 的意义让系统按顺序调用能力而不是把所有事都塞进一次 prompt 里让模型硬猜。对本地系统来说这种显式流程也更容易打印中间结果排错成本更低。最小 Agent 的价值不是替代检索而是把语义召回、实体识别、图谱查询和答案合成串成可排错的显式流程。四、搭建步骤下面按 5 步走。每一步只解决一个问题并且尽量给出完成标准。不要跳步前一步不稳定后一步通常也会跟着偏。第一步清洗原始文本为什么做如果原始数据格式混乱后面的向量检索和关系抽取都会一起劣化。尤其 PDF 转文本后常见问题包括• 分页残留• 断行严重• 页眉页脚重复• 编码乱码• 同一文档里混入目录、页码、脚注这些噪音不先处理embedding 会被污染实体抽取也容易把无意义词当实体。具体做什么把data/raw/下的文件清洗成统一 JSON 或 JSONL建议每个文档一条记录至少包含标题、来源、正文。示例配置{ chunk_size: 600, chunk_overlap: 120, entity_types: [Person, Project, Organization, Concept, Tool, Event], relation_types: [RELATED_TO, PART_OF, WORKS_ON, MENTIONS, DEPENDS_ON, CAUSED_BY]}一个极简清洗脚本思路from pathlib import Pathimport jsonimport reraw_dir Path(data/raw)clean_dir Path(data/clean)clean_dir.mkdir(parentsTrue, exist_okTrue)for fp in raw_dir.glob(*.txt): text fp.read_text(encodingutf-8, errorsignore) text re.sub(r\n{2,}, \n, text) text re.sub(r[ \t], , text) doc { doc_id: fp.stem, title: fp.stem, source: str(fp), content: text.strip() } (clean_dir / f{fp.stem}.json).write_text( json.dumps(doc, ensure_asciiFalse, indent2), encodingutf-8 )如果你的输入不止txt而是 markdown 或 PDF 转文本建议在这一步统一处理不要把“不同来源格式差异”留到后面的切块脚本里。做到什么算完成•data/clean/里有结构统一的文档• 随便打开几篇内容没有明显乱码、重复页眉、截断•doc_id、title、source都能正常对应原始文件• 抽查 5~10 篇文档确认正文不是空字符串也不是只剩标题和目录如果这一关没过不建议继续建索引。因为后面出现的“召回不准”“实体抽错”很可能只是数据清洗问题。**注意**清洗阶段不过关时后续检索和抽取问题往往只是表象先停在这一层排查更省成本。第二步建向量索引为什么做图谱擅长表示关联不擅长承载完整上下文所以你得先把相关原文片段稳定召回出来。具体做什么• 对清洗后的文档切块• 生成 embedding• 写入 Chroma• metadata 里保留doc_id、title、chunk_id切块别只按字符数硬切尽量保留段落边界metadata 也别省尤其chunk_id和doc_id后面回溯和引用都会用到。做到什么算完成• 你能输入一个问题返回 3~5 个相关片段• 片段能追溯到原始文档• 同一个问题多次测试召回结果至少大体相关而不是完全漂移查询示例可以长这样import chromadbclient chromadb.PersistentClient(pathstorage/chroma)collection client.get_or_create_collection(kb_chunks)results collection.query( query_texts[Graph-RAG 为什么比传统 RAG 更适合知识管理], n_results3)for doc, meta in zip(results[documents][0], results[metadatas][0]): print(meta[title], meta[chunk_id]) print(doc[:200], \n)如果这里召回明显不相关先别往下走。优先排查 chunk 大小、embedding 是否适合中文以及清洗后文本是否还保留足够语义信息。第三步抽取实体与关系为什么做传统RAG只能告诉你“有这段话”Graph-RAG还要回答“这段话里谁和谁有关、关系是什么、证据在哪”。具体做什么对每个文本块调用 LLM抽取• 实体列表• 关系三元组• 每条关系对应的来源 chunk一个通用输出格式示例{ entities: [ {name: Graph-RAG, type: Concept}, {name: Neo4j, type: Tool}, {name: 知识图谱, type: Concept} ], relations: [ {source: Graph-RAG, target: 知识图谱, type: RELATED_TO}, {source: Graph-RAG, target: Neo4j, type: MENTIONS} ]}一开始先把边界定住不要追求“自动抽取一切关系”先限定实体类型和关系类型抽取结果必须带来源 chunk如果模型输出不稳定先追求少而准。中文场景里尤其要做实体规范化不然全称、简称、英文名会很快长出重复节点。做到什么算完成• 每个 chunk 至少能抽出少量高置信实体• 关系数量不需要多但要可解释、可回溯• 你能人工 spot check 10 条关系大部分是合理的• 同一实体不会因为大小写、别名、空格差异被拆成一堆节点如果模型经常不按 JSON 输出先在抽取层加约束和校验不要急着改图谱结构。第四步写入 Neo4j为什么做只有把抽取结果落到图数据库你才能做路径查询、邻居扩展和关系筛选否则它们只是一些离散 JSON 文件。具体做什么节点建议最少三类•Entity•Document•Chunk关系建议最少四类•(Document)-[:HAS_CHUNK]-(Chunk)•(Chunk)-[:MENTIONS]-(Entity)•(Entity)-[:RELATED_TO]-(Entity)•(Entity)-[:EVIDENCED_BY]-(Chunk)或在关系上挂 source 信息写入示例from neo4j import GraphDatabasedriver GraphDatabase.driver(bolt://localhost:7687, auth(neo4j, password123))def upsert_relation(tx, s, s_type, rel, t, t_type, chunk_id): tx.run( MERGE (a:Entity {name:$s}) SET a.type $s_type MERGE (b:Entity {name:$t}) SET b.type $t_type MERGE (c:Chunk {id:$chunk_id}) MERGE (a)-[r:%s]-(b) MERGE (r)-[:EVIDENCED_BY]-(c) % rel, ss, s_types_type, tt, t_typet_type, chunk_idchunk_id)with driver.session() as session: session.execute_write(upsert_relation, Graph-RAG, Concept, RELATED_TO, 知识图谱, Concept, doc1_chunk_3)说明一下上面是思路型示例。真实工程里通常会先校验关系名是否合法再拼接 Cypher避免动态关系类型带来的注入问题。另一个关键点是Chunk和Document最好都入库不要只存Entity否则很快就丢失证据链。做到什么算完成• Neo4j 浏览器里能看到节点和边• 你能查某个概念的邻居实体• 每条关系能追到来源 chunk• 相同实体重复写入时不会无限生成重复节点如果写入后图里节点数量异常膨胀优先排查实体规范化和去重逻辑。第五步接上 Agent为什么做如果没有编排层向量库和图数据库就是两个孤立能力。Agent 的作用只是把检索、抽取、查询、生成按顺序接起来。具体做什么设计一个简单流程用户提问向量检索召回相关 chunk从问题和召回结果里识别核心实体去 Neo4j 查询这些实体的邻居和路径把“原文证据 关系上下文”喂给模型生成答案最小问答策略可以很朴素用户问“是什么 / 原文怎么说”就侧重向量检索用户问“和谁有关 / 有什么联系 / 影响路径”就增加图查询。调试阶段建议把检索命中的 chunk、识别出的实体、图查询返回的路径以及最终送给模型的上下文都打印出来这样一旦回答不对能立刻判断问题卡在哪一层。做到什么算完成• 你问一个概念系统能返回原文摘要• 你再问“它和哪些项目 / 工具相关”系统能给出关系型回答• 答案里至少能附上来源文档或 chunk 线索• 当图谱没有命中时系统至少能回退到纯检索答案而不是直接胡编五、最小运行顺序 / 执行入口如果你按本文自己拆脚本推荐这个执行顺序python scripts/clean.pypython scripts/build_vector.pypython scripts/extract_graph.pypython scripts/ask.py对应含义clean.py清洗原始文本输出标准文档build_vector.py切块、向量化、写入 Chromaextract_graph.py抽取实体关系写入 Neo4jask.py接收问题执行“向量召回 图谱查询 答案生成”比较稳妥的做法是每跑完一步就做一次检查而不是四个脚本一口气跑完后再一起排错•clean.py跑完抽查清洗结果•build_vector.py跑完手测几个查询•extract_graph.py跑完进 Neo4j 看图•ask.py跑完再做端到端问答验证你也可以在ask.py里做一个最小 CLIpython scripts/ask.py Graph-RAG 和传统 RAG 的差别是什么python scripts/ask.py Graph-RAG 和 Neo4j、知识图谱之间是什么关系六、验证 / 验收跑通后应该看到什么不要只看“程序没报错”。至少做三层验收分别验证检索、图谱、问答是否都真的起作用。1向量检索验收输入一个你资料里明确存在的话题应该召回相关 chunk且标题、来源基本正确。建议至少测 3 类问题• 明确关键词问题• 同义表达问题• 比较模糊但资料里确实提过的问题如果只有第一类能召回说明它更像关键词搜索语义检索效果可能还不够稳定。2图谱验收在 Neo4j 中执行类似查询MATCH (e:Entity {name:Graph-RAG})-[r]-(n)RETURN e, r, nLIMIT 20;你应该看到•Graph-RAG节点存在• 它与若干概念、工具或项目有边• 边不是全都重复也不是明显胡连• 至少部分边能回查到 chunk 或文档来源如果查询结果里全是泛化关系或者大量节点只是“系统”“方法”“问题”这类空泛词说明抽取约束还要继续收紧。3问答验收问两类问题• 检索型问题“某篇笔记里是怎么定义 Graph-RAG 的”• 关联型问题“Graph-RAG 和 Neo4j、知识图谱、传统 RAG 分别是什么关系” 如果第二类问题的回答明显比纯向量 RAG 更能讲清“关联链路”说明你的最小 Graph-RAG 闭环已经成立。验收时还要注意两点• 答案里最好能带来源线索而不是只有一段总结• 当图谱证据不足时系统应明确说明“未找到足够关系证据”不要补全臆测。注意问答层宁可明确证据不足也不要用生成结果替代关系证据。七、常见坑 / 排错 / 边界1抽取结果很花图谱一团乱原因通常不是 Neo4j而是抽取阶段约束太弱。处理办法• 限定实体类型• 限定关系集合• 加实体规范化比如“知识图谱”“Knowledge Graph”统一成一个主名• 先只抽高频核心实体不要全量开放• 对明显无意义的实体做停用过滤一个实用的判断标准是肉眼看 20 条边时如果已经觉得“大部分没法解释”说明问题出在抽取质量它还没达到入库标准。2向量召回不准导致图谱也查偏Graph-RAG 不是跳过检索而是建立在检索之上。先检查• chunk 是否太大或太碎• embedding 模型是否适合中文• 清洗是否保留了足够上下文• metadata 是否完整能否回查原始文档经验上中文知识库切块在 400~800 字常常比特别小的 chunk 更稳定。但这不是固定值最终还是要结合你的文档类型测试。3图里有关系但问答没用上通常是 Agent 没有真的把图查询结果并入 prompt。排查时别只看最终答案要打印中间结果• 检索到了哪些 chunk• 识别了哪些实体• Neo4j 返回了哪些邻居 / 路径• 最终传给模型的上下文里是否真的包含图查询结果能看到中间态问题就好修。最怕的是所有步骤都封装起来最后只剩一个“不太对”的答案根本不知道哪一层失真。4本地模型抽取不稳定这是最常见的边界。最小可用方案里不追求一次抽取完美而是坚持结构化 JSON 输出、字段校验、失败重试和抽取后的规则过滤。如果本地小模型质量不够可以把“抽取”单独换成更强模型而把“存储与问答”继续留在本地。这是很常见的折中方案尤其适合先验证流程是否成立。5不要过早上企业级组件个人第二大脑阶段别急着上分布式向量库、复杂工作流平台或者全自动实时同步十几个数据源。先把 100 篇文档跑通做到能查到原文、能追溯来源、能看出几个关键概念之间的关系出错时也知道去哪里排查。这比堆更多组件更有价值。八、跑通之后再考虑的扩展方向主流程跑通后你可以再往前走但建议一项一项加不要同时改多处。比较常见的下一步是做实体消歧把“苹果公司/ 苹果水果”这种同名对象分开给事件关系补时间戳支持“演化路径”查询从 Notion、飞书、Obsidian、网页收藏做多源接入把用户问过的问题和修正过的答案写回图谱或者把问答型 Agent 继续扩成阅读链路、项目复盘、人物关系卡这类任务型 Agent。扩展前最好先问自己两个问题现在的瓶颈到底在数据接入、抽取质量还是问答编排新能力会不会增加大量维护成本但对当前知识库规模并不必要。只有这两个问题想清楚扩展才不会变成“系统越来越复杂但答案并没有变好”。九、结语所谓“私有第二大脑”不是把文件堆进一个更会搜索的盒子里而是让系统逐步具备四种能力知道这是什么知道它和什么有关知道它来自哪里也知道它为什么会和另一个概念连在一起。这正是Graph-RAG在个人知识库场景里的价值。如果你按本文搭完最小闭环手里会有一套足够实用的本地系统原始文本可回溯向量检索能找原文图谱能查关联Agent 能把两者串成可问答的数字助理。先别追求大而全。先让你的知识库第一次具备“关系感”能从“找到一段话”走到“说明这段话和什么相关、证据在哪”。这一步跑通了后面的扩展才有意义。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】