利用语义基准构建自我优化的 Text-to-Query Agent

@levibkline
英语2026年9月03日
160K
70
2
6
12

TL;DR

深入探讨如何通过中间表示、确定性编译器和语义基准来优化 Text-to-Query Agent,实现 2 秒内的延迟和 97% 的准确率。

我们的文本转查询 Agent 从使用前沿模型时的 45 秒,降到了使用 GLM 5.3 Flash 时的 2 秒,在保持相同准确率的同时,成本仅为原来的 1/20。

我们在 Conversion 近期的大部分 AI 工作都集中在通用营销智能上。

营销自动化团队跨系统执行着广泛的工作:研究客户、构建受众群体、规划营销活动、撰写内容,以及根据绩效数据采取行动。我们一直在构建能够跨这些工作流进行推理,并使用熟练营销人员会使用的相同工具的 Agent。

这些系统受益于功能强大的通用模型。工作本身是开放式的,良好的判断力往往比快速完成任务更重要。

但我们也有一个积压的、更小、更聚焦的 AI 功能需求。其中之一是自然语言筛选器:让用户用日常英语描述一个受众群体,然后将该描述转化为一个他们可以在 Conversion 现有语句构建器中查看和编辑的筛选器。(在 Conversion 中,筛选器被称为语句。)

起初,这看起来像是一个直接的结构化生成任务。给模型提供可用的字段,描述输出格式,然后让它生成 JSON。结果发现,这比想象中要困难得多。

Levi - inline image

使用 GLM 5.3 Flash 在 5 秒内生成的复合语句。

以下面这个例子为例:

查找在过去 30 天内至少提交过一次演示表单,并且在一家拥有价值超过 50,000 美元开放商机的软件公司工作的联系人。

这要求系统能够:

  • 找到用户所说的“演示表单”具体指哪个表单
  • 确定哪个字段代表公司的行业
  • 了解该工作区如何表示“软件”,这意味着要查看该字段中实际存储的值,而不是猜测
  • 从联系人遍历到其公司,再到该公司的商机
  • 确保“开放”和“超过 50,000 美元”应用于同一个商机
  • 应用相对事件窗口

同时,它还需要足够快地完成所有这些操作,以提供筛选器界面的体验,而不是研究型 Agent。

这个看似简单的提示工程任务,变成了一个受限的文本转查询问题。解决它需要一个使用工具的 Agent、一个中间表示、一个确定性编译器以及一个语义基准测试。

我们通过最终生成的基准测试 Statement Bench,对八个模型进行了评估,包括 Claude Opus 5、Kimi K3、GLM 5.3 Flash 以及今天早上发布的 Gemini 3.8 Flash。结果如下。

为 Agent 提供工具

回答上述请求所需的大部分信息都特定于客户的环境。单个工作区可能包含数亿个历史字段值,以及其资产和对象。出于显而易见的原因,我们无法将所有信息都放入一个提示中。

我们第一个有用的架构决策是,不再将这个问题视为普通的结构化生成。相反,模型会收到一小套工具。它可以搜索字段、检查历史值,并解析特定于业务的资产,如表单、营销活动、电子邮件和受众群体。它仅在请求需要时才使用这些工具。

这个搜索基础设施的很大一部分来自我们最近的全局搜索工作,该工作提供了对 Conversion 中所有记录进行文本和语义搜索的能力。我们计划很快分享更多相关信息!

基本流程如下所示:

text
1自然语言请求
2 |
3 v
4 使用工具的 Agent <-----------------+
5 / | \ |
6字段 资产 关系 | 带原因的拒绝
7 \ | / |
8 v |
9 受限的中间表示 |
10 | |
11 v |
12 验证器和编译器 ---------------+
13 |
14 v
15 生产环境语句

这保持了初始上下文的精简。它也使失败更容易理解。如果一条语句是错误的,我们可以确定是 Agent 找到了错误的资产、选择了错误的字段、误解了关系、错误地表示了正确的意图,还是编译器存在 bug。这个区分后来对我们的评估循环变得非常重要。

创建一种更小的语言

使用工具解决了上下文问题,但没有解决延迟问题。

从早期反馈中得到的一个教训是:用户对专用界面中的延迟容忍度远低于聊天界面。

这指向了一个更广泛的悖论。我们设定延迟期望是基于任务给我们的感觉有多难,而不是对系统来说有多难。撰写内容感觉困难,因为我们能看到工作本身。描述一个筛选器感觉简单,因为我们的思维会默默地解析上下文、实体、关系和意图。对于模型来说,重建这些隐藏的假设就是任务本身。用户感知到的工作越少,他们留给系统完成工作的时间就越少。

根据早期反馈,我们设定了两个目标:对于常见查询,准确率超过 95%,响应时间约为 5 秒。

Conversion 拥有一种表达力丰富的内部查询语言。在我们早期的测试中,直接使用生产环境格式,只有像 Claude Opus 这样最大的模型才能可靠地生成它。即使是简单的语句也需要大约 45 秒。

可视化语句构建器只暴露了完整语言的一个子集。我们为这个子集创建了一个更小、对 Agent 更友好的中间表示。较小的模型可以使用更少的 token 来生成它,而一个确定性编译器则负责处理完整的生产环境格式。

考虑以下语句:

职位名称包含“总监”。

原始的生产环境语句如下所示:

json
1{
2 "type": "LOGICAL",
3 "version": 1,
4 "logical": {
5 "operator": "OR",
6 "operands": [
7 {
8 "type": "LOGICAL",
9 "version": 1,
10 "logical": {
11 "operator": "AND",
12 "operands": [
13 {
14 "type": "VARIABLE",
15 "version": 1,
16 "variable": {
17 "variableSchemaId": "550e8400-e29b-41d4-a716-446655440000",
18 "where": {
19 "type": "LOGICAL",
20 "version": 1,
21 "logical": {
22 "operator": "AND",
23 "operands": [
24 {
25 "type": "LOGICAL",
26 "version": 1,
27 "logical": {
28 "operator": "CONTAINS",
29 "operands": [
30 {
31 "type": "ATTRIBUTE",
32 "version": 1,
33 "attribute": {
34 "name": "value"
35 }
36 },
37 {
38 "type": "CONSTANT",
39 "version": 1,
40 "constant": {
41 "value": "Director"
42 }
43 }
44 ]
45 }
46 }
47 ]
48 }
49 }
50 }
51 }
52 ]
53 }
54 }
55 ]
56 }
57}

同一筛选器面向模型的表示是:

json
1{
2 "field": "550e8400-e29b-41d4-a716-446655440000",
3 "op": "contains",
4 "value": "Director"
5}

这个中间表示已经经历了多次迭代,最新版本是通过观察小模型在早期版本上失败而塑造的。一个重大的改进是引入了更好的同记录语义(这是模式验证无法捕捉到的):

json
1{
2 "related": "OPPORTUNITY",
3 "all": [
4 { "field": "<stage uuid>", "op": "equals", "value": "Closed Won" },
5 { "field": "<amount uuid>", "op": "gt", "value": 100000 }
6 ]
7}

这种模型与代码的分离为我们带来了一些有用的特性:

  • 难以表达不支持的语句
  • 同记录关系语义是可见的
  • 字段和关系引用可以被验证
  • 编译器可以独立于模型进行测试
  • 生成的语句在现有 UI 中仍然可编辑

中间表示最终简化了模型的工作:Agent 解析用户的意图并生成一个受限的计划;代码则处理生产环境格式。

构建一个语义基准测试

一个输出可能完全有效,但仍然可能是错误的。以这个请求为例:

在拥有价值超过 100,000 美元已赢单商机的公司工作的联系人。

联系人属于一家公司,而一家公司可以拥有多个商机。匹配这个筛选器意味着遍历关系(联系人到公司,公司到商机),并沿途检查两个条件:交易已赢单,且交易价值超过 100,000 美元。

难点在于这些条件必须对同一个商机成立。如果它们被独立检查,一家拥有一个已赢单的 20,000 美元交易和一个开放的 150,000 美元交易的公司,可以同时满足这两个条件:每个条件匹配一个不同的交易。模式验证永远无法捕捉到这一点。

一旦有几个这样的例子通过了,编辑提示就有可能使它们退化。我们需要一种方法来检查含义,而不仅仅是有效性,并且在每次有变化时都进行检查。

我们围绕产品的行为构建了 Statement Bench,这些行为源自我们客户之前构建的匿名受众模式。该测试套件现在包含 15 个类别的 100 个案例,例如纯字段条件、事件、相对和日历时间窗口、关系以及复合查询。

每个案例都在一个逼真的工作区沙盒中运行。Agent 接收与生产环境中相同的数据和工具。

评估器检查多个层面:

  1. Agent 是否返回了一条语句?
  2. 中间表示是否满足其模式?
  3. 引用的字段和关系是否存在?
  4. 语句能否编译并通过生产环境验证?
  5. 它是否代表了请求的含义?
  6. 它需要多少模型步骤、工具调用、token 和被拒绝的提交?

第五点是最有趣的,因为有效性并不能保证语义等价。

语义检查会读取编译后的语句,断言诸如“一个商机条件同时携带了阶段和金额”、“一个电子邮件事件,其类型是点击,而不是打开”,或者“一个网络研讨会条件,而不是自定义营销活动条件”之类的事情。

运行一个评估驱动的优化循环

这个基准测试改变了我们继续开发该功能的方式。我们不再要求编码 Agent“改进提示”或“实现一个新的中间表示”,而是可以给它一个可执行的改进定义。

循环如下所示:

  1. 运行基准测试
  2. 根据根本原因对失败进行分组
  3. 检查 Agent 的工具轨迹和提交的中间表示
  4. 更改提示、工具、验证器或编译器
  5. 再次运行完整的基准测试
  6. 仅当更改在不引入回归的情况下改进了系统时才保留它

编码 Agent 可以使用基准测试来比较模型、试验中间表示、改进工具描述,并自主优化提示。每次更改后运行完整测试套件也防止了我们过度拟合于个别失败,我们还保留了另外 50 个案例来确认这一点。

一些更改带来了最大的改进:

  • 将路径、类型和结构移入编译器。 我们的第一个中间表示让模型显式写出所有关系:联系人到公司,公司到商机。字段的元数据已经隐含了该路径,因此编译器现在可以推断它。我们对日期、类型转换、否定放置和分组嵌套也做了同样的处理。将规则移入编译器简化了中间表示并减少了模式失败。
  • 附带解释和修复方案进行拒绝。 每次模式和编译器的拒绝都会说明应该写什么(如果可用的话):“gt 不能在此字段上取反;请使用 lte”、“从 campaign_list 复制 id”。小模型在一两次重试后就能收敛,生产环境模型每百个请求中只有几个被拒绝。
  • 为小模型结构化提示。 重新组织提示并没有改变准确率,但它将重试次数减半,这直接改善了延迟。这受到了 Anthropic 的 提示最佳实践 的启发。
  • 使用示例而非散文。 在我们的格式参考中增加两个额外的示例,解决了一类用大段解释未能解决的遗漏问题,将拒绝提交的数量大致减半。
  • 提供完整的上下文,或者不提供。 模型在调用工具之前会优先使用上下文中的内容。当上下文包含一组部分或不带标签的字段时,模型会使用最近的字段而不是进行搜索,从而产生语义不正确的语句。通过减少部分上下文并鼓励工具调用,我们提高了构建率并将输入 token 减少了五分之一。

最终的生产环境配置,GLM 5.3 Flash,完成了所有 100 个基准测试案例,中位延迟为 2.3 秒,第 95 百分位延迟为 7.1 秒。并且,100 个中有 97 个在语义上是正确的。与最初的生产环境格式方法相比,简单筛选器从大约 45 秒缩短到略高于 1 秒,成本仅为原来的 1/20。

在 Statement Bench 上比较模型

这个基准测试也为我们提供了一种在实际任务上比较模型的方法。

在 2026 年 9 月 2 日,我们在八个模型上运行了相同的 100 个案例。每个模型都收到了相同的提示、工具、中间表示、编译器和 30 秒的请求超时时间。

提供商路由、提示缓存和临时推理负载都会影响延迟。

模型

有效构建

语义正确

P50 延迟

P95 延迟

缓存读取

工具调用

被拒绝的提交

每 1,000 次请求预估成本

Claude Opus 5

100/100 (100%)

100/100 (100%)

3.16s

8.53s

91.1%

162

0

$27.51

GLM 5.2

100/100 (100%)

100/100 (100%)

4.38s

13.02s

93.5%

201

5

$14.94

Kimi K3

100/100 (100%)

100/100 (100%)

5.17s

11.84s

34.3%

157

0

$48.51

GLM 5.3 Flash

100/100 (100%)

97/100 (97%)

2.34s

7.07s

92.8%

163

2

$1.33

DeepSeek V4 Pro

96/100 (96%)

96/96 (100%)

5.53s

24.31s

47.8%

172

1

$12.00

Gemini 3.7 Flash

77/100 (77%)

77/77 (100%)

15.14s

30.01s

26.5%

228

1

$18.24

Gemini 3.8 Flash

76/100 (76%)

76/76 (100%)

14.29s

30.01s

35.4%

266

1

$27.44

DeepSeek V4 Flash

56/100 (56%)

55/56 (98%)

6.79s

30.00s

41.5%

100

1

$0.56

预估成本基于 2026 年 9 月 2 日各提供商列出的非促销费率,使用观察到的输入、缓存输入和输出 token 计算每 1,000 次尝试请求的成本。缓存输入按提供商公布的缓存读取费率计费(如果提供商公布了该费率),否则按完整输入费率计费。

Levi - inline image

图 1. 正确性与成本对比。GLM 5.3 Flash 达到了 97% 的正确率,成本约为 Claude Opus 5 的二十分之一。

Levi - inline image

图 2. 延迟分布,中位数和第 95 百分位,按 P95 排序。

一些发现值得注意。

模型大小和价格都不能预测延迟。 最快的模型是最小和最便宜的。第二快的模型是最大和最贵的。

失败已从错误答案转变为缓慢答案。 八个模型中有六个在它们完成的每条语句上都是语义正确的;它们之间的差异几乎完全在于有多少请求在超时时间内完成。在中间表示和提示的早期迭代中,大多数较小的模型在构建步骤就未能通过基准测试,语义准确率低于 50%。

推理 token 的消耗超过了工具调用。 Gemini 3.8 Flash 在其 192,000 个输出 token 中花费了 180,000 个用于推理,并进行了 266 次工具调用;Claude Opus 5 花费了 813 个 token 用于推理,进行了 162 次调用,并完成了所有案例。我们的全局搜索工作将每次工具查找时间降低到了毫秒级,因此剩余的成本在于模型在两次调用之间的周转。

要点

模型擅长解决歧义,代码擅长强制执行精确性,而我们早期的大部分失败都源于要求模型同时做这两件事。构建这个 Agent 的工作,就是决定这两者各自应负责哪一部分。我们相信,对于文本转 SQL 和大多数其他自然语言界面来说,情况也是如此。

如果你对这些问题的任何一个感兴趣,请联系我们!我们正在招聘。

一键保存

使用 YouMind AI 深度阅读爆款文章

保存原文、追问细节、总结观点,并在一个 AI 工作空间里把爆款文章沉淀成可复用笔记。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章