面向客户与零售分析的GraphRAG代理
这是一个端到端的工作示例,用于构建GraphRAG代理以加速客户和零售分析。它涵盖了整个过程,从:
-
快速从混合的非结构化和结构化数据源构建图谱
-
在此过程中解析和链接图谱中的实体
-
创建多样化的图谱检索工具,包括查询模板、向量搜索、动态text2Cypher和图谱社区检测,以回答更广泛的问题
-
使用Semantic Kernel构建代理,用于执行分析和响应复杂的用户问题
所有这些都使用一个中心的事实来源图谱Schema来管理流程和AI交互,确保更高的数据和检索质量。
此工作流程可适用于各种其他业务领域的分析、报告和问答——特别是当:
-
数据源包含结构化和非结构化数据的混合。
-
AI需要导航一个非简单的业务领域模型以获得准确的响应。
-
用例需要灵活性和扩展到复杂、不断演进的AI驱动任务的能力。
请按照以下说明自行尝试!🚀

设置
克隆 GitHub 仓库。
git clone https://github.com/neo4j-product-examples/graphrag-examples.git
创建并激活一个新的Python虚拟环境。
python -m venv graphrag_venv
source graphrag_venv/bin/activate
切换到项目目录并安装依赖项。
cd graphrag-examples
pip install -r requirements.txt
根据此处的指示创建一个 Neo4j DB 实例。
切换到 `customer-graph` 目录并通过复制 `.env.template` 创建 `.env` 文件
cd customer-graph
cp .env.template .env
将 Neo4j 凭据和 OpenAI 密钥替换为您自己的。
从源数据创建图谱
创建图谱需要摄入非结构化和结构化数据。您将使用 `ontos` 文件夹中的Schema来驱动它们。有关这些Schema如何从中心源生成的更多信息,请参阅Schema生成部分。
源数据是H&M个性化时尚推荐数据集的样本,它包含真实客户的购买数据,其中包含丰富的关于产品的信息,包括名称、类型、描述。我们使用ChatGPT进一步增强了这些数据——模拟了不同商品的供应商和退货/退款的贷记单。 `data` 文件夹包含结果的结构化数据(CSV格式)和非结构化数据,形式为 `credit-notes.pdf`,其中包含退货/退款数据。
注意:请按以下顺序执行步骤,顺序颠倒可能会导致一些重复数据删除和索引问题。
1) 加载非结构化数据
运行非结构化数据摄入。这将需要几分钟。
python unstuctured_ingest.py
此脚本对 `credit-notes.pdf` 文件执行实体提取,并根据客户Schema将实体和关系写入图谱。
完成后,您可以检查数据库以查看生成的图谱。转到Aura控制台并导航到“查询”选项卡。

选择“连接实例”按钮

系统将提示您选择您的Aura实例。选择您为此项目创建的实例并输入您的凭据

进入查询选项卡后,您应该在侧边栏中看到包含CreditNode、Order、Article、Document和Chunk的节点和关系。

运行以下简单的Cypher查询以查看数据样本并进行探索。
MATCH p=()--() RETURN p LIMIT 1000
您应该看到订单、贷记单和商品之间清晰的关系,以及它们与源块(即文档文本块)以及包含元数据的单个文档节点的连接。

2) 合并结构化数据
我们将使用 Aura Importer,它允许您将CSV或其他关系数据库中的结构化数据映射到图谱。
前往Aura控制台,导航到“导入”选项卡

选择左上角的省略号,然后从下拉菜单中选择“打开模型”

选择 `ontos` 文件夹中的 `customer-struct-import.json`。生成的数据模型应如下所示

现在您需要选择数据源。Aura Import 允许您从多种类型的数据库导入数据,但今天我们将使用本地 CSV 文件。在“数据源”面板顶部选择“浏览”。

选择 `data` 目录中的所有 CSV 文件。完成后,您应该在每个节点和关系上看到绿色的勾号。选择一个节点时,您还应该看到节点属性和 CSV 文件中列之间的映射。

我们现在准备运行导入。选择屏幕左上角的蓝色“运行导入”按钮。系统将提示您选择您的Aura实例——选择您为此项目创建的实例并输入您的凭据

导入只需几秒钟。完成后,您应该会看到一个“导入结果”弹出窗口,其中包含“成功完成”消息和一些统计信息。

运行代理
目前,运行代理的最佳方式是通过命令行工具 `cli_agent.py`。streamlit 应用程序 `app.py` 仍在开发中,并且在多轮问答对话中仍存在挂起问题。
要运行,请导航到 `graphrag` 文件夹并运行文件
cd graphrag
python cli_agent.py
一些可以尝试的示例问题:
-
春天有什么好的毛衣吗?不要太保暖的!
-
哪些供应商的退货(即贷记单)数量最多?
-
供应商1616退货最多的3种产品是什么?获取这些产品代码,并找到其他退货较少的供应商,我可以用他们来替代。
-
您能进行客户细分分析吗?
-
每个细分市场最常见的购买产品类型是什么?
-
您能进行客户细分分析吗?对于最大的群体,为他们制定一个富有创意的春季促销活动,突出推荐产品。以电子邮件形式起草。
⚠️ 注意:代理AI仍是一项不断发展的技术,可能并非总是按预期开箱即用。例如,代理可能会选择与预期不同的工具,导致错误或不良响应。本项目提供了一个最小的代理示例,重点关注GraphRAG的增强和集成,而不是构建一个完全健壮的代理系统。要使用Semantic Kernel为代理行为增加更多稳定性和规范化,请参阅其文档。对于在类似数据集上使用确定性工具和检索查询(而非代理)的GraphRAG示例,请参阅面向客户体验的GraphRAG^。
Schema生成
单源图谱Schema是 `ontos` 目录中的 `customer.ttl`。它是在webprotege中构建并以turtle (ttl) 格式导出的。 `ontos` 目录中的其他Schema只是它的派生,并将在下面更详细地描述。
根据 GoingMeta 系列S2 第5集中描述的过程,此Schema被转换为JSON格式以上传到 Aura Import。其源代码位于此处。该Schema在 Aura Import 中进行了调整,以生成用于结构化数据摄入的 `customer-struct-import.json`。这些调整包括添加CSV属性映射和排除结构化数据摄入中不需要的一些节点。
非结构化数据摄入(`unstructured_ingest.py`)直接使用源 TTL Schema 来指导实体提取和图写入过程。如果您查看 `customer.ttl` 文件,您会看到一些类和属性的“注释”注解。这些注解被传递给 LLM,以更好地描述数据 Schema 并提高实体提取的数据质量。
`ontos` 目录中的最终Schema是 `text-to-cypher.json`,它被 graphrag 应用程序用于 text2Cypher 查询生成——特别是在 `graphrag/retail_service.py` 中。它是通过对数据库运行以下查询生成的
CALL apoc.meta.stats() YIELD relTypes
WITH KEYS(relTypes) as relTypes
UNWIND relTypes as rel
WITH rel, split(split(rel, '[:')[1],']') as relationship
WITH rel, relationship[0] as relationship
CALL apoc.cypher.run("MATCH p = " + rel + " RETURN p LIMIT 10", {})
YIELD value
WITH relationship as relationshipType, nodes(value.p) as nodes, apoc.any.properties(nodes(value.p)[0]) as startNodeProps, apoc.any.properties(nodes(value.p)[-1]) as endNodeProps
WITH DISTINCT labels(nodes[0]) as startNodeLabels, relationshipType, labels(nodes[-1]) as endNodeLabels, KEYS(startNodeProps) as startNodeProps, KEYS(endNodeProps) as endNodeProps
WITH startNodeLabels, relationshipType, endNodeLabels, COLLECT(endNodeProps) as endNodeProps, COLLECT(startNodeProps) as startNodeProps
WITH startNodeLabels, relationshipType, endNodeLabels, apoc.coll.toSet(apoc.coll.flatten(endNodeProps)) as endNodeProps, apoc.coll.toSet(apoc.coll.flatten(startNodeProps)) as startNodeProps
RETURN COLLECT({source:{label:startNodeLabels , properties:startNodeProps}, relationship:relationshipType, target:{label:endNodeLabels , properties:endNodeProps}}) as schema