多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

SpringBoot3+LangChain4j+Vue3实战:构建AI应用平台

SpringBoot3+LangChain4j+Vue3实战:构建AI应用平台 简介基于 Spring Boot 3、LangChain4j 与 Vue 3 构建的 AI 应用平台源码适合具备 Java 全栈基础、希望快速搭建智能体与工作流应用的开发者。项目覆盖智能代码生成、AI 智能体、LangGraph4j 工作流编排及 Tool Calling 调用并配套可视化编辑、一键部署、应用管理和智能路由能力同时集成多级存储与 Nginx借助 ARMS、Prometheus、Grafana 实现运行监控可支撑较完整的全栈 AI 开发实践。资源包共 216 个文件以 143 个 Java 文件为主配合 Vue/TypeScript 前端、JSON/XML 配置及 SQL 初始化脚本整体仅 1.14MB结构紧凑。已有 250 人学习。通过源码目录可了解前后端分离架构、流式对话实现及监控埋点方式适合用于学习框架整合与项目二次开发。1. AI应用平台到底是什么智能体、工作流与可视化交付的合体把大模型从聊天窗口拽进业务系统第一道坎从来不是“模型效果不好”而是工程化怎么让模型稳定地完成“生成代码、调用工具、执行流程”这一串动作怎么把写死的Prompt链变成能编排、能回滚的工作流怎么把命令行里的Demo变成团队能登录使用、能一键上线的应用。标题里这个基于SpringBoot3LangChain4jVue3的AI应用平台本质是把这三件事打包成一套可落地的产品形态用LangChain4j把LLM封装成会调工具的AI智能体用LangGraph4j工作流把决策逻辑升级成可编辑的状态图再用Vue3做可视化控制台把创建智能体、拖拽工作流、配置Tool Calling、发布应用、看调用数据全部变成界面操作。它面向的是主栈在Java/Spring生态、想把大模型能力沉淀成内部可复用平台的团队而不是单纯做一个聊天机器人壳。2. 技术底座三件套SpringBoot3、LangChain4j和Vue3为什么能搭在一起动手写代码之前先把选型层面的四个“为什么”讲清楚。标题把这三项技术绑定在一起说明选型前提是“纯Java技术栈做LLM应用工程化”。这个前提成立不成立直接决定后面每一步的维护成本。2.1 SpringBoot3是硬门槛不是可选项JDK 17、Jakarta与虚拟线程SpringBoot3不是换个版本号那么简单。LangChain4j要求JDK 17以上Spring Boot 3.x同样以JDK 17为基线两者是同一时代的产物。如果团队现在还在JDK 8那么做这个平台的第一件事不是写代码而是先迁移JDK并把依赖里的javax.*全部调整到jakarta.*命名空间。这个适配工作量大而且容易出现“编译能过、启动就炸”的诡异问题我建议在项目启动清单里把JDK升级单独立项。第二个理由是并发模型。Spring Boot 3.2以上版本在JDK 21环境下支持虚拟线程可以一行配置全局开启。LLM调用是典型的IO密集型场景大部分时间花在等待网络和模型返回上虚拟线程可以把单机并发能力提升一个量级。这一点在JDK 8加Spring Boot 2时代是完全没有的属于选SpringBoot3才有的红利。第三个理由是集成方式。Spring Boot 3把自动配置统一收口到AutoConfiguration.imports机制LangChain4j这类第三方库接入Spring生态时入口更清晰。常见的做法是定义一个配置类把所有模型参数收敛到一个统一配置类里由Spring托管ChatLanguageModel这个Bean。Configuration EnableConfigurationProperties(LlmProperties.class) public class LlmAutoConfiguration { Bean ConditionalOnMissingBean public ChatLanguageModel chatLanguageModel(LlmProperties props) { return OpenAiChatModel.builder() .apiKey(props.apiKey()) .modelName(props.model()) .temperature(props.temperature()) .maxTokens(props.maxTokens()) .build(); } }这段配置的作用是把模型供应商、模型名、apiKey、温度、最大token都收敛到LlmProperties里业务代码不直接接触模型构造逻辑。ConditionalOnMissingBean是其中的关键它允许业务方在需要时覆盖默认模型Bean而不是被这个自动配置卡死。apiKey必须从环境变量或配置中心注入绝对不能写死在仓库里这是血泪经验。在代码生成场景下temperature默认值建议直接调成0.1以下后面讲智能体时再展开说明。从工程拆分看我一般会把后端按“能力域”分包而不是按“页面”分包。智能体定义、工作流引擎、应用管理、基础设施四块互不渗透这样以后接入新模型厂商时只需要改基础设施层的网关适配其他层完全不动。2.2 LangChain4j给Java生态补了什么课接口抽象与Agent运行时Java生态不缺HTTP客户端缺的是把对话管理、工具调用、记忆、输出解析串起来的编排框架。LangChain4j补的正是这一课。它对上统一了不同模型厂商的差异无论OpenAI还是本地部署的Ollama都抽象成同一个ChatLanguageModel接口对下提供了AiServices这种声明式编码方式让开发者定义一个普通Java接口就能得到一个具备完整Agent能力的服务。public interface OrderAssistant { String chat(UserMessage String userMessage); }然后一句话构建实现。OrderAssistant assistant AiServices.builder(OrderAssistant.class) .chatLanguageModel(model) .tools(new OrderTools()) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .build();UserMessage标注入参AiServices会在运行时替你把用户消息包装成标准Prompt。MessageWindowChatMemory.withMaxMessages(10)表示只保留最近10条消息这是最省token也最容易维护的短期记忆策略。如果场景需要长期记忆就必须换成持久化的ChatMemoryStore把消息存到数据库或Redis不能继续用默认的内存实现否则应用一重启对话上下文全部丢光。很多AI应用表面上“忘了之前的对话”其实只是用了内存态记忆这个坑到生产环境才暴露。LangChain4j的模块命名很规律langchain4j-open-ai、langchain4j-ollama、langchain4j-azure-open-ai分别对应不同模型供应商的适配模块配合Spring Boot Starter多数场景只需要在配置中心换供应商和API Key业务代码一行不用改。这就是Java技术栈做AI应用相对Python方案的核心优势模型厂商可以随时换业务系统的依赖不换。还有一个容易忽略的点LangChain4j社区里大量Example是围绕聊天场景写的真正放到生产环境时要自己补的往往是错误处理、重试、超时、限流这些工程化能力。框架只保证“能跑通”不保证“跑得稳”这部分必须结合Spring的Resilience4j或Sentinel自己封装。2.3 Vue3在平台里不是页面是整套可视化设计器的运行环境前端选Vue3不是因为它比另一个框架好而是因为工作流编辑器这个核心场景对响应式状态管理的要求极高。画布上的节点坐标、节点参数、连线关系、运行状态是强关联数据一个节点参数改变后续所有节点的校验状态都要联动刷新。Vue3的组合式API配合reactive和computed处理这类联动非常顺手比命令式DOM操作同步画布要省心得多。画布组件主流选vue-flow/core它是数据驱动的维护好节点和边的数组画布会自动重绘。const nodes ref([ { id: generate, type: agent, position: { x: 0, y: 0 } }, { id: review, type: tool, position: { x: 300, y: 0 } }, ]) const edges ref([{ source: generate, target: review }])这段代码定义了整个可视化编辑器的数据契约工作流在后端是一张有向图前端用同样的node与edge结构渲染。新增节点、拖拽位置、建立连线都只改这两个数组。真正的复杂度在于把后端StateGraph的状态定义和节点参数序列化成这份JSON并在保存时还原回后端图结构下一章详细展开。2.4 最小可运行脚手架后端依赖声明与前端的初始化命令后端pom的关键依赖先看BOM部分。LangChain4j官方提供BOM用它统一管理各模块版本能避免自己维护一堆版本号导致的版本漂移。dependencyManagement dependencies dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-bom/artifactId version${langchain4j.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement然后是实际依赖声明。这里要注意除了langchain4j主体还要引入Spring Boot Starter它负责把LangChain4j的组件自动装配进Spring容器。dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-spring-boot-starter/artifactId /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-open-ai/artifactId /dependency /dependenciesBOM负责版本对齐starter负责自动装配open-ai适配模块负责把OpenAI协议请求翻译成ChatLanguageModel接口。如果后续换成国内兼容OpenAI协议的模型只需要改baseUrl和apiKey。模型参数建议全部放配置中心因为温度、最大token、系统提示词这些属于运行期高频调整项。前端只有几条命令。npm create vitelatest ai-console -- --template vue cd ai-console npm install pinia vue-flow/corepinia负责应用管理模块的全局状态vue-flow/core负责工作流画布。模板用vue即可如果团队习惯类型约束可以加--ts。画布组件选择上实测下来vue-flow/core对自定义节点类型的支持是最好的给Agent节点、Tool节点、开始结束节点各写一个组件就能覆盖绝大多数场景。这套骨架跑通之后第一件事不是去写界面而是先把模型连通性验证做掉。配置好LlmProperties和ChatLanguageModel之后直接用ApplicationContext取出Bean做一次同步调用输出“模型可用”就算第一关过了。3. AI智能体与Tool Calling代码生成如何从“花架子”变成“真工具”代码生成是这个平台里最有说服力的场景也是AI智能体和Tool Calling结合得最紧密的地方。把这两块讲透其他应用场景基本就是换提示词和换工具集的事。3.1 为什么智能代码生成不能靠一次Prompt完成很多人第一次做代码生成就是写一个大Prompt让模型输出完整代码。等代码跑到第三步就会发现模型不知道你的表结构、不知道你的项目分层规范、不知道编译环境里缺什么依赖。一次生成出来的代码看着像模像样一编译全是错。代码生成本质上是一个循环理解需求获取上下文生成代码编译验证发现问题再修复反复直到通过。这个循环靠普通的一次性Prompt调用无法完成因为模型需要外部信息反馈。要拿到表结构就得查数据库元数据要验证编译结果就得执行构建命令这些动作模型本身做不到必须由程序提供工具、由模型决定调用时机。这就是AI智能体的运行机制模型不再只是“生成文本”而是在循环里做决策——判断当前需要什么信息、调用哪个工具、拿到结果后继续处理。用户需求 - 智能体解析 - 查询表结构 - 生成代码 - 编译验证 ^ | | v -- 失败则修复 --这个循环是LangGraph4j工作流也是Tool Calling的用武之地。Tool Calling解决的是“模型如何调用外部方法”而智能体解决的是“什么时候调用、调完怎么办”。LangGraph4j则把整个循环显式地建模成一张图每一步都是图里的一个节点。三者在这个场景形成了完整闭环。3.2 用Tool给智能体装上“手和脚”LangChain4j里注册一个工具非常简单核心就是一个带Tool注解的Bean方法。工具的方法名和描述会作为元数据传给模型模型看到描述后会决定何时调用。Slf4j Component public class CodeGenTool { Tool(根据表名查询数据库表结构返回DDL建表语句调用前先解析出表名) public String getTableDdl(String tableName) { // 从元数据中心查询省略实现细节 return ddl; } Tool(对指定Maven模块执行编译命令返回退出码与日志末尾100行) public String runCompile(String modulePath) { // 用ProcessBuilder执行mvn -q compile返回stdout与stderr合并后的尾部 return tailLog; } }这段代码有两个决定成败的细节。第一是注释里的描述文本它不会被编译进调用逻辑但会被序列化进工具元数据送给模型。模型的判断完全依赖这段描述写得模糊模型就不知道该在什么时机调用这个工具。第二是方法参数必须有业务含义参数名tableName而不是a或b因为参数的语义也会传递给模型清晰参数名能显著降低错误调用的概率。实践中最常见的翻车点是工具方法体里直接抛异常。模型调用工具后拿到异常消息往往会反复重试同一个错误调用浪费token还拖慢响应。工具方法内部必须做好异常兜底把错误信息变成一句话返回给模型让模型有机会换一种方式处理。3.3 用AiServices组装一个带记忆的代码生成智能体工具定义好了下一步就是把它组装成智能体。LangChain4j提供AiServices这层抽象会把接口、模型、工具、记忆四者缝合在一起。public interface CodeGenAgent { SystemMessage( 你是平台内置的代码生成智能体。 任务流程 1. 先解析用户需求必要时调用 getTableDdl 获取表结构 2. 生成符合项目分层规范的 Java 代码 3. 生成后调用 runCompile 验证编译失败则根据日志修复最多重试 3 次 4. 最终返回结果时附上文件清单与编译结论 ) String generate(UserMessage String requirement); }CodeGenAgent agent AiServices.builder(CodeGenAgent.class) .chatLanguageModel(model) .tools(new CodeGenTool()) .chatMemory(MessageWindowChatMemory.withMaxMessages(16)) .build(); CodeGenResult result agent.generate(生成订单模块包含订单主表和订单明细表编译通过);SystemMessage定义了智能体的行为约束它比每次调用时拼接字符串要规范得多因为提示词被固化在接口定义里可以随版本一起管理。chatMemory窗口设为16对应大约8轮对话覆盖需求澄清和修复迭代就够用。如果需要在多轮迭代中保持上下文同时控制token消耗这组参数是比较好用的起点。AiServices在运行时生成接口实现类。你写的接口方法签名就是Agent的能力边界入参是用户需求返回值是生成结果。generate方法内部会自动完成“模型决策、工具调用、结果回填、再次模型调用”这个循环业务代码感知不到循环细节。3.4 智能代码生成的三个必调参数与边界认知代码生成场景下模型参数不是默认值能直接用的。以下是实践里最值得调的三项。temperature: 0.1 maxTokens: 6000 frequencyPenalty: 0.0温度必须控制在0.1以下。代码生成是强确定性的任务温度一高编译不过的“幻觉代码”就会明显增多。最大token要给足代码加注释加文件清单动辄几千token默认的几百根本不够用。frequencyPenalty保持为0避免模型为了avoid重复而刻意换一种写法那反而破坏代码风格一致性。边界认知也要清楚代码生成智能体再强也只能在上下文可见的范围内工作。它看不到全局代码仓库不知道团队规范文档除非你把这些内容通过工具暴露给它。更合理的拆分是表结构、依赖清单、Git提交记录、静态检查结果都做成工具让模型按需调用而不是把整个仓库塞进上下文。这既是成本问题也是可靠性问题。上下文越短幻觉越少这是代理平台的核心方法论。4. LangGraph4j工作流可视化编辑与状态编排的实现要点智能体解决了单次任务里的自主循环但一个真正要交付的AI应用往往要串起多个智能体和工具调用并且每个步骤之间有依赖、有分支、有重试。这个层面的编排就是LangGraph4j工作流要解决的问题。4.1 LangGraph4j做了什么把对话循环变成带记忆和检查点的图LangChain4j的AiServices适合单智能体任务但它很难表达“步骤A失败后走BB的结果再回到A”这类分支逻辑。LangGraph4j把工作流定义成一张显式图节点是业务步骤边是执行顺序条件边可以按状态动态决定下一步走到哪个节点。它比普通链路编排强在两点允许环执行状态可以被持久化。允许环是Agent场景的关键。代码生成里的“编译失败然后修复然后重新生成”就是一个环用线性链表达只能靠模型自身循环用图表达则把循环控制权交还给程序每一步都显式可观测、可记录、可回滚。状态持久化解决的是长任务问题工作流执行到一半服务重启了可以从持久化的检查点恢复而不是整个重跑这在生产环境里是必须的能力。4.2 最小表达一个带条件回边的代码评审工作流定义一个最简工作流包含生成节点、评审节点、条件回边。public class CodeReviewState { private String requirement; private String generatedCode; private ListString reviewComments; private Boolean passed; }StateGraphCodeReviewState graph new StateGraph(CodeReviewState.class) .addNode(generate, generateNode) .addNode(review, reviewNode) .addEdge(generate, review) .addConditionalEdge(review, state - { if (Boolean.TRUE.equals(state.getPassed())) { return List.of(__end__); } return List.of(generate); });addNode定义业务执行单元addEdge建立顺序边addConditionalEdge是工作流真正灵活的地方它读取当前状态返回下一步要进入的节点ID。__end__是LangGraph约定中的结束节点返回它代表工作流正常收尾。这里generateNode与reviewNode可以是普通函数也可以是用AiServices封装好的智能体调用。与手写循环相比这种图结构带来的直接好处是可观测。工作流状态的每一次变迁都可以被记录哪个节点耗时多久、走了哪条边、状态里残留了什么数据全部变成可查询的数据。排查问题时不再需要从日志里猜直接看状态快照就能定位。4.3 可视化编辑器的数据模型一份JSON同时驱动后端执行与前端画布可视化编辑的核心问题是如何把平台运行时的图结构与前端画布的视觉结构绑定为同一份数据。常见做法是定义一个中间JSON格式既包含节点坐标等视觉信息也包含节点ID、类型、参数、边条件等执行信息。{ workflowId: code-review-flow, nodes: [ { id: generate, type: agent, position: { x: 120, y: 80 }, config: { model: code-generator, maxRetries: 3 } }, { id: review, type: tool, position: { x: 480, y: 80 }, config: { toolName: codeReview } } ], edges: [ { source: generate, target: review, label: }, { source: review, target: generate, label: !passed } ] }这份JSON里的id、type、position是前端画布渲染的必需字段config是节点执行参数edges里的label会显示为前端连线上的条件文本。后端保存工作流时只需要把这份JSON转换成StateGraph的节点注册和条件边策略前端加载工作流时把后端持久化的JSON直接丢给vue-flow/core渲染即可。数据模型设计上有一个关键的长期决策执行参数和视觉参数必须分开存。position不参与图执行逻辑但如果不加区分地混在一个字段里将来调整布局就会被误判为工作流变更。保存时只比较config和edges是否变化position变化不触发版本变更能省掉大量无意义的历史版本。4.4 工作流可视化编辑落地的三个边界问题第一个边界是节点类型扩展。平台刚起步时只有Agent节点和Tool节点跑一段时间就会冒出来“用户输入节点”“条件判断节点”“代码执行节点”。节点类型要做成插件化而不是在画布组件里堆switch分支。为每种节点单独实现配置面板与执行器注册到统一注册表里新增一种节点就不需要动核心代码。第二个边界是图的合法性校验。可视化拖拽很自由但并不是任意图都能执行。常见不合法的状态有存在无法到达的节点、存在没有出口的循环、节点启用了但未配置模型。保存时必须做静态校验简单做法是把图遍历一遍标记不可达节点与死循环在界面上高亮报错。这个校验不能等执行时才暴露否则用户拖了两个小时的工作流一跑就废。第三个边界是执行超时与中断。工作流里任何一个节点都可能因为模型接口超时或工具异常卡住因此工作流引擎必须为每个节点设置独立超时并支持取消信号传递。LangGraph4j的状态持久化在这里帮了大忙节点超时后可以从最近一个检查点恢复而不是整个工作流作废。5. 部署与应用管理避坑五个必须提前知道的坑平台做得再漂亮部署和应用管理环节出问题前面所有努力都会变成“演示环境能跑生产环境翻车”。以下是按真实发生频率排序的五个坑每一条都是现象、原因、解决的完整链路。5.1 一键部署的“一键”是假象环境依赖检查不能省现象点击控制台的“一键部署”容器成功启动但智能体调用全部失败。排查发现容器里没有配置模型网关地址也没有给工具调用留出网络出口。一键部署变成了“一键启动”业务逻辑根本没通。原因AI应用是所有应用类型里外部依赖最多的。它依赖模型API、依赖向量库、依赖代码仓库、依赖内部工具服务。普通Web应用只需要数据库和配置中心AI应用在这之上还要多出一整套模型链路。部署脚本只做了进程拉起没做依赖检查。解决在部署流程里增加部署前检查环节常称为Pre-flight Check。检查项至少包括模型API连通性、配置中心连通性、密钥存在性、工具服务白名单放行。容器启动命令里把健康检查接口设为/actuator/info/ai-ready由后端在启动时自动检测模型连通性连通才返回200。这样一次典型的部署失败不用再靠人肉看日志。5.2 SSE流式输出中断长连接被各种中间层悄悄切断现象前端Vue界面里智能体输出流式文本每次都在几十个token之后戛然而止。页面看不出报错但输出永远不完整。原因SSE是长连接在模型返回过程中任意一环超时都会导致连接中断。常见元凶有三个Nginx没有关闭缓冲缓冲满了才转发模型没结束就一直囤积网关层的读超时设太短Spring MVC的异步请求超时没有配置。解决逐层放行。Nginx侧配置关闭SSE缓冲把读超时和代理超时都拉长到模型最大时长Spring Boot侧配置异步请求超时和使用虚拟线程提升并发。spring: mvc: async: request-timeout: 60000这个配置表示异步请求最长60秒运行时要按实际模型最慢响应调整。50秒内模型还没返回第一个token大概率是模型端出了问题等下去没有意义。如果你用事件监听器或WebFlux对应配置在不同位置原理一致两层中间件都不能让它“默默断连”宁可超时报错也不能让用户看到半截话。5.3 密钥管理API Key泄漏往往发生在最不起眼的地方现象代码仓库扫描工具告警发现某配置文件里有一串OpenAI格式的API Key。查下来是早期实现时图省事把Key写进了application.yml之后又提交到了Git仓库。原因LLM应用的密钥比普通数据库密码更敏感因为模型调用直接产生费用泄漏的Key可以被盗刷。而AI应用的配置项里天然存在多个密钥模型API Key、向量库Key、私有仓库Token分散在各处很容易看漏。解决密钥强制走环境变量或配置中心代码仓库里只放占位符。Git提交历史的敏感信息要重写用git-filter-repo这类工具清一遍再重新推远端。这一步没有“以后再说”的余地密钥泄漏的账单会比项目本身的模型调用费高几个数量级。5.4 会话记忆无限膨胀内存态记忆导致OOM现象平台运行几天后后端服务内存持续走高最后触发OOM。重启后恢复正常过几天又涨上去规律非常明显。原因开发环境用的MessageWindowChatMemory是内存实现消息窗口只限制“模型看到多少条”但已从窗口滑出的消息可能仍被某些实现持有着当智能体实例被反复创建时内存里堆了大量会话对象。另一个元凶是长期记忆的持久化存储没设TTL历史消息无限累积。解决会话记忆必须分层管理。短期记忆用窗口持久化到Redis并设置TTL长期记忆单独建表存储按用户维度做生命周期清理。给Redis里的会话Key设置过期时间是第一道保险比依赖代码里主动清理可靠得多。# 在 Redis 中为会话记忆设置 24 小时过期 EXPIRE session:{userId}:{sessionId} 86400这条命令的意义在于即使应用层忘了清理存储层的过期策略也会兜底。不要指望所有开发者都记得在代码里写清理逻辑存储层的TTL才是持久的契约。5.5 多租户串线一个静态ChatMemory毁掉隔离性现象A用户创建的智能体对话内容出现在B用户的会话历史列表里。B用户点开自己的应用看到的是别人的需求描述。原因实现时有人为了方便把ChatMemory定义成了Spring的单例Bean所有用户共用一个记忆容器。多租户场景下没有按用户维度隔离会话Key数据自然串了。解决ChatMemory必须按租户和会话维度隔离。常见做法是覆盖ChatMemoryStore接口实现一个按tenantId:userId:sessionId分桶的存储层每一层维度都作为Redis的Key前缀。Override public ChatMemory get(ChatMemoryKey key) { String redisKey chat:memory: key.tenantId() : key.userId(); ListChatMessage messages redisTemplate.opsForList() .range(redisKey, 0, MAX_MESSAGES - 1); return MessageWindowChatMemory.builder() .maxMessages(MAX_MESSAGES) .chatMemoryStore(redisStore) .build(); }这里的核心是key必须带上租户与用户维度并且存储和读取使用同一个Key构造逻辑。隔离性不是靠框架保证的而是靠Key设计保证的。这个隔离做好才谈得上商业化多租户。6. 进阶把AI应用平台推向生产的四个关键动作工作流能跑、应用能部署这时平台已经进入“能用”阶段。继续往下走真正决定口碑的是稳定性与可维护性。我最后想分享四个动作希望对你有用。第一个动作是给AI调用加全链路观测。模型调用、工具调用、工作流节点执行每一步都要产出结构化日志包含租户ID、应用ID、模型名、输入输出token数、耗时、状态码。别把这些当普通日志打直接打到独立的调用明细表或链路追踪系统。排查线上问题时链路数据比模型效果更重要它让你能立刻分辨“是模型问题还是平台问题”。否则AI应用就是个黑匣子出问题只能靠猜。第二个动作是给提示词和工具元数据上版本。系统和用户的提示词一旦上线就不是字符串了是资产。提示词每次修改都生成新版本工作流保存时记录当时的提示词版本这样业务反馈“上周还好好的这周变笨了”一查就能定位到是哪次提示词变更引入的回归。第三个动作是模型路由与降级。至少配置主备两条模型链路主链路超时或返回异常时自动切换到备链路。这一步能在模型供应商出问题的时候把故障时间从一个下午压缩到几十秒。不要把所有流量绑在一个模型上平台层做路由业务层无感。第四个动作是限流与预算控制。AI应用与普通API不同一次调用的成本波动很大。要按应用维度做token限额和预算告警超出阈值自动降级到低配模型或拒绝新对话。成本失控是AI平台在企业内部翻车的最常见原因这一层必须前置。最后说个习惯我在上线任何AI平台前都会强制自己做一次故障演练把模型API的Key删掉看系统会不会优雅报错把工作流中间节点杀死看状态能不能恢复。演练过一遍才敢把平台的宣传语从“能用”改成“好用”。希望帮到你。本文还有配套的精品资源点击获取
返回列表