背景
过程
1. 安装 graphrag
创建虚拟环境,以免pip安装的软件和系统冲突了
python3 -m venv myenv
# 在 Linux 或 macOS 上
source myenv/bin/activate
然后在虚拟环境里面执行:
pip install graphrag==1.1.0
我的python3 版本我3.10.16,pip 版本为 25.0.1。 如果不能下载,注意可以切换一个pip软件安装的镜像源
(myenv) root@ubuntu:/graphrag# pip --version
pip 25.0.1 from /graphrag/myenv/lib/python3.10/site-packages/pip (python 3.10)
2. 检查graphrag的版本
(myenv) root@ubuntu:/graphrag# pip show graphrag
Name: graphrag
Version: 1.1.0
Summary: GraphRAG: A graph-based retrieval-augmented generation (RAG) system.
Home-page:
Author: Alonso Guevara Fernández
Author-email: alonsog@microsoft.com
License: MIT
Location: /graphrag/myenv/lib/python3.10/site-packages
Requires: aiofiles, azure-cosmos, azure-identity, azure-search-documents, azure-storage-blob, devtools, environs, fnllm, future, graspologic, httpx, json-repair, lancedb, matplotlib, networkx, nltk, numpy, openai, pandas, pyaml-env, pyarrow, pydantic, python-dotenv, pyyaml, rich, tenacity, tiktoken, tqdm, typer, typing-extensions, umap-learn
Required-by:
3. 创建检索项目文件夹
mkdir -p ./openl/input
然后上传一个数据集 ID3、C4.5决策树的建模流程.txt
文件
目录结构如下:
(myenv) root@ubuntu:/graphrag# ll ./openl/input/
total 20
drwxr-xr-x 2 root root 4096 Mar 4 22:32 ./
drwxr-xr-x 3 root root 4096 Mar 4 22:32 ../
-rw-r--r-- 1 root root 10065 Mar 3 17:21 ID3、C4.5决策树的建模流程.txt
(myenv) root@ubuntu:/graphrag# pwd
/graphrag
4. 初始化项目
(myenv) root@ubuntu:/graphrag# graphrag init --root ./openl
Initializing project at /graphrag/openl
5. 填写DeepSeek 配置 参数
打开 .env 文件,填写DeepSeek API-KEY
打开 setting.yaml 文件,填写模型名称和反向代理地址:
embeddings 模型可以选择其他的模型,有一些免费的,我用的智普AI。
我的配置是这样的。
6. GraphRAG 索引Indexing过程执行
使用GraphRAG 脚本自动执行indexing
graphrag index --root ./openl
运行成功后:
运行结束后,各知识图谱相关书籍都保存在output文件夹中:
索引阶段的主要输出内容如下:
-
实体表(Nodes Table)
- 文件名:
create_final_nodes.parquet
- 内容:知识图谱中的实体节点(例如:人、地点、组织)。
- 包含信息:
- 实体的名称(如 "John Doe")。
- 实体的类别(如 "PERSON", "ORGANIZATION", "LOCATION")。
- 与社区相关的信息(如实体所属的社区)。
- 实体的度数(degree),表示该实体在图谱中的连接数。
- 文件名:
-
关系表(Relationships Table)
- 文件名:
create_final_relationships.parquet
- 内容:知识图谱中实体之间的关系(即图谱的边)。
- 包含信息:
- 两个实体之间的关系描述(例如 "works for", "lives in")。
- 关系的强度(数值化,用于衡量关系的显著性或重要性)。
- 文件名:
-
嵌入向量表(Entity Embedding Table)
- 文件名:
create_final_entities.parquet
- 内容:实体的语义嵌入,用于表示实体的语义信息。
- 用途:支持语义搜索(通过嵌入计算实体之间的相似性)。
- 文件名:
-
社区报告表(Community Reports Table)
- 文件名:
create_final_community_reports.parquet
- 内容:社区的摘要信息。
- 用途:支持全局搜索(通过社区信息回答关于数据集整体的问题)。
- 文件名:
-
文本单元表(Text Units Table)
- 文件名:
create_final_text_units.parquet
- 内容:被切分的原始文本单元(TextUnits)。
- 用途:将知识图谱和原始文本结合,为 LLM 提供上下文支持。
- 文件名:
-
社区表(Community Table)
- 文件名:
create_final_Communities.parquet
- 内容:每个社区基本情况。
- 文件名:
-
文件表(Documents Table)
- 文件名:
create_final_documents.parquet
- 内容:用于记录所有参与知识图谱构建的文件情况。
- 文件名:
为什么用 Parquet 格式保存知识图谱?
高效存储:
知识图谱中的数据通常是结构化的,包含大量的实体、关系、嵌入等。
Parquet 的列式存储能够显著减少磁盘占用,同时提高读取效率。
快速读取:
查询阶段需要快速加载实体、关系、嵌入等数据到内存中。
Parquet 支持按需加载所需的列,避免了不必要的数据读取。
兼容性好:
- Parquet 是一个开放的标准,广泛支持各种数据处理工具(如 Pandas、Spark、Hadoop)。
- GraphRAG 可以在 Python 中使用 Pandas 或其他工具轻松读取这些文件。
7. GraphRAG问答流程
直接使用graphrag 命令方式查询
除了使用Python代码环境进行问答外,若希望快速测试问答性能,也可以直接在命令行中,借助graphrag提供的脚本命令进行快速问答,例如:
graphrag query --root ./openl --method local --query "请帮我介绍下ID3算法"
即可完成问答。
构建LocalSearch(本地搜索) 搜索引擎进行回答
首先执行代码需要安装以下依赖:
# 基础数据处理
pip install pandas pyarrow # 读取 Parquet 文件需要 pyarrow/fastparquet
# 向量数据库
pip install lancedb # LanceDB 向量存储
# OpenAI 相关
pip install openai tiktoken # OpenAI API 和分词工具
# 异步支持 (代码中有 await 调用)
pip install aiohttp nest_asyncio
# 其他工具
pip install ipython # 用于 display(Markdown) 的交互式输出
然后创建python代码如下:
import os
import asyncio
import pandas as pd
import tiktoken
from graphrag.query.context_builder.entity_extraction import EntityVectorStoreKey
from graphrag.query.indexer_adapters import (
read_indexer_covariates,
read_indexer_entities,
read_indexer_relationships,
read_indexer_reports,
read_indexer_text_units,
)
from graphrag.query.llm.oai.chat_openai import ChatOpenAI
from graphrag.query.llm.oai.embedding import OpenAIEmbedding
from graphrag.query.llm.oai.typing import OpenaiApiType
from graphrag.query.question_gen.local_gen import LocalQuestionGen
from graphrag.query.structured_search.local_search.mixed_context import (
LocalSearchMixedContext,
)
from graphrag.query.structured_search.local_search.search import LocalSearch
from graphrag.vector_stores.lancedb import LanceDBVectorStore
INPUT_DIR = "./openl/output"
LANCEDB_URI = f"{INPUT_DIR}/lancedb"
COMMUNITY_REPORT_TABLE = "create_final_community_reports"
ENTITY_TABLE = "create_final_nodes"
ENTITY_EMBEDDING_TABLE = "create_final_entities"
RELATIONSHIP_TABLE = "create_final_relationships"
TEXT_UNIT_TABLE = "create_final_text_units"
COMMUNITY_LEVEL = 2
# read nodes table to get community and degree data
entity_df = pd.read_parquet(f"{INPUT_DIR}/{ENTITY_TABLE}.parquet")
entity_embedding_df = pd.read_parquet(f"{INPUT_DIR}/{ENTITY_EMBEDDING_TABLE}.parquet")
entities = read_indexer_entities(entity_df, entity_embedding_df, COMMUNITY_LEVEL)
# load description embeddings to an in-memory lancedb vectorstore
# to connect to a remote db, specify url and port values.
description_embedding_store = LanceDBVectorStore(
collection_name="default-entity-description",
)
description_embedding_store.connect(db_uri=LANCEDB_URI)
print(f"Entity count: {len(entity_df)}")
entity_df.head()
relationship_df = pd.read_parquet(f"{INPUT_DIR}/{RELATIONSHIP_TABLE}.parquet")
relationships = read_indexer_relationships(relationship_df)
print(f"Relationship count: {len(relationship_df)}")
relationship_df.head()
report_df = pd.read_parquet(f"{INPUT_DIR}/{COMMUNITY_REPORT_TABLE}.parquet")
reports = read_indexer_reports(report_df, entity_df, COMMUNITY_LEVEL)
print(f"Report records: {len(report_df)}")
report_df.head()
text_unit_df = pd.read_parquet(f"{INPUT_DIR}/{TEXT_UNIT_TABLE}.parquet")
text_units = read_indexer_text_units(text_unit_df)
print(f"Text unit records: {len(text_unit_df)}")
text_unit_df.head()
sd_api_key = "你的chat模型APIKEY"
openai_api_key = "你的Embending 模型KEY"
llm_model = "deepseek-chat"
embedding_model = "embedding-2"
llm_api_base = "https://api.deepseek.com"
embedding_model_api_base = "https://open.bigmodel.cn/api/paas/v4"
llm = ChatOpenAI(
api_key=sd_api_key,
model=llm_model,
api_base=llm_api_base,
api_type=OpenaiApiType.OpenAI,
max_retries=20,
)
token_encoder = tiktoken.get_encoding("cl100k_base")
text_embedder = OpenAIEmbedding(
api_key=openai_api_key,
api_base=embedding_model_api_base,
api_type=OpenaiApiType.OpenAI,
model=embedding_model,
deployment_name=embedding_model,
max_retries=20,
)
context_builder = LocalSearchMixedContext(
community_reports=reports,
text_units=text_units,
entities=entities,
relationships=relationships,
covariates=None,
entity_text_embeddings=description_embedding_store,
embedding_vectorstore_key=EntityVectorStoreKey.ID,
text_embedder=text_embedder,
token_encoder=token_encoder,
)
local_context_params = {
"text_unit_prop": 0.5,
"community_prop": 0.1,
"conversation_history_max_turns": 5,
"conversation_history_user_turns_only": True,
"top_k_mapped_entities": 10,
"top_k_relationships": 10,
"include_entity_rank": True,
"include_relationship_weight": True,
"include_community_rank": True,
"return_candidate_context": True,
"embedding_vectorstore_key": EntityVectorStoreKey.ID,
"max_tokens": 12_000,
}
llm_params = {
"max_tokens": 2_000,
"temperature": 0.0,
}
search_engine = LocalSearch(
llm=llm,
context_builder=context_builder,
token_encoder=token_encoder,
llm_params=llm_params,
context_builder_params=local_context_params,
response_type="multiple paragraphs",
)
async def main():
# 原代码中的异步调用部分
result = await search_engine.asearch("请帮我介绍下ID3决策树算法")
print(result.response)
if __name__ == "__main__":
asyncio.run(main()) # 启动异步事件循环
sd_api_key = "你的chat模型APIKEY" openai_api_key = "你的Embending 模型KEY" 这两个需要使用你自己申请的AIPkey
文件命名为 graphrag_local_search.py
然后执行
python3 graphrag_local_search.py
效果如下:
构建GlobalSearch(全局搜索) 搜索引擎进行回答
python代码如下:
import asyncio
import pandas as pd
import tiktoken
from graphrag.query.indexer_adapters import (
read_indexer_communities,
read_indexer_entities,
read_indexer_reports,
)
from graphrag.query.llm.oai.chat_openai import ChatOpenAI
from graphrag.query.llm.oai.typing import OpenaiApiType
from graphrag.query.structured_search.global_search.community_context import (
GlobalCommunityContext,
)
from graphrag.query.structured_search.global_search.search import GlobalSearch
INPUT_DIR = "./openl/output"
LANCEDB_URI = f"{INPUT_DIR}/lancedb"
COMMUNITY_TABLE = "create_final_communities"
COMMUNITY_REPORT_TABLE = "create_final_community_reports"
ENTITY_TABLE = "create_final_nodes"
ENTITY_EMBEDDING_TABLE = "create_final_entities"
COMMUNITY_LEVEL = 2
community_df = pd.read_parquet(f"{INPUT_DIR}/{COMMUNITY_TABLE}.parquet")
entity_df = pd.read_parquet(f"{INPUT_DIR}/{ENTITY_TABLE}.parquet")
report_df = pd.read_parquet(f"{INPUT_DIR}/{COMMUNITY_REPORT_TABLE}.parquet")
entity_embedding_df = pd.read_parquet(f"{INPUT_DIR}/{ENTITY_EMBEDDING_TABLE}.parquet")
communities = read_indexer_communities(community_df, entity_df, report_df)
reports = read_indexer_reports(report_df, entity_df, COMMUNITY_LEVEL)
entities = read_indexer_entities(entity_df, entity_embedding_df, COMMUNITY_LEVEL)
sd_api_key = "你的chat模型APIKEY"
openai_api_key = "你的Embending 模型KEY"
llm_model = "deepseek-chat"
embedding_model = "embedding-2"
llm_api_base = "https://api.deepseek.com"
embedding_model_api_base = "https://open.bigmodel.cn/api/paas/v4"
llm = ChatOpenAI(
api_key=sd_api_key,
model=llm_model,
api_base=llm_api_base,
api_type=OpenaiApiType.OpenAI,
max_retries=20,
)
token_encoder = tiktoken.get_encoding("cl100k_base")
context_builder = GlobalCommunityContext(
community_reports=reports,
communities=communities,
entities=entities,
token_encoder=token_encoder,
)
context_builder_params = {
"use_community_summary": False,
"shuffle_data": True,
"include_community_rank": True,
"min_community_rank": 0,
"community_rank_name": "rank",
"include_community_weight": True,
"community_weight_name": "occurrence weight",
"normalize_community_weight": True,
"max_tokens": 12_000,
"context_name": "Reports",
}
map_llm_params = {
"max_tokens": 1000,
"temperature": 0.0,
"response_format": {"type": "json_object"},
}
reduce_llm_params = {
"max_tokens": 2000,
"temperature": 0.0,
}
search_engine = GlobalSearch(
llm=llm,
context_builder=context_builder,
token_encoder=token_encoder,
max_data_tokens=12_000,
map_llm_params=map_llm_params,
reduce_llm_params=reduce_llm_params,
allow_general_knowledge=False,
json_mode=True,
context_builder_params=context_builder_params,
concurrent_coroutines=32,
response_type="multiple paragraphs",
)
async def main():
# 原代码中的异步调用部分
result = await search_engine.asearch("请帮我介绍下ID3决策树算法")
print(result.response)
if __name__ == "__main__":
asyncio.run(main()) # 启动异步事件循环
sd_api_key = "你的chat模型APIKEY" openai_api_key = "你的Embending 模型KEY" 这两个需要使用你自己申请的AIPkey
文件命名为 graphrag_global_search.py
然后执行
python3 graphrag_global_search.py
效果如下:
这个两个检索技术的区别,主要是广度和深度上的区别