# JManus 存储层架构与设计思想深度解析
## 引言
JManus 作为基于 Spring AI Alibaba 构建的 AI Agent 管理系统,其存储层设计体现了现代分布式系统中数据持久化的最佳实践。本文将从架构和设计思想的角度,深入剖析 JManus 存储层的设计理念、技术选型、核心组件以及实现细节,为读者呈现一个完整的企业级存储解决方案。
## 一、整体架构概览
### 1.1 架构设计理念
JManus 存储层采用**分层解耦、多数据库支持、领域驱动设计**三大核心设计理念:
- **分层解耦**:通过 Repository 模式将数据访问逻辑与业务逻辑分离,实现关注点分离
- **多数据库支持**:支持 H2、MySQL、PostgreSQL 三种数据库,满足不同场景需求
- **领域驱动设计**:按照业务领域划分存储模块,每个领域拥有独立的实体和存储逻辑
### 1.2 技术栈选型
```mermaid
graph TD
A[Spring Boot 3.5.6] --> B[Spring Data JPA]
B --> C[Hibernate]
C --> D[H2/MySQL/PostgreSQL]
E[Spring AI] --> F[Chat Memory]
F --> G[Multi-database Support]
H[Jackson] --> I[JSON Serialization]
I --> J[Entity Conversion]
K[HikariCP] --> L[Connection Pool]
L --> M[Database Performance]
```
核心依赖:
- **Spring Data JPA 3.5.6**:提供声明式数据访问
- **Hibernate**:ORM 框架,支持自动 DDL 生成
- **HikariCP**:高性能数据库连接池
- **Jackson**:JSON 序列化与反序列化
- **Spring AI**:AI 对话内存管理
## 二、多数据库支持架构
### 2.1 数据库配置策略
JManus 采用**配置文件分离**的策略,为每种数据库提供独立的配置:
#### H2 数据库配置(开发环境)
```yaml
spring:
datasource:
url: jdbc:h2:file:./h2-data/openmanus_db;MODE=MYSQL;DATABASE_TO_LOWER=TRUE
driver-class-name: org.h2.Driver
username: sa
password: $FSD#@!@#!#$!12341234
jpa:
database-platform: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: update
```
#### MySQL 配置(生产环境)
```yaml
spring:
datasource:
url: jdbc:mysql://your-mysql-host:3306/openmanus_db?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
username: your_mysql_username
password: your_mysql_password
jpa:
database-platform: org.hibernate.dialect.MySQLDialect
hibernate:
ddl-auto: update
```
#### PostgreSQL 配置(企业环境)
```yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/openmanus_db
driver-class-name: org.postgresql.Driver
username: postgres
password: 123456
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: update
```
### 2.2 连接池优化配置
JManus 使用 HikariCP 作为连接池,提供了精细化的配置:
```yaml
spring:
datasource:
hikari:
maximum-pool-size: 20 # 最大连接数
minimum-idle: 5 # 最小空闲连接
connection-timeout: 30000 # 连接超时时间
idle-timeout: 600000 # 空闲连接超时
max-lifetime: 1800000 # 连接最大生命周期
pool-name: Spring-AI-Alibaba-JManus-${spring.profiles.active}-Pool
connection-test-query: SELECT 1
validation-timeout: 5000
leak-detection-threshold: 60000
```
### 2.3 数据库特定内存支持
JManus 为每种数据库实现了特定的聊天内存存储:
#### 抽象基类设计
```java
public abstract class JdbcChatMemoryRepository implements ChatMemoryRepository {
protected abstract String hasTableSql(String tableName);
protected abstract String createTableSql(String tableName);
protected abstract String getAddSql();
protected abstract String getGetSql();
}
```
#### H2 实现
```java
public class H2ChatMemoryRepository extends JdbcChatMemoryRepository {
@Override
protected String createTableSql(String tableName) {
return String.format(
"CREATE TABLE %s (id BIGINT AUTO_INCREMENT PRIMARY KEY, "
+ "conversation_id VARCHAR(256) NOT NULL, content LONGTEXT NOT NULL, "
+ "type VARCHAR(100) NOT NULL, timestamp TIMESTAMP NOT NULL, "
+ "CONSTRAINT chk_message_type CHECK (type IN ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL')))",
tableName);
}
}
```
#### MySQL 实现
```java
public class MysqlChatMemoryRepository extends JdbcChatMemoryRepository {
@Override
protected String hasTableSql(String tableName) {
return String.format(
"SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '%s'",
tableName);
}
}
```
#### PostgreSQL 实现
```java
public class PostgresChatMemoryRepository extends JdbcChatMemoryRepository {
@Override
protected String createTableSql(String tableName) {
return String.format(
"CREATE TABLE %s (id BIGSERIAL PRIMARY KEY, "
+ "conversation_id VARCHAR(256) NOT NULL, content TEXT NOT NULL, "
+ "type VARCHAR(100) NOT NULL, timestamp TIMESTAMP NOT NULL, "
+ "CONSTRAINT chk_message_type CHECK (type IN ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL')))",
tableName);
}
}
```
## 三、实体设计与 JPA 实现
### 3.1 实体设计原则
JManus 的实体设计遵循以下原则:
1. **领域边界清晰**:每个业务领域拥有独立的实体
2. **关系映射合理**:使用适当的 JPA 关系注解
3. **索引优化**:为频繁查询的字段添加索引
4. **数据完整性**:使用约束保证数据质量
### 3.2 核心实体架构
#### 计划执行记录实体
```java
@Entity
@Table(name = "plan_execution_record")
public class PlanExecutionRecordEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "current_plan_id", nullable = false, unique = true)
private String currentPlanId;
@Column(name = "root_plan_id")
private String rootPlanId;
@Column(name = "parent_plan_id")
private String parentPlanId;
@Column(name = "user_request", columnDefinition = "LONGTEXT")
private String userRequest;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "plan_execution_id")
private List
agentExecutionSequence;
}
```
#### Agent 执行记录实体
```java
@Entity
@Table(name = "agent_execution_record", indexes = { @Index(columnList = "step_id") })
public class AgentExecutionRecordEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "step_id", unique = true)
private String stepId;
@Column(name = "agent_request", columnDefinition = "LONGTEXT")
private String agentRequest;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "agent_execution_record_id")
private List thinkActSteps;
}
```
### 3.3 复杂类型转换
JManus 使用 JPA 属性转换器处理复杂数据类型:
```java
@Converter
public class MapToStringConverter implements AttributeConverter