- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- Agent 工作流
- RAG
- MCP Clients
- 强化学习
【免费下载链接】agent-core-java
openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。
AddColumnOperation是 openJiuwen agent-core-java 记忆(LongTermMemory)SQL 迁移体系中的核心操作对象,它以纯数据对象(DTO)的形式描述一次"新增数据库列"的变更意图。本文将以 AddColumnOperation.md 为骨架,结合memory模块源码、SqlMigrator执行器与测试用例,完整讲解该操作的字段语义、构造方式、执行链路与实战约束,帮助你在为记忆库 SQL 表演进 schema 时正确使用它。
一、AddColumnOperation 是什么
在 openJiuwen 的记忆引擎中,长期记忆数据既可以落盘到 SQL 数据库(如 H2、MySQL、SQLite),也可以存放到向量库或 KV 存储。为了让存储结构随产品迭代平滑演进,com.openjiuwen.memory.migration提供了一套声明式迁移框架:迁移以"操作对象"为单位描述变更,由注册表按版本组织,最终交给对应的 Migrator 执行。
AddColumnOperation就是这套框架中描述SQL 新增列的操作对象。它在 AddColumnOperation.java 中定义,继承自纯 DTO 基类BaseOperation,本身不包含任何执行逻辑,只负责承载"在哪张表、加哪一列、什么类型、是否可空、默认值是什么"这些信息。真正的执行由 SqlMigrator.java 完成。
public class AddColumnOperation extends BaseOperation从源码注释可以确认,该实现对应 Python 版 openjiuwen 的AddColumnOperation(openjiuwen/core/memory/migration/operation/operations.py),两者保持语义一致。
二、核心字段与语义
AddColumnOperation共持有 5 个业务字段,语义如下:
| 字段 | 类型 | 说明 |
|---|---|---|
table | String | 目标表名。 |
columnName | String | 新增列名。 |
columnType | String | 新增列的 SQL 类型(逻辑类型名,见下方类型映射)。 |
nullable | boolean | 新增列是否允许NULL。 |
defaultValue | Object | 新增列的默认值;可为null。 |
2.1 columnType 的逻辑类型与 SQL 类型映射
columnType传入的是逻辑类型名(如"STRING"、"INTEGER"),SqlMigrator会通过getSqlalchemyType将其转换为具体 SQL DDL 类型。完整映射关系见 SqlMigrator.java:
| 逻辑类型 | 生成的 SQL 类型 |
|---|---|
STRING/VARCHAR | VARCHAR(255) |
STRING(128)/VARCHAR(128) | VARCHAR(128)(保留参数长度) |
INTEGER/INT | INTEGER |
DATETIME/TIMESTAMP | TIMESTAMP |
BOOLEAN/BOOL | BOOLEAN |
TEXT/CLOB | CLOB |
FLOAT/DOUBLE/REAL | DOUBLE |
| 其他 / 空值 | CLOB(兜底) |
其中带参数的形式会被解析:STRING(128)会被识别为VARCHAR(128),TEXT则统一映射为CLOB(适配跨数据库方言)。
2.2 nullable 与 defaultValue 的 DDL 语义
nullable = false时,生成的 DDL 会附加NOT NULL;defaultValue非空时,生成的 DDL 会附加DEFAULT <值>,且字符串默认值会被单引号包裹并对内部单引号做转义('→''),见 SqlMigrator.java。
例如构造nullable=false, defaultValue=42的新列,最终 SQL 形如:
ALTER TABLE user_message ADD COLUMN default_col INTEGER NOT NULL DEFAULT 42三、构造方法与访问器
3.1 构造方法
AddColumnOperation提供两个构造方法:
// 便捷构造:默认 nullable = true、defaultValue = null public AddColumnOperation( OperationMetadata metadata, String table, String columnName, String columnType ) // 完整构造 public AddColumnOperation( OperationMetadata metadata, String table, String columnName, String columnType, boolean nullable, Object defaultValue )其中metadata是 OperationMetadata,封装两个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
schemaVersion | int | 本次操作对应的 schema 版本号,迁移时按此版本过滤与排序。 |
description | String | 操作描述,可空;为空时BaseOperation.getDescription()回退为类名。 |
3.2 公开方法
| 方法 | 说明 |
|---|---|
public String getTable() | 返回目标表名。 |
public String getColumnName() | 返回新增列名。 |
public String getColumnType() | 返回新增列的 SQL 类型。 |
public boolean isNullable() | 返回该列是否允许为空。 |
public Object getDefaultValue() | 返回默认值对象。 |
此外,通过基类 BaseOperation.java 还可调用getSchemaVersion()与getDescription(),它们被注册表排序和日志输出使用。
四、完整使用示例:创建并执行一次新增列迁移
4.1 单表迁移
下面以记忆库的user_message表为例,新增一列source(类型STRING、可空、默认值"manual"),并通过SqlMigrator直接执行:
import com.openjiuwen.memory.manage.mem_model.DbModel; import com.openjiuwen.memory.manage.mem_model.SqlDbStore; import com.openjiuwen.memory.migration.migrator.SqlMigrator; import com.openjiuwen.memory.migration.operation.AddColumnOperation; import com.openjiuwen.memory.migration.operation.OperationMetadata; // 1. 创建 AddColumnOperation AddColumnOperation operation = new AddColumnOperation( new OperationMetadata(2, "add source column"), DbModel.USER_MESSAGE_TABLE, // "user_message" "source", "STRING", true, "manual"); // 2. 用 SqlDbStore 构造迁移器并执行 SqlMigrator migrator = new SqlMigrator(sqlDbStore); boolean success = migrator.tryMigrate(DbModel.USER_MESSAGE_TABLE, List.of(operation)).join();执行成功后,user_message表将新增source VARCHAR(255) DEFAULT 'manual'列,且memory_meta表中该表的schema_version被更新为2。
4.2 通过 RunMigrations 统一执行
如果操作已注册到全局 SQL 注册表,可改用 RunMigrations 的静态入口统一调度:
import com.openjiuwen.memory.migration.MigrationPlan; import com.openjiuwen.memory.migration.RunMigrations; // 注册:以"实体键"为维度组织操作链,实体键需与表配置一一对应 MigrationPlan.getSqlRegistry().register("user_messages", operation); // 启动阶段统一执行 SQL 注册表中的全部迁移 RunMigrations.runSqlMigrations(sqlDbStore).join();MigrationPlan维护 SQL / 向量 / KV / 消息 / 索引五套注册表(见 MigrationPlan.java),RunMigrations.runSqlMigrations会按实体键顺序逐个调用SqlMigrator,任一实体失败则整体返回失败。
4.3 表白名单约束
SqlMigrator对可迁移的表有白名单限制:仅支持DbModelSupport.MEMORY_TABLES_CONFIG中声明的表,即:
user_message(实体键user_messages)scope_user_mapping(实体键scope_user_mapping)
相关校验见 SqlMigrator.java 与 DbModelSupport.java。对白名单之外的表执行迁移会返回false并记录错误日志。
五、注册表、版本链与幂等执行
5.1 OperationRegistry 的版本递增校验
OperationRegistry 以实体键为单位维护"递增的操作链":register时要求新操作的schemaVersion严格大于该实体当前最大版本,否则抛出MEMORY_REGISTER_OPERATION_VALIDATION_INVALID错误。这保证了同一实体的操作可以按版本顺序线性执行。
5.2 tryMigrate 的过滤与幂等
SqlMigrator.tryMigrate的执行逻辑(SqlMigrator.java)如下:
- 从
memory_meta读取该表当前schema_version; - 过滤掉版本号不高于当前版本的操作(已应用过的操作不会重复执行,天然幂等);
- 开启事务,逐个执行待执行操作;
- 全部成功后,将目标版本写回
memory_meta并commit; - 任一操作失败则
rollback并返回false。
测试 SqlMigratorTest.java 中的tryMigrateIsIdempotentForAlreadyAppliedVersion用例验证了同一操作连续执行两次不会产生重复列。
六、源码级执行原理:SqlMigrator 如何消费 AddColumnOperation
当操作链执行到AddColumnOperation时,SqlMigrator的executeOperation会分派到migrateAddColumn(SqlMigrator.java),其 SQL 拼接规则为:
ALTER TABLE <table> ADD COLUMN <columnName> <mappedType> [NOT NULL] [DEFAULT <value>]其中:
- 标识符安全校验:
table与columnName必须匹配[A-Za-z_][A-Za-z0-9_]*,否则抛出IllegalArgumentException,见requireIdentifier(SqlMigrator.java); - 方言探测:迁移器通过 JDBC
DriverName识别sqlite/h2/mysql/postgresql,见detectDialect(SqlMigrator.java); - 事务保证:迁移在单事务中执行,失败整体回滚,不会留下"列已加但版本未更新"的中间状态。
ALTER TABLE ... ADD COLUMN属于大多数数据库支持的轻量 DDL,因此新增列不需要像 SQLite 改列类型那样重建整表;SQLite 的重建策略(临时表复制数据再重命名)只用于UpdateColumnTypeOperation,与新增列无关。
七、测试用例与可验证依据
memory模块的测试直接验证了AddColumnOperation的完整行为:
- SqlMigratorTest.java
tryMigrateAddsColumnAndUpdatesMetaVersion:新增列并确认memory_meta.schema_version更新; - SqlMigratorTest.java
tryMigrateAddsColumnWithDefaultValue:验证nullable=false, defaultValue=42的INTEGER NOT NULL DEFAULT 42场景; - SqlMigratorTest.java
batchMigrateReturnsPerTableResults:验证批量迁移对user_message与scope_user_mapping两张表分别执行; - RunMigrationsTest.java
runSqlMigrationsAppliesRegisteredOperations:验证注册到MigrationPlan.getSqlRegistry()后经RunMigrations.runSqlMigrations完整落地。
这些用例均基于 H2(MODE=MySQL)内存库与 SQLite 运行,可作为理解该操作行为的可靠参考。
八、使用约束与常见注意事项
- 版本必须严格递增:同一实体键下注册的多个操作,
schemaVersion必须逐步增大,否则注册即失败。 - 仅支持白名单表:新增列目标表只能是
user_message、scope_user_mapping;自定义表需自行扩展MEMORY_TABLES_CONFIG或走应用层 DDL。 - 默认值类型:字符串默认值会自动加单引号并转义内部单引号;数值、布尔值按原样拼接,请确保传入可被目标数据库接受的类型。
- 类型映射兜底:无法识别的
columnType会映射为CLOB,声明类型前请确认符合预期。 - 迁移失败返回
false:tryMigrate失败不会抛出异常,而是返回false并记录MEMORY日志;RunMigrations则在任一实体失败时抛出迁移执行错误,便于启动阶段快速感知。
九、扩展阅读
- BaseOperation.md:所有迁移操作的抽象基类与描述回退规则;
- OperationMetadata.md:
schemaVersion与描述字段; - OperationRegistry.md:版本链注册与区间查询;
- SqlMigrator.md:SQL 迁移执行器行为说明;
- MigrationPlan.md 与 RunMigrations.md:注册表组织与统一执行入口;
- operation.README.md:operation 包全部操作类型总览。
- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- Agent 工作流
- RAG
- MCP Clients
- 强化学习
【免费下载链接】agent-core-java
openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。
相关推荐
openJiuwen 记忆引擎(LongTermMemory)实战指南:配置、读写、检索与外部记忆接入
openJiuwen 记忆引擎(LongTermMemory)实战指南:配置、读写、检索与外部记忆接入 导读 本篇文章基于 openJiuwen agent c
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen 记忆引擎 LongTermMemory 使用指南:从配置到检索的完整实战
openJiuwen 记忆引擎 LongTermMemory 使用指南:从配置到检索的完整实战 导读 LongTermMemory 是 openJiuwen(a
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen Agent 长期记忆引擎实践指南:openjiuwen.core.memory 模块全解析
openJiuwen Agent 长期记忆引擎实践指南:openjiuwen.core.memory 模块全解析 openjiuwen.core.memory
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考