Java 工程师必看:大模型应用实战指南,收藏学习,掌握LLM、Agent、RAG、Skill一网打尽
一、为什么这篇文章值得 Java 工程师认真读完?
大模型已经不是“试一试”的技术,而是开始进入核心业务链路。
对 Java 工程师来说,真正的挑战从来不是“会不会调用一个 LLM API”,而是下面这些更现实的问题:
- • 如何避免大模型一本正经地胡说八道
- • 如何把企业知识库、安全权限、订单系统、工单系统接进来
- • 如何在高并发下扛住流量,同时控制模型调用成本
- • 如何让系统具备可灰度、可观测、可扩展、可回退的工程能力
很多文章把 LLM、Agent、RAG、Tool、Skill 拆开讲,但在企业落地里,它们从来不是孤立存在的。真正可上线的智能系统,通常是这样一条链路:
-
LLM负责理解、推理、生成。
-
RAG负责把“企业真实知识”注入上下文,抑制幻觉。
-
Agent负责判断什么时候该检索、什么时候该调用工具、什么时候该结束。
-
Skill负责把工具能力做成稳定、自治、可治理的业务能力单元。
这篇文章不只解释“是什么”,而是站在资深架构师视角,带你搭一套真正能进生产的大模型应用架构。全文以一个典型的企业智能助手场景展开:
- • 员工咨询制度政策
- • 查询个人余额、档案、订单、工单
- • 发起 IT 支持、退款、审批等动作型请求
- • 支持高并发访问、流式响应、异步执行和全链路审计
技术栈会尽量贴近 Java 主流工程体系:
- •
Spring Boot 3.x - •
Spring WebFlux - •
Redis - •
Kafka - •
Milvus / PgVector - •
Micrometer + Prometheus + Grafana - •
Kubernetes - •
LangChain4j / AgentScope Java
二、先统一认知:LLM、RAG、Agent、Skill 到底各解决什么问题?
2.1 LLM:负责语言理解与生成,但不等于“事实真相”
LLM 本质上是一个基于上下文预测下一个 token 的概率模型。它强在:
- • 自然语言理解
- • 多轮对话
- • 摘要归纳
- • 推理规划
- • 结构化输出
但它天然存在三个工程痛点:
- • 没有企业私域知识
- • 容易幻觉
- • 对实时状态无感,比如订单状态、审批结果、库存变化
所以,企业系统里不能把 LLM 直接当作“事实数据库”或“业务系统”。
它更适合做两类事情:
-
- 把人类自然语言翻译成系统可执行意图。
-
- 基于可信上下文,生成对用户友好的最终回答。
2.2 RAG:把“企业事实”实时塞进大模型上下文
RAG,Retrieval-Augmented Generation,检索增强生成。
它解决的是“模型不知道你的内部知识”这个根本问题。
经典链路如下:
-
- 文档清洗
-
- 文档切片
-
- 向量化 embedding
-
- 存入向量库
-
- 用户问题向量化
-
- 相似度检索
-
- 重排筛选
-
- 将证据片段注入 prompt
-
- LLM 基于证据生成答案
RAG 的本质不是“让模型更聪明”,而是“让模型回答时有证据”。
2.3 Agent:让模型从“会说”进化到“会做”
如果只有 LLM + RAG,系统通常只能“回答问题”。
但企业场景里,用户经常不是只想知道,而是要系统执行动作,比如:
- • “帮我查一下年假余额”
- • “帮我创建一个 VPN 故障工单”
- • “帮我提交退款申请”
这时候就需要 Agent。
Agent 的核心作用是:
- • 识别用户意图
- • 决定是否需要调用外部工具
- • 决定调用哪个工具
- • 根据工具结果继续推理
- • 生成最终答案
工程上常见范式是 ReAct:
- •
Reasoning:先思考 - •
Acting:调用工具 - •
Observation:读取工具结果 - • 再次思考,直到得出最终答案
2.4 Skill:工具的工程化抽象,而不是随手封个 HTTP Client
很多团队在做 Agent 时,会把 Tool 设计成直接调用某个接口的方法。这样早期能跑,但一到生产就会暴露问题:
- • 权限边界不清晰
- • 超时、重试、幂等没有治理
- • 审计记录不完整
- • 无法独立扩容
- • 业务逻辑散落在 Agent 层
因此,更好的做法是把工具抽象为 Skill。
Skill 可以理解为“可被 Agent 调度的业务能力单元”,它有自己的:
- • 输入输出契约
- • 权限规则
- • 重试熔断
- • 幂等控制
- • 审计日志
- • SLA 指标
一句话总结四者分工:
- •
LLM负责理解与生成 - •
RAG负责提供事实证据 - •
Agent负责决策编排 - •
Skill负责落地执行
三、企业级大模型应用的正确架构,不是“一个 Controller 调 OpenAI”
很多 Demo 的结构是:
Controller -> Prompt -> LLM API -> return
这只能叫“接了大模型”,远远不能叫“系统架构”。
生产级架构至少要同时考虑:
- • 请求接入与限流
- • 对话状态管理
- • 意图识别与路由
- • 检索增强链路
- • Agent 工具编排
- • 业务 Skill 执行
- • 审计与观测
- • 缓存与成本控制
- • 异步削峰与高可用回退
下面给出一套推荐的参考架构。
Client / Web / App
API Gateway
Chat Service
Intent Router
RAG Pipeline
Agent Orchestrator
Embedding Service
Vector DB
Rerank Service
Skill Registry
Order Skill
Refund Skill
IT Ticket Skill
Profile Skill
Redis Session / Cache
Kafka Async Bus
Observability
LLM Gateway
OpenAI / Qwen / Private Model
Prometheus / Grafana / ELK
这套架构有几个非常关键的设计点。
3.1 Chat Service 不直接承载所有复杂逻辑
Chat Service 的责任应该是“编排入口”,而不是“大一统业务中心”。
它主要负责:
- • 接收请求
- • 维护上下文
- • 调用意图路由
- • 决定走 RAG、Agent 或普通问答
- • 汇总结果并返回
而真正的知识检索、业务执行、异步任务、模型调用,都应该被下沉到独立组件。
3.2 LLM Gateway 是非常值得单独抽象的一层
不要在业务代码里到处散落 OpenAiChatModel.builder()。
LLM Gateway 至少要统一以下能力:
- • 模型路由
- • 超时控制
- • 重试策略
- • 限流熔断
- • token 统计
- • 请求日志脱敏
- • 提示词模板版本管理
否则,当你从一个模型切换到多模型,或者从公有云切换到私有化推理集群时,改造成本会非常高。
3.3 Skill 要有“服务化思维”
Skill 不应只是 Agent 的注解方法,更应该具备完整工程属性:
- • 明确的领域边界
- • 可独立测试
- • 可单独限流
- • 可独立扩缩容
- • 具备审计记录
如果一个 Skill 涉及修改订单、退款、审批这类强业务动作,最好走独立服务或独立执行器,而不是简单的同步内存调用。
四、核心原理深入:为什么很多 RAG 项目上线后效果并不好?
RAG 最容易被低估,也最容易被做坏。
很多团队上线后发现:
- • 明明接了向量库,还是答非所问
- • 召回结果不少,但有效证据很少
- • 模型经常“拿到错误上下文后更加自信地胡说”
原因通常不在模型,而在检索链路设计。
4.1 文档切片决定召回上限
切片太大,会导致:
- • 一个 chunk 包含多个主题
- • 检索相似度被噪音稀释
切片太小,会导致:
- • 单个 chunk 缺乏完整语义
- • 模型拿到碎片信息后无法正确总结
比较稳妥的策略通常是:
- • 逻辑切片优先于字符切片
- • 先按标题、段落、表格、列表等结构切
- • 再做定长递归切片
- • 保留一定 overlap,减少上下文断裂
经验值可参考:
- • 普通制度文档:
500-800tokens - • FAQ:
200-400tokens - • 技术文档:按小节切,再限制最大 token 数
4.2 召回不是越多越好,关键是“高质量证据”
如果一次检索返回 10 个片段,但其中只有 2 个真正相关,其余 8 个是噪音,那么模型很容易被污染。
因此,生产链路通常不是单阶段检索,而是:
-
- 粗召回:向量检索 TopK
-
- 过滤:按租户、部门、知识域、时间范围做元数据过滤
-
- 精排:Rerank 模型重新排序
-
- 裁剪:控制最终注入模型的证据数量和 token 总量
4.3 强制 RAG 比“让模型自己决定要不要检索”更稳定
很多团队喜欢让 Agent 自由决定是否调用知识库工具,这在开放式问答里没问题,但在制度、政策、规范类场景里,风险很高。
更稳妥的做法是:
- • 对某些意图类型强制进入 RAG 模式
- • 先检索,再总结
- • 明确要求模型“只能基于检索结果回答”
这会明显降低幻觉率,也是很多企业知识问答系统的主流实践。
4.4 RAG 的上线指标,不是只有“像不像”
线上评估不能只看“回答读起来通不通顺”,更要看:
- •
Recall@K:目标答案是否被召回 - •
MRR / NDCG:相关文档排序质量 - •
Citation Accuracy:引用来源是否正确 - •
Answer Groundedness:答案是否可由证据支撑 - •
Latency P95 / P99 - •
Cache Hit Ratio - •
Cost per Request
只有把“效果”和“工程”一起量化,RAG 才能真正落地。
五、Java 落地方案:生产级模块拆分应该怎么做?
推荐按以下方式拆分模块,而不是把所有逻辑堆在一个 service 里:
smart-ai-assistant├── chat-api # HTTP/SSE 接口层├── ai-orchestrator # Agent / RAG / Prompt / 路由编排├── knowledge-service # 文档摄取、切片、embedding、检索、rerank├── skill-sdk # Skill 契约、工具注册、审计模型├── skill-order # 订单相关 Skill├── skill-refund # 退款相关 Skill├── skill-employee # 员工/HR 相关 Skill├── session-store # Redis 会话、摘要压缩├── llm-gateway # 多模型适配、限流、熔断、token 统计└── ops-observability # 指标、日志、链路追踪、告警
这样拆分有三个价值:
- • 代码职责明确,便于团队协作
- • 单模块可以独立压测、扩容、灰度
- • 后期从单体演进到微服务时更平滑
六、代码实战一:先搭一个可演进的基础工程
6.1 Maven 依赖建议
下面给出一份更接近生产的依赖组合。你可以使用 LangChain4j 或 AgentScope Java,核心思想相同,本文以 Java 生态通用能力为主。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>0.35.0</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>0.35.0</version> </dependency> <dependency> <groupId>io.milvus</groupId> <artifactId>milvus-sdk-java</artifactId> <version>2.5.8</version> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot3</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency></dependencies>
6.2 配置文件不要只放 API Key
真正有价值的配置通常包含:
- • 模型名称与超时
- • embedding 维度
- • RAG 检索阈值与 TopK
- • Agent 最大迭代次数
- • 限流参数
- • 会话窗口大小
- • 强制 RAG 的意图开关
- • 降级与回退策略
server: port: 8081spring: application: name: smart-ai-assistant data: redis: host: redis port: 6379 kafka: bootstrap-servers: kafka:9092management: endpoints: web: exposure: include: health,info,metrics,prometheusai: llm: provider: openai chat-model: gpt-4.1-mini embedding-model: text-embedding-3-small timeout-seconds: 20 max-retries: 2 temperature: 0.0 rag: top-k: 8 final-top-n: 3 min-score: 0.72 chunk-size: 700 chunk-overlap: 120 agent: max-iters: 5 force-rag-intents: - POLICY_RAG - FAQ_RAG session: history-size: 10 summary-threshold: 30 skill: async-timeout-ms: 3000resilience4j: ratelimiter: instances: llmGateway: limit-for-period: 120 limit-refresh-period: 1s timeout-duration: 200ms circuitbreaker: instances: llmGateway: failure-rate-threshold: 50 sliding-window-size: 20

七、代码实战二:先做“意图路由”,别一上来就把所有请求都丢给 Agent
很多系统一开始就让 LLM 决定一切,这样很贵,也不稳定。
更合理的策略是先做一层轻量意图路由,把请求分流到不同链路:
- • 普通寒暄
- • 强制 RAG
- • 结构化查询
- • 动作型执行
- • 复杂开放问答
package com.example.aiqa.domain.service;import com.example.aiqa.domain.model.ChatCommand;import com.example.aiqa.domain.model.IntentType;import org.springframework.stereotype.Service;@Servicepublic class IntentRouter { public IntentType route(ChatCommand command) { String message = command.message().trim().toLowerCase(); if (containsAny(message, "你好", "hello", "hi", "在吗")) { return IntentType.SMALL_TALK; } if (containsAny(message, "年假", "报销", "制度", "流程", "政策", "规范", "激励")) { return IntentType.POLICY_RAG; } if (containsAny(message, "余额", "工号", "员工", "部门", "档案")) { return IntentType.EMPLOYEE_QUERY; } if (containsAny(message, "创建工单", "提工单", "申请", "审批", "报修", "vpn")) { return IntentType.ACTION_REQUEST; } if (message.length() <= 8) { return IntentType.FAQ; } return IntentType.COMPLEX; } private boolean containsAny(String message, String... keywords) { for (String keyword : keywords) { if (message.contains(keyword)) { return true; } } return false; }}
这个设计的价值很大:
- • 简单请求不必经过完整 Agent 推理链
- • 制度类问题可以强制走 RAG
- • 动作型请求可以优先进入工具编排链
- • 可以显著降低平均 token 消耗和响应时延
八、代码实战三:把 RAG 做成真正可用的检索链路
下面这段代码来自企业知识检索服务的典型实现思路。重点不在“有没有调 Milvus”,而在于它体现了几个生产特征:
- • 启动时不因向量库不可达而整体崩掉
- • 检索时支持按部门过滤
- • 支持文档重建与导入
- • 能把结果同时作为结构化对象和文本证据输出
@Servicepublic class MilvusKnowledgeService { private final QaProperties properties; private final EmbeddingService embeddingService; private volatile MilvusClientV2 client; private volatile String unavailableReason; public List<KnowledgeDocument> search(String question, String department, int topK) { if (!isAvailable()) { return List.of(); } initializeCollection(); List<Float> queryVector = embeddingService.embed(question); SearchReq searchReq = SearchReq.builder() .databaseName(properties.milvus().dbName()) .collectionName(properties.milvus().collectionName()) .data(List.of(new FloatVec(queryVector))) .topK(topK) .annsField(properties.milvus().vectorField()) .metricType(IndexParam.MetricType.COSINE) .filter(buildFilter(department)) .outputFields(List.of("*")) .build(); SearchResp resp = client().search(searchReq); List<KnowledgeDocument> result = new ArrayList<>(); for (List<SearchResp.SearchResult> group : resp.getSearchResults()) { for (SearchResp.SearchResult item : group) { Map<String, Object> entity = item.getEntity(); result.add(new KnowledgeDocument( String.valueOf(entity.getOrDefault("documentId", "")), String.valueOf(entity.getOrDefault("title", "")), String.valueOf(entity.getOrDefault("content", "")), String.valueOf(entity.getOrDefault("source", "")), String.valueOf(entity.getOrDefault("department", "")), null )); } } return result; } public String searchAsText(String question, String department, int topK) { List<KnowledgeDocument> docs = search(question, department, topK); if (docs.isEmpty()) { return "未检索到知识。"; } return docs.stream() .map(doc -> "【" + doc.title() + "】" + doc.content() + "(来源:" + doc.source() + ")") .collect(Collectors.joining("\n")); }}
8.1 为什么这里一定要有元数据过滤?
因为企业知识不是一个“公共大语料池”,而是强上下文、强权限、强领域隔离的数据集合。
举例:
- • HR 制度不应该和财务制度混召回
- • 华东区售后知识不应该给华北区客服用
- • A 租户的数据不能被 B 租户检索到
因此,向量检索一定要配合 metadata filter。
8.2 文档摄取链路也不能只写个 for 循环
真正上线时,文档摄取建议设计成独立任务流:
-
- 文件上传
-
- 格式解析
-
- 清洗去噪
-
- 结构切片
-
- embedding 批量生成
-
- 向量写入
-
- 索引加载
-
- 版本切换
为了避免线上检索命中半成品数据,推荐使用“双集合切换”策略:
- • 新知识先导入
knowledge_v2 - • 建索引、预热完成后切换别名
- • 老集合
knowledge_v1延后下线
这比在线直接重建集合稳定得多。
九、代码实战四:Agent 不该是“自由发挥”,而是“受控编排”
这里给出一段非常值得借鉴的 Agent 编排代码。它体现了两个关键思想:
-
- 制度类问题强制先检索知识,再总结。
-
- 非制度类问题才进入 Agent 工具调用链。
@Servicepublic class AgentScopeQaService { private final QaProperties properties; private final IntentRouter intentRouter; private final EnterpriseToolFunctions toolFunctions; public AgentAnswer answer(ChatContext context) { String intent = intentRouter.route(context.question()); if ("RAG".equals(intent)) { return answerWithForcedRag(context); } if (properties.dashscopeApiKey() == null || properties.dashscopeApiKey().isBlank()) { return fallbackAnswer(intent, context); } DashScopeChatModel model = DashScopeChatModel.builder() .apiKey(properties.dashscopeApiKey()) .modelName(properties.chatModel()) .formatter(new DashScopeChatFormatter()) .build(); Toolkit toolkit = new Toolkit(); toolkit.registerTool(new AgentTools(toolFunctions, context.department(), context.userId())); ReActAgent agent = ReActAgent.builder() .name("enterprise-qa-agent") .sysPrompt(buildPrompt(intent, context)) .model(model) .toolkit(toolkit) .memory(new InMemoryMemory()) .maxIters(properties.agent().maxIters()) .build(); Msg msg = Msg.builder().name("user").role(MsgRole.USER).textContent(context.question()).build(); Msg response = agent.call(msg).block(); String answer = response == null ? fallbackAnswer(intent, context).answer() : response.getTextContent(); return new AgentAnswer(answer, "AGENTSCOPE_REACT", List.of(), ToolAuditContext.snapshot()); }}
9.1 为什么“强制 RAG + 受控 Agent”比纯 ReAct 更适合企业
因为企业知识问答最大的风险不是“答不上来”,而是“答错了但看起来很像对的”。
把链路改成:
- • 制度/规范/知识类问题:强制 RAG
- • 查询/动作类问题:受控 Agent + Skill
- • 超复杂问题:路由给人工或高级模型
会比“一股脑都交给 Agent 自主决定”稳定得多。
9.2 Agent 的系统提示词必须写出明确边界
真正生产里的 Prompt,不是“你是一个乐于助人的助手”这种空话,而应该明确:
- • 当前用户是谁
- • 当前部门是什么
- • 允许使用哪些工具
- • 哪些场景必须先检索
- • 没有依据时必须明确拒答
- • 工具失败时如何回退
例如:
private String buildPrompt(String intent, ChatContext context) { String history = context.history() == null || context.history().isEmpty() ? "无" : String.join("\n", context.history()); return """ 你是企业知识问答助手,负责基于企业知识库和结构化工具提供可信答案。 当前用户:%s 当前部门:%s 当前意图:%s 最近对话历史: %s 规则: 1. 如果问题涉及余额、员工资料、工单等,调用对应工具。 2. 回答时尽量给出来源或说明数据来自哪个系统。 3. 如果没有把握,不要编造,明确说明缺少依据。 """.formatted(context.userId(), context.department(), intent, history);}
这类 Prompt 不是为了“文采”,而是为了压缩模型的自由度,提升稳定性。
十、代码实战五:Skill 的生产级写法是什么样?
Skill 的关键不是 @Tool 注解本身,而是它背后的治理。
先看一个典型的工具聚合层:
@Componentpublic class EnterpriseToolFunctions { private final MilvusKnowledgeService milvusKnowledgeService; public List<KnowledgeDocument> searchKnowledgeDocuments(String question, String department) { List<KnowledgeDocument> documents = milvusKnowledgeService.search(question, department, 4); ToolAuditContext.record("searchKnowledge", Map.of( "question", question, "department", department == null ? "" : department ), formatKnowledgeDocuments(documents)); return documents; } public String queryLeaveBalance(String employeeId) { String result = "员工 " + employeeId + " 当前 annual 年假余额为 6.5 天。"; ToolAuditContext.record("queryLeaveBalance", Map.of("employeeId", employeeId), result); return result; } public String createItTicket(String employeeId, String title, String description) { String result = "已为员工 " + employeeId + " 创建 IT 工单,标题:" + title + ",描述:" + description; ToolAuditContext.record("createItTicket", Map.of( "employeeId", employeeId, "title", title, "description", description ), result); return result; }}
10.1 为什么工具调用审计是必选项?
因为上线后你一定会遇到这些问题:
- • 模型为什么调用了这个工具
- • 工具传参是不是错了
- • 哪一步超时了
- • 最终回答基于哪次调用结果
- • 有没有越权调用敏感接口
因此,Tool Audit 不是锦上添花,而是生产基本盘。
可以像下面这样,通过线程上下文或 Reactor Context 记录每次工具调用:
public final class ToolAuditContext { private static final ThreadLocal<List<ToolCallRecord>> TOOL_CALLS = ThreadLocal.withInitial(ArrayList::new); public static void clear() { TOOL_CALLS.remove(); } public static void record(String toolName, Map<String, Object> arguments, String result) { ToolCallRecord record = new ToolCallRecord(toolName, arguments, result, Instant.now()); TOOL_CALLS.get().add(record); } public static List<ToolCallRecord> snapshot() { return List.copyOf(TOOL_CALLS.get()); }}
10.2 真正的 Skill 至少还要补这四件事
-
权限校验
不是所有用户都能查任何数据,更不是所有用户都能发起退款或审批。
-
幂等控制
对于创建工单、提交退款、发起审批这类动作,必须有业务幂等键,否则 Agent 重试一次就可能重复执行。
-
超时与熔断
不要让一个慢下游把整个问答链路拖死。每个 Skill 都要有自己的超时预算和失败策略。
-
结果标准化
Skill 返回结果最好是稳定 JSON,而不是任意文本。因为后续还要被模型或编排器消费。
十一、代码实战六:会话管理、SSE 流式输出与上下文压缩
企业聊天系统不是一次性请求,必须管理上下文。
一个简化但很有代表性的会话存储实现如下:
@Componentpublic class ConversationSessionStore { private final QaProperties properties; private final ObjectMapper objectMapper; public List<String> history(String sessionId) { try { Path path = sessionFile(sessionId); if (!Files.exists(path)) { return new ArrayList<>(); } return objectMapper.readValue(Files.readString(path), new TypeReference<>() {}); } catch (Exception ex) { return new ArrayList<>(); } } public void append(String sessionId, String role, String message) { try { Path path = sessionFile(sessionId); Files.createDirectories(path.getParent()); List<String> history = history(sessionId); history.add(role + ": " + message); int maxSize = properties.session().historySize() * 2; if (history.size() > maxSize) { history = new ArrayList<>(history.subList(history.size() - maxSize, history.size())); } Files.writeString(path, objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(history)); } catch (Exception ex) { throw new IllegalStateException("Failed to persist session history", ex); } }}
这段代码适合本地样例或单节点验证,但真正生产环境建议这样升级:
- • 存储从本地文件切换到
Redis - • 长会话增加
摘要压缩 - • 区分
recent window和long-term summary - • 上下文内容脱敏后再进模型
推荐上下文策略:
-
- 最近
N轮对话直接保留。
- 最近
-
- 更早的历史做摘要。
-
- 用户资料、部门、租户等稳定信息单独作为 profile 注入。
-
- 检索证据与会话历史分层拼装,避免互相污染。
流式输出方面,Java 强烈建议使用 WebFlux + SSE:
@RestController@RequestMapping("/api/chat")public class ChatController { @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> streamChat(@RequestParam String sessionId, @RequestParam String message) { return llmStreamingService.stream(sessionId, message); }}
这样做的价值很直接:
- • 用户体感更快
- • 长回答不必阻塞整个请求
- • 前端可以边生成边渲染
十二、动作型请求不要都同步执行,异步 Skill 才是高并发下的正确姿势
对于“查一下余额”这种读操作,同步执行没问题。
但对下面这些动作:
- • 提交退款
- • 创建工单
- • 发起审批
- • 调用外部 ERP / CRM / OA
如果还放在同步链路里,会出现几个问题:
- • 用户等待时间过长
- • 上游连接占满
- • 下游慢接口把 Chat Service 拖垮
- • 峰值流量时请求洪峰直接打爆业务系统
因此,建议把动作型 Skill 设计为异步执行。
12.1 典型异步编排链路
用户请求 -> Chat Controller -> Agent 识别为动作型请求 -> 生成标准化执行命令 -> 写入 Kafka -> 立刻返回“任务已受理,处理中” -> Skill Worker 异步消费执行 -> 执行结果写回状态表 / 推送消息 / WebSocket 通知
12.2 推荐的消息模型
public record SkillCommand( String requestId, String sessionId, String userId, String skillName, Map<String, Object> arguments, Instant createdAt) {}
12.3 为什么要标准化成 SkillCommand?
因为这样你就可以做到:
- • 消息可重放
- • 执行可追踪
- • 失败可补偿
- • 幂等可校验
- • 审计可回放
这一点在金融、电商、审批类场景尤其重要。
十三、高并发与可扩展:架构师必须补上的工程化能力
文章讲到这里,核心能力已经通了,但如果没有工程化加固,依然扛不住生产流量。
下面这些是高并发场景里的关键设计。
13.1 多级缓存:把最贵的链路挡在外面
大模型系统里最贵的通常有三段:
- • embedding 生成
- • 向量检索
- • LLM 推理
因此要建立多级缓存:
-
L1:Caffeine 本地热点缓存
-
L2:Redis 分布式缓存
-
L3:向量库 / LLM 实际调用
常见可缓存对象包括:
- • query -> embedding
- • normalized question -> answer
- • question -> retrieved passages
- • intent routing result
13.2 语义缓存比字符串缓存更有价值
用户会用不同问法表达同一个意思:
- • “年假还剩多少”
- • “我还有几天年假”
- • “帮我查一下年假余额”
如果只做字符串 key 缓存,命中率很低。
更好的做法是:
- • 对问题做归一化
- • 或直接做语义 embedding 相似匹配
- • 相似度高于阈值时返回缓存结果
这类语义缓存通常能显著降低 RAG 和 LLM 请求量。
13.3 LLM 网关必须限流、熔断、超时隔离
LLM 是昂贵且不稳定的外部依赖。
至少要做:
- • 每秒并发限流
- • 单请求超时
- • 错误重试上限
- • 熔断快速失败
- • 降级到小模型或本地规则
示意代码如下:
@Servicepublic class LlmGateway { @RateLimiter(name = "llmGateway") @CircuitBreaker(name = "llmGateway", fallbackMethod = "fallback") public Mono<String> chat(ChatRequest request) { return remoteModelClient.chat(request) .timeout(Duration.ofSeconds(20)); } public Mono<String> fallback(ChatRequest request, Throwable ex) { return Mono.just("当前智能服务繁忙,我先为你返回简化结果,请稍后重试更复杂问题。"); }}
13.4 横向扩展的前提是“真正无状态”
如果会话历史存在本地内存、文件系统,或者 Agent 状态散在单节点里,那么你的 Chat Service 就无法平滑扩容。
无状态设计要求:
- • 会话放 Redis
- • 异步任务状态放 DB/Redis
- • Prompt 配置放配置中心
- • 文档索引放外部向量库
- • 实例本身不保存关键业务状态
这样一来,服务就可以通过 HPA 按 CPU、QPS、队列堆积自动扩缩容。
13.5 Skill Registry 要支持“注册即治理”
别把 Skill 注册理解为“丢进一个 Map”。
更好的做法是给每个 Skill 绑定治理元数据:
- • 名称
- • 描述
- • 参数 Schema
- • 读/写属性
- • 幂等要求
- • 超时预算
- • 权限域
- • 是否允许 Agent 自动调用
这样后续可以做:
- • 灰度开放某些 Skill
- • 针对高风险 Skill 增加人工确认
- • 对写操作 Skill 强制审计
十四、生产级案例:企业智能助手完整请求链路解析
下面以一个典型请求为例:
“我的 VPN 连不上,顺便帮我查一下年假余额,再给我提一个 IT 工单。”
这不是一个简单问答,而是一个复合任务。合理链路应该是:
14.1 第一步:意图拆解
系统识别出两个子任务:
- •
queryLeaveBalance - •
createItTicket
如果模型能力较强,可以在 Agent 内拆解;如果追求稳定性,也可以先做规则 + LLM 混合解析。
14.2 第二步:执行顺序规划
这里其实不需要 RAG,因为它不是制度问答,而是结构化查询 + 动作执行。
因此,Agent 可以生成如下计划:
-
- 查询当前用户年假余额
-
- 基于 VPN 故障描述创建工单
-
- 汇总两步结果,用自然语言回答用户
14.3 第三步:工具调用与审计
每一步调用都要记录:
- • toolName
- • arguments
- • result
- • timestamp
- • traceId
这样最终可以返回:
{ "sessionId": "s-001", "answer": "你的当前年假余额为 6.5 天;已为你创建 IT 工单,标题为 VPN 连接异常。", "agent": "AGENTSCOPE_REACT", "toolCalls": [ { "toolName": "queryLeaveBalance", "arguments": { "employeeId": "E1024" }, "result": "员工 E1024 当前 annual 年假余额为 6.5 天。" }, { "toolName": "createItTicket", "arguments": { "title": "VPN 连接异常", "description": "我的 VPN 连不上" }, "result": "已为员工 E1024 创建 IT 工单,标题:VPN 连接异常,描述:我的 VPN 连不上" } ]}
这类返回对前端、客服后台、审计平台都很友好。
14.4 第四步:失败回退
如果工单系统超时,回答不应该是“创建成功”,而应该变成:
- • 年假余额正常返回
- • 工单创建失败明确说明
- • 如有必要,自动转人工或提示稍后再试
这才是工程系统,而不是“只要模型说得通就行”。
十五、可观测性、治理与安全:这是很多文章完全没讲到的关键层
如果你准备把大模型能力放进企业核心流程,这一层必须补齐。
15.1 指标体系应该看什么?
至少监控以下指标:
- • 总请求量、成功率、错误率
- •
P50/P95/P99响应时延 - • LLM 调用次数、失败率、平均耗时
- • embedding 调用次数与耗时
- • 向量检索耗时、召回数量、空结果比例
- • Skill 调用次数、超时数、失败数
- • 缓存命中率
- • 每请求平均 token 消耗
- • 每日模型调用成本
15.2 日志要能回答“这次答案是怎么来的”
一条完整日志链路最好能串起:
- •
traceId - • 用户请求
- • 意图类型
- • 检索证据
- • prompt 版本
- • 工具调用记录
- • 模型返回
- • 最终答案
只有做到这一点,线上问题才可定位、可复盘。
15.3 Prompt 也应该纳入配置治理
Prompt 不应硬编码在代码里散落管理。
建议做法:
- • 以模板形式放配置中心
- • 版本号管理
- • 支持灰度发布
- • 支持 A/B 实验
因为 Prompt 在大模型系统里,本质上也是“业务逻辑的一部分”。
15.4 安全边界必须前置
大模型应用比传统接口更容易出现“隐式越权”。
重点防护包括:
- • Prompt Injection
- • 数据越权检索
- • 敏感字段泄露
- • 高风险 Skill 误触发
- • 训练/日志中的隐私泄露
因此建议:
- • 检索前先做租户和权限过滤
- • Skill 执行前做服务端二次鉴权
- • 对敏感数据脱敏后再进模型
- • 对写操作要求显式确认或审批
十六、部署与弹性伸缩:从单机试验到 K8s 生产集群
16.1 Dockerfile 建议
FROM eclipse-temurin:17-jreWORKDIR /appCOPY target/smart-ai-assistant.jar app.jarENTRYPOINT ["java","-Xms1g","-Xmx1g","-XX:+UseG1GC","-XX:MaxGCPauseMillis=200","-jar","app.jar"]
16.2 Kubernetes 部署关键点
- • Chat Service 无状态化
- • 使用 HPA 自动扩缩
- • Redis、Kafka、Milvus 独立部署
- • 通过 Secret 管理 API Key
- • 通过 ConfigMap/Nacos 管理 Prompt 和模型路由
示例:
apiVersion: apps/v1kind: Deploymentmetadata: name: smart-ai-assistantspec: replicas: 3 selector: matchLabels: app: smart-ai-assistant template: metadata: labels: app: smart-ai-assistant spec: containers: - name: app image: registry.example.com/smart-ai-assistant:1.0.0 ports: - containerPort: 8081 env: - name: OPENAI_API_KEY valueFrom: secretKeyRef: name: llm-secret key: api-key resources: requests: cpu: "500m" memory: "1Gi" limits: cpu: "2" memory: "3Gi"---apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: smart-ai-assistant-hpaspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: smart-ai-assistant minReplicas: 3 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70
16.3 别忘了“冷启动成本”
很多团队压测时忽略了冷启动问题,结果上线后第一次请求很慢。
建议预热:
- • 模型连接池
- • 常用 Prompt 模板
- • 热门问题缓存
- • 向量集合加载
- • 常用 Skill 依赖连接
十七、常见落坑清单:这些问题我建议你上线前逐条对照
17.1 只做向量检索,不做 rerank
容易召回一堆“看起来相关、实际不关键”的片段。
17.2 让 Agent 自由调用所有工具
高风险 Skill 很容易被误触发,尤其是写操作。
17.3 把会话历史原样无限拼接
最后一定会撞 token 上限,也会把噪音带进 prompt。
17.4 工具返回纯文本,没有标准 Schema
后续很难做结构化编排、审计、重放和自动测试。
17.5 没有回退方案
只要模型服务、向量库、外部系统任何一个抖动,整个链路就不可用。
17.6 只测功能,不测成本和延迟
能回答,不代表能上线;能上线,不代表上线后扛得住。
十八、一套可落地的演进路线图
如果你所在团队刚开始做大模型应用,不建议一上来就搞最复杂的多智能体体系。
更推荐下面这条演进路线:
阶段一:LLM API 接入
目标:
- • 跑通对话
- • 建立 Prompt 规范
- • 打通流式输出
阶段二:引入 RAG
目标:
- • 补足企业知识
- • 建立文档摄取链路
- • 建立引用与评估体系
阶段三:引入受控 Agent
目标:
- • 让系统具备工具调用能力
- • 打通查询型和动作型请求
- • 建立 Tool Audit
阶段四:Skill 工程化
目标:
- • 独立服务化
- • 做权限、超时、幂等、审计
- • 支持异步执行与补偿
阶段五:平台化
目标:
- • 模型网关统一
- • Prompt 平台化
- • A/B 实验
- • 多模型路由
- • 统一观测治理
这条路线能让团队以最小风险逐步升级,而不是一开始就陷入复杂度泥潭。
十九、总结:Java 工程师做大模型应用,真正的壁垒不在“接模型”,而在“把系统做对”
回到文章开头那句话:
Java 工程师的大模型应用实战,绝不只是“调一个聊天接口”。
真正有工程含量的,是把以下四层能力组合起来:
- •
LLM:理解与生成 - •
RAG:基于证据回答 - •
Agent:进行任务编排与工具决策 - •
Skill:承接企业真实业务能力
当这四者被正确组织后,系统才能同时具备:
- • 可信性:回答有依据,不靠“模型想象”
- • 可执行性:不仅能答,还能查、能办、能流转
- • 工程稳定性:限流、熔断、缓存、异步、回退一应俱全
- • 扩展能力:模型、知识库、工具、业务流程都能演进
如果你是 Java 后端、架构师、技术负责人,我建议你用这样一句话重新定义“大模型项目”:
这不是一个模型接入项目,而是一个“新型企业应用架构项目”。
你要解决的,依然是那些老问题:
- • 架构分层
- • 并发处理
- • 状态管理
- • 系统治理
- • 安全审计
- • 可观测与成本控制
只是这次,LLM 成了新的核心执行单元。
这恰恰意味着,Java 工程师并不会在大模型时代失去价值,反而会因为擅长复杂系统工程,而拥有更大的舞台。
二十、附录:生产落地速查清单
架构设计
- • 是否区分了 LLM、RAG、Agent、Skill 四层职责
- • 是否存在统一的 LLM Gateway
- • 是否实现了意图路由,而不是所有请求都交给 Agent
RAG 质量
- • 是否有合理切片策略
- • 是否支持 metadata filter
- • 是否有 rerank
- • 是否有引用返回与离线评估
Agent 治理
- • 是否限制最大迭代次数
- • 是否对高风险 Skill 做权限与确认
- • 是否具备工具调用审计
工程稳定性
- • 是否做了缓存、限流、熔断、回退
- • 是否做了异步削峰
- • 是否支持无状态水平扩展
运维治理
- • 是否采集延迟、成本、token、命中率指标
- • 是否可以追踪一次回答的完整证据链
- • 是否支持 Prompt 配置化和灰度
如果这份清单里大部分都已经勾上,那么你的大模型系统就已经不再是一个 Demo,而是一套具备生产价值的企业智能应用。
普通人如何抓住AI大模型的风口?
领取方式在文末
为什么要学习大模型?
目前AI大模型的技术岗位与能力培养随着人工智能技术的迅速发展和应用 , 大模型作为其中的重要组成部分 , 正逐渐成为推动人工智能发展的重要引擎 。大模型以其强大的数据处理和模式识别能力, 广泛应用于自然语言处理 、计算机视觉 、 智能推荐等领域 ,为各行各业带来了革命性的改变和机遇 。
目前,开源人工智能大模型已应用于医疗、政务、法律、汽车、娱乐、金融、互联网、教育、制造业、企业服务等多个场景,其中,应用于金融、企业服务、制造业和法律领域的大模型在本次调研中占比超过 30%。
随着AI大模型技术的迅速发展,相关岗位的需求也日益增加。大模型产业链催生了一批高薪新职业:
人工智能大潮已来,不加入就可能被淘汰。如果你是技术人,尤其是互联网从业者,现在就开始学习AI大模型技术,真的是给你的人生一个重要建议!
最后
只要你真心想学习AI大模型技术,这份精心整理的学习资料我愿意无偿分享给你,但是想学技术去乱搞的人别来找我!
在当前这个人工智能高速发展的时代,AI大模型正在深刻改变各行各业。我国对高水平AI人才的需求也日益增长,真正懂技术、能落地的人才依旧紧缺。我也希望通过这份资料,能够帮助更多有志于AI领域的朋友入门并深入学习。
真诚无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发
【附赠一节免费的直播讲座,技术大佬带你学习大模型的相关知识、学习思路、就业前景以及怎么结合当前的工作发展方向等,欢迎大家~】
大模型全套学习资料展示
自我们与MoPaaS魔泊云合作以来,我们不断打磨课程体系与技术内容,在细节上精益求精,同时在技术层面也新增了许多前沿且实用的内容,力求为大家带来更系统、更实战、更落地的大模型学习体验。

希望这份系统、实用的大模型学习路径,能够帮助你从零入门,进阶到实战,真正掌握AI时代的核心技能!
01 教学内容

-
从零到精通完整闭环:【基础理论 →RAG开发 → Agent设计 → 模型微调与私有化部署调→热门技术】5大模块,内容比传统教材更贴近企业实战!
-
大量真实项目案例: 带你亲自上手搞数据清洗、模型调优这些硬核操作,把课本知识变成真本事!
02适学人群
应届毕业生: 无工作经验但想要系统学习AI大模型技术,期待通过实战项目掌握核心技术。
零基础转型: 非技术背景但关注AI应用场景,计划通过低代码工具实现“AI+行业”跨界。
业务赋能突破瓶颈: 传统开发者(Java/前端等)学习Transformer架构与LangChain框架,向AI全栈工程师转型。

vx扫描下方二维码即可
【附赠一节免费的直播讲座,技术大佬带你学习大模型的相关知识、学习思路、就业前景以及怎么结合当前的工作发展方向等,欢迎大家~】
本教程比较珍贵,仅限大家自行学习,不要传播!更严禁商用!
03 入门到进阶学习路线图
大模型学习路线图,整体分为5个大的阶段:
04 视频和书籍PDF合集

从0到掌握主流大模型技术视频教程(涵盖模型训练、微调、RAG、LangChain、Agent开发等实战方向)

新手必备的大模型学习PDF书单来了!全是硬核知识,帮你少走弯路(不吹牛,真有用)
05 行业报告+白皮书合集
收集70+报告与白皮书,了解行业最新动态!
06 90+份面试题/经验
AI大模型岗位面试经验总结(谁学技术不是为了赚$呢,找个好的岗位很重要)

07 deepseek部署包+技巧大全

由于篇幅有限
只展示部分资料
并且还在持续更新中…
真诚无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发
【附赠一节免费的直播讲座,技术大佬带你学习大模型的相关知识、学习思路、就业前景以及怎么结合当前的工作发展方向等,欢迎大家~】
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)