作者:互联网 时间: 2026-09-01 20:18:53
必须使用 CompletableFuture 并行调用多个已注册的 ModelClient 实例,共享同一 Prompt 对象,通过 allOf 等待全部完成并分别获取结果,确保输入一致性和同步响应。
要在同一请求中让多个大语言模型(如 deepseek-chat、deepseek-reasoner、qwen2.5-72b)并行响应、同步返回结果,必须绕过串行调用的天然延迟,构建真正共享输入、独立推理、统一收口的执行通路。
启动前确认所有目标模型已通过 Spring AI 的 ModelClient 抽象完成注册。每个模型需绑定唯一 ID(如 deepseek-chat-v3、deepseek-reasoner-cot、qwen2.5-72b),且对应配置已加载至 ModelRegistry。若任一模型 ID 未注册,后续并发调用将直接抛出 ModelNotFoundException。
在 Spring Boot 启动类或 Configuration 类中,显式声明三个 ModelClient Bean,分别注入不同 model-id:
@Bean public ModelClient deepseekChatClient(ModelRegistry registry) { return registry.getClient("deepseek-chat-v3"); }
@Bean public ModelClient deepseekReasonerClient(ModelRegistry registry) { return registry.getClient("deepseek-reasoner-cot"); }
@Bean public ModelClient qwenClient(ModelRegistry registry) { return registry.getClient("qwen2.5-72b"); }
使用 CompletableFuture 批量提交异步请求,避免阻塞主线程。每个任务封装一次完整的 ModelClient.call() 调用,并携带完全相同的 Prompt 实例——这是保证输入一致性的关键前提。
第一步:创建共享 Prompt 对象,设置 system 和 user 消息内容,不修改任何模型专属参数;
第二步:对每个 ModelClient 调用 CompletableFuture.supplyAsync(() -> client.call(prompt)),生成三个独立 Future;
第三步:用 CompletableFuture.allOf(f1, f2, f3).join() 等待全部完成;
第四步:用 f1.join()、f2.join()、f3.join() 分别获取结果,按模型 ID 映射为 Map 返回。
【必须确保所有 Future 共享同一个 Prompt 实例,而非各自 new 一个副本】 否则因 Prompt 内部 token 缓存或随机 seed 差异,可能导致微小输入偏移,破坏“同步执行”的语义一致性。
方法一:逐个 await 并收集结果
遍历三个 Future,对每个调用 get(15, TimeUnit.SECONDS) 设置超时。任一模型响应超时或失败,立即记录 warn 日志,但不中断其余任务——这是“尽力同步”的核心设计。
方法二:使用 allOf + thenApply 组合式编排
将三个 Future 封装进 allOf,再链式调用 thenApply 提取各结果。此方式天然支持函数式错误传播,但需手动 catch ExecutionException 并降级为 null 值占位。
方法三:引入 Resilience4j 的 Bulkhead 隔离
为每个模型 Client 配置独立线程池(如 deepseek-pool、qwen-pool),防止某模型高延迟拖垮整体吞吐。Bulkhead 配置必须启用 maxConcurrentCalls = 5,否则默认为 100,可能引发线程耗尽。