1.1 稳固开发基础:Spring Boot 核心机制
自动配置原理(Auto-Configuration)
Spring Boot 的自动配置机制是其"约定优于配置"理念的核心实现。它通过 @EnableAutoConfiguration 注解触发,利用 SpringFactoriesLoader 机制加载自动配置类。
⚠️ 重要更新(Spring Boot 2.7+) :从 Spring Boot 2.7 开始,传统的 META-INF/spring.factories 配置方式已标记为弃用,Spring Boot 3.x 版本已完全移除对该方式的支持。新的配置方式使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,每行一个全限定类名,不再使用键值对格式。
2.7+
2.6及以前
是
否
启动类 @SpringBootApplication
包含 @EnableAutoConfiguration
SpringFactoriesLoader 扫描
Spring Boot 版本判断
读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
读取 META-INF/spring.factories
key=EnableAutoConfiguration
加载所有 AutoConfiguration 类
条件评估: @ConditionalOnClass / OnProperty / OnMissingBean
条件是否满足?
配置类生效
配置类跳过
自动注入 Bean 到 Spring 容器
自动配置的完整生命周期:
-
启动触发 :
@SpringBootApplication是一个组合注解,包含@EnableAutoConfiguration,它通过@Import(AutoConfigurationImportSelector.class)触发自动配置流程 -
配置加载 :
AutoConfigurationImportSelector实现ImportSelector接口,在容器刷新阶段调用selectImports()方法,通过SpringFactoriesLoader.loadFactoryNames()读取类路径下的配置文件 -
条件评估 :每个自动配置类都带有条件注解(Condition),Spring 使用
ConditionEvaluator在运行时评估:@ConditionalOnClass:类路径存在指定类时生效(如OpenAiApi.class存在才加载 OpenAI 自动配置)@ConditionalOnProperty:配置文件中指定属性为特定值时生效(如spring.ai.openai.api-key存在)@ConditionalOnMissingBean:容器中不存在指定 Bean 时才生效(避免覆盖用户自定义)@ConditionalOnWebApplication:仅在 Web 应用环境下生效
-
属性绑定 :通过
@EnableConfigurationProperties将@ConfigurationProperties标注的类注册为 Bean,实现外部配置(application.yml)到结构化 Java 对象的类型安全绑定 -
执行顺序 :通过
@AutoConfigureOrder和@AutoConfigureAfter控制配置类加载顺序,确保依赖关系正确处理
优化替代方案 - 自定义自动配置:
java
// 1. 创建配置属性类
@ConfigurationProperties(prefix = "custom.ai")
public class CustomAiProperties {
private String apiKey;
private String baseUrl = "https://api.default.com";
private Duration timeout = Duration.ofSeconds(30);
// getters and setters
}
// 2. 创建自动配置类
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CustomAiClient.class) // 类路径存在才生效
@ConditionalOnProperty(prefix = "custom.ai", name = "api-key") // 配置了api-key才生效
@EnableConfigurationProperties(CustomAiProperties.class)
@AutoConfigureAfter({RestTemplateAutoConfiguration.class}) // 在RestTemplate配置之后
public class CustomAiAutoConfiguration {
private final CustomAiProperties properties;
public CustomAiAutoConfiguration(CustomAiProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean // 用户未定义时才创建
public CustomAiClient customAiClient(RestTemplateBuilder restTemplateBuilder) {
return new CustomAiClient(
properties.getApiKey(),
properties.getBaseUrl(),
properties.getTimeout(),
restTemplateBuilder.build()
);
}
}
// 3. 在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中注册
// 文件内容:com.example.ai.autoconfigure.CustomAiAutoConfiguration
三层架构(Controller-Service-Repository)
企业级应用的标准分层架构确保关注点分离(Separation of Concerns)。实际生产环境中,这个架构通常扩展为五层或六层,以处理更复杂的业务需求。
基础设施层 Infrastructure Layer
数据访问层 Data Access Layer
业务层 Business Layer
表现层 Presentation Layer
接入层 API Gateway
客户端层 Client Layer
Web/App/第三方系统
API网关
鉴权/限流/路由
Controller
处理 HTTP 请求/响应
参数校验/转换
调用 Service
返回统一响应格式
Request DTO
入参对象
Response DTO
出参对象
View Object
视图对象
Service Interface
业务逻辑接口定义
Service Impl
业务逻辑实现
事务管理
跨领域协调
Business Object
业务对象
Repository/Mapper
数据持久化接口
Repository Impl
查询实现
数据库交互
Entity/PO
持久化对象
Database
Redis
Message Queue
File Storage
分层架构详解与补充:
-
Controller 层(表现层):
- 核心职责:接收 HTTP 请求、参数校验、DTO 转换、调用 Service、封装统一响应、处理异常转换
- 禁止事项 :绝不包含业务逻辑,不进行事务控制,不直接操作数据库
- DTO(Data Transfer Object):用于层间数据传输,Controller 接收 Request DTO,返回 Response DTO,避免直接暴露 Entity 结构
- 参数校验 :使用
@Valid或@Validated触发 Bean Validation,配合全局异常处理器统一返回错误格式
-
Service 层(业务层):
- 核心职责 :承载核心业务逻辑,管理事务边界(
@Transactional),协调多个 Repository 或外部服务,实现业务规则的完整性校验 - 设计原则:接口与实现分离(基于接口编程),便于单元测试和 AOP 代理
- 事务管理 :在 Service 层通过
@Transactional控制事务边界,确保 ACID 特性。涉及多数据源时使用分布式事务(Seata)或 Saga 模式 - 领域对象:使用 BO(Business Object)封装复杂业务逻辑,避免 Entity 直接参与业务计算
- 核心职责 :承载核心业务逻辑,管理事务边界(
-
Repository/Mapper 层(数据访问层):
- 核心职责:封装数据访问细节,对外暴露领域对象的持久化操作,屏蔽底层数据库差异
- 技术选型 :
- Spring Data JPA:适合复杂对象关系、快速开发场景,通过方法名派生查询
- MyBatis/MyBatis-Plus:适合复杂 SQL、高性能优化、遗留系统改造
- Entity/PO(Persistent Object) :与数据库表结构一一映射,仅包含字段和 getter/setter,禁止包含业务逻辑
- 查询优化:复杂查询使用 CQRS(命令查询职责分离)模式,读操作直接返回 DTO 避免 Entity 转换开销
分层间的数据流转:
DB Entity Repository BO Service DTO Controller Client DB Entity Repository BO Service DTO Controller Client HTTP Request (JSON) 反序列化为 RequestDTO @Valid 参数校验 调用方法,传入 DTO DTO 转换为 BO/Entity 调用持久化方法 操作 Entity 执行 SQL 返回结果 返回 Entity 业务逻辑处理 Entity/BO 转换为 ResponseDTO 返回 DTO HTTP Response (JSON)
1.2 观念与实践:依赖注入与验证机制
依赖注入(Dependency Injection, DI)
Spring 的 DI 容器通过 控制反转(IoC) 模式管理对象生命周期和依赖关系。IoC 是一种设计原则,DI 是其具体实现方式之一。
三种注入方式深度对比:
| 注入方式 | 代码示例 | 适用场景 | 优点 | 缺点 | Spring 推荐度 |
|---|---|---|---|---|---|
| 构造器注入 | public Service(UserRepo repo) {...} |
强制依赖、不可变依赖 | 1. 依赖不可变(final) 2. 确保对象创建时完整 3. 便于单元测试 4. 循环依赖可检测 | 参数过多时构造器臃肿 | ⭐⭐⭐⭐⭐ 首选 |
| Setter 注入 | @Autowired setUserRepo(...) |
可选依赖、配置属性 | 1. 灵活性高 2. 可在创建后重新配置 | 1. 对象可能处于不完整状态 2. 难以追踪依赖 | ⭐⭐⭐ 特定场景 |
| 字段注入 | @Autowired private UserRepo repo |
快速开发、遗留代码 | 代码简洁 | 1. 隐藏依赖(违反单一职责) 2. 无法单元测试(需反射) 3. NPE 风险 | ⭐ 不推荐 |
构造器注入最佳实践(Lombok 版本):
java
@Service
@RequiredArgsConstructor // Lombok 生成包含 final 字段的构造器
public class KnowledgeBaseService {
// final 确保不可变性
private final DocumentRepository documentRepository;
private final VectorStore vectorStore;
private final EmbeddingModel embeddingModel;
// 可选依赖使用 Setter 注入
private AuditLogger auditLogger;
@Autowired(required = false) // required=false 表示可选
public void setAuditLogger(AuditLogger auditLogger) {
this.auditLogger = auditLogger;
}
@Transactional
public Document saveDocument(DocumentDTO dto) {
// 所有强制依赖通过构造器传入,确保对象创建时即完整可用
// 无需担心 NPE
Document doc = convertToEntity(dto);
Document saved = documentRepository.save(doc);
// 异步处理向量嵌入
vectorStore.add(List.of(
new Document(saved.getContent(),
Map.of("docId", saved.getId().toString()))
));
// 可选依赖使用前检查
if (auditLogger != null) {
auditLogger.log("DOCUMENT_SAVED", saved.getId());
}
return saved;
}
}
循环依赖问题与解决方案:
当 Bean A 依赖 B,B 又依赖 A 时,构造器注入会抛出 BeanCurrentlyInCreationException。
构造器依赖
构造器依赖
Service A
Service B
解决方案(按推荐度排序):
- 重构代码(推荐):通过抽取公共逻辑到第三个 Service C,打破循环依赖
- Setter 注入:将其中一个依赖改为 Setter 方式,延迟注入
- @Lazy 延迟加载 :在构造器参数上使用
@Lazy,注入代理对象而非真实实例
java
@Service
public class ServiceA {
private final ServiceB serviceB;
// 使用 @Lazy 延迟注入,解决循环依赖
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
- ObjectFactory/Provider :使用
ObjectFactory<ServiceB>延迟获取实例
数据验证(Validation)
Spring 使用 Bean Validation 3.0(Jakarta Validation,原 JSR-380) 规范,通过 Hibernate Validator 实现声明式校验。Spring Boot 3.x 已迁移到 Jakarta EE 命名空间(jakarta.validation),不再使用 javax.validation。
常用约束注解分类:
| 分类 | 注解 | 说明 | 适用类型 |
|---|---|---|---|
| 空值检查 | @NotNull |
值不能为 null | 任意 |
@NotEmpty |
字符串/集合非 null 且非空(长度>0) | String, Collection | |
@NotBlank |
字符串非 null 且至少包含一个非空白字符 | String | |
| 范围检查 | @Size(min, max) |
长度/大小在范围内 | String, Collection, Map, Array |
@Min / @Max |
数值最小/最大值 | Number | |
@Range(min, max) |
数值范围(Hibernate 扩展) | Number | |
@DecimalMin / @DecimalMax |
小数范围 | BigDecimal 等 | |
| 模式检查 | @Pattern(regexp) |
正则表达式匹配 | String |
@Email |
邮箱格式验证 | String | |
@URL |
URL 格式验证(Hibernate 扩展) | String | |
| 时间检查 | @Past / @Future |
过去/未来时间 | Date, Temporal |
| 业务逻辑 | @AssertTrue / @AssertFalse |
自定义验证逻辑 | Boolean |
@Valid |
级联验证嵌套对象 | Object |
分组验证与顺序控制:
java
// 定义验证分组接口
public interface ValidationGroups {
interface Create {} // 创建时验证
interface Update {} // 更新时验证
interface Delete {} // 删除时验证
}
public class DocumentDTO {
@Null(groups = ValidationGroups.Create.class) // 创建时ID必须为null
@NotNull(groups = ValidationGroups.Update.class) // 更新时ID必须存在
private Long id;
@NotBlank(message = "文档标题不能为空")
@Size(max = 100, message = "标题长度不能超过100字符")
private String title;
@NotBlank(groups = ValidationGroups.Create.class) // 仅创建时验证内容
private String content;
@Valid // 级联验证嵌套对象
private List<TagDTO> tags;
}
// Controller 中使用分组
@RestController
public class DocumentController {
@PostMapping("/documents")
public ResponseEntity<?> create(
@Validated(ValidationGroups.Create.class) @RequestBody DocumentDTO dto) {
// 仅执行 Create 组的验证
return ResponseEntity.ok(service.create(dto));
}
@PutMapping("/documents/{id}")
public ResponseEntity<?> update(
@Validated(ValidationGroups.Update.class) @RequestBody DocumentDTO dto) {
// 仅执行 Update 组的验证
return ResponseEntity.ok(service.update(dto));
}
}
统一异常处理机制(增强版):
java
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// 处理参数校验失败异常(MethodArgumentNotValidException)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(
MethodArgumentNotValidException ex,
WebRequest request) {
List<FieldErrorDetail> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> new FieldErrorDetail(
error.getField(),
error.getRejectedValue(),
error.getDefaultMessage(),
error.getCode() // 错误类型码
))
.collect(Collectors.toList());
log.warn("参数校验失败: URI={}, Errors={}",
request.getDescription(false), errors);
ErrorResponse response = ErrorResponse.builder()
.code("VALIDATION_ERROR")
.message("请求参数校验失败")
.errors(errors)
.timestamp(Instant.now())
.path(request.getDescription(false))
.build();
return ResponseEntity.badRequest().body(response);
}
// 处理请求体缺失或格式错误
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ErrorResponse> handleMessageNotReadable(
HttpMessageNotReadableException ex) {
String message = "请求体格式错误";
if (ex.getCause() instanceof InvalidFormatException ife) {
message = String.format("字段'%s'类型不匹配,期望%s",
ife.getPath().get(0).getFieldName(),
ife.getTargetType().getSimpleName());
}
return ResponseEntity.badRequest()
.body(new ErrorResponse("FORMAT_ERROR", message));
}
// 处理约束违反异常(通常发生在 Service 层 @Validated)
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleConstraintViolation(
ConstraintViolationException ex) {
List<String> errors = ex.getConstraintViolations()
.stream()
.map(v -> v.getPropertyPath() + ": " + v.getMessage())
.collect(Collectors.toList());
return ResponseEntity.badRequest()
.body(new ErrorResponse("CONSTRAINT_ERROR", "约束违反", errors));
}
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
log.error("业务异常: {}", ex.getMessage(), ex);
return ResponseEntity.status(ex.getHttpStatus())
.body(ErrorResponse.builder()
.code(ex.getErrorCode())
.message(ex.getMessage())
.timestamp(Instant.now())
.build());
}
// 兜底异常处理
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception ex) {
log.error("系统异常", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("INTERNAL_ERROR", "系统内部错误,请联系管理员"));
}
}
// 统一错误响应结构
@Data
@Builder
public class ErrorResponse {
private String code; // 业务错误码
private String message; // 错误描述
private List<?> errors; // 详细错误列表
private Instant timestamp; // 时间戳
private String path; // 请求路径
@Data
@AllArgsConstructor
public static class FieldErrorDetail {
private String field; // 字段名
private Object rejectedValue; // 拒绝的值
private String message; // 错误消息
private String code; // 验证器类型
}
}
1.3 安全配置:API Key 管理策略
企业级 AI 应用必须妥善管理大模型 API Key,避免硬编码泄露风险。API Key 属于高敏感凭证,泄露可能导致严重的财务损失和数据安全问题。
安全风险等级评估:
API Key 管理方式
硬编码
❌ 极高风险
配置文件明文
⚠️ 高风险
环境变量
✅ 中等风险
密钥管理系统
✅ 低风险
动态凭证
✅ 极低风险
推荐方案演进:
阶段一:环境变量 + Spring 配置属性(开发/测试环境)
yaml
# application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY:} # 从环境变量读取,无默认值,缺失时为空字符串
base-url: ${OPENAI_BASE_URL:https://api.openai.com}
azure:
openai:
api-key: ${AZURE_OPENAI_KEY:}
endpoint: ${AZURE_OPENAI_ENDPOINT:}
# 国产大模型配置
zhipuai:
api-key: ${ZHIPUAI_API_KEY:}
dashscope: # 通义千问
api-key: ${DASHSCOPE_API_KEY:}
阶段二:配置加密(生产环境基础防护)
使用 Jasypt 或 Spring Cloud Config 加密敏感配置:
yaml
# 加密后的配置(ENC(...) 为加密标记)
spring:
ai:
openai:
api-key: ENC(AQOqC8W7hBv3x8f4cWQwQzYxNjc5...)
java
@Configuration
public class JasyptConfig {
@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
// 从环境变量读取主密钥,而非配置文件
config.setPassword(System.getenv("JASYPT_ENCRYPTOR_PASSWORD"));
config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
}
阶段三:密钥管理系统(KMS)- 生产环境标准方案
使用云厂商提供的密钥管理服务,实现动态注入和自动轮换:
java
@Configuration
public class CloudSecretConfig {
@Bean
@RefreshScope // 支持配置刷新
public OpenAiApi openAiApi(SecretClient secretClient) {
// 从 Azure Key Vault 获取密钥
String apiKey = secretClient.getSecret("openai-api-key").getValue();
return new OpenAiApi(
"https://api.openai.com",
apiKey,
RestClient.builder()
);
}
}
阶段四:完整的密钥安全治理方案
技术实现层
密钥生命周期管理
密钥创建
密钥分发
密钥使用
密钥轮换
密钥吊销
密钥审计
Vault
HashiCorp/AWS/Azure
IAM 角色绑定
Pod Identity
内存安全
不在磁盘落盘
传输加密
TLS 1.3
生产环境强化方案完整清单:
-
密钥轮换机制:
- 实现双密钥并发机制(新旧密钥同时有效过渡期)
- 定期自动轮换(建议 90 天周期)
- 紧急吊销能力(应对泄露场景)
-
最小权限原则:
- 为不同环境(dev/staging/prod)使用独立的 API Key
- 限制 API Key 的模型访问范围(如仅允许 GPT-4,禁止 GPT-3.5)
- 设置调用频率限制和额度上限
-
监控与审计:
- 记录所有 API Key 的使用日志(调用时间、IP、模型、token 数)
- 异常流量检测(突增的调用量或错误率)
- 成本告警(日消费限额告警)
-
安全传输与存储:
- 传输层强制 TLS 1.3
- 内存中存储(避免写入日志或堆转储)
- 使用
char[]而非String存储密钥(便于清零)
1.4 Spring AI 核心价值:统一 AI 模型接入层
Spring AI 的核心价值主张是 "解耦 AI 模型与业务代码",它通过抽象层屏蔽底层大模型(OpenAI、Azure、Anthropic、Ollama 等)的差异,让开发者像使用标准数据源(JdbcTemplate、JPA)一样使用 AI 能力。
底层大模型
模型提供商 Adapters
Spring AI 抽象层 Core Abstractions
应用层 Application Layer
业务代码
ChatClient / ChatModel
ChatClient API
Fluent Interface
统一入口
Model 抽象
ChatModel / EmbeddingModel
ImageModel / AudioModel
Prompt 管理
PromptTemplate
Message 体系
顾问机制
Advisor API
横切关注点
输出解析
OutputParser
Bean 提取
OpenAI
GPT-4/3.5
Azure OpenAI
企业级 GPT
Anthropic
Claude 3.5
Ollama
本地模型
智谱 AI
GLM-4
通义千问
Qwen
百度文心
ERNIE
DeepSeek
R1/V3
GPT-4o / o1
Claude 3.5 Sonnet
Llama 3 / Mistral
Gemma
GLM-4 / ChatGLM3
Qwen-Max / Qwen-Plus
Spring AI 架构核心组件:
-
ChatClient(推荐入口) :Fluent API,采用 Builder 模式 构建请求,支持链式调用配置 Prompt、上下文、工具等。它是高层次的抽象,简化了大多数场景的使用。
-
ChatModel(底层接口):直接操作模型通信,适合需要精细控制请求/响应的场景。
-
Prompt 体系:
Prompt:包含 Message 列表和模型选项的完整请求Message:角色(System/User/Assistant/Tool) + 内容 + 元数据PromptTemplate:支持占位符${variable}的模板,用于动态构建 Prompt
-
Advisor 机制(横切关注点):类似 Spring AOP,在请求处理前后插入逻辑,实现日志、重试、缓存、安全过滤等功能。
ChatClient 核心设计详解:
java
// 基础用法 - 简单调用
String response = chatClient.prompt()
.system("你是一位专业的企业知识库助手") // 系统消息:设定 AI 角色和行为准则
.user("查询请假流程") // 用户消息:用户输入
.call() // 执行同步调用
.content(); // 提取文本响应
// 进阶用法 - 完整配置
ChatResponse response = chatClient.prompt()
.system(s -> s.text("你是一位{role},使用{tone}语气回答")
.param("role", "企业知识库助手")
.param("tone", "专业且友好")) // 系统消息支持参数化模板
.user("查询请假流程")
.advisors(a -> a // 添加顾问链
.param("chat_memory_conversation_id", "user-123")
.param("chat_memory_response_size", 10))
.options(OpenAiChatOptions.builder() // 模型参数配置
.withModel("gpt-4-turbo-preview")
.withTemperature(0.7) // 创造性 vs 确定性 (0-2)
.withMaxTokens(2000) // 最大生成 token 数
.withTopP(1.0) // 核采样
.withFrequencyPenalty(0.0) // 频率惩罚(避免重复)
.withPresencePenalty(0.0) // 存在惩罚(鼓励新话题)
.build())
.call()
.chatResponse(); // 获取完整响应对象(包含元数据)
// 流式调用(SSE)
Flux<String> stream = chatClient.prompt()
.user("请详细解释 Spring Boot 自动配置原理")
.stream() // 改为 stream 方法
.content();
输出解析与结构化数据提取:
Spring AI 提供 OutputParser 将模型输出转换为 Java 对象,避免手动解析 JSON:
java
// 定义 Bean 结构
public record EmployeeInfo(
String name,
String department,
double salary,
List<String> skills
) {}
// 使用 BeanOutputParser 自动解析
BeanOutputParser<EmployeeInfo> parser = new BeanOutputParser<>(EmployeeInfo.class);
EmployeeInfo info = chatClient.prompt()
.system("从以下文本中提取员工信息,按指定格式返回 JSON")
.user("张三,研发部高级工程师,月薪25000,精通Java和Spring")
.call()
.entity(parser); // 自动解析为 EmployeeInfo 对象
// 或使用 MapOutputParser 动态解析
MapOutputParser mapParser = new MapOutputParser();
Map<String, Object> result = chatClient.prompt()
.user("提取关键信息")
.call()
.entity(mapParser);
顾问(Advisor)机制详解:
Advisor 是 Spring AI 的强大扩展点,用于封装横切关注点:
ChatModel RetryAdvisor MemoryAdvisor LoggerAdvisor Client ChatModel RetryAdvisor MemoryAdvisor LoggerAdvisor Client 发送 Prompt 记录请求日志 传递 Prompt 检索历史消息 合并上下文到 Prompt 传递增强 Prompt 设置重试策略 调用模型 返回响应 传递响应(失败时重试) 保存新消息到记忆 传递响应 记录响应日志 返回最终结果
常用内置 Advisor:
| Advisor | 功能 | 使用场景 |
|---|---|---|
MessageChatMemoryAdvisor |
对话记忆管理 | 多轮对话保持上下文 |
QuestionAnswerAdvisor |
RAG 检索增强 | 结合向量数据库回答 |
SafeGuardAdvisor |
内容安全检查 | 过滤敏感词和有害内容 |
RetryAdvisor |
自动重试 | 模型调用失败时重试 |
LoggerAdvisor |
日志记录 | 记录请求/响应详情 |
配置示例:
java
@Bean
public ChatClient chatClient(ChatClient.Builder builder,
ChatMemory chatMemory,
VectorStore vectorStore) {
return builder
.defaultSystem("你是一位专业的企业助手")
.defaultOptions(OpenAiChatOptions.builder()
.withTemperature(0.7)
.build())
.defaultAdvisors(
new MessageChatMemoryAdvisor(chatMemory), // 记忆管理
new QuestionAnswerAdvisor(vectorStore), // RAG 增强
new RetryAdvisor(3, Duration.ofSeconds(1)) // 失败重试
)
.build();
}
通过这套架构,业务代码只需关心 Prompt 设计 和 业务逻辑,底层模型切换(从 OpenAI 切换到 Azure 或国产模型)只需修改配置,无需改动业务代码。