Files
spring-ai-demo/docs/开发指南.md

547 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fintec AI Framework 开发指南
## 📚 文档目录
- [快速开始](#快速开始)
- [架构概览](#架构概览)
- [模块说明](#模块说明)
- [使用示例](#使用示例)
- [最佳实践](#最佳实践)
- [常见问题](#常见问题)
---
## 快速开始
### 环境要求
- JDK 17+
- Spring Boot 3.4.6+
- Spring AI 1.1.1+
- Maven 3.6+
### 引入依赖
在项目的 `pom.xml` 中添加依赖:
```xml
<!-- Agent Starter(对话能力) -->
<dependency>
<groupId>com.ccb.fintec</groupId>
<artifactId>fintec-framework-agent-spring-boot-starter</artifactId>
</dependency>
<!-- RAG Starter(知识库问答) -->
<dependency>
<groupId>com.ccb.fintec</groupId>
<artifactId>fintec-framework-rag-spring-boot-starter</artifactId>
</dependency>
<!-- MCP Server Starter(工具暴露) -->
<dependency>
<groupId>com.ccb.fintec</groupId>
<artifactId>fintec-framework-mcp-server-spring-boot-starter</artifactId>
</dependency>
```
### 基础配置
`application.yml` 中配置 AI 模型:
```yaml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com/v1
chat:
options:
model: gpt-4
temperature: 0.7
app:
ai:
# 安全防护
safety:
enabled: true
block-keywords:
- 暴力
- 色情
- 赌博
# 限流配置
rate-limit:
max-requests-per-minute: 60
# 重试策略(自动处理网络波动)
retry:
enabled: true
max-attempts: 3
backoff-ms: 1000
```
---
## 架构概览
### 整体架构
```
┌─────────────────────────────────────────────┐
│ 业务应用层 (Business App) │
├─────────────────────────────────────────────┤
│ Agent+Graph+MCP Client │ RAG │
│ Starter │ Starter │
├─────────────────────────────────────────────┤
│ Core 核心层 (统一抽象) │
├─────────────────────────────────────────────┤
│ Spring AI (模型适配层) │
├─────────────────────────────────────────────┤
│ OpenAI │ Ollama │ Anthropic │ 其他模型 │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ MCP Server (独立部署) │
│ SSE + STDIO + Streamable-HTTP │
└─────────────────────────────────────────────┘
```
### 设计原则
1. **分层解耦**: 技术实现与业务编排分离
2. **多模型支持**: 通过 Spring AI 抽象,支持切换不同模型厂商
3. **开箱即用**: 自动配置,零样板代码
4. **可扩展性**: 基于 Spring Boot Starter 机制,易于扩展
---
## 模块说明
### 1. fintec-framework-ai-core (核心模块)
**职责**: 提供统一的 AI 配置和能力抽象
**功能**:
- 全局 AI 配置管理 (`AiCoreProperties`)
- 公共的接口和DTO公共回复等解耦...
---
### 2. fintec-framework-agent-spring-boot-starter (Agent 模块)
**职责**: 提供对话式 AI、Graph 工作流编排和 MCP Client 能力
**核心组件**:
- `AgentTemplate`: 封装常用对话模式(内置重试)
- `MultimodalTemplate`: 多模态能力(图片/文档理解)
- `ChatClient`: 统一的聊天客户端
- `ChatMemory`: 对话记忆管理
- Graph 工作流: `Node`, `Condition`, `SequentialWorkflow`, `ParallelWorkflow`, `RoutingWorkflow`, `LoopWorkflow`
- `McpClientAutoConfiguration`: MCP Client 自动配置
- `RetryAutoConfiguration`: 自动重试机制
- `SafetyAspect`: 敏感词过滤切面
**主要功能**:
- 简单问答
- 带系统提示的对话
- Function Calling(工具调用)
- 结构化输出
- 流式响应
- 对话记忆
- **图片理解**: 分析图片内容、OCR识别
- **Graph 工作流**: Sequential/Parallel/Routing/Loop
- **MCP Client**: 连接外部 MCP Server
- **安全防护**: 敏感词过滤(请求+响应双向检查)
- **自动重试**: 处理网络波动、临时故障
**典型场景**: 智能客服、AI助手、代码生成、多模态应用、复杂工作流编排
---
### 3. fintec-framework-rag-spring-boot-starter (RAG 模块)
**职责**: 提供检索增强生成、ETL 和图片生成能力
**核心组件**:
- `RagTemplate`: 封装 RAG 调用模式
- `ImageGenerationTemplate`: 图片生成能力
- `QuestionAnswerAdvisor`: 向量检索顾问
**主要功能**:
- **ETL**: 文档读取和解析PDF、Word、TXT等
- **Embedding**: 文本向量化
- **VectorStore**: 向量存储和检索
- 基于知识库的问答
- 自定义相似度阈值和 TopK
- 流式输出
- 结合对话记忆
- **图片生成**: 根据文本描述生成图片
**典型场景**: 企业知识库问答、文档检索、智能搜索、AI绘画
---
### 4. fintec-framework-mcp-server-spring-boot-starter (MCP Server 模块)
**职责**: 提供 Model Context Protocol Server 支持,将工具暴露给外部 Agent
**核心组件**:
- `McpAutoConfiguration`: MCP Server 自动配置
- `ToolCallbackProvider`: 自动扫描 `@Tool` 注解
**主要功能**:
- 自动注册工具函数
- **SSE**: Server-Sent Events 传输
- **STDIO**: 标准输入输出传输
- **Streamable-HTTP**: 流式 HTTP 传输
- 工具发现与调用
**典型场景**: AI 调用外部 API、数据库查询、业务系统集成独立部署
---
## 使用示例
### Agent 模块示例(包含 Graph 工作流)
```java
@Service
public class CustomerService {
@Autowired
private AgentTemplate agentTemplate;
// 简单问答
public String answer(String question) {
return agentTemplate.ask(question);
}
// 带系统提示
public String answerWithRole(String question) {
return agentTemplate.ask(
"你是一位专业的客服代表,请用礼貌的语气回答",
question
);
}
// 流式输出
public Flux<String> streamAnswer(String question) {
return agentTemplate.stream(question);
}
// 带对话记忆
public String chat(String conversationId, String message) {
return agentTemplate.askWithMemory(conversationId, message);
}
// 结构化输出
public OrderInfo extractOrder(String text) {
return agentTemplate.askForObject(
"从以下文本中提取订单信息: " + text,
OrderInfo.class
);
}
}
```
### Graph 工作流示例
```java
@Service
public class WorkflowService {
@Autowired
private GraphTemplate graphTemplate;
// 顺序工作流: 数据清洗 -> 翻译 -> 总结
public String processText(String text) {
var workflow = GraphTemplate.sequential(
GraphTemplate.node("清洗", t -> t.trim()),
GraphTemplate.node("翻译", t -> translate(t)),
GraphTemplate.node("总结", t -> summarize(t))
);
return workflow.execute(text);
}
// 并行工作流: 多维度分析
public List<String> analyzeText(String text) {
var workflow = GraphTemplate.parallel(
GraphTemplate.node("情感分析", t -> sentiment(t)),
GraphTemplate.node("关键词提取", t -> keywords(t)),
GraphTemplate.node("分类", t -> classify(t))
);
return workflow.execute(text);
}
// 路由工作流: 根据问题类型选择处理逻辑
public String routeQuestion(String question) {
var workflow = GraphTemplate.routing()
.addBranch("技术",
q -> ((String)q).contains("技术"),
GraphTemplate.node("技术回答", q -> techAnswer(q)))
.addBranch("业务",
q -> ((String)q).contains("业务"),
GraphTemplate.node("业务回答", q -> businessAnswer(q)))
.setDefault(GraphTemplate.node("通用回答", q -> generalAnswer(q)));
return workflow.execute(question);
}
}
```
```java
@Service
public class KnowledgeService {
@Autowired
private RagTemplate ragTemplate;
// 基于知识库问答
public String askKnowledge(String question) {
return ragTemplate.ask(question);
}
// 自定义检索参数
public String askWithConfig(String question) {
return ragTemplate.askWithConfig(
question,
0.8, // 相似度阈值
5 // TopK
);
}
// 流式输出
public Flux<String> streamAsk(String question) {
return ragTemplate.stream(question);
}
}
```
### Graph 模块示例
```java
@Service
public class WorkflowService {
@Autowired
private GraphTemplate graphTemplate;
// 顺序工作流: 数据清洗 -> 翻译 -> 总结
public String processText(String text) {
var workflow = GraphTemplate.sequential(
GraphTemplate.node("清洗", t -> t.trim()),
GraphTemplate.node("翻译", t -> translate(t)),
GraphTemplate.node("总结", t -> summarize(t))
);
return workflow.execute(text);
}
// 并行工作流: 多维度分析
public List<String> analyzeText(String text) {
var workflow = GraphTemplate.parallel(
GraphTemplate.node("情感分析", t -> sentiment(t)),
GraphTemplate.node("关键词提取", t -> keywords(t)),
GraphTemplate.node("分类", t -> classify(t))
);
return workflow.execute(text);
}
// 路由工作流: 根据问题类型选择处理逻辑
public String routeQuestion(String question) {
var workflow = GraphTemplate.routing()
.addBranch("技术",
q -> ((String)q).contains("技术"),
GraphTemplate.node("技术回答", q -> techAnswer(q)))
.addBranch("业务",
q -> ((String)q).contains("业务"),
GraphTemplate.node("业务回答", q -> businessAnswer(q)))
.setDefault(GraphTemplate.node("通用回答", q -> generalAnswer(q)));
return workflow.execute(question);
}
}
```
---
## 最佳实践
### 1. 对话记忆管理
**推荐做法**:
```java
// 使用业务ID作为会话ID
String conversationId = "user_" + userId + "_session_" + sessionId;
agentTemplate.askWithMemory(conversationId, message);
// 定期清理过期会话
@Component
public class MemoryCleanupTask {
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点
public void cleanup() {
// 清理7天前的会话
}
}
```
**避免做法**:
- 使用 UUID 作为会话ID(每次都是新会话)
- 不清理会话数据(内存泄漏)
- 不同用户共用同一会话ID
---
### 3. RAG 优化
**推荐做法**:
```java
// 调整相似度阈值(根据业务场景)
ragTemplate.askWithConfig(question, 0.75, 3);
// 文档切片策略
// - 技术文档: 500-800 tokens/chunk
// - FAQ: 按问题拆分
// - 合同: 按条款拆分
// 添加元数据过滤
SearchRequest.builder()
.similarityThreshold(0.8)
.topK(5)
.filterExpression("category == 'technical'")
.build();
```
**避免做法**:
- TopK 设置过大(增加成本)
- 相似度阈值过低(返回不相关内容)
- 不处理文档切片重叠
---
### 4. 工作流设计
**推荐做法**:
```java
// 为节点命名(便于调试)
GraphTemplate.node("数据验证", data -> validate(data));
// 设置合理的循环上限
GraphTemplate.loop(node, condition, 5); // 最多5次迭代
// 异常处理
try {
return workflow.execute(input);
} catch (Exception e) {
log.error("工作流执行失败", e);
return fallbackResult;
}
```
**避免做法**:
- 循环不设上限(死循环风险)
- 节点逻辑过于复杂(应拆分为多个节点)
- 不记录工作流执行日志
---
### 5. 性能优化
**推荐做法**:
```java
// 使用流式输出提升用户体验
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(String message) {
return agentTemplate.stream(message);
}
// 并行执行独立任务
var results = GraphTemplate.parallel(
node1, node2, node3
).execute(input);
// 缓存常见问题的答案
@Cacheable(value = "faq", key = "#question")
public String getFaqAnswer(String question) {
return ragTemplate.ask(question);
}
```
**避免做法**:
- 同步等待大模型响应(超时风险)
- 串行执行可并行的任务
- 重复调用相同的 Prompt
---
## 常见问题
### Q1: 如何切换不同的 AI 模型?
**A**: 修改 `application.yml` 配置即可:
```yaml
# 切换到 Ollama
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama3
# 切换到通义千问
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
chat:
options:
model: qwen-max
```
---
### Q2: 如何实现多轮对话?
**A**: 使用 `askWithMemory` 方法:
```java
// 第一次对话
String answer1 = agentTemplate.askWithMemory("session_001", "你好");
// 第二次对话(能记住上下文)
String answer2 = agentTemplate.askWithMemory("session_001", "我刚才说了什么?");
```
---
### Q3: RAG 检索不到相关内容怎么办?
**A**: 检查以下几点:
1. 降低相似度阈值(如从 0.8 降到 0.6)
2. 增加 TopK 数量
3. 优化文档切片策略
4. 检查 Embedding 模型质量
5. 添加更多相关文档
---
### Q4: 如何调试工作流?
**A**: 启用 DEBUG 日志:
```yaml
logging:
level:
com.ccb.fintec.graph: DEBUG
```
查看每个节点的输入输出和执行时间。
---
### Q5: 如何保证 AI 输出的安全性?
**A**: 多层防护:
1. 配置敏感词过滤 (`app.ai.safety.block-keywords`)
2. 设置输出长度限制 (`max-tokens-per-request`)
3. 人工审核关键业务输出