之前分享了几篇关于GraphRAG的科普与实践文章,收到了不少读者的反馈。不过,最近我发现一个高频问题:很多人在实际操作中发现,GraphRAG在实体与关系抽取上的表现不够理想,这直接影响了问答系统的效果。遇到这种情况,通常我会先问一句:是否尝试过Prompt Tuning(提示调优)?遗憾的是,许多人都没有进行这一步,甚至有人把Prompt Tuning与模型的Finetune(微调)混为一谈。
因此,本文专门为大家讲解GraphRAG的Prompt Tuning,将原理与操作步骤详细阐述,帮助大家用最小的投入显著提升问答效果。真正的目标不仅是学会使用,更是理解其背后的机制——从更高维度审视它,才算真正有所收获。
使用Prompt Tuning
在深入原理之前,我们先来看看具体操作。根据实践经验,进行Prompt Tuning时,所选用的模型必须足够大、性能足够好,否则生成的提示词质量可能会打折扣,甚至出现格式错误。实测下来,gpt-4系列是首选。
GraphRAG自带生成领域定制提示词的能力,专门用于知识图谱的构建。这一步虽然并非必须,但强烈建议执行一遍,索引跑出来的结果会明显更优。
Prompt Tuning的大致流程如下(后续会用源码详细拆解):
- 加载输入数据,将文本切割成一个个文本块。
- 然后进行一系列的LLM调用和模板替换,最终得到定制化的提示词。
先决条件
在开始自动模板生成之前,务必先使用 graphrag.index --init 初始化工作空间,这样才能生成必要的配置文件和默认提示词。
用法
运行主脚本的命令行选项如下:
python -m graphrag.prompt_tune [--config CONFIG] [--root ROOT] [--domain DOMAIN] [--selection-method SELECTION_METHOD] [--n_subset_max N_SUBSET_MAX] [--k K] [--limit LIMIT] [--max-tokens MAX_TOKENS] [--min-examples-required MIN_EXAMPLES_REQUIRED] [--chunk-size CHUNK_SIZE] [--language LANGUAGE] [--no-entity-types] [--output OUTPUT]
--config:用于生成提示词的配置文件(YAML格式),必填。--root(可选):项目根目录,默认为当前目录。--domain(可选):输入数据所属的领域,例如 'space science'、'microbiology'、'environmental news'。若不指定,系统会从输入数据中自动推断。--selection-method(可选):文档选择方法,默认值为random。--n_subset_max(可选):使用自动选择法时嵌入的文本块数量,默认值为300。--k(可选):使用自动选择法时,每个中心点最多选取的文档数量,默认值为15。--limit(可选):使用随机或顶部选择法时加载的文档数量,默认值为15。--max-tokens(可选):生成提示词时使用的最大令牌数,默认值为2000。--min-examples-required(可选):实体抽取提示词中至少需要的示例数量,默认值为2。--chunk-size(可选):生成文本块时使用的令牌数,默认值为200。--language(可选):输入处理的语言。若与输入语言不一致,LLM会进行翻译。默认为空,会自动检测。--no-entity-types(可选):使用未标记的实体抽取生成。当数据涵盖多个主题或高度随机时,推荐使用此选项。--output(可选):保存生成提示词的目录,默认值为 'prompts'。
说明:本文使用的GraphRAG版本为v0.3.0,网上许多关于Prompt Tune的说明基于旧版本,在参数上存在一些差异。
执行Prompt_Tune
这里以《海贼王》的内容为例进行演示,执行命令如下:
python -m graphrag.prompt_tune --root ./ragtest --domain 'Anime and Manga' --language Chinese --limit 2 --chunk-size 500 --config ./ragtest/settings.yaml
输出以下内容表示执行成功:
INFO: Reading settings from ragtest/settings.yaml
Loading Input (text).
INFO: Generating persona...
INFO: Generating community report ranking description...
INFO: Generating entity types...
INFO: Generating entity relationship examples...
INFO: Generating entity extraction prompt...
INFO: Generating entity summarization prompt...
INFO: Generating community reporter role...
INFO: Generating community summarization prompt...
INFO: Writing prompts to prompts
当前prompts目录下生成了三个文件:community_report.txt、entity_extraction.txt和summarize_descriptions.txt。我们先查看entity_extraction.txt,其中一个示例如下:
-Examples-
######################
Example 1:
entity_types: [character, organization, dream, ability, bounty, location]
text:
的能力者。“草帽一伙”第六位加入的成员。梦想“找到空白的100年历史”,以此为目标在大海上航行。
船匠
弗兰奇
“草帽一伙”的船匠,外号“铁人·弗兰奇”。南海出身,悬赏金3亿9400万贝里。使用改造后的身体以及自制兵器进行战斗。“草帽一伙”第七位加入的成员。梦想“乘坐自己制作的梦想之船绕伟大航路一周”,以此为目标在大海上航行。
音乐家
布鲁克
“草帽一伙”的音乐家,外号“鼻歌·布鲁克”、“灵魂之王”。西海出身,悬赏金3亿8300万贝里。食用了黄泉果实的能力者。使用一把西洋剑战斗的剑士,战斗时会使用黄泉果实的能力作为辅助。“草帽一伙”第八位加入的成员。梦想“与拉布汇合,实现与拉布的约定”,以此为目标在大海上航行。
舵手
甚平
“草帽一伙”的舵手,外号“海侠甚平”。龙宫王国出身,悬赏金11亿贝里。鱼人族的鲸鲨鱼人,使用鱼人空手道和鱼人柔道进行战斗。“草帽一伙”第九位加入的成员,原王下七武海之一
------------------------
可以看到,提示词要求抽取的实体类型为character, organization, dream, ability, bounty, location。但连最常见的person都没有涵盖,覆盖面明显不足。
于是我们尝试调整chunk-size,从500提升到2000。这次生成的entity_extraction.txt中实体类型变成了person, organization, location, concept, event, item,覆盖面显著改善。接下来用新生成的提示词重新建立索引:

将索引文件导入neo4j后,我们发现抽取出的实体数量更多,内容也更加丰富:

测试
在进行Prompt Tune之前,如果想查询“悬赏金最高的海贼是谁?”,GraphRAG的回答是“鹰眼”。虽然我也很喜欢这个角色,但文本中悬赏金最高的其实是白胡子。
SUCCESS: Local Search Response: # 赏金最高的海贼
在《海贼王》的世界中,赏金的高低通常反映了一个海贼的威胁程度和实力。根据现有的数据,赏金最高的海贼是乔拉可尔·米霍克,他的悬赏金高达35亿9000万贝里 [Data: Entities (84)]。
## 乔拉可尔·米霍克
乔拉可尔·米霍克是世界最强剑士,曾是王下七武海的一员。在七武海制度被废除后,他的悬赏金被重新评估并大幅提升,达到了35亿9000万贝里 [Data: Sources (4)]。米霍克不仅以其剑术闻名,还与红发香克斯有着深厚的友谊,并且是草帽一伙成员罗罗诺亚·索隆的师傅。
## 其他高赏金海贼
除了米霍克,其他赏金较高的海贼还包括巴基和波雅·汉库克。巴基的悬赏金为31亿8900万贝里,他是巴基海贼团的船长,曾是罗杰海贼团的见习生 [Data: Entities (28); Sources (4)]。波6); Sources (4)]。
## 赏金的意义
在《海贼王》的世界中,悬赏金不仅是对海贼威胁程度的评估,也是世界政府对其抓捕优先级的体现。高额的悬赏金通常意味着该海贼在世界范围内具有极大的影响力和威胁性。
完成Prompt Tune之后,再次执行Local Search,同样询问“悬赏金最高的海贼是谁?”,这次回答就正确了(我提供的文档中不含罗杰):
SUCCESS: Local Search Response: ## 赏金最高的海贼
在《海贼王》的世界中,赏金是衡量海贼威胁程度的重要指标。根据现有数据,赏金最高的海贼是**“白胡子”爱德华·纽盖特**,他的悬赏金高达**50亿4600万贝里**。他是白胡子海贼团的船长,以其强大的实力和影响力闻名,曾被视为世界上最强的海贼之一 [Data: Entities (30); Sources (4)]。
紧随其后的是**“百兽”凯多**,他的悬赏金为**46亿1110万贝里**,同样是四皇之一,掌管着百兽海贼团 [Data: Entities (127); Sources (4)]。此外,**“BIG MOM”夏洛特·玲玲**的悬赏金es (126); Sources (4)]。
最后,**“红发”香克斯**的悬赏金为**40亿4890万贝里**,他是红发海贼团的船长,也是四皇之一 [Data: Entities (30); Sources (4)]。这些海贼不仅力量强大,他们的高额赏金也体现了他们在海贼世界中的地位和影响力。
## 总结
综上所述,当前赏金最高的海贼是爱德华·纽盖特,其次是凯多、夏洛特·玲玲和香克斯。这些海贼的悬赏金不仅代表了他们的实力,也体现了他们在海贼世界中的重要性和威胁程度 [Data: Entities (30)]
查询准确性显著提升。但这已经是极限了吗?当然不是——我们还可以通过手动微调提示词,进一步优化效果。
手动微调提示词
Prompt Tune的局限性
虽然Prompt Tune借助LLM自动微调了提示词来适配输入文件的领域,但我们发现,它给出的实体列表有点像抽卡,每次结果都不太一样。
这些实体类型是否真正符合需求?能否更贴近特定领域的实际要求?如果给它更明确的指引,或者使用更强的模型来划定实体范围,结果会不会更好?答案是肯定的。接下来,我就讲讲如何手动调整提示词,让它更好地贴合你的文档。
需要修改什么
Prompt Tune只生成三个文件:community_report.txt、entity_extraction.txt和summarize_descriptions.txt。后两个文件主要将角色设定为领域专家,与实体抽取关系不大,一般无需调整。真正需要动手修改的是与实体抽取相关的entity_extraction.txt。
借助GPT-4辅助优化
要确定一篇文档应该包含哪些实体类型,除了咨询领域专家,也可以借助GPT-4进行模拟分析。在日常工作中,我经常使用GPT-4,它的输出质量相当高,足以作为参考标准。
具体操作方法是:从文档中选取几段内容丰富的段落,让GPT-4抽取对应的实体类型。然后,根据GPT-4给出的类型,修改entity_extraction.txt中的任务说明、示例中的entity_types以及Real Data部分的entity_types。
实体类别更新后,还需要同步更新few-shot示例的输出。同样,让GPT-4生成新的示例输出,并复制到entity_extraction.txt的对应位置。这样,一个手动微调版的entity_extraction.txt就完成了。
