做了三年AI应用,我的感受是:Demo和产品之间隔着一整条生产线。朋友圈里炫的AI聊天机器人、RAG问答神器,绝大多数都停在了玩具阶段——本地跑得欢,一上生产就崩。这不怪模型,怪工程。真正让我觉得AI应用"从玩具变成工具"的转折点,是上个月把一套客服知识库系统完整跑在Spring AI Alibaba Admin这套工程化栈上的时候。这篇文章不聊概念,只聊我为什么选它、怎么落地、踩了哪些坑。
如果你是那种已经用Python写过几个LangChain脚本、但发现生产环境根本没有脚本容身之地的开发者,或者你正在为一个AI项目做技术选型,这篇经验贴应该能帮到你。它解决的核心问题只有一个:AI应用怎么从"能跑"变成"能上线、能维护、能控制成本"。
1. 先搞清楚一个事:玩具和工具的分界线到底在哪
1.1 Demo时代的三宗罪
先说说我自己的第一个AI项目。2023年底,我用开源模型微调了一个文档问答机器人,给同事演示的时候效果炸裂——领导当场拍板要上线。结果呢?上线第一个月,模型接口超时、Token费用超预算三倍、向量库同步失败导致回答过期、用户问了几个敏感词直接触发幻觉输出了一堆不该有的内容。
Collapse
这就是典型的玩具级应用。它的特点很一致:模型在本地或API上孤零零地跑,旁边没有任何工程设施。没有超时控制,没有降级方案,没有Prompt版本管理,没有上下文长度约束,没有数据和模型的权限隔离。最致命的是,所有的能力都是"写死在代码里"的——换一个模型要改代码,换一套Prompt要改代码,连调一个温度参数都要重新打包部署。
我后来总结了一句话:玩具应用是在"伺候模型",工具应用是在"管理模型"。你如果把模型当成一个永远正确的黑盒,那它迟早会给你颜色看。工程化不是给模型加补丁,而是把模型当成一个不可靠的组件,像对待外部API一样做好容错、监控、隔离和降级。
1.2 工程化的核心需求清单
经历了那次翻车之后,我做任何AI项目都会先列一份工程化需求清单。这份清单今天看起来像废话,但在实际选型时每一条都会卡掉一堆方案:
- 模型层可替换:不能和某一个模型供应商深度绑定,至少能在大模型、开源模型、多厂商API之间切换
- 上下文和记忆管理:会话状态、窗口长度、长期记忆要做成可配置、可观测的组件,不能靠手写拼接
- 知识库接入:RAG流程要标准化,向量库的索引、召回、重排序要有统一抽象
- 请求治理:超时、重试、限流、熔断,一个都不能少
- Prompt管理:Prompt要能版本化、能动态模板化,最好可以在后台改而不用发版
- 可观测性:每一次调用都要能追踪Token消耗、延迟、反馈质量
- 安全与权限:模型能访问什么数据、谁有权限发起调用,必须可控
用这个清单去对比市面上的方案,你会发现纯粹的大模型API调用、"LangChain式脚本"、以及某些强调Agent编排的低代码平台都各有短板。它们要么管不住模型层,要么管不住数据层,要么根本不考虑运维视角。
1.3 为什么Spring Boot成了AI工程化的自然土壤
在Java生态里做AI应用,Spring Boot几乎是绕不开的基座。原因不复杂:Java企业应用积累的治理能力太完整了。你随便找一个跑了两年的Spring Boot系统,里面一定有现成的鉴权、配置中心、监控告警、限流熔断、链路追踪。把AI能力接进这样的系统,等于给模型穿上了一层生产级铠甲。
而Spring AI的出现,让这件事变得顺理成章。它学的是Spring Data那套思路:不同数据库有不同方言,但对业务代码暴露的Repository是一样的。Spring AI把不同模型厂商的差异封装成了统一的ChatClient、EmbeddingModel接口,业务代码只依赖接口,不依赖厂商。Spring AI Alibaba则在国内模型接入、灵活配置方面做了更贴近实际场景的增强,加上Admin管理端的思路,正好补上了运维治理这块短板。
2. 方案选型:我为什么没选LangChain,也没选纯自研
2.1 三种路线的真实对比
选型那两周,我把主流路线都跑了一遍,结论用一张表说清楚:
| 方案 | 模型接入 | 工程治理 | 上手成本 | 生产可用度 |
|---|---|---|---|---|
| 直接用SDK调大模型API | 强依赖一家厂商 | 几乎没有,全要自己写 | 低 | 低 |
| LangChain / LlamaIndex | 多厂商支持,但抽象过重 | 比较弱,偏研究和原型 | 中 | 中 |
| Spring AI + Spring AI Alibaba Admin | 统一接口,多云可切换 | 强,有运维后台和治理组件 | 中高 | 高 |
LangChain的问题不在于不好用,而在于它骨子里还是研究工具。它给了你一万个组件,但你得自己证明这些组件在生产环境能扛住并发。我不否认有团队用LangChain做出了生产系统,但代价是花费大量精力去补工程短板:会话管理、持久化、监控、重试策略,每一样都要额外找方案。纯自研就更不必说了,光是多模型适配、RAG管线和后台管理这三块,就够一个小组忙半年。
选Spring AI Alibaba Admin,我看中的是"模型能力和工程能力的匹配度":Spring Boot的成熟生态提供治理底座,Spring AI提供统一抽象,Spring AI Alibaba补齐国内模型接入和增强功能,Admin管理后台解决可观测和配置管理的最后一公里。
2.2 Spring AI Alibaba Admin 到底解决了什么
很多人第一次看到这个名字会问:这不就是一个管理后台吗?把它当成"后台"就理解窄了。Admin在我实际使用中的定位是"AI应用的中控台"。模型路由规则、Prompt模板、知识库文件、Token额度预警、调用链路追踪,这些分散在各系统里的东西,在这里集中展示和配置。
举一个真实场景:上线初期业务方反馈回答风格太生硬,希望更口语化。传统做法是改代码里的System Prompt,走开发、测试、上线流程,半个工作日没了。而在这个框架下,Prompt以模板形式存在配置中心,运营人员在后台改一条文案,刷新即生效。AI应用的迭代速度第一次追上了业务需求的变化速度,这件事对生产力的提升比模型本身大得多。
2.3 用它就是选了一个"标准答案"
说句实在话,选择这个技术栈还有一个隐性收益:标准统一。团队里的初级工程师也能照着统一的Controller模板、统一的服务层规范去写AI功能,而不是今天学这一段、明天发明那一段。代码的可维护性,有时候比技术本身的前沿性重要得多。
3. 实操落地:五步把AI功能接入企业级应用
3.1 环境准备和依赖引入
实操部分我用Spring Boot 3.3 + Spring AI Alibaba Admin作为基础版本组合,项目结构是标准的Maven多模块工程。引入依赖的时候要注意,Spring AI相关的starter必须统一版本,否则容易出现组件兼容问题,我建议直接用Spring父POM统一管理相关依赖版本,避免手工记版本号。
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>1.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>实际的AI功能依赖,最核心的是模型接入starter和管理端依赖:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-dashscope</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-admin-starter</artifactId> </dependency>注意:管理端后台如果不需要,可以只引入模型starter。Admin的定位是治理,不是强制组件,它拆得很干净,这点在工程上非常友好。
3.2 配置文件里的门道
第一次配置时最容易踩的坑,是把所有配置写成固定值。我的建议是:API Key或者密钥必须走环境变量,模型名称、温度、最大Token等参数放进配置文件,并且区分多环境。这里给一份参考配置:
spring: application: name: ai-customer-service ai: dashscope: api-key: ${DASHSCOPE_API_KEY} chat: options: model: qwen-plus temperature: 0.7 max-tokens: 1024 # RAG向量库配置 embedding: type: dashscope options: model: text-embedding-v3 datasource: url: jdbc:mysql://localhost:3306/ai_admin_console username: ${DB_USERNAME} password: ${DB_PASSWORD}这里有一个关键点:很多教程会把temperature写成0.3甚至0,这其实是照搬了"追求准确"的惯性思维。实际做客服场景时,0.7的随机性反而让回答更自然。不要把模型参数当成可以一劳永逸的定值,不同场景要单独设置。Admin后台一个很方便的功能就是按应用维度管理这些参数,而不是写死在代码里。
3.3 编写第一个工程化Controller
工程化和Demo代码最大的区别,是Controller不再直接暴露ChatClient。在我的实践里,业务侧调用AI能力要走统一的Service层,加上超时控制和结果格式化:
@RestController @RequestMapping("/api/ai") public class AiChatController { private final AiChatService aiChatService; public AiChatController(AiChatService aiChatService) { this.aiChatService = aiChatService; } @PostMapping("/chat") public AiChatResponse chat(@RequestBody AiChatRequest request) { // 统一入参校验、鉴权、限流都在这一层完成 return aiChatService.chat(request.getSessionId(), request.getPrompt()); } }Service层内部才去使用Spring AI的ChatClient:
@Service public class AiChatService { private final ChatClient chatClient; private final ChatMemory chatMemory; public AiChatService(ChatClient.Builder builder, ChatMemory chatMemory) { this.chatClient = builder .defaultSystem("你是企业客服助手,回答要求简洁专业,不要编造事实。") .build(); this.chatMemory = chatMemory; } public AiChatResponse chat(String sessionId, String prompt) { // 业务上通过sessionId管理会话记忆 return chatClient.prompt() .user(prompt) .chatMemory(chatMemory) .sessionId(sessionId) .call() .entity(AiChatResponse.class); } }这段代码看着简单,但它是从玩具走向工具的关键一步。所有企业级能力:身份识别、参数校验、会话管理、限流熔断,都在ChatClient调用之前完成了。模型在这里只是最内层的一个可替换组件。
3.4 让RAG真正能用于生产
知识库问答是AI应用最常见的落地场景,但Demo阶段的RAG几乎都有同一个毛病:文档切完就扔进去,从来没有考虑过切分质量和召回效果。我在接入Spring AI Alibaba Admin的文档管理功能后,才真正把RAG做成了一条可控的流水线。
核心环节包括:文档解析、文本切分、向量化、索引存储、召回、重排序。这里有一个很多人不重视的重排序步骤,初期不做重排序,召回Top5文档里经常混着无关片段,回答自然不靠谱。我接入了重排序模型后,回答准确性肉眼可见地提升。成本上虽然增加了一次调用,但换来的是用户信任,这笔账很划算。
另外要强调的是,知识库不是"灌进去就完事"。文档更新后必须同步刷新向量索引,这个链路如果没有Admin后台的索引管理页面,靠手工跑脚本,迟早会出数据不一致的事故。
3.5 Prompt模板的管理方式
我之前做Demo时,Prompt是拼字符串拼出来的。而工程化的做法是把Prompt定义成模板,并且支持变量注入:
public final class PromptTemplates { public static final String CUSTOMER_SERVICE = """ 你是{role},你的任务是回答用户关于{product}的问题。 回答要求: 1. 语气{tone} 2. 如果知识库中没有答案,明确告知用户"需要人工介入" 3. 禁止编造数据 用户问题:{question} 参考知识:{context} """; }这样的模板配合Admin后台,就能做到同一个Agent在不同业务线之间复用。我见过太多团队,每个业务线各写一套Prompt,最后改动一个需求要同步改五六个项目,苦不堪言。
4. 工程化最硬的骨头:可观测、降级与成本控制
4.1 每一次调用都要有迹可循
AI应用最大的运维噩梦,是用户反馈"回答不对",但你根本不知道模型当时收到了什么。传统日志打一条"调用成功"没有任何意义,必须把完整的请求上下文记录下来:用户问题、系统Prompt版本、模型参数、返回结果、Token消耗、耗时。
Spring AI Alibaba Admin内置了调用链追踪,我在实际使用中最常用的是按会话ID查一次完整对话的上下文还原。这功能在排查"为什么用户生气了"的时候简直是救命稻草。没有这个能力,客服场景的AI系统根本谈不上维护。
我用一个切面来统一记录这些关键信息:
@Aspect @Component public class AiCallAuditAspect { @Around("@annotation(aiCallAudit)") public Object auditAround(ProceedingJoinPoint pjp, AiCallAudit aiCallAudit) throws Throwable { long start = System.currentTimeMillis(); try { Object result = pjp.proceed(); long cost = System.currentTimeMillis() - start; auditService.record(aiCallAudit.bizType(), AiCallStatus.SUCCESS, cost); return result; } catch (Exception e) { auditService.record(aiCallAudit.bizType(), AiCallStatus.FAILED, System.currentTimeMillis() - start); throw e; } } }4.2 模型不可用时系统不能瘫痪
生产环境一定会遇到模型服务商抖动、限流甚至故障。好的系统设计要有自动降级能力。我的降级策略分三层:
第一层,模型服务不可达时,自动切换到备用模型供应商。Spring AI的统一接口让切换成本降到了最低,只需要改配置。第二层,AI能力整体不可用时,回落到人工客服,或者说返回预设的兜底文案,而不是让用户看到一个异常报错页。第三层,对关键业务场景设置超时熔断。
曾经有一次模型供应商大规模故障,我的系统因为降级策略,用户体验只是从"智能回答"变成了"我们收到了您的问题,客服会尽快联系您"。如果没有这层设计,那天的线上事故报告够我写三页。
4.3 Token费用的失控是最隐蔽的坑
AI应用的成本大头不是服务器,是Token。很多团队上线AI功能的时候,连一次会话的平均Token成本都没算过。我的经验是两步:第一步,在Admin后台设置单会话Token上限和月度预算告警;第二步,对Prompt模板做Token节省优化,比如删除不必要的历史消息、限制知识库召回的上下文长度。
我做过一个客服系统优化:通过裁剪历史消息、动态设定最大上下文长度,单次调用的Token消耗下降了大约40%。这笔节省在月调用量达到百万级时,就是实实在在的利润。
4.4 安全管控不能靠模型自觉
AI应用最容易忽视的安全问题包括:提示词注入、敏感数据外泄、越权访问知识库。我的底线原则是:模型不可信,一切进出都要校验。用户输入要进行敏感词过滤,AI返回结果要经过内容安全审核,知识库目录要按角色权限隔离,绝不能把全量知识库暴露给所有用户。
在实际项目中,我用了一套双保险:请求侧做输入合规检查和权限校验,返回侧做敏感信息检测和越权数据拦截。
5. 常见问题与排查技巧实录
5.1 模型回答幻觉严重怎么办
先说结论:幻觉不可能完全消除,但可以控制在可接受范围。我的排障顺序是:一查知识库召回的内容是否相关,二看用户问题是否超出知识库覆盖范围,三检查System Prompt是否允许模型推测。对应措施:提升重排序精度、对无法回答的问题设置明确话术、降低temperature。
5.2 并发一高就超时、报错
AI API的响应速度远慢于普通HTTP接口,高并发下必须做线程池隔离。我用了一个独立线程池处理AI调用,并设置信号量限流,保证AI服务的慢请求不会拖垮主业务的Tomcat线程。
spring: task: execution: pool: core-size: 8 max-size: 32 queue-capacity: 1005.3 向量库召回效果差
优先检查切分策略。一个几百K的PDF,如果按固定1024字符切分,很多语义被切断,召回必然差。我改用了按标题结构切分,并且让相邻片段保留部分重叠,召回率提升明显。
5.4 后台管理配置不生效
注意配置的加载顺序。Admin后台做的动态修改,有时会被启动时的本地配置覆盖。解决办法:后台修改的配置要明确标记为"运行时配置",并把本地配置文件里的相同项删除或注释,避免两处不同配置打架。
5.5 调用链追踪日志太多
全量记录会产生海量日志。我的策略是:正常调用记录精简摘要,失败和长耗时调用记录完整上下文。同时在日志中打上traceId,方便快速关联。
6. 最后说点我的真实体会
我见过太多团队在AI项目上重蹈当年大数据项目的覆辙——技术选型时被各种Agent框架迷花眼,最后落不了地。如果你问我现在还想不想用ChatClient来造一个DEMO,当然想。但如果你问我要不要用它做生产项目,我强烈建议把工程化能力放在第一位。Spring AI Alibaba Admin让我感觉最舒服的地方,是它给了模型一个稳定、可治理的"家",而不是让模型光着脚在生产环境里裸奔。
如果你正在纠结选型,我给你一个最朴素的建议:先列出你自己的治理清单,然后拿这个清单去对照每个候选方案,看哪些能开箱即用、哪些要自己补。补的东西越多,项目离死亡越近。
我自己已经把球队的几套知识库系统都迁到了这个技术栈上,后面打算把Agent编排也接进来。AI应用这条路还很长,但至少现在,路线图是清楚的。