Postgres
快速开始
使用 Postgres 蓝图为现有 Flue 项目添加持久化共享 Postgres 存储。在终端或你选择的编码智能体中运行以下命令:
flue add database postgres
概述
Postgres 蓝图会安装 @flue/postgres 并重用现有的 Postgres 驱动,或者默认添加 pg 和匹配的 @types/pg 开发依赖。它会在源代码根目录创建 db.ts,并在项目已有环境文档时更新它。默认生成的适配器使用连接池进行普通查询,并为每个事务保持在一个签出的连接上:
import { postgres } from '@flue/postgres';
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export default postgres({
query: async (text, params) => (await pool.query(text, params)).rows,
transaction: async (fn) => {
const client = await pool.connect();
try {
await client.query('BEGIN');
const result = await fn({
query: async (text, params) => (await client.query(text, params)).rows,
});
await client.query('COMMIT');
return result;
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
},
close: () => pool.end(),
});Flue 在构建时发现适配器并将其连接到生成的 Node 服务器。启动时,它会创建或验证所需的 flue_* 表。规范的智能体对话、不可变附件和已接受的提交随后会在进程替换后得以保留。副本可以共享持久状态,但每个智能体实例仍然需要一个活动的 Node 所有者;Postgres 不启用主动 - 主动的同实例执行。应用业务数据仍由应用自行管理。此蓝图仅适用于 Node 目标,因为 Cloudflare 部署使用 Durable Object SQLite。
配置
| 变量 | 用途 |
|---|---|
DATABASE_URL | 必需 — Postgres 连接字符串,例如 postgresql://user:pass@host:5432/db。 |
你的驱动在运行时读取 DATABASE_URL — 它不会被烘焙到构建中。对于本地开发,vite dev 会加载项目 .env 文件,而 flue run --env <file> 会选择替代的 .env 格式文件。在生产环境中,请从你平台的密钥存储中提供它。
蓝图默认使用 pg 安装 @flue/postgres,并在源代码根目录创建包装它的 db.ts。Flue 在构建时发现 db.ts 并将其连接到生成的 Node 服务器。运行命令后,规范的智能体对话、不可变附件和已接受的提交会持久化到 Postgres,而不是内存状态。
@flue/postgres 是一个 Node.js 适配器。Cloudflare 目标会自动使用 Durable Object SQLite,并在构建时拒绝 db.ts 文件,因此本指南适用于 Node 部署。有关每个目标如何存储状态的完整信息,请参阅数据库。
使用自定义驱动
@flue/postgres 不会选择或捆绑数据库驱动。它运行在你围绕已配置驱动包装的小型运行器上,因此你拥有驱动选择、连接池、TLS 和所有其他连接选项。运行器包含三个函数:query(带编号 $N 占位符的 SQL 字符串加上位置参数,返回结果行)、transaction(在一个连接上的一个事务中运行其回调)和 close。
使用 pg(node-postgres)时,transaction 会签出一个客户端并自行发出 BEGIN/COMMIT/ROLLBACK — 连接池无法跨任意连接运行事务:
import { postgres } from '@flue/postgres';
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export default postgres({
query: async (text, params) => (await pool.query(text, params)).rows,
transaction: async (fn) => {
const client = await pool.connect();
// ...
},
close: () => pool.end(),
});相同的接缝可以适配支持在一个连接上进行交互式事务的驱动。对于 Neon,请使用其 WebSocket Pool;HTTP 查询客户端无法实现此回调事务契约。
迁移
适配器的 migrate() 钩子会在生成的 Node 服务器启动时自动运行。它会幂等地创建 Flue 的 flue_* 表并标记格式版本,因此首次启动时会配置新数据库,重启时会重用现有数据库。没有单独的迁移命令需要运行,由较新 Flue 版本写入的数据库会拒绝启动,而不是损坏状态。
存储内容
Flue 数据库存储运行时状态,而不是整个应用。
由 Flue 存储:
- 规范的智能体对话流和压缩记录;
- 不可变附件负载;
- 已接受的直接提示和
dispatch(...)提交; - 持久化提交声明、租约和结算记录。
不由 Flue 存储:
- 沙盒文件和已安装的依赖项;
- 外部 API 副作用;
- 应用拥有的业务数据,除非你自己的工具存储它;
- 提供商凭证或密钥。
提交行是使已接受的工作在中断后可恢复的关键。有关恢复如何使用它们的信息,请参阅持久性, 有关确切适配器契约的信息,请参阅数据持久化 API。
何时选择 Postgres
| 用例 | 适配器 |
|---|---|
| 本地开发,或不需要重启持久性 | 来自 @flue/runtime/node 的 sqlite()(文件路径或内存) |
| 单主机 Node 部署 | 文件支持的 sqlite() |
| 多副本 Node 部署,或状态必须在主机丢失后保留 | @flue/postgres,每个智能体实例一个活动所有者 |
| Cloudflare 部署 | 内置 Durable Object SQLite(无 db.ts) |
当替换进程必须恢复已接受的工作时,当副本需要共享对话状态时,或者当单个主机的磁盘不是状态足够持久的存储位置时,请选择 Postgres。为每个智能体实例保留一个活动所有者,并在副本之间使用实例亲和路由。托管的 Postgres 与容器部署目标自然配对 — 有关 RDS 的信息,请参阅在 AWS 上部署, 有关在服务器旁边配置数据库的信息,请参阅其他部署指南。