Prisma Next 如何用 pgvector 扩展声明向量列并执行余弦相似度查询?
如果你已经在用 Prisma Next 管理 PostgreSQL 数据库,现在需要给表加一个向量列来存 embedding,并支持“按余弦相似度找最相似的 N 条记录”这类查询,pgvector 扩展包就是官方提供的路径。@prisma/orm-extension-pgvector 为 PostgreSQL 增加 vector 数据类型的支持以及向量相似度操作(如余弦距离),并在扩展被组成进应用时自动安装数据库端的 pgvector 扩展。当前公开包版本为 8.0.0-rc.8(见 公开发布包 package.json),本文所有步骤都围绕“声明向量列 → 安装服务端扩展 → 执行余弦相似度查询”这一条路径展开。
准备条件与安装
- 数据库是 PostgreSQL,且允许执行
CREATE EXTENSION安装 pgvector 服务端扩展; - 项目通过 Prisma Next 的
extensions机制组成扩展包。
安装公开包:
pnpm add @prisma/orm-extension-pgvector
这个包的入口点见 公开发布包 README:
| 入口点 | 用途 |
|---|---|
/pack |
组成进 extensions: [...] 的扩展 pack,纯数据、无运行时导入 |
/column-types |
向量列 author(维度化 vector 列) |
/codec-types、/operation-types |
生成的 contract 引用的类型 |
/runtime |
注册 codec 和向量操作的运行时扩展 |
/control |
控制端描述符与安装服务端扩展的 baseline migration |
注意区分:仓库内部扩展包文档(packages/3-extensions/pgvector/README.md)中的示例代码使用 @internal/... 包名;公开发布包 @prisma/orm-extension-pgvector 提供同名入口点,下文的 TS 契约示例即引自该内部 README,包名对应关系以此为准。
把扩展组成进 prisma.config.ts
在 prisma.config.ts 中导入 /control 入口并加入 extensions 数组。仓库示例应用 prisma-8-demo 的配置 是真实可运行的参考(示例中还组成了另一个 engagementStatsControl 扩展,与向量无关,可省略):
import 'dotenv/config';
import { defineConfig } from '@prisma/cli-engine';
import pgvector from '@prisma/orm-extension-pgvector/control';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';
export default defineConfig({
orm: ormConfig({
contract: './src/prisma/contract.prisma',
extensions: [pgvector],
db: {
// biome-ignore lint/style/noNonNullAssertion: loaded from .env
connection: process.env['DATABASE_URL']!,
},
}),
});
contract 指向你的契约文件,路径按你的项目调整;DATABASE_URL 需通过环境变量提供。
声明向量列
内部扩展包 README 给出的 TS 契约写法是:通过 pack ref 启用 pgvector 命名空间,并用带维度的 vector(N) 工厂声明列:
import { int4Column, textColumn } from '@internal/adapter-postgres/column-types';
import sqlFamily from '@internal/family-sql/pack';
import { defineContract, field, model } from '@internal/sql-contract-ts/contract-builder';
import { vector } from '@internal/extension-pgvector/column-types';
import pgvector from '@internal/extension-pgvector/pack';
import postgres from '@internal/target-postgres/pack';
export const contract = defineContract({
family: sqlFamily,
target: postgres,
extensions: { pgvector },
models: {
Post: model('Post', {
fields: {
id: field.column(int4Column).id(),
title: field.column(textColumn),
// Dimensioned vector — `field.embedding` resolves to `Vector<1536>`.
embedding: field.column(vector(1536)).optional(),
},
}).sql({ table: 'post' }),
},
});
关于 vector(N) 工厂,文档明确的两点:
- 每个 pgvector 列必须通过
vector(N)声明显式维度——paramsSchema在契约边界校验维度,renderOutputType据此生成contract.d.ts中的列类型; field.embedding因此解析为Vector<1536>,这是一个带维度的 brandednumber[]类型;运行时代码侧类型则是CodecTypes['pg/vector@1']['output'] = number[]。
如果沿用示例应用的 PSL 契约,向量列在 contract.prisma 中声明为 embedding Embedding1536?(可空),扩展仍然通过上面 prisma.config.ts 的 extensions 组成。
应用 baseline migration 安装服务端扩展
这一步是必做项。pgvector 包在契约空间内携带一个 on-disk baseline migration,执行内容为 CREATE EXTENSION IF NOT EXISTS vector。只要扩展已经通过 extensions 组成进应用,prisma db init 和 prisma db update 会自动应用该 baseline(以及后续迁移);如果手动建库,等价的 DDL 是:
CREATE EXTENSION IF NOT EXISTS vector;
文档强调:在运行任何使用向量列的查询之前,先确认 baseline migration(或等价 DDL)已经应用。
执行余弦相似度查询
扩展注册了 cosineDistance 和 cosineSimilarity 两个操作,对应能力键 pgvector.cosine:
cosineDistance:余弦距离,SQL 上使用 pgvector 的<=>操作符(vector1 <=> vector2),签名cosineDistance(rhs: number[] | vector): number;cosineSimilarity:余弦相似度,定义为1 - (vector1 <=> vector2)。
示例应用提供两条查询路径,都来自可运行的代码。
主路径:SQL 查询通道。similarity-search.ts 对一个查询向量检索最相似的 N 篇文章:
import { db } from '../prisma/db';
/**
* Search for posts by cosine distance to a query vector.
* Returns the top N posts ordered by similarity (closest first).
*/
export async function similaritySearch(queryVector: number[], limit = 10) {
const plan = db.sql.public.post
.select('id', 'title')
.select('distance', (f, fns) => fns.cosineDistance(f.embedding, queryVector))
.orderBy((f, fns) => fns.cosineDistance(f.embedding, queryVector), { direction: 'asc' })
.limit(limit)
.build();
return db.runtime().query(plan);
}
db 是示例应用生成后的客户端入口(src/prisma/db.ts),queryVector 是你自己的查询向量(number[]),limit 控制返回条数。距离通过 select('distance', ...) 作为结果列带出,并按距离升序排序。pack README 中还给出了参数化写法:cosineDistance(param('queryVector')) 配合 .build({ params: { queryVector } }),适合把查询向量绑定为 SQL 参数的场景。
可选路径:ORM 客户端通道。find-similar-posts.ts 演示了以“已有文章的 embedding 作为查询向量”找相似文章:先按 id 取出目标文章的 embedding,再以列上的 .cosineDistance(embedding) 作为谓词和排序键。示例中的过滤条件 .where((p) => cosineDistanceFrom(p).lt(1)) 是该演示代码使用的示例阈值,不是扩展的固定判定标准,实际取值应结合你的数据自行决定:
const cosineDistanceFrom = (fromPost: ModelAccessor<Contract, 'Post'>) =>
fromPost.embedding.cosineDistance(embedding);
return db.Post.where((p) => p.id.neq(typedPostId))
.where((p) => cosineDistanceFrom(p).lt(1))
.orderBy((p) => cosineDistanceFrom(p).asc())
.select('id', 'title', 'userId')
.limit(limit)
.all();
验证结果
- 类型层面:emit 后的 contract 类型文件中出现维度化向量类型。示例应用生成的 contract.d.ts 中即为
readonly embedding: Vector<1536> | null;,说明vector(1536)的维度元数据已进入生成的类型。 - 查询层面:运行
similaritySearch得到按距离升序排列的 top N 行(文档注释即“closest first”);若走 ORM 通道,all()返回按余弦距离升序的相似文章列表。两个示例函数都没有固定输出值,判断依据是结果包含distance/排序语义且条数不超过limit。
限制与边界
- 该 pack 面向 PostgreSQL:为“已安装 pgvector 扩展的 PostgreSQL 数据库”提供
vector类型与相似度操作,不适用于其他数据库目标; - 未带维度的向量列不被支持——
vector(N)的显式维度是描述符签名的前提; - 向量查询依赖服务端扩展:baseline migration(或
CREATE EXTENSION IF NOT EXISTS vector)未应用前,向量列的负载无法运行; - 公开包处于
8.0.0-rc.x预发布版本线,API 面以对应版本的文档和示例为准。
延伸阅读:扩展包命名与布局见 Extension-Packs-Naming-and-Layout.md,参数化类型的高阶 codec 模型见 ADR 208,示例应用的完整用法见 examples/prisma-8-demo。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00