AI写SQL,实体识别老错误?一文说清如何“精准调教”大模型

一、那个叫“比亚迪”的集团,到底是谁?

你是否遇到过这样的场景?

你满怀期待地向 AI 助手发出指令:“帮我查一下『比亚迪』上个季度的销售额。”

AI 助手迅速响应,生成了一段 SQL 代码:SELECT SUM(sales) FROM sales_data WHERE group_name = "比亚迪"。

结果,数据库返回的是一个冰冷的“查无此据”。

picture.image

你一查数据库,恍然大悟:在公司的数据库里,它的标准名称是 “比亚迪汽车” 。

picture.image

这个小小的差错,暴露了在构建 AI 应用时一个普遍且棘手的难题:实体链接(Entity Linking) 。

AI 很强大,但它本质上是一个语言模型,并不天然具备你所在业务领域的“常识”。

它无法凭空知道,“比亚迪”、“BYD”、“比亚迪新能源”在你的数据库里,都指向同一个实体——“比亚迪汽车”。

当你的数据库里有几十上百个这样的标准名称,而用户的日常叫法又千奇百怪、花样繁多时,我们该如何“调教”AI,让它变得更“聪明”,总能生成准确无误的查询条件呢?

今天,我们就以 Dify 平台为例,深入探讨如何通过工作流(Workflow)的优化,彻底解决大模型在实体识别上的“模糊病”。

二、核心思路:解耦“理解”与“生成”

问题的根源在于,我们把 “理解用户模糊的意图” 和 “生成精确的代码” 这两个难度不同的任务,打包成一个扔给了 AI。一个更健壮、更可靠的思路,是把它们彻底分开,分两步走:

picture.image

第一步:意图理解与校准

在正式生成 SQL 之前,增加一个中间环节。这个环节的核心任务是,借助一个我们预先准备好的“知识库”,将用户的模糊说法(如“比亚迪”、“吉利”)精确地映射到数据库里的标准名称(如“比亚迪汽车”、“浙江吉利控股集团”)。

第二步:精确指令生成

当获取到校准后的标准名称后,再把它连同用户的原始问题,一起作为“清晰无歧义的指令”交给 AI,让它心无旁骛地生成最终的 SQL。这个增加的“校准”步骤,就是我们提升准确率的关键。

三、向量知识库 - 更智能的“模糊匹配法”

如果用户的说法非常随意,甚至包含错别字(比如把“比亚迪”说成“比亚迪汽东”),手动维护别名库就会非常繁琐且无法穷尽。这时,Dify 内置的知识库(其背后是向量数据库技术)就派上了大用场。

1-实现思路

这个方法在 Dify 中实现起来更简单,我们几乎不需要自己写代码,只需要“喂”给 Dify 一份标准名单即可。

picture.image

  1. 创建“标准名”知识库 :把所有汽车行业内的标准集团名称(要求每个名称占一行)整理到一个 .csv 文件里。

  2. 上传到 Dify 知识库 :在 Dify 中创建一个新知识库,把这个 .txt 文件传上去。Dify 会自动为每个名称计算“向量”,你可以把它理解为给每个名字生成一个独特的、可用于数学计算的“指纹”。

  3. 在工作流中“召回” :当用户提问后,Dify 会把问题中的公司名(如“比亚迪”)也转换成一个“数学指纹”,然后去知识库里通过计算,找出“指纹”最相似、距离最近的那个标准名。

2-在 Dify 中用“知识库召回”实现指南

步骤1:创建知识库

  • 在 Dify 工作台点击进入 知识库 (Knowledge)

  • 创建一个新的知识库,例如命名为 group_names_standard。

  • 将包含所有标准名称的 .csv 文件上传到该知识库,并等待 Dify 完成处理。

picture.image

导入的.csv文件只需要保留一个标准查询名一行即可:

picture.image

接下来,测试一下召回,看看效果。单集团查询:25 年 6 月小鹏销量。

测试结果:通过。

picture.image

多集团主体问题:截止5月比亚迪总体销量是多少?环比和同比如何?相对上汽如何?

测试结果:通过。

picture.image

步骤2:编排工作流

[知识检索节点]

这是关键一步,在工作流中问题分类器(也就是识别了用户是要进来做数据查询)后,添加“知识库检索”节点。

picture.image

  • 选择知识库 :选择刚刚创建的 汽车集团数据库标准查询名

picture.image

  • 召回策略 :这里有一个细节,知识库解析的时候,Top K 可以设置成 3,预防用户一次问多个汽车集团数据的情况出现。ReRank 设置,选择权重设置,按照 70% 关键词,30% 语义的方式进行设定。

picture.image

接下来,点击右上角的三角形测试一下,在查询变量区域输入比亚迪。

picture.image

然后,这里有一个细节需要留意,知识检索出来的数据OutPut 是一个复杂的 Object,是没办法被后续的节点正常引用的,这个 Object 长这样。我们只想要查询结果相关的标准查询名称。

  
{  
  "result": [  
    {  
      "metadata": {  
        "\_source": "knowledge",  
        "dataset\_id": "42ecfbfb-4f19-4382-8685-ae098814da87",  
        "dataset\_name": "汽车集团数据库标准查询名",  
        "document\_id": "74bc1e9f-3d62-4123-8df9-2307583a80a7",  
        "document\_name": "汽车集团数据库标准查询名",  
        "data\_source\_type": "upload\_file",  
        "segment\_id": "ffeb53ef-f0ad-4d0a-8009-6359b7e8f82e",  
        "retriever\_from": "workflow",  
        "score": 0.6397522,  
        "segment\_hit\_count": 18,  
        "segment\_word\_count": 17,  
        "segment\_position": 14,  
        "segment\_index\_node\_hash": "8c55206c086c277d6b799b2b8dc1d564b5c0fd0088ac96264f609a54b4ac4b44",  
        "doc\_metadata": null,  
        "position": 1  
      },  
      "title": "汽车集团数据库标准查询名",  
      "content": "字段标准查询名称\":\"比亚迪汽车\""  
    },  
    {  
      "metadata": {  
        "\_source": "knowledge",  
        "dataset\_id": "42ecfbfb-4f19-4382-8685-ae098814da87",  
        "dataset\_name": "汽车集团数据库标准查询名",  
        "document\_id": "74bc1e9f-3d62-4123-8df9-2307583a80a7",  
        "document\_name": "汽车集团数据库标准查询名",  
        "data\_source\_type": "upload\_file",  
        "segment\_id": "0ee8f92b-d4b4-480c-89f7-7f624c7c0592",  
        "retriever\_from": "workflow",  
        "score": 0.48187650000000004,  
        "segment\_hit\_count": 3,  
        "segment\_word\_count": 16,  
        "segment\_position": 21,  
        "segment\_index\_node\_hash": "21045537485032870ec912fabae6e465aab026ff7783e8e8cc5ca3879ab2d981",  
        "doc\_metadata": null,  
        "position": 2  
      },  
      "title": "汽车集团数据库标准查询名",  
      "content": "字段标准查询名称\":\"长城汽车\""  
    },  
    {  
      "metadata": {  
        "\_source": "knowledge",  
        "dataset\_id": "42ecfbfb-4f19-4382-8685-ae098814da87",  
        "dataset\_name": "汽车集团数据库标准查询名",  
        "document\_id": "74bc1e9f-3d62-4123-8df9-2307583a80a7",  
        "document\_name": "汽车集团数据库标准查询名",  
        "data\_source\_type": "upload\_file",  
        "segment\_id": "585a82ef-e3ba-4c94-8900-f450156a1877",  
        "retriever\_from": "workflow",  
        "score": 0.4750757,  
        "segment\_hit\_count": 3,  
        "segment\_word\_count": 16,  
        "segment\_position": 22,  
        "segment\_index\_node\_hash": "7f2524126f964638ff86f258d7a666a1846c3b2fa53bf56ebf2e8004ee522344",  
        "doc\_metadata": null,  
        "position": 3  
      },  
      "title": "汽车集团数据库标准查询名",  
      "content": "字段标准查询名称\":\"长安汽车\""  
    }  
  ]  
}

[代码处理节点]

使用上一步知识检索节点的输出 result Array[Object] 作为输入。

picture.image

代码类型选择 Python3,然后,代码区输入这段代码:

  
  
def main(arg1: dict) -> dict:  
    return {  
        "result": [item["content"].split(":\"")[1].rstrip("\"") for item in arg1],  
    }  

测试一下效果,把上一个知识检索查询的结果,当做代码节点的输入。

picture.image

点击开始运行后,我们就拿到这样的运行结果。完美!提取到的都是这个数据库里的标准汽车集团查询名。

picture.image

[LLM 节点 - 生成 SQL]

最后,这个就是水到渠成的事儿了。

在升成 SQL 节点,将代码处理的结果,作为变量引入到提示词中。

在最终的 Prompt 中,增加关于数据库字段标准写法的定义。结合这个变量和原始问题,即可生成精准的 SQL。

picture.image

我们来看一下效果:

picture.image

picture.image

picture.image

四、结语

我们看到,使用知识库召回,能最大程度放大 Dify 这类 Agent 平台的原生优势,实现简单、效果智能,且长期维护成本极低。这是处理此类问题的最佳实践。

其实“调教”AI 的过程,并非是什么黑魔法,其本质是 将一个复杂、模糊的大问题,拆解成一系列简单、明确的小步骤 。

通过在工作流中创造性地增加一个“实体校准”环节,我们就能成功地引导大模型跨越“语义鸿沟”,让它从一个“差不多就行”的语言助手,蜕变为一个“精准可靠”的业务专家。

希望这篇文章能给你在构建自己的 AI 应用时带来切实的启发。现在就动手,去优化你的工作流吧!

0
0
0
0
评论
未登录
暂无评论