@Sumanth_077: https://x.com/Sumanth_077/status/2107473852850909566
摘要
作者在 Vercel eve 上构建了一个数据分析师 agent,其中 Qwen 负责生成 SQL,而 Jev 作为独立的评审层,同时通过确定性的代码强制执行只读访问、行数限制和人工审批——展示了如何将生成、判断与安全检查分拆到不同的层次中。
查看缓存全文
缓存时间: 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
Vercel 发布了 Eve,这是一个开源框架,用于构建和扩展 AI 代理,采用文件系统优先的方法,将代理视为文件目录。该框架开箱即用地提供了持久会话、沙盒、审批、追踪和评估功能。
@rauchg:“其他人让容易的部分更容易。Vercel 让困难的部分变得简单”——今天来自 AI 代理技术负责人的直接引述……
Guillermo Rauch 宣布推出 eve,这是来自 Vercel Labs 的持久化 AI 代理框架,原生兼容 React 和 Next.js,具备内置沙箱、人在回路和评估能力。
@yan5xu:Jev 特别适合处理数据量大且对缺失数据有容忍度的场景。每个人都值得一试。
Jev 定位为面向高吞吐量、容忍缺失数据场景的工具,同时推出了一款名为 jevable 的新 CLI,它让智能体通过将自然语言规则与 TypesafeAI 的 Jev 判断相结合,按语义过滤任意数据流,将常驻运行的智能体成本最多降低 86%。
@sairahul1: https://x.com/sairahul1/status/2058832033628241931
一个Twitter推文串,描述了如何使用Claude Code并配合七个专门的AI代理来构建软件工厂,以避免vibe coding的陷阱,使单个开发者能够高效地交付功能。
@omarsar0:如今,我验证 Agent 编写代码的时间比亲自编写还多。这是所谓的软… ...个大瓶颈
ContextQA 的 Ship 被定位为一名自主 QA 工程师,能够测试已部署的 PR、复现 Slack 或 Linear 中报告的 bug,并将上下文反馈给 Claude Code 或 Codex,从而解决验证 Agent 编写代码这一瓶颈问题。