在很多团队的实际落地过程中,“多智能体”很容易停留在 Demo 层面:
- • 能跑通几个 Agent 互相调用
- • 能生成一段看起来不错的内容
- • 能在单机环境完成一次链路演示
但一旦进入真实业务环境,问题会马上出现:
- • 请求量上来后,模型调用延迟和成本不可控
- • 多个智能体之间上下文不一致,生成结果互相冲突
- • 缺少编排、限流、重试、降级、缓存、可观测,系统无法稳定运行
- • 代码层面只展示了简单样例,距离生产级实现差距很大
本文不再停留在“如何写一个多 Agent Demo”,而是从架构师和资深工程师视角,系统讲清楚如何基于 Spring AI Alibaba 构建一个真正可落地的 故事创作多智能体系统。文章重点包括:
- • 多智能体协作的原理与架构设计
- • 面向高并发场景的工程化方案
- • 生产级代码实现与核心设计模式
- • 缓存、异步化、限流、降级、可观测与部署方案
- • 一个贴近业务的完整案例:在线故事创作平台
如果你希望的不只是“能生成故事”,而是“能支撑业务上线”,这篇文章会更接近你真正需要的答案。
2.1 目标业务场景
我们假设要建设一个在线 AI 创作平台,面向 C 端作者、内容社区、教育平台或互动小说应用,提供如下能力:
- • 用户输入主题、风格、受众、篇幅、角色偏好
- • 系统自动完成故事策划、角色设定、场景设计、章节生成、风格统一
- • 支持大批量并发生成
- • 支持流式返回和异步任务模式
- • 支持作品二次编辑、续写、重写
典型请求示例:
2.2 为什么适合用多智能体
故事创作天然不是一个单点能力问题,而是一个复杂任务分解问题。一个高质量故事至少包含:
- • 世界观和主线冲突设计
- • 角色目标、动机与成长弧
- • 场景和章节推进
- • 文风统一和润色
- • 结果校验与质量评估
如果把所有任务交给一个“大一统 Prompt”,常见问题是:
- • 输出长度不稳定
- • 结构松散
- • 风格漂移
- • 人物设定前后矛盾
- • 场景信息遗漏
因此更合理的方式是:将复杂创作任务拆解为多个专业化智能体,由编排层协调执行,再由汇总智能体整合输出。
2.3 真实工程挑战
当系统进入生产环境,真正难的不是“写 Prompt”,而是解决以下问题:
- • 如何定义智能体职责边界,避免重复劳动和上下文污染
- • 如何保证多个智能体之间的数据契约一致
- • 如何让模型调用具备超时、重试、熔断、限流能力
- • 如何应对高并发下的线程池、连接池、消息积压与缓存击穿
- • 如何支持同步、流式、异步三种调用模式
- • 如何沉淀监控指标,定位慢调用、坏输出和成本异常
3.1 从“Prompt 拼接”到“任务编排”
多智能体系统的本质不是多个 LLM 实例,而是 面向复杂任务的分工协作系统。它通常由四层组成:
- 接入层:接收用户请求,做鉴权、限流、参数校验
- 编排层:负责任务拆解、执行顺序、并行控制、超时控制
- 智能体层:执行具体任务,如情节设计、人物塑造、风格统一
- 基础设施层:模型网关、缓存、数据库、MQ、监控、日志、追踪
3.2 多智能体协作模式
常见协作模式有三种:
模式一:串行链式协作
适合强依赖型流程,例如:
- • 先生成故事大纲
- • 再基于大纲生成人物
- • 再基于人物和大纲生成章节
优点:
- • 结果可控
- • 上下文依赖明确
缺点:
- • 总耗时较长
- • 某一步失败会阻塞整体
模式二:并行协作
适合弱依赖或可提前拆分的任务,例如:
- • 角色设定
- • 场景设定
- • 风格约束
优点:
- • 总时延低
- • 适合高并发优化
缺点:
- • 汇总阶段复杂
- • 容易出现结果不一致
模式三:评审闭环协作
适合质量要求高的场景:
- • 生成智能体产出初稿
- • 评审智能体检查逻辑、风格、重复率、敏感内容
- • 修订智能体进行再加工
优点:
- • 内容质量更稳定
缺点:
- • Token 成本更高
- • 处理链路更长
实际生产中,往往是“串行 + 并行 + 评审闭环”的组合。
3.3 本文采用的协作拓扑
是
否
用户请求
API Gateway
Story Application Service
Workflow Orchestrator
Plot Agent
Character Agent
Scene Agent
Chapter Agent
Shared Story Context
Style Agent
Review Agent
质量达标?
持久化/缓存/MQ
Rewrite Agent
这里有三个关键设计思想:
- • 共享上下文对象:避免每个 Agent 自己拼 Prompt,导致上下文失真
- • 编排层控制执行:Agent 只关注能力,不关心调度细节
- • 评审闭环:将质量控制前置,而不是把低质量输出直接交给用户
4.1 系统总体架构
Web/App/开放API
API Gateway
Story Service
Agent Orchestrator
Spring AI Alibaba Model Gateway
Redis
MySQL
Kafka/RocketMQ
Prometheus + Grafana + Trace
Async Story Worker
4.2 分层职责
1)API Gateway
职责:
- • Token 校验与租户隔离
- • 接口限流和黑白名单
- • 请求透传 traceId
- • 路由同步接口与异步接口
2)应用服务层
职责:
- • 参数校验
- • 幂等控制
- • 返回任务单或流式响应
- • 选择合适执行模式
3)编排层 Orchestrator
职责:
- • 任务拆解
- • 并行编排
- • 超时控制
- • 审核闭环
- • 失败补偿
4)Agent 能力层
职责:
- • 只负责领域任务
- • 不耦合数据库、MQ、控制器
- • 输入输出通过 DTO/Domain Object 约束
5)基础设施层
职责:
- • 模型调用适配
- • 缓存
- • 消息驱动异步执行
- • 数据持久化
- • 监控和审计
4.3 为什么不建议直接在 Controller 里串 Agent
很多初学者实现是这样的:
- • Controller 接收请求
- • 直接 new/注入多个 Agent
- • 顺序调用模型
- • 拼一个结果返回
这种做法在 Demo 阶段没问题,但在生产环境存在明显风险:
- • 缺少职责分离,无法扩展
- • 无法复用编排逻辑
- • 无法做统一超时、熔断、重试
- • 测试困难
- • 后续难以接入异步任务、审核流、回调机制
正确方式应该是:
- • Controller 只做接入
- • Application Service 只做用例编排入口
- • Orchestrator 负责业务级工作流
- • Agent 负责纯能力实现
- 领域建模:先把数据结构设计对
多智能体系统最容易失控的点之一,就是各 Agent 输入输出随意定义。生产环境里,必须先做 统一领域对象建模。
6.1 核心请求对象
package com.example.story.domain;import jakarta.validation.constraints.Max;import jakarta.validation.constraints.Min;import jakarta.validation.constraints.NotBlank;import jakarta.validation.constraints.NotEmpty;import java.util.List;public record StoryRequest( @NotBlank String requestId, @NotBlank String theme, @NotBlank String genre, @NotBlank String style, @NotBlank String targetAudience, @Min(1) @Max(20) int chapters, @NotEmpty List
keywords, String language) {}
6.2 共享上下文对象
package com.example.story.domain;import java.time.Instant;import java.util.ArrayList;import java.util.List;public class StoryContext { private final String requestId; private final StoryRequest request; private StoryOutline outline; private List
characters = new ArrayList<>(); private List
scenes = new ArrayList<>(); private List
chapters = new ArrayList<>(); private StoryReview review; private Instant startedAt = Instant.now(); public StoryContext(String requestId, StoryRequest request) { this.requestId = requestId; this.request = request; } public String requestId() { return requestId; } public StoryRequest request() { return request; } public StoryOutline outline() { return outline; } public void setOutline(StoryOutline outline) { this.outline = outline; } public List
characters() { return characters; } public void setCharacters(List
characters) { this.characters = characters; } public List
scenes() { return scenes; } public void setScenes(List
scenes) { this.scenes = scenes; } public List
chapters() { return chapters; } public void setChapters(List
chapters) { this.chapters = chapters; } public StoryReview review() { return review; } public void setReview(StoryReview review) { this.review = review; } public Instant startedAt() { return startedAt; }}
6.3 统一输出对象
package com.example.story.domain;import java.time.Instant;import java.util.List;public record StoryResult( String requestId, String title, StoryOutline outline, List
characters, List
chapters, StoryReview review, Instant createdAt) {}
6.4 为什么共享上下文是关键
如果没有 StoryContext 这种共享领域对象,系统很容易出现:
- • PlotAgent 输出大纲字段 A
- • CharacterAgent 需要字段 B
- • ChapterAgent 又拼接另一套 Prompt
- • 最后 StyleAgent 根本拿不到完整语义
本质上,上下文对象就是多智能体系统里的“状态中枢”。它让多 Agent 从“无序 Prompt 串联”变成“有约束的数据驱动编排”。
7.1 设计目标
我们不希望业务代码直接散落大量模型调用细节,而是封装统一的 LLM Gateway,负责:
- • Prompt 构造
- • 模型参数设置
- • 超时与重试
- • 结构化输出解析
- • 调用日志记录
- • Token 与耗时指标上报
7.2 模型网关封装
package com.example.story.infrastructure.ai;import io.micrometer.core.instrument.MeterRegistry;import io.micrometer.core.instrument.Timer;import java.time.Duration;import java.util.Map;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.prompt.Prompt;import org.springframework.ai.chat.prompt.PromptTemplate;import org.springframework.stereotype.Component;@Slf4j@Component@RequiredArgsConstructorpublic class StoryModelGateway { private final ChatClient chatClient; private final MeterRegistry meterRegistry; public String call(String template, Map
variables, StoryModelOptions options) { Timer.Sample sample = Timer.start(meterRegistry); try { Prompt prompt = new PromptTemplate(template).create(variables); String content = chatClient.prompt(prompt) .advisors(advisorSpec -> advisorSpec.param("requestId", options.requestId())) .options(options.toChatOptions()) .call() .content(); sample.stop(Timer.builder("story.ai.call.latency") .tag("scene", options.scene()) .tag("model", options.model()) .register(meterRegistry)); meterRegistry.counter("story.ai.call.success", "scene", options.scene(), "model", options.model()).increment(); return content; } catch (Exception ex) { meterRegistry.counter("story.ai.call.error", "scene", options.scene(), "model", options.model()).increment(); log.error("LLM call failed, requestId={}, scene={}", options.requestId(), options.scene(), ex); throw ex; } } public record StoryModelOptions( String requestId, String scene, String model, Double temperature, Integer maxTokens, Duration timeout ) { public org.springframework.ai.openai.OpenAiChatOptions toChatOptions() { return org.springframework.ai.openai.OpenAiChatOptions.builder() .model(model) .temperature(temperature) .maxTokens(maxTokens) .build(); } }}
7.3 为什么需要统一网关
如果每个 Agent 都自己直接调 ChatClient,后果通常是:
- • 参数风格不统一
- • 超时策略不一致
- • 指标无法汇总
- • 故障排查困难
统一网关的价值是:将“模型调用”从业务实现细节提升为平台能力。
8.1 Agent 接口抽象
package com.example.story.agent;import com.example.story.domain.StoryContext;public interface StoryAgent
{ T execute(StoryContext context); String name();}
8.2 情节设计智能体
职责:
- • 生成世界观
- • 生成主线冲突
- • 给出章节纲要
package com.example.story.agent;import com.example.story.domain.StoryContext;import com.example.story.domain.StoryOutline;import com.example.story.infrastructure.ai.StoryModelGateway;import com.fasterxml.jackson.databind.ObjectMapper;import java.util.Map;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Component;@Component@RequiredArgsConstructorpublic class PlotAgent implements StoryAgent
{ private static final String PROMPT = """ 你是资深小说策划编辑,请基于以下信息输出故事大纲。 主题: {theme} 类型: {genre} 风格: {style} 目标读者: 章节数: {chapters} 关键词: {keywords} 输出要求: 1. 给出标题 2. 给出世界观设定 3. 给出主线冲突 4. 给出章节级大纲 5. 严格输出 JSON """; private final StoryModelGateway modelGateway; private final ObjectMapper objectMapper; @Override public StoryOutline execute(StoryContext context) catch (Exception ex) { throw new IllegalStateException("Failed to parse outline JSON", ex); } } @Override public String name() { return "PlotAgent"; }}
8.3 人物塑造智能体
职责:
- • 根据大纲生成角色
- • 明确人物关系、目标、秘密、成长弧
package com.example.story.agent;import com.example.story.domain.StoryCharacter;import com.example.story.domain.StoryContext;import com.example.story.infrastructure.ai.StoryModelGateway;import com.fasterxml.jackson.core.type.TypeReference;import com.fasterxml.jackson.databind.ObjectMapper;import java.util.List;import java.util.Map;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Component;@Component@RequiredArgsConstructorpublic class CharacterAgent implements StoryAgent
> { private static final String PROMPT = """ 你是角色设定专家,请根据故事大纲生成核心人物列表。 故事标题: {title} 世界观: {world} 主线冲突: {conflict} 输出要求: 1. 至少 3 个角色 2. 每个角色包含:name、age、identity、personality、goal、arc、relationship 3. 严格输出 JSON 数组 """; private final StoryModelGateway modelGateway; private final ObjectMapper objectMapper; @Override public List
execute(StoryContext context) { var outline = context.outline(); String content = modelGateway.call( PROMPT, Map.of( "title", outline.title(), "world", outline.worldSetting(), "conflict", outline.mainConflict() ), new StoryModelGateway.StoryModelOptions( context.requestId(), "character", "qwen-plus", 0.8, 1800, java.time.Duration.ofSeconds(20) ) ); try { List
characters = objectMapper.readValue(content, new TypeReference<>() {}); context.setCharacters(characters); return characters; } catch (Exception ex) { throw new IllegalStateException("Failed to parse characters JSON", ex); } } @Override public String name() { return "CharacterAgent"; }}
8.4 章节生成智能体
职责:
- • 按章节落地内容
- • 对齐大纲和人物弧线
8.5 风格统一智能体
职责:
- • 消除不同章节文风漂移
- • 统一叙事视角、语言节奏和修辞风格
8.6 评审智能体
职责:
- • 检查逻辑冲突
- • 检查人物行为一致性
- • 检查重复片段
- • 检查敏感内容
这里的核心思想是:
- • 生成型 Agent 负责创造
- • 评审型 Agent 负责约束
这和真实编辑部工作流是高度一致的。
很多文章讲多智能体时,重点都在 Agent 本身;但在工程实践中,真正决定系统上限的是 编排层。
9.1 编排层职责
- • 决定哪些步骤串行,哪些步骤并行
- • 控制每一步超时
- • 控制失败重试次数
- • 聚合结果并形成共享上下文
- • 根据质量评审结果进入修订分支
9.2 生产级 Orchestrator 实现
package com.example.story.workflow;import com.example.story.agent.ChapterAgent;import com.example.story.agent.CharacterAgent;import com.example.story.agent.PlotAgent;import com.example.story.agent.ReviewAgent;import com.example.story.agent.SceneAgent;import com.example.story.agent.StyleAgent;import com.example.story.domain.StoryContext;import com.example.story.domain.StoryRequest;import com.example.story.domain.StoryResult;import java.time.Instant;import java.util.concurrent.CompletableFuture;import java.util.concurrent.Executor;import java.util.concurrent.TimeUnit;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Component;@Component@RequiredArgsConstructorpublic class StoryWorkflowOrchestrator return new StoryResult( request.requestId(), context.outline().title(), context.outline(), context.characters(), context.chapters(), context.review(), Instant.now() ); }}
9.3 这里的关键点
1)大纲先串行
因为角色和场景都依赖大纲,所以先串行生成大纲。
2)角色和场景并行
这两者依赖大纲,但彼此之间弱依赖,可以并行,降低整体 RT。
3)章节生成放在并行任务之后
章节需要综合大纲、角色、场景,所以必须在聚合之后执行。
4)评审失败进入修订闭环
这是保证质量稳定的关键机制。
如果系统只做少量请求,以上架构已经够用;但如果进入真正的高并发场景,还必须进行系统级工程化升级。
10.1 同步接口与异步接口分层
建议将故事生成拆成两类接口:
同步接口
适合:
- • 短篇内容
- • 大纲生成
- • 角色设定
- • 轻量润色
特征:
- • 直接返回结果
- • 接口超时控制在 3 秒到 15 秒
异步接口
适合:
- • 长篇故事
- • 多章节创作
- • 多轮修订
特征:
- • 返回任务 ID
- • 后台工作流异步执行
- • 通过轮询/WebSocket/回调获取状态
10.2 异步任务化设计
package com.example.story.application;import com.example.story.domain.StoryRequest;import com.example.story.infrastructure.messaging.StoryCreationProducer;import java.util.UUID;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Service;@Service@RequiredArgsConstructorpublic class AsyncStoryApplicationService { private final StoryCreationProducer producer; private final StoryTaskRepository storyTaskRepository; public String submit(StoryRequest request) { String taskId = UUID.randomUUID().toString(); storyTaskRepository.create(taskId, request.requestId(), "PENDING"); producer.send(taskId, request); return taskId; }}
消费者异步处理:
package com.example.story.infrastructure.messaging;import com.example.story.domain.StoryRequest;import com.example.story.workflow.StoryWorkflowOrchestrator;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.kafka.annotation.KafkaListener;import org.springframework.stereotype.Component;@Slf4j@Component@RequiredArgsConstructorpublic class StoryCreationConsumer { private final StoryWorkflowOrchestrator orchestrator; private final StoryTaskRepository storyTaskRepository; private final StoryResultRepository storyResultRepository; @KafkaListener(topics = "story-create-topic", groupId = "story-worker-group") public void consume(StoryCreateMessage message) { try { storyTaskRepository.updateStatus(message.taskId(), "RUNNING"); var result = orchestrator.execute(message.request()); storyResultRepository.save(message.taskId(), result); storyTaskRepository.updateStatus(message.taskId(), "SUCCESS"); } catch (Exception ex) { log.error("Async story create failed, taskId={}", message.taskId(), ex); storyTaskRepository.updateStatus(message.taskId(), "FAILED"); } }}
10.3 为什么异步化是必须的
模型调用本质是高延迟 IO 任务,并且存在不确定性。如果所有请求都同步阻塞:
- • Web 容器线程会被长期占用
- • 突发流量下线程池很快打满
- • 用户体验会因为长尾请求显著恶化
异步化的本质价值是:
- • 把高耗时任务从用户主请求链路中剥离出来
- • 通过 MQ 做削峰填谷
- • 提高系统在高并发场景下的稳定性
10.4 线程池配置
不要直接用 CompletableFuture.supplyAsync() 默认线程池,必须显式声明业务线程池。
package com.example.story.config;import java.util.concurrent.Executor;import java.util.concurrent.ThreadPoolExecutor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configurationpublic class ExecutorConfig }
线程池参数建议根据以下因素评估:
- • CPU 核数
- • 平均模型响应时间
- • 峰值并发数
- • 下游模型网关限额
对于 AI 场景,线程池不是越大越好。更大的线程池可能带来:
- • 上游请求更多
- • 模型网关被打爆
- • 平均延迟上升
- • 失败率增加
因此要配合 限流与背压 一起使用。
10.5 限流、熔断、降级
生产系统一定要有“保护模型服务”的能力。
建议策略:
- • 单租户限流
- • 单接口 QPS 限流
- • 模型调用超时熔断
- • 下游异常率过高时快速失败
- • 降级到“小模型生成大纲 + 大模型润色”
Resilience4j 示例:
package com.example.story.infrastructure.resilience;import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;import io.github.resilience4j.retry.annotation.Retry;import io.github.resilience4j.timelimiter.annotation.TimeLimiter;import java.util.concurrent.CompletableFuture;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Service;@Service@RequiredArgsConstructorpublic class ResilientStoryAiService { private final StoryAiDelegate delegate; @Retry(name = "story-ai") @CircuitBreaker(name = "story-ai", fallbackMethod = "fallback") @TimeLimiter(name = "story-ai") public CompletableFuture
generate(String prompt) { return CompletableFuture.supplyAsync(() -> delegate.generate(prompt)); } public CompletableFuture
fallback(String prompt, Throwable throwable) { return CompletableFuture.completedFuture("当前生成服务繁忙,请稍后重试。"); }}
10.6 缓存设计
AI 场景中,缓存不只是“提高速度”,更重要的是 降低成本和保护下游模型资源。
可以缓存的对象包括:
- • 热门题材大纲
- • 常见角色模板
- • 风格模板
- • Prompt 渲染结果
- • 异步任务状态
- • 幂等请求结果
缓存键设计示例:
story:outline:{hash(theme+genre+style+keywords)}story:task:{taskId}story:result:{taskId}story:idempotent:{requestId}
缓存注意点:
- • 不要缓存未审核内容太久
- • 大文本建议压缩后缓存
- • 防止缓存雪崩和击穿
- • 对热点 Key 做互斥重建
11.1 同步接口
package com.example.story.web;import com.example.story.application.StoryApplicationService;import com.example.story.domain.StoryRequest;import com.example.story.domain.StoryResult;import jakarta.validation.Valid;import lombok.RequiredArgsConstructor;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestHeader;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api/v1/stories")@RequiredArgsConstructorpublic class StoryController { private final StoryApplicationService storyApplicationService; @PostMapping("/generate") public StoryResult generate( @Valid @RequestBody StoryRequest request, @RequestHeader(value = "X-Request-Id", required = false) String requestId) { return storyApplicationService.generate(requestId, request); }}
11.2 异步接口
package com.example.story.web;import com.example.story.application.AsyncStoryApplicationService;import com.example.story.domain.StoryRequest;import jakarta.validation.Valid;import java.util.Map;import lombok.RequiredArgsConstructor;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api/v1/story-tasks")@RequiredArgsConstructorpublic class StoryTaskController { private final AsyncStoryApplicationService asyncStoryApplicationService; private final StoryTaskQueryService storyTaskQueryService; @PostMapping public Map
submit(@Valid @RequestBody StoryRequest request) { String taskId = asyncStoryApplicationService.submit(request); return Map.of("taskId", taskId, "status", "PENDING"); } @GetMapping("/{taskId}") public StoryTaskResponse get(@PathVariable String taskId) { return storyTaskQueryService.query(taskId); }}
11.3 幂等控制
AI 生成接口非常适合做幂等,尤其是用户网络重试、网关重试、客户端超时重发时。
推荐做法:
- • 要求客户端传
requestId - • 服务端使用 Redis
SETNX - • 已存在则直接返回历史结果或任务状态
12.1 场景描述
某互动小说平台希望提供“输入一句话,自动生成 6 章短篇小说”的能力,要求:
- • 首屏 2 秒内返回受理结果
- • 普通用户并发 300 QPS
- • 峰值活动时并发 1200 QPS
- • 生成成功率不低于 99%
- • 章节内容前后设定一致
12.2 方案拆解
系统采用以下执行策略:
快速响应层
- • 用户请求进入 API Gateway
- • 参数校验和幂等检查通过后
- • 直接写入任务表和 Kafka
- • 立即返回 taskId
异步工作层
- • Worker 消费任务消息
- • 先生成大纲
- • 并行生成人物、场景设定
- • 生成章节
- • 风格统一
- • 评审与必要重写
- • 落库并刷新缓存
结果分发层
- • 前端轮询任务状态
- • 或通过 WebSocket 推送完成事件
12.3 为什么这个方案有效
因为它把用户感知时延与模型真实执行时延做了拆分:
- • 用户只需等待任务受理
- • 模型复杂生成在后台完成
- • 峰值流量被 MQ 平滑吸收
12.4 容量估算示例
假设:
- • 平均生成一次完整故事耗时 18 秒
- • 单个 Worker Pod 稳定并发处理 20 个任务
- • 峰值每分钟 3600 个请求
则至少需要:
- • 每秒请求 60
- • 在 18 秒平均处理时长下,系统在途任务约 1080 个
- • 若每 Pod 处理 20 个在途任务,则至少需要约 54 个 Worker 并发槽位
如果每个 Worker Pod 配置 2 个并发执行线程,则大约需要 27 个 Pod,实际部署建议再留 20% 到 30% 冗余。
这就是为什么 AI 系统容量规划不能只看 QPS,必须看“平均耗时 × 在途任务数”。
多智能体系统的另一个重点不是“能生成”,而是“稳定生成”。
13.1 结构化输出优先
尽量要求各 Agent 输出 JSON 或明确结构,而不是长篇自由文本。原因是:
- • 更易解析
- • 更易校验
- • 更易供下游 Agent 使用
13.2 审核规则前置
评审智能体应至少检查:
- • 人物数量与主角关系是否完整
- • 章节是否都有明确推进事件
- • 是否存在人物名称漂移
- • 是否存在世界观矛盾
- • 是否存在重复段落
- • 是否触发敏感内容策略
13.3 规则引擎 + LLM 双校验
不要把所有质量判断都交给模型。建议采用:
- • 规则引擎做强约束校验
- • LLM 做语义质量评估
例如:
- • 章节数不匹配,用规则直接判失败
- • 人物成长弧是否自然,用 LLM 做评审
13.4 Prompt 模板化
不要把 Prompt 写死在代码里到处散落。建议:
- • 统一模板目录
- • 模板版本化
- • 支持灰度发布
这样可以做到:
- • A/B 测试不同提示词
- • 不改代码快速调整效果
- • 不同租户使用不同模板
如果没有监控,多智能体系统出现问题时几乎无法定位。
14.1 必须监控的指标
系统层指标
- • CPU
- • 内存
- • JVM GC
- • 线程池活跃线程数
- • Kafka Lag
应用层指标
- • 接口 QPS
- • P95/P99 响应时间
- • 错误率
- • 限流次数
- • 熔断次数
AI 层指标
- • 每个 Agent 调用耗时
- • 各模型成功率/失败率
- • 平均 Token 消耗
- • 单请求模型成本
- • 审核失败率
- • 重写率
14.2 日志设计
日志至少要带:
- • requestId
- • taskId
- • tenantId
- • agentName
- • modelName
- • latency
- • tokenUsage
- • resultStatus
14.3 链路追踪
建议每次生成请求从入口开始透传 traceId,贯穿:
- • Gateway
- • 应用服务
- • 编排层
- • Agent 调用
- • MQ 消费
- • 结果持久化
这样当用户反馈“这个故事生成了 40 秒”,你才能快速定位是:
- • Kafka 堆积
- • 某个 Agent 超时
- • 模型接口抖动
- • 数据库写入慢
15.1 建议的表设计
至少需要三类核心表:
story_task
用于记录异步任务状态:
- • task_id
- • request_id
- • status
- • created_at
- • updated_at
- • error_message
story_result
用于保存最终作品:
- • task_id
- • title
- • outline_json
- • character_json
- • chapter_json
- • review_json
- • model_info
story_agent_audit
用于记录 Agent 级调用审计:
- • request_id
- • task_id
- • agent_name
- • model_name
- • prompt_version
- • latency_ms
- • success_flag
- • error_message
15.2 为什么审计日志很重要
当出现以下问题时,审计日志是核心依据:
- • 某一版 Prompt 效果突然变差
- • 某个模型版本出错率升高
- • 某租户生成内容质量异常
- • 成本突然上涨
16.1 application.yml
server: port: 8080 tomcat: threads: max: 300 min-spare: 20 accept-count: 200spring: application: name: story-agent-service datasource: url: jdbc:mysql://mysql:3306/story_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: story_user password: ${DB_PASSWORD} hikari: maximum-pool-size: 30 minimum-idle: 10 connection-timeout: 3000 validation-timeout: 1000 data: redis: host: redis port: 6379 lettuce: pool: max-active: 64 max-idle: 16 min-idle: 8 kafka: bootstrap-servers: kafka:9092 listener: concurrency: 6 producer: acks: all retries: 3 consumer: group-id: story-worker-group max-poll-records: 50management: endpoints: web: exposure: include: health,info,prometheus,metrics metrics: tags: application: ${spring.application.name}story: ai: default-model: qwen-plus timeout-seconds: 20 review-threshold: 0.75
16.2 Kubernetes Deployment
apiVersion: apps/v1kind: Deploymentmetadata: name: story-agent-servicespec: replicas: 4 selector: matchLabels: app: story-agent-service template: metadata: labels: app: story-agent-service spec: containers: - name: app image: registry.example.com/story-agent-service:1.0.0 ports: - containerPort: 8080 env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: story-secret key: db-password resources: requests: cpu: "1000m" memory: "2Gi" limits: cpu: "2000m" memory: "4Gi" readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 20 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 30 periodSeconds: 20---apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: story-agent-service-hpaspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: story-agent-service minReplicas: 4 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70
16.3 部署建议
- • Web 接入层和异步 Worker 分开部署
- • Worker 建议单独设置 HPA
- • 大文本结果不要只放内存,及时落 Redis/MySQL/对象存储
- • 配置中心统一管理 Prompt 版本和模型参数
17.1 为什么生成结果前后不一致
常见原因:
- • Agent 之间没有共享统一上下文
- • Prompt 模板风格不一致
- • 章节生成时没有明确约束人物设定
解决方案:
- • 引入
StoryContext - • 统一 Prompt 规范
- • 在章节生成阶段明确引用角色设定与大纲
17.2 为什么高峰期 RT 飙升
常见原因:
- • 同步请求过多
- • 默认线程池失控
- • 模型下游限额触发排队
- • Kafka 消费能力不足
解决方案:
- • 长任务异步化
- • 显式线程池 + 队列长度控制
- • 增加 Worker 副本
- • 引入限流与熔断
17.3 为什么成本失控
常见原因:
- • 所有环节都使用大模型
- • 重复请求没有缓存
- • Prompt 冗长,导致 Token 浪费
- • 评审失败频繁触发重写
解决方案:
- • 大纲/分类用中等模型,润色用大模型
- • 建立缓存体系
- • 精简上下文
- • 对质量阈值做动态调优
17.4 为什么异步任务堆积严重
常见原因:
- • 入队速度远高于消费速度
- • 单个任务执行时间过长
- • 重试策略过于激进
解决方案:
- • 扩容 Worker
- • 拆分任务颗粒度
- • 控制最大重试次数
- • 对超大任务启用排队或预约生成
建议按四个阶段推进:
第一阶段:单体验证
目标:
- • 跑通主流程
- • 验证 Agent 分工是否合理
- • 验证 Prompt 模板效果
技术形态:
- • 单体 Spring Boot
- • 同步接口
- • 本地缓存
第二阶段:服务化改造
目标:
- • 引入统一编排层
- • 加入 Redis、MySQL
- • 实现基本监控和审计
技术形态:
- • 分层服务
- • 结构化输出
- • 线程池治理
第三阶段:高并发升级
目标:
- • 支持异步任务化
- • 引入 Kafka/RocketMQ
- • 接入限流、熔断、降级
技术形态:
- • Web/Worker 分离
- • HPA 自动扩缩容
- • 多副本部署
第四阶段:平台化能力沉淀
目标:
- • Prompt 配置中心化
- • 模型路由能力
- • 成本分析
- • 多租户隔离
技术形态:
- • Agent 平台化
- • 模型网关平台化
- • 运营化仪表盘
基于 Spring AI Alibaba 构建多智能体故事创作系统,真正难的从来不是“把几个 Agent 连起来”,而是把它做成一个 可编排、可扩展、可治理、可观测、可上线 的生产系统。
从架构上看,核心是四件事:
- • 用 统一上下文对象 管理多智能体共享状态
- • 用 编排层 管理串并行流程、超时、重试和闭环修订
- • 用 异步化、缓存、限流、熔断 支撑高并发稳定性
- • 用 监控、审计、追踪 保证系统可运维
从工程实践看,建议你牢记一句话:
多智能体系统不是 Prompt 的堆砌,而是一个带有 AI 能力的分布式业务系统。
只有当你用分布式系统的方法去设计它,才有可能真正支撑业务落地。
如果继续往前演进,这个系统还可以进一步升级:
- • 增加记忆智能体,支持角色长期设定继承
- • 增加编辑智能体,支持“续写、改写、缩写、扩写”
- • 接入向量检索,支持故事设定库和风格库召回
- • 引入多模型路由,根据任务类型自动选择模型
- • 增加成本控制中心,实现租户级 Token 预算治理
- • 引入人工反馈闭环,持续优化 Prompt 与审核策略
当这些能力逐步补齐后,你得到的就不再只是一个“写故事工具”,而是一套真正具备商业化潜力的 内容创作智能体平台。
🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!
有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!
就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇
学习路线:
以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!
我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/253728.html