基于 Oracle Database 构建 Mastra 存储与向量检索:@mastra/oracledb 全解析
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
导读
@mastra/oracledb是 Mastra 官方提供的 Oracle Database 存储与向量检索 Provider。它利用 Oracle 原生 JSON、VECTOR数据类型、连接池与事务能力,为 Mastra Agent 提供**存储(Storage)与向量相似度搜索(Vector Search)**双引擎能力。本文基于仓库 stores/oracledb 的 README 与源码实现,系统讲解其安装、连接配置、存储 API、向量索引与检索、Schema 管理及本地测试方案,帮助你快速将 Oracle 数据库接入 Mastra 应用,并在生产环境中正确使用 Oracle 向量搜索。
一、认识 @mastra/oracledb
Mastra 是一个面向 AI 应用与 Agent 的 TypeScript 框架,@mastra/oracledb是它官方的 Oracle Database 数据层集成包。包的核心能力在 README.md 中定义:基于 Oracle JSON、OracleVECTOR数据类型、连接池(connection pooling)与事务支持,提供存储和向量相似度搜索。
从包结构上看,它实际导出两大对象(见 src/index.ts):
OracleStore:Mastra 通用存储实现,负责线程(thread)、消息(message)、资源(resource)、工作流快照、可观测性(spans/logs)、评分(scores)、MCP 客户端注册与 Agent 注册等多个存储域;OracleVector:Mastra 向量存储实现,基于 Oracle 23ai 的VECTOR数据类型与向量索引(HNSW / IVF),提供 upsert、query、delete、update 等向量 API。
两者共用同一个 OraclePoolManager 连接池管理器,共享生命周期。另外还导出:
ORACLEDB_PROMPT:供 LLM 构造合法向量过滤条件的提示词模板;OracleConnectionConfig等类型;- 完整的 schema 导出工具
exportSchemas。
前置条件:该包依赖
oracledb ^6.10.0(node-oracledb),要求 Node.js >= 22.13.0(见 package.json)。向量功能依赖 Oracle Database 23ai 的VECTOR类型;存储功能兼容更广泛的 Oracle 版本,但以 23ai 为推荐基线。
二、安装
在 Mastra 项目中安装:
npm install @mastra/oracledb包的类型定义与运行时入口见 package.json 的exports字段:import对应 ESM 构建dist/index.js,require对应 CJS 构建dist/index.cjs,同时导出./package.json。
包以@mastra/core(>=1.61.0-0, <2.0.0-0)作为 peer 依赖,使用时需确保核心包版本匹配。仓库内的集成测试还提供了 Docker 一键启动 Oracle Free 23ai 的方式(详见下文"本地测试"一节),可作为本地开发环境的参考。
三、连接配置与连接池
3.1 OracleStore 基础用法
README 中的最小示例(存储部分):
import { OracleStore } from '@mastra/oracledb'; const store = new OracleStore({ id: 'oracle-store', user: process.env.ORACLE_DATABASE_USER, password: process.env.ORACLE_DATABASE_PASSWORD, connectString: process.env.ORACLE_DATABASE_CONNECT_STRING, }); await store.init(); const memory = await store.getStore('memory'); if (!memory) throw new Error('Oracle memory store is not available'); // 创建线程 await memory.saveThread({ thread: { id: 'thread-123', resourceId: 'resource-456', title: 'My Thread', metadata: { key: 'value' }, createdAt: new Date(), }, }); // 向线程追加消息 await memory.saveMessages({ messages: [ { id: 'msg-789', threadId: 'thread-123', role: 'user', content: { content: 'Hello' }, resourceId: 'resource-456', createdAt: new Date(), }, ], }); // 查询线程与消息 const savedThread = await memory.getThreadById({ threadId: 'thread-123' }); const { messages } = await memory.listMessages({ threadId: 'thread-123' });await store.init()会触发一次幂等的 schema 迁移(migration),随后即可通过store.getStore('memory')获取内存域进行操作。
3.2 连接参数全表
OracleConnectionConfig定义于 src/shared/connection.ts,包含以下字段:
| 参数 | 类型 | 说明 |
|---|---|---|
user | string | 数据库用户名。使用externalAuth时可省略 |
password | string | 数据库密码。使用externalAuth时可省略 |
connectString | string | 连接串(host:port/service_name),必填(除非传入pool) |
pool | Pool | 外部传入的 node-oracledb 连接池;传入后由外部管理生命周期 |
poolMin | number | 池最小连接数,默认0 |
poolMax | number | 池最大连接数,默认4 |
poolIncrement | number | 池扩容步长,默认1 |
configDir | string | Oracle Wallet / TNS 配置目录(可选) |
walletLocation | string | Oracle Wallet 目录(可选) |
walletPassword | string | Wallet 密码(可选) |
externalAuth | boolean | 启用外部认证(OS / Kerberos / Wallet TLS),此时可省略用户名密码 |
校验规则(validateOracleConnectionConfig):
- 若未传入
pool,则必须提供connectString,且除非externalAuth为 true 否则必须提供user; - 除非
externalAuth开启,否则password必填。
3.3 连接池生命周期
OraclePoolManager采用懒加载 + Promise 记忆化策略:首次getPool()时才调用oracledb.createPool(),创建失败会重置内部 Promise,避免一次性故障永久污染管理器(见 connection.ts)。
withConnection(callback)负责连接的获取与归还,事务所有权仍归调用方——它只管理 acquire/release(见 connection.ts)。
OracleStore与OracleVector都支持两种池管理方式:
- 自建池:不传
poolManager,由 Provider 内部创建;调用disconnect()/close()时自动关闭池; - 共享池:通过
poolManager注入同一个OraclePoolManager实例,让存储与向量共享一个连接池,并由外部统一管理生命周期(ownsPool为 false 时close()不会关闭外部池)。
从源码结构可以推断:生产环境推荐共享池模式——OracleStore与OracleVector各自只持有一个OraclePoolManager引用,共享后能显著减少连接数。
四、OracleStore:存储域与自动迁移
4.1 七个存储域
OracleStore继承 Mastra 的MastraCompositeStore,构造时一次性装配 7 个存储域(见 src/storage/index.ts):
| 域 | 职责 |
|---|---|
memory | 线程、消息、资源、工作记忆(working memory)、观测记忆(observational memory) |
workflows | 工作流快照(durable workflow 状态) |
observability | spans 与日志事件(Mastra 可观测性) |
scores | 评分与评估结果 |
scorerDefinitions | Scorer 定义注册表 |
mcpClients | MCP 客户端注册表 |
agents | Agent 注册表 |
每个域均为独立的 Oracle 领域实现(如MemoryOracle、WorkflowsOracle),共享同一个OraclePoolManager,从而保证连接池统一、域间隔离。
4.2 自动迁移机制
init()触发幂等迁移:runMigrations依次执行 7 个 repeatable 迁移(R001_MEMORY_SCHEMA 到 R007_AGENTS_SCHEMA),每个迁移声明自己管理的表集合(MANAGED_TABLES),迁移内容为对应域的init()DDL(见 src/storage/index.ts)。
迁移是可重复执行的(repeatable类型):每次运行都会计算包含索引配置在内的 SHA-256 校验和(domainMigrationChecksum),当 DDL 或索引配置变化时才会重新应用。迁移记录写入migrationTableName(默认常量见DEFAULT_ORACLE_MIGRATIONS_TABLE),多个逻辑 Mastra 部署共享同一 Oracle schema 时可覆盖该表名。
DDL 执行封装在 connection.ts 的executeDdl中:对 Oracle 在线 DDL 常见的锁冲突错误码(-54、-14411)采用 100ms 到 1500ms 的指数退避重试。
4.3 OracleStoreConfig 配置项
OracleStoreConfig定义于 src/storage/types.ts,除连接参数外还包括:
| 参数 | 说明 |
|---|---|
id | 存储实例标识 |
schemaName | 目标 Oracle schema 名(默认当前用户 schema) |
poolManager | 共享连接池管理器(可选) |
messageBatchSize | 每次executeMany写入的消息条数;整个saveMessages在事务边界只提交一次 |
skipDefaultIndexes | 为 true 时不创建默认性能索引(适合 DBA 单独管理索引的场景) |
indexes | 初始化时创建的 Oracle 原生自定义索引列表,按目标表路由到所属域 |
migrationTableName | 迁移记录表名(多部署共享 schema 时覆盖) |
vectorRegistryTableName | 与OracleVector.registryTableName一致时,用于消息/线程删除时发现语义召回向量表 |
disableInit | 禁用自动初始化(继承自MastraCompositeStoreConfig) |
4.4 CLOB 与 JSON 的底层处理
Mastra 的富文本字段(消息 content、instructions、workingMemory、observational memory 等)在 Oracle 中存储为CLOB;查询时通过fetchInfo配置将这些 CLOB 以字符串形式拉取,简化领域映射(见 connection.ts)。
JSON 字段使用 Oracle 原生 JSON 类型。写入时,jsonBind将 JSON 对象序列化为文本后绑定为DB_TYPE_VARCHAR,由服务端编码为 OSON 二进制格式(见 connection.ts)。源码注释指出:若由 node-oracledb 瘦驱动客户端编码,其生成的 OSON 头部标志会导致 DBeaver/DataGrip/SQL Developer 渲染报UnsupportedOperationException,因此特意将编码移到服务端——这保证了第三方工具的可读性。
此外,safeJsonStringify会递归清理运行时对象:丢弃函数、symbol、循环引用,bigint 转为字符串,确保 JSON 列只写入 JSON 安全值。
五、OracleVector:向量索引与检索
5.1 快速上手
import { OracleVector } from '@mastra/oracledb'; const vector = new OracleVector({ id: 'oracle-vector', user: process.env.ORACLE_DATABASE_USER, password: process.env.ORACLE_DATABASE_PASSWORD, connectString: process.env.ORACLE_DATABASE_CONNECT_STRING, }); // 创建索引(dimension 与向量维度一致) await vector.createIndex({ indexName: 'my_vectors', dimension: 1536, metric: 'cosine', indexConfig: { type: 'hnsw', accuracy: 95 }, metadataIndexes: ['thread_id', 'resource_id'], }); // 写入向量 await vector.upsert({ indexName: 'my_vectors', vectors: [[0.1, 0.2, ...]], metadata: [{ thread_id: 't1', text: 'hello' }], }); // 查询(精确 / 近似检索) const results = await vector.query({ indexName: 'my_vectors', queryVector: [0.1, 0.2, ...], topK: 10, filter: { thread_id: 't1' }, queryMode: 'approx', });5.2 向量索引模型
OracleVector的数据模型(见 src/vector/ddl.ts)由三层组成:
- 逻辑索引:面向 Mastra 的 API 名称(
indexName); - 物理表:每个逻辑索引对应一张专用
VECTOR表,表名 =tablePrefix+ 索引名规范化后的结果(默认前缀MASTRA_VEC,见DEFAULT_TABLE_PREFIX)。表结构为vector_id、embedding VECTOR(dimension, format)、metadata JSON、时间戳列; - 注册表:
MASTRA_VECTOR_INDEXES(DEFAULT_REGISTRY_TABLE)记录逻辑索引到物理对象的映射(index_name、table_name、dimension、metric、index_type、vector_format、accuracy 等),是映射的"事实来源"(source of truth)。
5.3 索引类型、向量格式与度量
相关类型定义见 src/vector/types.ts:
- 索引类型
OracleVectorIndexType:hnsw|ivf|none。none表示不建近似索引,仅用精确VECTOR_DISTANCE搜索; - 向量格式
OracleVectorFormat:vector(默认,float32 向量)|bit(二进制向量)|int8(量化向量); - 度量
OracleMetric:cosine|euclidean|dotproduct|hamming|jaccard; - 查询模式
OracleQueryMode:approx(近似检索)|exact(精确检索)。
OracleVectorIndexConfig支持:
{ type?: 'hnsw' | 'ivf' | 'none', accuracy?: number, // 目标精度,默认 95(%) hnsw?: { neighbors?: number, efConstruction?: number }, ivf?: { neighborPartitions?: number }, }创建索引时默认accuracy: 95。createIndex支持vectorFormat、indexConfig、buildIndex(是否同步创建物理向量索引,默认 true)与metadataIndexes(为常见元数据字段创建JSON_VALUE函数索引,默认thread_id、resource_id、message_id、source_id,见DEFAULT_METADATA_INDEXES)。
物理索引 DDL 形态(由vectorPhysicalIndexStatement生成,见 schema.ts):
CREATE VECTOR INDEX ... ON ... (embedding) ORGANIZATION INMEMORY NEIGHBOR GRAPH -- HNSW -- 或 ORGANIZATION NEIGHBOR PARTITIONS -- IVF DISTANCE COSINE WITH TARGET ACCURACY 95IndexRegistry内部还维护每个逻辑索引一把锁(indexLocks),防止两个调用方并发创建/删除同一索引;并提供索引元数据缓存(indexInfoCache)减少重复查询。
5.4 写入路径:upsert / update / delete
upsert:默认每批 200 条向量(DEFAULT_VECTOR_UPSERT_BATCH_SIZE,可用upsertBatchSize覆盖),使用executeMany批量写入;deleteFilter+ upsert 在同一事务内完成,避免索引部分刷新(见 src/vector/upsert.ts);- 不传
ids时自动生成 UUID; updateVector/deleteVector/deleteVectors均基于vector_id与元数据过滤条件实现;- 当前版本不支持稀疏向量(
sparseVector/sparseVectors会直接报错),仅支持稠密向量。
5.5 查询路径:精确与近似检索
查询实现在 src/vector/query.ts:
- 核心距离计算使用
VECTOR_DISTANCE(embedding, :queryVector, <metric>),再转换为 Mastra 的 score 语义; - 默认查询模式:
indexType === 'none'时为exact,否则为approx;可通过queryMode显式覆盖; filter通过buildMetadataWhereClause编译为 SQL 谓词,支持纯元数据召回(不传 queryVector 时);- 支持
minScore(默认 -1)过滤与includeVector(返回 embedding 原文); - Oracle 近似检索要求
ORDER BY与FETCH位于同一查询块,实现遵循该约束以保证走索引。
5.6 元数据过滤:支持的运算符
元数据存储为 Oracle JSON。ORACLEDB_PROMPT(见 src/vector/prompt.ts)明确定义了可用的过滤运算符与编译规则,并随包导出,供 Agent 在生成过滤条件时遵循:
编译规则:
- 标量比较 →
JSON_VALUE(metadata, ...); - 数组/存在性/元素匹配 →
JSON_EXISTS(metadata, ...); - 正则 → Oracle
REGEXP_LIKE; - 字符串包含 → 大小写不敏感的
LIKE; - 所有用户元数据值一律作为绑定参数,不允许在过滤器中内嵌原始 SQL。
运算符清单:
| 类别 | 运算符 | 说明 | 示例 |
|---|---|---|---|
| 比较 | $eq | 精确匹配(默认) | { "category": "electronics" } |
$ne | 不等于 | { "category": { "$ne": "electronics" } } | |
$gt/$gte | 大于 / 大于等于 | { "price": { "$gt": 100 } } | |
$lt/$lte | 小于 / 小于等于 | { "price": { "$lt": 100 } } | |
| 数组 | $in/$nin | 属于 / 不属于 | { "category": { "$in": ["electronics", "books"] } } |
$all | 数组包含全部 | { "tags": { "$all": ["premium", "sale"] } } | |
$elemMatch | 数组元素满足条件 | { "items": { "$elemMatch": { "price": { "$gt": 100 } } } } | |
$contains | 字符串子串 / 数组包含 | { "title": { "$contains": "oracle" } } | |
| 逻辑 | $and/$or | 与 / 或 | { "$or": [{ "price": { "$lt": 50 } }, ...] } |
$not/$nor | 非 / 或非 | { "$not": { "category": "electronics" } } | |
| 元素 | $exists | 字段是否存在 | { "rating": { "$exists": true } } |
| 特殊 | $size | 数组长度 | { "tags": { "$size": 2 } } |
$regex | 正则(REGEXP_LIKE) | { "source": { "$regex": "oracle.*database" } } |
使用限制(来自ORACLEDB_PROMPT):
- 嵌套字段使用点号(dot notation)访问;
- 顶层只能使用逻辑运算符(
$and/$or/$not/$nor),其余运算符必须位于字段条件内; - 逻辑运算符只能出现在顶层或嵌套在其他逻辑运算符中,不能位于字段内部;
$not必须是非空对象,可用于字段级或顶层;$elemMatch必须接收带条件的对象。
5.7 运维与诊断 API
configureVectorMemory({ size, scope }):为本地/自管数据库配置 Vector Pool 内存(MEMORY|SPFILE|BOTH),HNSW 构建前需要;getIndexStatus({ indexName }):查看索引稳态 catalog 状态;indexAccuracyQuery({ indexName, queryVector, topK, targetAccuracy }):近似索引的精度诊断;listIndexes()/describeIndex():枚举与描述索引;disconnect()/close():释放连接池。
六、Schema 导出:面向 DBA 的离线 DDL
exportSchemas()(见 src/schema.ts)可离线导出与运行时迁移完全一致的 DDL,供 DBA 审阅或预建 schema:
import { exportSchemas } from '@mastra/oracledb'; const sql = exportSchemas({ schemaName: 'MASTRA', domains: ['memory', 'workflows', 'observability', 'vector'], vector: { indexes: [ { indexName: 'doc_embeddings', dimension: 1536, metric: 'cosine', indexConfig: { type: 'hnsw', accuracy: 95 } }, ], }, }); console.log(sql);ExportOracleSchemasOptions支持schemaName、domains(migrations/memory/workflows/observability/scores/scorerDefinitions/mcpClients/agents/vector)、skipDefaultIndexes、indexes(自定义索引)与vector配置。域输出顺序固定:migrations → 存储域 → vector,与运行时初始化路径一致。
导出的 DDL 与运行时实现共享同一套表结构,例如 memory 域的messages表包含content CLOB NOT NULL、role VARCHAR2(64)等 Oracle 专属类型选择(见 schema.ts);vector 注册表插入使用MERGE INTO,保证 DDL 可重复执行而不产生重复注册行。
七、本地测试:Docker 启动 Oracle 23ai
仓库自带 docker-compose.yaml,用于集成测试与本地开发:
export ORACLE_DATABASE_USER=mastra export ORACLE_DATABASE_PASSWORD=yourpassword docker compose up -d --wait # 如需使用 HNSW 向量索引,重启一次使 Vector Pool 生效: docker compose restart db容器使用gvenzl/oracle-free:23-slim-faststart,通过环境变量注入用户/密码,并把 scripts/configure-vector-memory.sql 挂载到初始化目录以持久化VECTOR_MEMORY_SIZE。
需要注意:VECTOR_MEMORY_SIZE只有在数据库重启后才生效。不重启的情况下,Vector Pool 为 0:精确检索(默认)与 IVF 索引仍可工作,只有 HNSW 索引构建需要这一步(docker-compose 注释明确说明)。
包脚本(见 package.json):
pnpm test:unit:单元测试(vitest,排除集成测试);pnpm test:integration:先docker compose up -d --wait,再分别运行存储与向量集成测试,最后docker compose down -v清理;pnpm typecheck/pnpm lint:类型检查与 ESLint。
八、与 Mastra 生态的集成方式
8.1 与 Agent 内存集成
OracleStore通过getStore('memory')返回内存域,可与 Mastra 的Memory组合使用:
import { Memory } from '@mastra/memory'; const memory = new Memory({ storage: store }); await memory.init();8.2 共享连接池模式
当存储与向量需要共享连接池时,注入同一个OraclePoolManager:
import { OraclePoolManager } from '@mastra/oracledb'; const poolManager = new OraclePoolManager({ user: process.env.ORACLE_DATABASE_USER, password: process.env.ORACLE_DATABASE_PASSWORD, connectString: process.env.ORACLE_DATABASE_CONNECT_STRING, poolMax: 10, }); const store = new OracleStore({ id: 'oracle-store', poolManager }); const vector = new OracleVector({ id: 'oracle-vector', poolManager }); // 应用退出时统一释放 await store.close(); await vector.close();8.3 与 RAG 集成
OracleVector继承 Mastra 的MastraVector基类,实现了upsert/query/deleteVector等标准向量接口,可无缝替换默认向量库,用于文档嵌入、语义检索、Memory 的语义召回等 RAG 场景。
九、总结
@mastra/oracledb将 Oracle Database 的能力完整桥接进 Mastra 生态:
- 存储侧:
OracleStore覆盖 7 个存储域,自动迁移、批处理写入、CLOB/JSON 正确编码,可直接作为 Mastra Memory、工作流、可观测性、评估与 Agent 注册的持久化后端; - 向量侧:
OracleVector基于 Oracle 23ai 原生VECTOR类型,支持 HNSW/IVF 近似索引与精确检索、多种度量与向量格式、完整的 JSON 元数据过滤语法,并提供索引状态与精度诊断工具; - 工程化:共享连接池、幂等迁移、离线 DDL 导出、Docker 一键测试环境,兼顾了开发效率与生产可维护性。
如果你的团队已经运行 Oracle 数据库,@mastra/oracledb提供了一条无需引入额外基础设施即可获得 AI 存储与向量检索能力的路径。
延伸阅读
- 包文档与版本历史:CHANGELOG.md
- 连接池与连接配置实现:src/shared/connection.ts
- 存储域实现:src/storage/
- 向量实现:src/vector/
- Schema 导出:src/schema.ts
- 本地开发环境:docker-compose.yaml、scripts/configure-vector-memory.sql </output文章>
【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考