Git 仓库: langchain4j-spring-agent/langchain4j-spring-ai/langchain4j-spring-ai-seg-flow
相关文章:三国演义向量检索实战:RAG 混合切分 + Qdrant + BGE(Recall@5=0.8 全流程)相关文章:RAG 增强与向量基础篇:继续搭建"模型 + 向量 + 会话 + 工具"协同底座
相关文章:零成本打造本地多引擎大模型与向量服务:Xinference 全栈部署 + 性能调优实战
这篇文章不是"概念科普",而是一套可以直接跑起来的 KAG(Knowledge-Augmented Generation)工程闭环:
- 用大模型从小说文本中抽取 知识图谱 JSON
- 一键导入 Neo4j
- 用评测集做 Recall@5 召回评测(LLM 参与生成 Cypher + 判定命中)
- 最后把同一套链路用于 KAG 图谱问答(LLM 生成 Cypher → 查图 → 再让 LLM 组织答案)
你可以把它当成:做 KAG / GraphRAG / KGQA 的最小可落地 MVP。
1. 为什么要做 KAG?我遇到的痛点
做 RAG 时,我踩过一个典型坑:
- 向量召回对"典故/情节类问题"并不稳定:
- 你搜"温酒斩华雄",但原文可能写成"其酒尚温"、人物可能是"云长/关公",词面变化导致召回波动。
- 如果分块策略偏大(窗口 512/overlap 80),章节内细粒度信息容易被稀释;如果分块过小,语义又不完整。
而知识图谱擅长的恰好是:
- 实体/事件/关系 的结构化表示(谁在什么事件中做了什么)
- "章回定位"类问题可以走更确定的路径:
- 通过
Event/Character -> APPEARS_IN -> Chapter精准落到具体章回
- 通过
所以我最终选择:
- RAG 负责"文本证据"与"长上下文生成"
- KG 负责"结构化召回、强约束定位",二者组合形成 KAG。
2. 本文工程结构:5 个测试类 + 1 个评测集
这套闭环全部以 JUnit 测试类的形式提供,方便你在工程里反复迭代。
2.1 评测集
doc/eval/sanguo-kg-eval.json
数据结构:
query:问题answers[]:标准答案集合chapterTitle:期望命中的章回标题accept[]:可接受关键词(用于判定命中)
2.2 抽取: LlmKgExtractTest
- 输入:
doc/aigc_chunk_store_to_graph.csv - 输出:
doc/kg_extract_result.json
做的事:
- 逐行读取 CSV(每行本质是一段"章回文本")
- 调用 LLM 抽取:
Character/Location/Event/Item- 关系
relations[{type, head, tail}](这里已要求 LLM 输出中文关系短语)
- 附带写入章回元信息:
documentName/chapterTitle/chapterIndex/text
2.3 入库: KgNeo4jImportTest
- 输入:
doc/kg_extract_result.json - 输出:Neo4j 图数据库
核心写入逻辑:
- 创建
(:Chapter {chapterKey})作为"章回锚点" - 创建实体节点:
(:Character|:Event|:Location|:Item {name}) - 把实体与章回相连:
cypher
(n)-[:APPEARS_IN]->(c:Chapter)
APPEARS_IN的含义:实体/事件出现在某章回。这个关系非常关键,它把"结构化实体世界"挂回到"可以回答问题的章回证据"。
2.4 schema 获取: Neo4jSchemaIntrospectTest
LLM 要生成靠谱的 Cypher,必须知道你图谱里:
- 有哪些 label
- 有哪些关系类型
- 每个 label 的关键属性是什么
所以我用 CALL db.labels() / CALL db.relationshipTypes() 做了 schema 探测。
2.5 召回评测: SanguoKgRecallEvalTest
核心:把"问题→图谱查询→命中判定"做成评测流程。
链路:
- 读取评测集
- 探测 Neo4j schema
- 对每个 query:
- LLM 抽取意图/关键词(intent/keywords/constraints)
- LLM 生成 Cypher(返回
{cypher, params}) - 对 Cypher 做 预检 :
EXPLAIN <cypher>- 若失败,把错误信息回灌给 LLM 做"修复",再预检
- 执行查询拿 TopK
- 再让 LLM 判定是否命中标准答案(hit/ reason)
- 汇总 Recall@5
2.6 KAG 问答: KagGraphLLMQATest
这是"评测链路"的应用版:
- 同样先拿 schema
- LLM → Cypher → 查询 → LLM 组织最终答案
这一步的意义:评测不是终点,你最终要的是"线上问答可用"。所以必须把评测链路的关键能力(schema+Cypher生成+预检/修复)迁移到问答链路里。
3. 环境准备(Neo4j + LLM)
3.1 Neo4j
默认连接:
bolt://localhost:7687- 用户名:
neo4j - 密码:测试代码里是
secretgraph(请按你的环境调整)
3.2 LLM(OpenAI 兼容接口)
当前测试类默认使用:
https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions- 模型:
qwen-plus
注意:
- 建议把 Key 放到环境变量里,不要提交到仓库。
4. 一键跑通闭环:推荐执行顺序
按这个顺序跑,最稳:
LlmKgExtractTest:从 CSV 抽取出doc/kg_extract_result.jsonKgNeo4jImportTest:清空 Neo4j → 写入 Chapter/Entity/RelationsNeo4jSchemaIntrospectTest:确认图谱结构是否如预期SanguoKgRecallEvalTest:跑 Recall@5KagGraphLLMQATest:用任意问题做 KAG 问答
5. 两个最关键的工程经验(决定你是不是能跑通)
5.1 让 LLM 生成 Cypher,必须先喂"真实 schema"
很多人 Cypher 生成失败,根本原因是:
- 你让 LLM 写
(:Chunk)/HAS_CHUNK,但你的图谱里可能压根没有 - 或者属性叫
chapterTitle还是title,LLM 猜错就全挂
所以 schema introspection 是必做项。
5.2 LLM 生成的 Cypher 必须预检 + 自动修复
LLM 写 Cypher 很容易出现:
- 聚合/ORDER BY 语法错误
- 用错 APOC
- 参数类型不匹配
解决方法:
- 预检:
EXPLAIN cypher - 若失败:把错误信息 + 原 cypher 回灌给 LLM → 让它修复
- 最多重试 1~2 次
这就是为什么 SanguoKgRecallEvalTest 的链路可复用到 KagGraphLLMQATest。
6. 召回评测怎么看?为什么能指导 KAG?
doc/eval/sanguo-kg-eval.json 的问题基本都是"章回定位"类:
- 桃园结义是哪一回?
- 温酒斩华雄出自哪一回?
- 草船借箭是哪一回?
这种任务对 KAG 很友好:
- 你只要能把问题映射成图谱查询
- 找到对应
Chapter的 title / index / text - LLM 再基于 text 给出最终回答
评测指标:
- Recall@5:标准答案是否出现在 Top5 返回结果里
它能直接反映:
- 你的图谱建模是否有效(有没有正确挂到
Chapter) - 你的 Cypher 生成策略是否靠谱(关键词拆分、AND/OR 降级)
- 你的命中判定是否稳定(accept 关键词、标题模糊匹配)
7. 下一步:从"章回定位"升级到真正 KAG(复杂问题)
本文的闭环是 KAG MVP,但已经为复杂问答铺好路:
- 先做"证据召回"(KG → Chapter/Text)
- 再做"证据生成"(LLM summarization / reasoning)
你后面可以继续扩展:
- 多跳查询:
人物 → 事件 → 地点 → 章回 - 关系约束:如只看
敌对/同盟/父子 - 图谱 + 向量混合检索:KG 决定范围,RAG 提供长证据
8. 常见坑位排雷(我踩过的都写了)
- LLM 响应解析 :一定要从 OpenAI 兼容结构里取
choices[0].message.content,否则你会把 error 当 content 用。 - 关系 type 中文化:如果 relation type 输出英文,Neo4j relationshipTypes 会爆炸增长,后续召回更难。
- Chapter 元数据必须写进 KG JSON:否则你只有实体,没有"章回锚点",无法做章回召回评测。
9. 你可以直接复用的 3 段核心 Prompt(建议收藏)
9.1 抽取 KG(实体+关系)
要求:关系 type 用中文短语;实体尽量原文;输出 JSON。
9.2 生成 Cypher(带 schema)
要求:
- 拆分/扩展关键词
- 避免高频人名作为严格 AND
- 返回 title/idx/doc/text
- LIMIT 5
9.3 命中判定(评测)
输入:query + answers + topK
输出:{hit, reason}
10. 结语:为什么我说这是"最小可落地 KAG"
很多 KAG 文章停留在概念图,但真正工程上,最难的是:
- 图谱 schema 不统一
- 查询不可控
- LLM 生成 Cypher 经常报错
- 没评测就没迭代方向
本文这套 JUnit 流程解决的恰恰是这些"落地问题"。
如果你也在做:
- GraphRAG / KGQA / KAG
- Neo4j + 大模型
- 召回评测体系
这套闭环可以直接作为你的工程起点。
附:本文提到的关键文件
doc/eval/sanguo-kg-eval.jsondoc/kg_extract_result.jsonsrc/test/java/com/soft/nda/segment/LlmKgExtractTest.javasrc/test/java/com/soft/nda/segment/KgNeo4jImportTest.javasrc/test/java/com/soft/nda/segment/Neo4jSchemaIntrospectTest.javasrc/test/java/com/soft/nda/segment/SanguoKgRecallEvalTest.javasrc/test/java/com/soft/nda/segment/KagGraphLLMQATest.java