@_avichawla: 另一个疯狂的 Jev 使用场景!传统数据库过滤需要精确的、预先定义好的条件,但许多问题是语义性的:

X AI KOLs Timeline 工具

摘要

pg-jev 是一个开源的 Postgres 扩展,通过 TypeSafe 的 Jev 模型,让你用自然语言条件对数据行进行过滤、分类和排序,无需向量列或 embedding 索引。

又一个疯狂的 Jev 使用场景! 传统数据库过滤需要精确的、预先定义好的条件。但许多问题其实是语义性的: - 这篇文章主要讲的是软件工程吗? - 哪个主题最能描述它? - 它看起来技术深度如何? 这些问题通常需要把数据行搬进应用代码,调用模型,解析其输出,再把结果写回去。 pg-jev 是一个开源的 Postgres 扩展,通过 SQL 函数暴露了 Jev 的能力。 - jev() 可以在 WHERE 子句中使用 - jev_prob() 返回一个概率值 - jev_choice() 选出一个标签 - jev_score() 可以在有序等级之间对数据行进行排名 它不需要任何向量列或 embedding 索引。 在底层,pg-jev 会将数据行批量发送给 Jev,再返回类型化后的结果,SQL 可以对这些结果进行过滤、排序、分组,并与精确谓词组合使用。 下面的演示是在 Postgres 中存储的真实 Hacker News 帖子上运行的。 它首先展示这些数据行,然后让 Jev 找出软件工程相关的帖子,按主题进行分类,再按技术深度排序。最后的查询会报告该数据库会话中的请求数、token 用量、费用和缓存命中情况。 GitHub 仓库:https://github.com/realZachi/pg-jev… (别忘了给它点个星 ⭐) Postgres 负责存储数据并控制查询,而 Jev 负责处理那些 SQL 无法表达为确定性条件的部分。 如果你想了解 Jev 在底层是如何工作的,我还写了一份实战指南,教你如何使用开源模型、完全在本地构建一个 Jev 风格的模型。 请在下方阅读。
查看原文
查看缓存全文

缓存时间: 2026/10/03 15:02

又一个疯狂的 Jev 使用场景!

传统的数据库过滤需要精确、预定义的条件。但很多问题是语义性的:

  • 这篇文章主要是关于软件工程的吗?
  • 哪个主题最适合描述它?
  • 它的技术深度看起来如何?

这些通常需要把数据行取出到应用代码中,调用模型,解析输出,再把结果写回。pg-jev 是一个开源的 Postgres 扩展,它通过 SQL 函数暴露了 Jev:

  • jev() 可以在 WHERE 中使用
  • jev_prob() 返回概率
  • jev_choice() 选择标签
  • jev_score() 在有序层级上对行进行排名

它不需要向量列或嵌入索引。在底层,pg-jev 会批量打包数据行,发送给 Jev,然后返回类型化的答案,SQL 可以对这些答案进行过滤、排序、分组,并与精确谓词组合使用。

下面的录制视频展示了它对存储在 Postgres 中的真实 Hacker News 故事运行的结果。视频首先展示数据行,然后让 Jev 找出软件工程相关的故事、按主题分类,并按技术深度排序。最后的查询会从数据库会话中报告请求数、token 数、成本和缓存命中情况。

GitHub 仓库:https://github.com/realZachi/pg-jev …(别忘了给它点个 Star ⭐)

Postgres 负责保存数据并控制查询,而 Jev 负责处理 SQL 无法表达为确定性条件的部分。如果你想了解 Jev 底层的工作原理,我还写了一份实战指南,教你用开源模型在本地完全离线地构建一个类似 Jev 的模型。请继续往下阅读。


realZachi/pg-jev

来源:https://github.com/realZachi/pg-jev

jev — 用自然语言向你的 Postgres 表提问

CI(https://github.com/realZachi/pg-jev/actions/workflows/ci.yml) PGXN(https://pgxn.org/dist/jev/) License Website(https://pgjev.com)

用你想表达的方式写条件,剩下的交给 Postgres。

jev 让你用自然语言条件来过滤、排序和分类数据行。每一行都由 TypeSafe 的 Jev(https://docs.typesafe.ai)进行判定,Jev 是一个 System One 模型,返回校准过的概率而不是生成的文本。无需索引、无需嵌入、无需向量列。

网站:pgjev.com(https://pgjev.com)

CREATE EXTENSION jev CASCADE;

SELECT * FROM people WHERE jev(people, 'the name is European');

SELECT subject, jev_prob(tickets, 'the customer is angry') AS p
FROM tickets
ORDER BY p DESC
LIMIT 20;

SELECT jev_choice(tickets, 'which team should handle this?',
                  ARRAY['billing', 'technical', 'security', 'sales']) AS team,
       count(*)
FROM tickets
GROUP BY 1;

SELECT name,
       jev_score(products, 'how luxurious is this product?',
                 ARRAY['budget', 'mid-range', 'premium', 'luxury']) AS luxury
FROM products
ORDER BY luxury DESC;

jev() 是一个普通的布尔函数,因此它可以与 SQL 中的其他一切组合使用:AND age > 40、JOIN、GROUP BY、LIMIT、ORDER BY jev_prob(...)。

工作原理

  1. jev(table, 'condition') 将数据行作为复合值接收。对于某个表 + 条件的首次调用会启动一个预读(read-ahead),按物理顺序流式读取表(TID 范围扫描;视图使用 OFFSET 分页),因此无论表多大,内存占用都保持恒定。

  2. 数据行按 jev.batch_size(默认 20)每请求打包成一个共享的 state({"condition": ..., "rows": [...]}),每行对应一个 Yes/No 的 Noul(https://docs.typesafe.ai/primitives/noul)问题。Jev 在一个 state 上并行评估所有问题,这摊薄了约 270 token 的请求开销(单行单独请求约需 435 token,而批量为 20 时每行仅需约 175 token)。

  3. 最多同时有 2 × jev.concurrency 个请求通过持久 HTTPS 连接处于飞行中(in-flight),并且每一批返回后就立即回答对应的行。因此 LIMIT 会在飞行窗口之外停止预读,而在 jev() 执行前就被更便宜的谓词过滤掉的行(如 WHERE age > 60 AND jev(...))会被跳过,而不会送去判定。

  4. 答案会按行内容在会话内缓存,因此重新执行、更改阈值或按概率排序都是免费的。来自子查询或 CTE(匿名 record 类型)的行无法预读,只能每次请求一个请求地判定;尽可能把 jev() 用在基表或视图上。

在一个来自欧洲的 2,000 行表上的实测(到 API 约 190 ms):首次运行 ≈ 3.5 秒,共发出 100 个请求,约 296k 输入 token,约 $0.012;第二次运行 ≈ 50 ms;对新条件执行 LIMIT 3 ≈ 0.6 秒。在会话中仍持有池化连接(空闲时间少于 jev.keepalive)时使用新条件 ≈ 2.3 秒:每条新连接上的首个请求是最慢的。版本 0.1.0 完整查询需要 8.5 秒(338k token),LIMIT 需要 8.4 秒。

为什么是每请求 20 行?

Jev 需要在数组中按位置找到 rows[i],而在长数组中这变得不可靠。以结构化列作为基准真相(职位名称、欧盟成员身份、自由文本字段中的某个短语;各 400 行)进行测试,1–20 行的批次准确率为 100%,40 行的批次为 92–98%,80 行的批次为 77–94%。即使行更宽(1,000 字符),在 20 行时也没有差异。给行命名而不是用索引引用也没有帮助。20 行的批次比 40 行的批次多花 4% 的 token,但速度一样快,因为请求的延迟几乎不受大小影响。

安装

要求:PostgreSQL 14–17,带 plpython3u(Debian/Ubuntu 上为包 postgresql-plpython3-NN,EDB 和 Postgres.app 构建中已包含),一个超级用户,以及来自 https://console.typesafe.ai 的 TypeSafe API 密钥。不提供超级用户权限或 plpython3u 的托管主机(Supabase、Neon、RDS 等)无法运行它;参见 Where it runs(https://pgjev.com/docs/getting-started/where-it-runs)。

通过 AI 代理安装(最简单)

仓库自带一个 agent skill,可通过 skills.sh(https://skills.sh)安装。将它安装到你的项目中,然后让 Claude Code、Codex、Cursor 或任何其他支持 skill 的代理来完成工作:

npx skills add realZachi/pg-jev

在这台服务器上安装 pgjev 并完成配置。

代理会运行预检(PostgreSQL 版本、plpython3u、超级用户权限),针对正确的 pg_config 执行 pgxn install jev 或 make install,执行 CREATE EXTENSION jev CASCADE,放置 API 密钥并运行冒烟测试。之后它还知道如何编写注重成本的 jev() 查询(“找出客户威胁要取消订阅的工单”),以及如何解释 pgjev 能做什么。文档也可以作为 Markdown 供代理阅读:在 https://pgjev.com/docs 下的任何页面后追加 .md 即可(参见 For agents(https://pgjev.com/docs/for-agents))。

通过 PGXN 安装

pip install pgxnclient   # 仅需一次;Debian/Ubuntu 和 Homebrew 中也可用 `pgxn-client`
pgxn install jev         # 从 pgxn.org 下载发行版,并对 PATH 上的 pg_config 运行 `make install`
psql -c "CREATE EXTENSION jev CASCADE"

当服务器上的 pg_config 不在 PATH 上,或扩展目录不可写时,使用 pgxn install jev --pg_config=/path/to/pg_config(或 sudo pgxn install jev)。

从源码编译(PGXS)

git clone https://github.com/realZachi/pg-jev.git && cd pg-jev
make install         # 使用 PATH 上的 pg_config;或者:make install PG_CONFIG=/path/to/pg_config
psql -c "CREATE EXTENSION jev CASCADE"   # 需要超级用户(plpython3u 是不信任语言);CASCADE 会创建 plpython3u

Docker

docker build -t pg-jev .   # 如需其他大版本,可加 --build-arg PG_MAJOR=17
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=pw -e TYPESAFE_API_KEY=your-key pg-jev
psql postgres://postgres:pw@localhost/postgres -c "CREATE EXTENSION jev CASCADE"

API 密钥

可以导出 PostgreSQL 服务器进程环境中的 TYPESAFE_API_KEY,也可以按会话或按角色设置:

SET jev.api_key = 'your-key';
ALTER ROLE analyst SET jev.api_key = 'your-key';  -- 持久化,按角色设置

函数

函数返回用途
jev(row, condition [, threshold])booleanWHERE 谓词。阈值:参数 → jev.threshold → 0.5
jev_prob(row, condition)float8该行满足条件的概率,范围 0..1
jev_score(row, question, levels text[])float8在有序层级上的概率加权位置(0 .. n-1)
jev_score_norm(row, question, levels)float8同上,归一化到 0..1
jev_choice(row, question, options text[])text该行最可能的选项
jev_confidence(row, question, kind, options)float8score/choice 答案的置信度
jev_eval(row, question, kind, options)jsonb完整的原始答案(概率、图例、置信度)
jev_stats()jsonb本会话的请求数、token 数、预估成本、缓存命中数、飞行中请求数和池化连接数
jev_cache_clear()void清除缓存的判定结果
jev_version()text扩展版本

row 是表别名本身(jev(people, ...))或子查询别名。

配置

所有配置都是普通的 GUC:SET jev.<setting> = ...、ALTER ROLE ... SET、ALTER DATABASE ... SET,或直接写在 postgresql.conf 中。

配置项默认值含义
jev.api_key环境变量 TYPESAFE_API_KEYTypeSafe API 密钥
jev.modeljev-latest模型名称或固定版本,如 jev-1.13.0
jev.threshold0.5jev() 返回 true 的概率阈值
jev.batch_size20每个 API 请求的数据行数。超过约 20–25 后准确率会显著下降(见上文)
jev.concurrency16并行 API 请求数;最多有其两倍数量的请求在执行器前方排队
jev.max_prefetch_rows5000缓存未命中时,预读会向后扫描多远以找到请求的行,以及为后续请求保留多少被跳过的行(内存上限)
jev.noticeson每个完成的请求输出一条进度 NOTICE,每个表输出一条摘要,包含请求数、token 数、预估成本和耗时
jev.api_urlhttps://api.typesafe.ai/v1/systemoneAPI 端点(可配置代理、模拟服务)
jev.timeout30每个 API 请求的超时秒数。等待是可中断的:statement_timeout 和取消请求会在 250 ms 内生效
jev.keepalive600池化的 API 连接可空闲多少秒才需要重新连接。新连接上的首个请求需要一次 TLS 握手,实测还有最多 1.5 秒的服务器端初始化,因此请让连接跨查询保持活跃;TCP keepalive 探测会发现被静默断开的连接
jev.max_rows_per_statement0(关闭)中止会向 API 发送超过此行数数据的语句。用于共享部署的费用护栏
jev.max_chars_per_statement0(关闭)同上,针对行数据的字符数

编写良好的条件

Jev 会按字面意思回答你写的问题。以下几点会有帮助(更多内容参见 TypeSafe 文档(https://docs.typesafe.ai/model-jaggedness/jev-1.13)):

  • 明确表述条件:'the customer threatens to leave, dispute a charge, or take legal action'(客户威胁要离开、对收费提出异议或采取法律行动)比 'churn risk'(流失风险)更好。
  • 把算术、日期和精确匹配留给 SQL 处理;让模型来判断语义。
  • 在确定阈值之前,先用 jev_prob() 看看分布。模糊的情况确实会落在 0.5 附近。
  • 只发送判定所需的列:创建一个包含相关列(以及任何预过滤条件)的视图,然后在视图上调用 jev(view_alias, ...)。视图与表一样会被预读和批量处理。

注意事项

  • 这是一个设计上的全表扫描:执行器询问的每一行都会发送到 API。WHERE 中更便宜的谓词会先运行,它们过滤掉的行会被跳过;LIMIT 会提前停止;jev.max_rows_per_statement 可以限制支出。
  • 行内容会发送到第三方 API。不要在你不能共享的数据上使用它。
  • 缓存存在于后端会话中(PL/Python GD)。连接池中每个会话都会各自维护自己的缓存。
  • plpython3u 是不信任语言:只有超级用户才能创建扩展,并且函数以服务器的 OS 权限运行。

开发

make docker-test  # 构建 test/Dockerfile 并运行回归测试套件(默认 PG_MAJOR=16)
make docker-test PG_MAJOR=17

在本地使用运行中的服务器和 PATH 上的 pg_config:

make install
python3 test/mock_api.py &   # TypeSafe API 的确定性替身
make installcheck  # pg_regress,测试位于 test/sql,预期输出位于 test/expected

回归测试从不调用真实 API。要尝试真实效果,设置 jev.api_key 并运行任意查询即可。

参见 CONTRIBUTING.md 和 docs/PUBLISHING.md 了解发布流程。

许可证

PostgreSQL License。Jev 和 TypeSafe 是其各自所有者的商标;本项目与 TypeSafe 无隶属关系。

相似文章

JevGPT

Product Hunt

JevGPT 是一款基于 TypeSafe 的 Jev 模型构建的聊天应用。Jev 是一款专为决策而非文本生成而设计的模型,其每条回复都是通过多项选择逐词构建而成。它是一款开源项目,被视为一次有趣但并不完美的实验。

SelfJev

Product Hunt

SelfJev 是一个可自行部署的开源 4B 决策模型,支持对任意文本提出有类型的提问(是/否、单选、多选、评分),并给出经过校准的概率;同时通过 TypeSafe 的 SDK 实现 Jev 兼容,并可用自有数据进行微调。