1. 项目背景与核心价值
去年在给某金融客户做技术咨询时,他们提出想快速搭建一个能处理专业问答的AI系统。传统方案要么需要组建NLP团队从头训练模型,要么调用公有云API存在数据安全隐患。而基于Spring AI框架整合通义千文大模型,我们仅用三周就交付了符合金融级安全要求的智能问答平台。
这种技术组合的优势在于:Spring Boot提供了成熟的工程化底座,通义千文作为国产大模型在中文场景表现优异,两者结合既能快速实现智能问答核心功能,又能保证系统可维护性和数据可控性。下面分享我们趟过的坑和验证过的方案。
2. 技术架构设计
2.1 整体架构分层
系统采用经典三层架构:
- 接入层:Spring MVC处理HTTP请求,JWT实现鉴权
- 业务层:Spring AI的ChatClient封装大模型交互
- 数据层:Redis缓存高频问答,MySQL存储对话日志
关键设计决策:
- 使用API网关做流量控制,防止大模型调用超限
- 对话历史采用向量化存储,方便后续相似问题匹配
- 单独部署模型微调服务,支持领域知识增量训练
2.2 模型选型对比
我们测试了多种大模型在金融QA场景的表现:
| 模型 | 中文理解 | 金融术语 | 响应速度 | 成本 |
|---|---|---|---|---|
| 通义千文 | ★★★★☆ | ★★★★ | 800ms | 0.12元/千次 |
| GPT-3.5 | ★★★☆ | ★★☆ | 1200ms | $0.002/千token |
| 文心一言 | ★★★★ | ★★★☆ | 900ms | 0.15元/千次 |
最终选择通义千文因其:
- 专门优化过中文长文本理解
- 支持金融领域微调
- 符合国产化要求
3. 核心实现步骤
3.1 环境准备
xml复制<!-- pom.xml关键依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qianwen</artifactId>
<version>0.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
注意:Spring AI仍在快速迭代,建议锁定版本号。我们遇到过0.7→0.8的API不兼容问题。
3.2 基础问答实现
java复制@RestController
public class QAController {
@Autowired
private ChatClient chatClient;
@PostMapping("/ask")
public String answer(@RequestBody QuestionDTO question) {
// 添加业务上下文
String prompt = "你是一名金融分析师,请用专业但易懂的语言回答:\n"
+ question.getContent();
return chatClient.call(prompt);
}
}
关键技巧:
- 在prompt中添加角色设定,显著提升回答专业性
- 对用户输入做敏感词过滤(使用AC自动机算法)
- 设置maxTokens=800避免生成内容过长
3.3 对话记忆实现
java复制// 使用Redis存储对话上下文
public class DialogService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void saveContext(String sessionId, String dialog) {
redisTemplate.opsForList().rightPush(
"dialog:" + sessionId,
dialog
);
redisTemplate.expire(
"dialog:" + sessionId,
30, TimeUnit.MINUTES
);
}
public String getFullPrompt(String sessionId, String newQuestion) {
List<String> history = redisTemplate.opsForList()
.range("dialog:" + sessionId, 0, -1);
return String.join("\n", history)
+ "\n用户最新问题:" + newQuestion;
}
}
4. 性能优化实战
4.1 缓存策略
采用两级缓存:
- 本地Caffeine缓存高频问题(命中率约35%)
- Redis缓存近期对话(TTL=30分钟)
测试对比:
| 方案 | QPS | 平均延迟 | 成本节省 |
|---|---|---|---|
| 无缓存 | 120 | 850ms | - |
| 仅本地缓存 | 210 | 420ms | 28% |
| 两级缓存 | 350 | 230ms | 52% |
4.2 异步处理
对非实时需求采用消息队列:
java复制@KafkaListener(topics = "async_questions")
public void handleAsyncQuestion(QuestionMessage message) {
String answer = chatClient.call(message.getContent());
emailService.sendResult(message.getEmail(), answer);
}
配置参数建议:
- 线程池:corePoolSize=CPU核数+1
- Kafka:acks=1, linger.ms=20
5. 安全防护方案
5.1 输入过滤
建立金融行业敏感词库(约1200词),使用DFA算法检测:
java复制public class SensitiveFilter {
private static final SensitiveWordFilter filter =
new SensitiveWordFilter("financial_keywords.txt");
public static String filter(String text) {
return filter.replace(text, "***");
}
}
5.2 输出审核
对接内容安全API进行双重校验:
java复制public boolean checkViolation(String content) {
// 阿里云内容安全API
Client client = new Client("accessKey", "secret");
ScanTextRequest request = new ScanTextRequest();
request.setText(content);
return client.scanText(request).getFlagged();
}
6. 监控与运维
6.1 Prometheus监控指标
关键监控项:
- model_invoke_duration_seconds:模型响应时间
- api_error_count:异常请求数
- cache_hit_rate:缓存命中率
Grafana看板配置示例:
yaml复制panels:
- title: 服务健康度
metrics:
- rate(api_error_count[5m]) > 0.1
- model_invoke_duration_seconds{quantile="0.95"} > 3000
6.2 日志规范
采用结构化日志:
json复制{
"timestamp": "2024-03-20T15:32:41Z",
"traceId": "abc123",
"level": "INFO",
"message": "Model response",
"metadata": {
"question": "如何计算IRR",
"model": "qianwen",
"duration": 784
}
}
7. 踩坑实录
-
长文本截断问题:
- 现象:回答突然截断
- 原因:未设置maxTokens参数
- 解决:根据通义千文文档,设置为maxTokens=800
-
并发超限:
- 现象:频繁返回429错误
- 原因:免费版QPS限制为5
- 解决:接入API网关实现请求排队
-
中文编码异常:
- 现象:部分中文变乱码
- 原因:HTTP未指定charset
- 解决:强制UTF-8编码
java复制@RequestMapping(produces = "application/json;charset=UTF-8")
8. 领域适配建议
针对不同行业的优化方向:
-
法律行业:
- 添加法条检索增强(RAG)
- 设置temperature=0.3减少创造性回答
-
医疗行业:
- 对接医学知识图谱
- 输出添加免责声明
-
教育行业:
- 实现分步骤解答
- 集成TTS语音播报
项目完整代码已脱敏上传GitHub,包含Docker部署脚本和压力测试报告。在实际落地时,建议先用小流量验证效果,再结合业务数据做微调。我们团队通过这个方案已成功落地5个企业级问答系统,平均开发周期比传统方案缩短60%。