跳转到内容

输入关键词开始搜索文档。

数据库

最后更新 查看 Markdown 源文件

Flue 将智能体对话持久存储在数据库中,通过单个文件进行配置:db.ts。本指南介绍 Flue 存储的内容、db.ts 入口模块的工作方式、默认的内存存储及其限制、内置的 sqlite() 适配器,以及 Postgres、libSQL 和其他后端的生态系统适配器。

预先说明一点:数据库是 Node.js 的关注点。在 Cloudflare 目标上,每个智能体对话都是一个 Durable Object,拥有自己内置的 SQLite 存储——无需配置,db.ts 文件在构建时会被拒绝。请参阅 Cloudflare 了解那里的存储工作方式。

Flue 存储的内容

Flue 数据库存储运行时自身的持久状态——而非你的应用业务数据。其中有三种记录:

  • 规范对话。 每个智能体对话是一条仅追加的记录流:用户消息、助手输出、工具调用和结果、压缩以及恢复事实。这条流是唯一的事实来源——后续的每一轮、每个重连的客户端、每次崩溃恢复都通过读取它来重建对话的画面。
  • 已接受的提交。 当提示或 dispatch(...) 输入被接受时,Flue 会在处理开始之前将其持久记录,同时记录声明和租约以跟踪哪个进程拥有该工作。这些行使得被接受的工作在中断后可恢复,而不是被静默丢失。
  • 持久化状态。 每次 usePersistentState 写入都会被记录在对话流中,这就是状态在对话生命周期内能够在重启后存活的原因。

附件负载(图片和其他二进制输入)作为不可变记录存储在对话旁边,规范流会引用它们。

Flue 不会 存储沙箱文件和已安装的依赖(参见 沙箱)、外部 API 副作用、提供商凭据或你应用自身的数据。持久数据库不会使沙箱持久化,持久工作区也不会保留对话历史——它们是不同的关注点。当工具写入你的应用数据库时,Flue 仅存储工具被调用及其返回值的记录。

db.ts 入口模块

要选择数据库,在项目的源码目录中创建一个 db.ts 文件,并默认导出一个持久化适配器:

src/db.ts
import { sqlite } from '@flue/runtime/node';

export default sqlite('./data/flue.db');

与 app.ts 一样,db.ts 入口通过约定发现——vite dev、vite build 和 flue run 都会从源码根目录(.flue/、src/ 或项目根目录)解析它并在启动时连接。要将其放在其他位置,请在配置文件中设置 db 路径;参见 配置。

因为该模块是普通的 TypeScript,适配器可以从环境变量读取连接字符串、构建驱动池并导出所需的内容。Flue 在启动时调用适配器的 migrate() 一次以创建或验证表,然后等待 connect()——因此不可达或配置错误的数据库会在启动时失败,而不是在第一次对话中间。

使用 start() 的独立脚本不经过构建,因此不会获取 db.ts——请通过 db 选项直接传递适配器。

默认的内存存储

没有 db.ts 时,Flue 使用内存中的 SQLite 运行。一切正常工作——对话、持久化状态、进程生命周期内的恢复——但 重启会丢失一切:每个对话、每个已接受的提交、每条状态。开发时没问题;在生产环境中,仅适用于真正可丢弃的智能体。

开发命令会软化这个默认行为:

命令没有 db.ts 时的表现
vite dev使用缓存文件(node_modules/.cache/flue/dev.db)——历史在代码重载后保留,开发服务器冷启动时重置。
flue run使用缓存文件(node_modules/.cache/flue/run.db)——永不重置,因此 --id 可以跨调用继续对话。
vite build使用内存——部署的服务器仅在进程生命周期内保留状态。

有 db.ts 时,三者都使用你的适配器,因此开发运行与生产使用相同的存储结构。

内置的 sqlite() 适配器

sqlite() 适配器随运行时发布,无需额外依赖——它运行在 Node 内置的 node:sqlite 模块上。将其指向一个文件路径以获得在重启后存活的存储:

src/db.ts
import { sqlite } from '@flue/runtime/node';

export default sqlite('./data/flue.db');

适配器在首次启动时创建文件(以及任何缺失的父目录)并以 WAL 模式打开。不带参数调用 sqlite()——或传入 ':memory:'——会得到与默认相同的内存数据库。

基于文件的 SQLite 数据库适用于单主机部署:它能在进程重启和同一台机器上的重部署中存活,但无法在主机本身丢失时存活。当状态必须在主机丢失后存活,或多个副本需要共享状态时,请使用外部数据库。

生态系统适配器

Flue 为各大数据库生态系统发布了适配器,每个都以蓝图形式提供——一份由你的编码智能体执行的 Markdown 实现指南,而非包安装器。蓝图名称是后端的小写名称:

flue add database postgres
后端适配器包
Postgres@flue/postgres
Supabase@flue/postgres
libSQL@flue/libsql
Turso@flue/libsql
MySQL@flue/mysql
MongoDB@flue/mongodb
Redis@flue/redis
Valkey@flue/redis

这些适配器共享自带驱动的设计:适配器实现 Flue 的存储契约,但它不选择、打包或配置数据库驱动。相反,你将配置好的驱动包装在一个小型运行器中——通常是一个 query 函数、一个 transaction 函数和一个 close 函数——然后交给适配器。你完全控制驱动选择、连接池、TLS 和凭据,Flue 与你应用现有的数据库通信方式共存:

src/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(),
});

每个蓝图为其生态系统的标准驱动生成一个完整的 db.ts,就像上面这样;每个生态系统页面记录了运行器契约和后端的持久化注意事项。

使用任何适配器都不需要手动运行迁移。migrate() 在首次启动时幂等地配置 Flue 的表,在重启时复用它们,并标记格式版本——不兼容的 Flue 版本写入的数据库会拒绝启动,而不是损坏状态。

共享数据库不支持主动 - 主动扩展。持久的外部数据库可以让替代进程恢复已接受的工作,可以让副本共享对话状态,但每个智能体对话仍然需要恰好一个活跃的 Node 所有者。请参阅 持久性 了解所有权规则和恢复实际回放的内容。

编写自定义适配器

如果你的后端不在目录中,可以自己实现存储契约。适配器是一个具有 connect()(返回三个存储——提交、对话流和附件)的对象,加上可选的 migrate() 和 close();类型定义在 @flue/runtime/adapter 中:

import type { PersistenceAdapter } from '@flue/runtime/adapter';

export default {
  migrate() {
    /* 创建或验证后备存储 */
  },
  connect() {
    return { submissionStore, conversationStreamStore, attachmentStore };
  },
  close() {
    /* 释放连接 */
  },
} satisfies PersistenceAdapter;

该契约有严格的原子性和排序要求——幂等准入、围栏化生产者声明、仅追加流——因此请将数据持久化 API 作为规范,并使用 @flue/runtime/test-utils 中的契约测试套件来测试你的实现。它们是每个内置适配器都通过的验收测试。

选择数据库

场景选择
本地开发使用默认值——仅在需要针对生产存储开发时添加 db.ts
单主机 Node 部署基于文件的 sqlite()
状态必须在主机丢失后存活,或有多个副本生态系统适配器,每个对话路由一个活跃所有者
Cloudflare 部署无需配置——Durable Object SQLite 是自动的
目录中没有的后端自定义 PersistenceAdapter

后续步骤