D7 上线篇提到 OtelTracingMiddleware,很多读者后台问我:中间件是不是就这一个?不是,那是冰山一角。
先说一个生产事故:某团队 Agent 上线后接入高峰,模型 API 频繁 429(限流),又赶上主模型服务商故障——没有降级,没有限流,整个客服入口直接瘫痪 40 分钟。事后复盘就一句:早知道有中间件和容灾配置,这事故根本不会发生。
不这么做你会踩什么坑?三个:① 模型调用没有限流,一个用户刷 100 次请求,你的账单先爆;② 主模型挂了没有降级,全站雪崩;③ 系统提示写死,上线后发现"现在几点"这种动态信息 Agent 永远答错。
AgentScope 的中间件是洋葱模型,5 个钩子层层嵌套,不修改 Agent 和模型一行代码:
onAgent(整轮回复) └── ReAct循环(每轮) ├── onReasoning(单轮推理) │ ├── onSystemPrompt(组装系统提示·管道型) │ └── onModelCall(模型API调用·最内层) └── onActing(单次工具调用)三个生产中间件,代码直接抄(完整源码回复关键词领取):
// ① 计时:每次模型调用耗时(成本/性能监控) public class TimingMiddleware implements MiddlewareBase { @Override public Flux<AgentEvent> onModelCall(Agent agent, ModelCallInput input, Function<ModelCallInput, Flux<AgentEvent>> next) { long start = System.nanoTime(); return next.apply(input) .doFinally(sig -> System.out.println( "[timing] " + (System.nanoTime() - start) / 1_000_000 + "ms")); } } // ② 限流:两次模型调用至少间隔500ms(单机AtomicLong版,生产换Redis分布式) new RateLimitMiddleware(Duration.ofMillis(500)) // ③ 动态提示词:把当前时间/环境注入system prompt,随调用刷新 new DynamicContextMiddleware(() -> "当前时间: " + Instant.now())装配一行:
ReActAgent agent = ReActAgent.builder() .model("dashscope:qwen-plus") .middlewares(List.of( new TimingMiddleware(), new RateLimitMiddleware(Duration.ofMillis(500)), new DynamicContextMiddleware(() -> "当前时间: " + Instant.now()))) .build();模型容灾三件套(优先级从高到低,面试必背):
// ① 最简:主模型失败自动切备用模型 + 单次调用重试2次 ReActAgent resilient = ReActAgent.builder() .model("dashscope:qwen-plus") .fallbackModel("openai:gpt-5.5") // 备用模型 .maxRetries(2) // 瞬时故障重试 .build(); // ② 更细粒度:手写 ModelFallbackMiddleware(onModelCall 里 onErrorResume,可加告警/计数) public class ModelFallbackMiddleware implements MiddlewareBase { private final Model fallback; @Override public Flux<AgentEvent> onModelCall(Agent agent, ModelCallInput input, Function<ModelCallInput, Flux<AgentEvent>> next) { return next.apply(input).onErrorResume(err -> { System.err.println("[fallback] 主模型失败,切换备用"); return next.apply(new ModelCallInput( input.messages(), input.tools(), input.options(), fallback)); }); } }多厂商切换是容灾的地基:模型 id 由 ModelRegistry 解析,换厂商只换依赖+字符串,业务代码零改动:
| 模型 id | 扩展依赖 |
|---|---|
dashscope:qwen-plus | agentscope-extensions-model-dashscope |
openai:gpt-5.5 | agentscope-extensions-model-openai |
anthropic:claude-sonnet-4-5 | agentscope-extensions-model-anthropic |
deepseek:deepseek-v4-flash | agentscope-extensions-model-deepseek |
gemini:gemini-2.0-flash | agentscope-extensions-model-gemini |
ollama:llama3 | agentscope-extensions-model-ollama |
我的观点:中间件是 Agent 项目里"性价比最高的一层抽象"——日志、限流、降级、动态提示词,全在框架层解决,不污染业务代码。判断一个 Agent 框架成熟度的硬指标,就是它的中间件体系够不够用。
面试话术模板:“我基于 AgentScope 中间件体系实现生产管控:利用 onModelCall/onSystemPrompt 等 5 个钩子无侵入注入调用计时、限流与动态上下文提示词;通过 Builder 原生 fallbackModel + maxRetries 与手写 ModelFallbackMiddleware 实现模型降级容灾;模型 id 由 ModelRegistry 解析,支持多厂商一键切换,为容灾/灰度/成本路由打底。”
📦 落地资源推荐
跑AgentScope的多Agent应用,更吃服务器资源,建议使用云服务器,能大大减少我们做其他事的精力,提高学习代码的专注力和学习AI的效率,免除后顾之忧,新用户首年特惠+专属渠道,https://www.aliyun.com/daily-act/ecs/activity_selection?userCode=fzoabro9,无需求忽略。
💡领取完整工程
找到图片上的水印即Java-AI工程师,然后只要能打出【AgentScope】即可5个中间件的完整源码
下期预告
工具越来越多,全量暴露给模型 = Schema塞爆上下文、Token白烧。下一期讲技能包+工具组按需加载:工具默认隐藏,模型加载技能才激活,上下文只留当下要用的。