@Sumanth_077: https://x.com/Sumanth_077/status/2107473852850909566

X AI KOLs Timeline 工具

摘要

作者在 Vercel eve 上构建了一个数据分析师 agent,其中 Qwen 负责生成 SQL,而 Jev 作为独立的评审层,同时通过确定性的代码强制执行只读访问、行数限制和人工审批——展示了如何将生成、判断与安全检查分拆到不同的层次中。

https://t.co/U8y9hmuRH3
查看原文
查看缓存全文

缓存时间: 2026/10/06 21:56

用 Jev 作为评审层来构建一个数据分析智能体

Jev 赋予了智能体一种大多数智能体都缺少的能力:一个独立用于判断的模型。

你不必让同一个 LLM 既生成答案、又评判自己的工作、再验证结果、最后决定是否继续,而是可以将这些职责拆分到不同的层。

我想测试一下这种架构在真实智能体中是什么样的。

于是我们用 Vercel eve 构建了一个数据分析智能体:Qwen 负责主要工作,Jev 围绕整个流程担任评审者。

Qwen 读取数据库 schema、编写 SQL,并解释返回的行数据。Jev 则检查:原始问题是否足够清晰可以回答?生成的 SQL 是否真的匹配用户意图?最终的解释是否有返回的数据作为依据?

所有不应该依赖模型判断的部分保持确定性执行:只读访问、行数限制,以及人工审批。

Qwen 负责生成,Jev 负责评审,代码负责强制约束,Vercel eve 运行整个循环。

这就是我们构建它的方式。

下面是一个快速演示:

各个组成部分,以及为什么采用它们

我们使用 Vercel eve 作为智能体运行时。

eve 负责处理智能体循环、工具执行和人工审批流程,而智能体本身只暴露我们希望模型拥有的能力。

对于这个项目,整体配置刻意保持精简:

  • 模型:Qwen(alibaba/qwen3.8-omni-flash),通过 Vercel AI Gateway 调用

  • 数据:SQLite,包含一个预置数据的销售数据库,内含客户、产品以及来自 2025 年的订单

  • 界面:Gradio

  • 工具:inspect_schema 和 run_sql

  • 评审层:来自 TypeSafe AI 的 Jev

SQLite 数据库是本地的,因此这个演示不依赖任何外部数据库 API。

而模型只获得两个数据库工具。

inspect_schema 让它可以看到表和列的结构。

run_sql 让它在通过周围的各项检查之后执行查询。

这里没有任何一部分本身特别复杂。

重要的是决定由哪一层负责哪些决策。

一个问题的实际流转过程

假设你问:

“各产品类别的总收入是多少?”

基本的智能体循环是:

问题
↓
inspect_schema
↓
Qwen 读取表和列的结构
↓
Qwen 编写一条只读 SELECT
↓
run_sql
↓
返回行数据
↓
Qwen 解释结果

模型从不直接访问数据库。

它通过一个工具查看 schema,提出 SQL,并通过另一个工具接收返回的行数据。

对于这个预置数据的演示,已完成订单的收入定义为:

quantity * unit_price

适用于满足以下条件的订单:

status = ‘completed’

智能体在答案中明确说明了这个定义,而不是悄悄决定“收入“意味着什么。

这个区别很快就变得非常重要。

一条查询可能在语法上完全正确,却回答了与用户本意不同的问题。

防护机制是确定性的,而非依赖模型判断

这是我们做的第一个拆分。

Qwen 可以提出 SQL。

但它无权决定这条 SQL 是否安全到可以执行。

这个决定由代码来做。

在查询触及数据库之前,run_sql 会应用确定性的检查。

它只接受恰好一条 SELECT 语句。

SQLite 以只读方式打开,并启用了仅查询模式。

任何试图写入或包含第二条语句的操作都会被拒绝。

该工具还会拒绝返回超过 200 行的查询,并要求智能体对结果做聚合处理或添加 LIMIT。

如果查询中没有 WHERE 子句,执行会暂停等待人工审批,然后才会执行大范围扫描。

这些检查中没有任何一项需要 Jev。

它们也不需要 Qwen。

调用模型反而会让它们变得不那么可靠。

如果一条规则可以被确定性地检查,就用确定性的方式去检查。

只有当问题真正需要语义判断时,才让模型介入。

生成 SQL 很容易,信任答案才是难点

确定性的防护机制解决了一个问题:

这条查询能否安全执行?

它们无法回答:

这条查询是否真的回答了用户想问的问题?

一条完全安全的查询仍然可能使用错误的指标。

它可能过滤了错误的日期范围。

它可能按错误的字段分组。

而且即使 SQL 是正确的,最终的解释也可能提出返回行数据无法支持的论断。

只读的数据库连接无法保护你免受上述任何一种失败。

这就是我们引入 Jev 的原因。

Jev 在三个不同的节点上对智能体进行评审。

1. 这个问题是否足够清晰可以回答?

在问题进入主智能体循环之前,Jev 会检查它能否基于现有的 schema 得到回答。

我们用这个问题进行了测试:

“我们最好的客户是谁?”

这听起来很合理,但“最好“是未定义的。

是按收入最好?

是购买次数最多?

是平均订单价值最高?

还是最近活跃?

Jev 将这个问题标记为含糊不清,并以 93% 的置信度返回了 clarify。

与其自己臆造一个指标、自信地回答错误的问题,智能体改为向用户请求定义“最好“的含义。

这是一个很小的决策,但它改变了整个智能体的行为方式。

2. 这条 SQL 是否真的对应问题?

下一次评审发生在 Qwen 编写 SQL 之后、查询执行之前。

Jev 收到的内容包括:

  • 用户的问题

  • 数据库 schema

  • 提出的 SQL

然后它判断这条查询是否真正代表了用户的意图。

如果存在明确的不匹配,智能体会收到原因,并有一次机会在执行前修改 SQL。

这与确定性的安全层不同。

正则表达式可以告诉你查询是一条 SELECT。

但它无法可靠地判断这条查询回答的是“上个月的收入“,而不是“所有时间段的总收入“。

那是一个语义判断。

3. 最终答案是否有返回的行数据作为依据?

在查询执行之后,还有一个失败点。

SQL 可能是正确的。

行数据可能是正确的。

但解释仍然可能是错误的。

因此,在 Qwen 生成最终答案之后,Jev 会将该答案与实际返回的行数据进行比对。

如果答案提出了结果无法支持的论断,我们不会把它当作已验证的内容直接呈现出来。

它会被显示为未经验证的草稿,SQL 和返回的行数据仍然可见,让用户可以检查究竟发生了什么。

这赋予了智能体三个独立的评审节点:

问题清晰度
↓
SQL 相关性
↓
答案的依据性

Jev 负责评审,但绝不接管驾驶权

这个分离非常重要。

Qwen 负责编写每一条查询和每一段解释。

确定性代码控制着什么被允许执行。

Jev 负责评审那些需要解读的环节。

但 Jev 的判定无法:

  • 批准不安全的 SQL

  • 取消行数上限

  • 绕过只读模式

  • 回答人工审批提示

  • 直接修改数据库

Jev 提供的是意见。

运行时仍然决定这些意见可以影响什么。

我们还刻意让评审层在失败时保持放行。

如果 Jev 响应缓慢、不可用,或返回的结果低于我们所需的阈值,应用不会突然变得无法使用。

答案仍然可以返回,同时附上一个明确的备注,说明评审未能完成。

评审者不可用时,应该降级为“没有意见“。

而不应该悄悄变成“已批准“。

置信度有助于判断,但它不是权限。

完整的循环

当所有这些部分组合在一起时,智能体看起来是这样的:

自然语言问题
↓
Jev 清晰度评审
↓
Qwen 查看 schema
↓
Qwen 编写只读 SQL
↓
Jev SQL 相关性评审
↓
确定性执行防护
↓
需要时的人工审批
↓
SQLite 执行查询
↓
返回行数据给 Qwen
↓
Qwen 撰写答案
↓
Jev 依据性评审
↓
答案被展示,或被标记为未经验证

这是我觉得这个项目中最有价值的部分。

没有哪一个单一模型负责一切。

每一层承担的工作范围都窄得多。

它会在哪里失效,以及在依赖它之前需要了解的事情

我们测试的是一个预置数据的 SQLite 数据库,而不是生产数据仓库。

目标是测试控制流程、评审行为,以及确定性检查与模型判断之间的分离方式。

这不是一个性能规模的基准测试。

还有一个实现细节值得了解。

清晰度评审和依据性评审直接调用评估端点,因此我们能拿到可以设置阈值的置信度值。

而 SQL 相关性检查目前通过 eve 的 evaluate 辅助函数运行。

这条路径会返回判定结果,但并不总是以同样的方式暴露置信度值。

因此该项评审可以在失败时放行,让查询继续执行而不会被阻塞。

这应当被理解为:

“没有意见。”

而不是:

“已批准。”

而且,所有这些评估检查都无法让 Jev 成为正确性的保证。

真正保证数据库访问安全的,仍然是那些确定性控制:

只读执行

行数限制

人工审批

Jev 帮助我们判断智能体的推理过程是否与任务相符。

但它无法取代这些控制。

决策规则

我想从这个项目中复用的主要规则很简单:

可以确定性检查的条件,用代码来守卫;问题真正需要判断时,才使用模型。

“这条查询是只读的吗?”

代码可以回答。

“这条查询是否返回了超过 200 行?”

代码可以回答。

“这条查询是否需要人工审批?”

代码可以回答。

但是:

“这个问题是否含糊不清?”

“这条 SQL 是否真的代表了用户的意图?”

“这个解释是否能从这些行数据中推导出来?”

这些都是语义问题。

正是在这里,像 Jev 这样的模型变得有用。

把这两类问题区分开,正是让这套架构比单纯在 LLM 响应之后追加一次评估调用有用得多的原因。

完整的代码和配置,包括预置数据库和 Gradio 应用,都在这里:

https://github.com/Sumanth077/Hands-On-AI-Engineering/tree/main/ai_agents/nl_data_analyst_agent

如果你想深入了解 Vercel eve 本身,Vercel 还将于 10 月 15 日在旧金山的 Ship 大会举办一场动手实践会:

https://vercel.com/ship

感谢 Vercel 与我一起完成这个项目。

相似文章

@omarsar0: https://x.com/omarsar0/status/2070884837372703196

X AI KOLs Following

Vercel 发布了 Eve,这是一个开源框架,用于构建和扩展 AI 代理,采用文件系统优先的方法,将代理视为文件目录。该框架开箱即用地提供了持久会话、沙盒、审批、追踪和评估功能。