Neo4j 数据库的隐藏技能:如何用 LlamaIndex 实现智能化查询?

检索增强生成(Retrieval-augmented generation,RAG)已经成为主流技术,并且有充分的理由支持其广泛应用。它是一种强大的框架,将先进的大语言模型与目标信息检索技术相结合,从而实现更快速的相关数据访问,并生成更准确、上下文感知的响应。尽管 RAG 应用通常集中于非结构化数据,我个人非常推崇将结构化数据整合进来——这是一种重要但经常被忽视的策略。其中,我最喜欢的方式之一是利用图数据库,例如 Neo4j。

通常,从图数据库中检索数据的首选方法是 Text2Cypher,即通过自然语言查询自动转换为 Cypher 语句,以查询图数据库。这种技术依赖于语言模型(或基于规则的系统)来解释用户查询,推断其潜在意图,并将其翻译为有效的 Cypher 查询,使 RAG 应用能够从知识图谱中检索相关信息并生成准确的答案。


【使用大语言模型生成 Cypher 查询 —— 图片来源:https://neo4j.com/developer-blog/fine-tuned-text2cypher-2024-model/】

Text2Cypher 提供了显著的灵活性,因为它允许用户以自然语言提出问题,而无需了解底层图数据库的模式或 Cypher 语法。然而,由于语言解释的细微差别以及对精确模式特定细节的需求,其准确性仍可能存在不足,如以下 Text2Cypher 文章所示。

以下可视化展示了基准测试的最重要结果:


【Text2Cypher 基准测试结果 —— 图片来源:https://medium.com/neo4j/benchmarking-using-the-neo4j-text2cypher-2024-dataset-d77be96ab65a】

从高层次来看,该基准测试比较了三组模型:

  • 为 Text2Cypher 任务微调的模型
  • 开放的基础模型
  • 封闭的基础模型

基准测试使用两种指标评估这些模型在生成正确 Cypher 查询方面的表现:Google BLEU(上图)和 ExactMatch(下图)。

  • Google BLEU 指标衡量生成的查询与参考查询之间的重叠程度(以 n-grams 为单位)。较高的分数通常表示与参考查询更接近,但这并不一定保证查询在数据库上下文中可以正确运行。

  • ExactMatch 是一种基于执行的指标。它表示生成的查询与正确查询文本完全匹配的百分比,这意味着它们在执行时会产生相同的结果。ExactMatch 是一种更严格的正确性衡量标准,与查询在真实场景中的实际效用直接相关。

尽管微调模型取得了一些令人鼓舞的结果,但整体准确率表明 Text2Cypher 仍是一项不断发展的技术。一些模型在每种情况下生成完全正确查询方面仍有困难,这凸显了进一步改进的必要性。

在本文中,我们将尝试使用 LlamaIndex 工作流来实现更具智能性的 Text2Cypher 策略。与通常的单次查询生成(大多数基准测试的运行方式)不同,我们将尝试一种多步骤方法,允许重试或替代查询形式。通过引入这些额外步骤和回退选项,我们旨在提高整体准确性并减少错误 Cypher 生成的情况。

代码已在 GitHub 上提供(https://github.com/tomasonjo-labs/text2cypher_llama_agent)。我们还提供了应用的托管版本。感谢 Anej Gorkic 对应用的贡献以及调试的帮助。

托管的 Web 应用程序,包含所有智能体,可访问:https://text2cypher-llama-agent.up.railway.app/

一、LlamaIndex 工作流

LlamaIndex 工作流是一种实用的方法,通过事件驱动系统将不同的操作连接起来,从而组织多步骤的 AI 处理过程。它有助于将复杂任务分解为更小、更易管理的部分,这些部分可以以结构化的方式相互通信。工作流中的每一步处理特定事件并生成新事件,从而创建一系列操作链,完成诸如文档处理、问答或内容生成等任务。系统会自动处理步骤之间的协调,使构建和维护复杂的 AI 应用程序变得更加容易。

二、简单的 Text2Cypher 流程

简单的 Text2Cypher 架构是一种将自然语言问题转换为 Neo4j 图数据库 Cypher 查询的精简方法。它通过以下三阶段工作流运行:

  1. 使用存储在向量数据库中的类似示例,通过少样本学习生成输入问题的 Cypher 查询。
  2. 系统针对图数据库执行生成的 Cypher 查询。
  3. 通过语言模型处理数据库结果,生成直接回答原始问题的自然语言响应。

这种架构保持了简单但高效的管道,利用向量相似性搜索(例如少样本检索)和大语言模型进行 Cypher 查询生成和响应格式化。

以下是简单 Text2Cypher 工作流的可视化:


【简单的 Text2Cypher 流程】

值得注意的是,大多数 Neo4j 模式生成方法在处理多标签节点时表现不佳。这不仅是由于复杂性增加,还因为标签的组合爆炸可能会使提示词超载。为缓解这一问题,我们在模式生成过程中排除了 ActorDirector 标签:

@step
async def generate_cypher(self, ctx: Context, ev: StartEvent) -> ExecuteCypherEvent:
    question = ev.input
    # Cypher query generation using an LLM
    cypher_query = await generate_cypher_step(
        self.llm, question, self.few_shot_retriever
    )
    # Streaming event information to the web UI.
    ctx.write_event_to_stream(
        SseEvent(
            label="Cypher generation",
            message=f"Generated Cypher: {cypher_query}",
        )
    )

    # Return for the next step
    return ExecuteCypherEvent(question=question, cypher=cypher_query)

管道从 generate_cypher 步骤开始:

@step
async def execute_query(
    self, ctx: Context, ev: ExecuteCypherEvent
) -> SummarizeEvent | CorrectCypherEvent:
    # Get global var
    retries = await ctx.get("retries")
    try:
        database_output = str(graph_store.structured_query(ev.cypher))
    except Exception as e:
        database_output = str(e)
        # Retry
        if retries < self.max_retries:
            await ctx.set("retries", retries + 1)
            return CorrectCypherEvent(
                question=ev.question, cypher=ev.cypher, error=database_output
            )

    return SummarizeEvent(
        question=ev.question, cypher=ev.cypher, context=database_output
    )

generate_cypher 步骤通过使用语言模型和从向量存储中检索类似示例,将自然语言问题转换为 Cypher 查询。该步骤还会实时将生成的 Cypher 查询流式传输回用户界面,提供查询生成过程的即时反馈。您可以查看完整代码和提示词。

三、带重试机制的简单 Text2Cypher 流程

这种增强版的 Text2Cypher 流程在原始架构的基础上增加了自我修正机制。当生成的 Cypher 查询执行失败时,系统不会直接报错,而是通过 CorrectCypherEvent 步骤将错误信息反馈回语言模型以修正查询。这使得系统更具弹性,能够处理初始错误,类似于人类在收到错误反馈后调整方法的方式。

以下是带重试机制的简单 Text2Cypher 工作流的可视化:


【带重试机制的简单 Text2Cypher 流程】

以下是 ExecuteCypherEvent 的示例:

@step
async def evaluate_context(
    self, ctx: Context, ev: EvaluateEvent
) -> SummarizeEvent | CorrectCypherEvent:
    # Get global var
    retries = await ctx.get("retries")
    evaluation = await evaluate_database_output_step(
        self.llm, ev.question, ev.cypher, ev.context
    )
    if retries < self.max_retries and not evaluation == "Ok":
        await ctx.set("retries", retries + 1)
        return CorrectCypherEvent(
            question=ev.question, cypher=ev.cypher, error=evaluation
        )
    return SummarizeEvent(
        question=ev.question, cypher=ev.cypher, context=ev.context
    )

execute 函数首先尝试运行查询,如果成功,则将结果传递给后续的总结步骤。然而,如果出现问题,它不会立即放弃,而是检查是否还有剩余的重试次数。如果有,它会将查询连同错误信息一起发送回修正步骤。这种机制创建了一个更容错的系统,能够从错误中学习,就像我们在收到反馈后调整方法一样。您可以查看完整代码和提示词(https://github.com/tomasonjo-labs/text2cypher_llama_agent/blob/main/app/workflows/naive_text2cypher_retry.py)。

四、带重试和评估机制的简单 Text2Cypher 流程

在带重试机制的简单 Text2Cypher 流程基础上,这种增强版增加了一个评估阶段,用于检查查询结果是否足以回答用户的问题。如果结果被认为不足,系统会将查询返回修正步骤,并附上改进建议。如果结果令人满意,流程则继续进入最终总结步骤。这一额外的验证层进一步增强了管道的弹性,确保用户最终获得最准确和完整的答案。

以下是带重试和评估机制的简单 Text2Cypher 工作流的可视化:


【带重试和评估机制的简单 Text2Cypher 流程】

附加的评估步骤实现如下:

@step
async def evaluate_context(
    self, ctx: Context, ev: EvaluateEvent
) -> SummarizeEvent | CorrectCypherEvent:
    # Get global var
    retries = await ctx.get("retries")
    evaluation = await evaluate_database_output_step(
        self.llm, ev.question, ev.cypher, ev.context
    )
    if retries < self.max_retries and not evaluation == "Ok":
        await ctx.set("retries", retries + 1)
        return CorrectCypherEvent(
            question=ev.question, cypher=ev.cypher, error=evaluation
        )
    return SummarizeEvent(
        question=ev.question, cypher=ev.cypher, context=ev.context
    )

evaluate_check 函数是一个简单的检查,用于确定查询结果是否充分回答了用户的问题。如果评估表明结果不足且还有剩余的重试次数,它会返回 CorrectCypherEvent,以便进一步改进查询。否则,它会继续执行 SummarizeEvent,表明结果适合进行最终总结。

后来我意识到,捕捉成功自我修正无效 Cypher 语句的实例是一个绝佳主意。这些实例可以作为动态少样本提示词,用于未来的 Cypher 生成。这种方法不仅使智能体能够自我修复,还能随着时间的推移不断自我学习和改进。

@step
async def summarize_answer(self, ctx: Context, ev: SummarizeEvent) -> StopEvent:
    retries = await ctx.get("retries")
    # If retry was successful:
    if retries > 0 and check_ok(ev.evaluation):
        # print(f"Learned new example: {ev.question}, {ev.cypher}")
        # Store success retries to be used as fewshots!
        store_fewshot_example(ev.question, ev.cypher, self.llm.model)

五、迭代规划流程

最后的流程是最复杂的,巧合的是,这是我最初雄心勃勃设计的流程。我保留了代码,以便您可以从我的探索中学习。

迭代规划流程通过引入迭代规划系统实现了更复杂的方法。它并不是直接生成 Cypher 查询,而是首先创建一个子查询计划,在执行前验证每个子查询 Cypher 语句,并包含一个信息检查机制。如果初始结果不足,它可以修改计划。系统最多进行三次信息收集迭代,每次根据先前结果优化方法。这种方式创建了一个更全面的问题回答系统,可以通过分解复杂查询为可管理的步骤并在每个阶段验证信息来处理复杂查询。

以下是迭代规划工作流的可视化:


【迭代规划流程】

让我们来看看查询规划提示词。我在一开始时非常有雄心壮志,期望语言模型生成如下响应:

class SubqueriesOutput(BaseModel):
    """Defines the output format for transforming a question into parallel-optimized retrieval steps."""

    plan: List[List[str]] = Field(
        description=(
            """A list of query groups where:
        - Each group (inner list) contains queries that can be executed in parallel
        - Groups are ordered by dependency (earlier groups must be executed before later ones)
        - Each query must be a specific information retrieval request
        - Split into multiple steps only if intermediate results return ≤25 values
        - No reasoning or comparison tasks, only data fetching queries"""
        )
    )

输出代表了一个将复杂问题转化为顺序和并行查询步骤的结构化计划。每一步包括一组可以并行执行的查询,后续步骤依赖于前面的结果。查询严格用于信息检索,避免推理任务,并在需要时拆分为更小的步骤以管理结果大小。例如,以下计划首先并行列出两位演员的电影,然后在第二步中从第一步的结果中找出票房最高的电影。

plan = [
# 2 steps in parallel
    [
        "List all movies made by Tom Hanks in the 2000s.",
        "List all movies made by Tom Cruise in the 2000s.",
    ],
# Second step
    ["Find the highest profiting movie among winner of step 1"],
]

这一想法无疑很酷。它是一种聪明的方法,可以将复杂问题分解为更小的、可操作的步骤,甚至使用并行化来优化检索。这听起来像是能够真正加速流程的策略。但在实践中,期望语言模型可靠地执行这一策略有些过于雄心勃勃。并行化虽然在理论上高效,但引入了很多复杂性。步骤间的依赖关系、中间结果以及保持并行步骤之间的逻辑一致性可能会让即使是高级模型也容易出错。顺序执行虽然不那么炫酷,但目前更可靠,并显著减少了模型的认知负担。

此外,语言模型在处理诸如列表嵌套等结构化工具输出时往往表现不佳,尤其是在推理步骤之间的依赖关系时。在这里,我很想看看仅通过提示词(而不依赖工具输出)能在这些任务中提升模型表现到何种程度。

查看迭代规划流程的代码:https://github.com/tomasonjo-labs/text2cypher_llama_agent/blob/main/app/workflows/iterative_planner.py

六、基准测试

为在 LlamaIndex 工作流架构中评估 Text2Cypher 智能体创建基准测试数据集,感觉像是向前迈出的令人兴奋的一步。

我们寻找了一种替代传统单次 Cypher 执行指标(如 ExactMatch)的方法,因为这些指标往往无法全面反映像迭代规划这样的工作流的潜力。在这些工作流中,通过多步骤流程来优化查询并检索相关信息,使得单步骤执行指标显得不足。

因此,我们选择了 Ragas 的**答案相关性(answer relevancy)**指标——它更符合我们想要衡量的内容。在这里,我们使用语言模型生成答案,然后将其作为裁判,与真实答案进行比较。我们准备了约 50 个样本的自定义数据集,设计时避免生成过多或过于详细的数据库输出(即过大的输出可能使语言模型裁判难以有效评估相关性)。保持结果简洁可以确保对单步骤和多步骤工作流的公平比较。

以下是结果:


【基准测试结果】

Claude 3.5 Sonnet、Deepseek-V3 和 GPT-4o 成为答案相关性方面的前三名模型,每个模型得分均超过 0.80。NaiveText2CypherRetryCheckFlow 通常产生最高的相关性,而 IterativePlanningFlow 的排名始终较低(最低降至 0.163)。

尽管 OpenAI o1 模型相当准确,但由于多次超时(设定为 90 秒),可能未能跻身榜首。Deepseek-V3 尤其令人期待,其得分较高且延迟相对较低。总体来看,这些结果强调了实际部署场景中不仅需要关注准确性,还需要关注稳定性和速度的重要性。

另附一张表格,便于查看不同流程之间的提升效果:


【基准测试结果】

Sonnet 3.5 的分数从 NaiveText2CypherFlow 的 0.596 稳步上升到 NaiveText2CypherRetryFlow 的 0.616,然后大幅跃升至 NaiveText2CypherRetryCheckFlow 的 0.843。GPT-4o 的整体模式类似,从 NaiveText2CypherFlow 的 0.622 略微下降到 NaiveText2CypherRetryFlow 的 0.603,但随后显著上升至 NaiveText2CypherRetryCheckFlow 的 0.837。这些改进表明,添加重试机制和最终验证步骤显著提高了答案相关性。

查看基准测试代码:https://github.com/tomasonjo-labs/text2cypher_llama_agent/blob/main/benchmark/benchmark_gridsearch.ipynb。

请注意,基准测试结果可能会有至少 5% 的波动,这意味着您可能会在不同运行中观察到略有不同的结果和表现最佳的模型。

七、收获与生产部署

这是一个为期两个月的项目,我在此过程中学到了很多。一个亮点是,在测试基准中达到了 84% 的相关性,这是一项重要成就。然而,这是否意味着您能在生产中达到 84% 的准确率?可能未必。

生产环境带来了自己的挑战——真实世界的数据通常比基准数据集更嘈杂、更多样化且更不结构化。我们尚未讨论的一点是,您会在真实应用和用户中看到,生产环境需要生产就绪的步骤。这不仅意味着专注于在受控基准测试中实现高准确率,还意味着确保系统在真实条件下可靠、适应性强并提供一致的结果。

在这些场景中,您需要实现某种类型的防护措施,以阻止无关问题通过 Text2Cypher 管道。


【无关问题】

我们有一个防护措施实现示例(https://github.com/tomasonjo-labs/text2cypher_llama_agent/blob/main/app/workflows/steps/iterative_planner/guardrails.py)。除了简单地重新路由无关问题,初始防护步骤还可以通过引导用户了解他们可以提出的问题类型、展示可用工具并演示如何有效使用它们来帮助教育用户。

在以下示例中,我们强调了添加一个将用户输入值映射到数据库的过程的重要性。这一步对于确保用户提供的信息与数据库模式一致至关重要,从而实现准确的查询执行并最大限度地减少因数据不匹配或模糊导致的错误。


【将值映射到数据库】

这是一个用户请求“科幻电影”的示例。问题在于,数据库中该类型存储为“Sci-Fi”,导致查询没有返回结果。

经常被忽视的是空值的存在。在真实世界数据中,空值很常见,必须加以考虑,尤其是在执行排序或类似操作时。未能妥善处理它们可能会导致意外结果或错误。


【处理空值】

在此示例中,我们得到了一部评分为 Null 的随机电影。为解决此问题,查询需要添加一个附加子句 WHERE m.imdbRating IS NOT NULL

还有一些情况,缺失信息不仅仅是数据问题,而是模式限制。例如,如果我们请求奥斯卡获奖电影,但模式中不包含任何关于奖项的信息,查询就无法返回所需结果。


【缺失数据】

由于大语言模型被训练为取悦用户,它仍然会生成一个符合模式但无效的结果。我还不确定如何最好地处理此类示例。

最后,我想提到查询规划部分。我使用以下查询计划来回答问题:

谁在 2000 年代制作了更多电影,汤姆·汉克斯还是汤姆·克鲁斯?对于获胜者,找到其票房最高的电影。

计划如下:

plan = [
# 2 steps in parallel
    [
        "List all movies made by Tom Hanks in the 2000s.",
        "List all movies made by Tom Cruise in the 2000s.",
    ],
# Second step
    ["Find the highest profiting movie among winner of step 1"],
]

看起来很令人印象深刻,但现实是,Cypher 非常灵活,GPT-4o 可以在单个查询中处理这个问题。

我认为并行化在这种情况下是多余的。如果您正在处理真正需要的复杂问题类型,可以包括查询规划器,但请记住,许多多跳问题可以通过单个 Cypher 语句高效处理。

这个示例突出了一个不同的问题:最终答案是模棱两可的,因为语言模型只获得了有限的信息,具体来说是汤姆·克鲁斯的《世界大战》。在这种情况下,推理已经在数据库中完成,因此语言模型不需要处理该逻辑。然而,语言模型往往默认以这种方式操作,因此提供完整上下文以确保准确且明确的响应非常重要。

最后,您还需要考虑如何处理返回大量结果的问题。


【返回大量结果】

在我们的实现中,我们对结果强制设置了 100 条记录的硬限制。虽然这有助于管理数据量,但在某些情况下仍可能过多,甚至可能在推理过程中误导语言模型。

此外,并非本文中介绍的所有智能体都具备对话功能。您可能需要在开始时添加一个问题重写步骤以使其具有对话性,或者将其作为防护步骤的一部分。如果您有一个无法完全传递到提示中的大型图模式,则需要设计一个动态获取相关图模式的系统。

在生产环境中需要注意很多事项!

八、总结

智能体非常有用,但最好从简单入手,避免一开始就陷入过于复杂的实现中。专注于建立一个可靠的基准,以有效评估和比较不同架构。在工具输出方面,考虑尽量减少使用或坚持最简单的工具,因为许多智能体难以有效处理工具输出,通常需要手动解析。


九、如何系统学习掌握AI大模型?

AI大模型作为人工智能领域的重要技术突破,正成为推动各行各业创新和转型的关键力量。抓住AI大模型的风口,掌握AI大模型的知识和技能将变得越来越重要。

学习AI大模型是一个系统的过程,需要从基础开始,逐步深入到更高级的技术。

这里给大家精心整理了一份全面的AI大模型学习资源,包括:AI大模型全套学习路线图(从入门到实战)、精品AI大模型学习书籍手册、视频教程、实战学习、面试题等,资料免费分享

1. 成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

这里,我们为新手和想要进一步提升的专业人士准备了一份详细的学习成长路线图和规划。可以说是最科学最系统的学习成长路线。
在这里插入图片描述

2. 大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础(书籍含电子版PDF)

在这里插入图片描述

3. 大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识

在这里插入图片描述

4. 2024行业报告

行业分析主要包括对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

在这里插入图片描述

5. 大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

在这里插入图片描述

6. 大模型面试题

面试不仅是技术的较量,更需要充分的准备。

在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

在这里插入图片描述

全套的AI大模型学习资源已经整理打包,有需要的小伙伴可以微信扫描下方CSDN官方认证二维码,免费领取【保证100%免费

### 将自然语言文本转换为Cypher查询语句的方法 为了实现从自然语言到Cypher查询的有效转换,可以采用多种方法和技术。一种有效的方式是通过预定义的模板和机器学习模型相结合的方式来处理这一问题。 #### 使用Neo4j-Cypher-FT进行转换 Neo4j-Cypher-FT是一个专门设计用于将自然语言问题转化为Cypher查询并返回自然语言形式的结果的工具[^1]。此工具的核心在于构建了一个桥梁,使得不懂技术背景的人也能轻松访问图数据库中的信息。具体来说: - **输入理解**:接收用户的自然语言提问作为输入。 - **模板匹配**:内部拥有大量预先编写的Cypher查询模板,这些模板覆盖了常见的查询场景。 - **参数提取**:自动识别并抽取问句中涉及的关键实体或属性值。 - **查询生成**:基于上述分析结果选择最合适的模板,并填充相应的变量以形成最终的Cypher查询语句。 - **执行与反馈**:向Neo4j发送所生成的Cypher指令获取数据后,再将其整理成易于理解的回答呈现给用户。 ```cypher // 示例 Cypher 查询语句 MATCH (p:Person {name:'Alice'})-[r:FRIEND]->(m) RETURN p.name, type(r), m.name; ``` 这种方法不仅简化了开发过程,还提高了查询效率以及准确性,尤其是在面对复杂结构化数据时尤为明显。 #### 利用SpCQL数据集训练模型 除了依赖固定的规则外,还可以借助像SpCQL这样的公开可用的数据集来训练自己的转换引擎[^4]。这类资源通常包含了大量配对好的自然语言描述及其对应的Cypher表达方式,非常适合用来教导计算机如何理解和翻译人类的语言习惯至编程领域内特定语法体系下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值