LangChain4j 接入多个模型时,别让 AI Service 自动“猜”该用谁
很多 Java 项目第一次接入 LangChain4j 时,代码会写得很顺:定义一个接口,加上 @AiService,业务层像调用普通 Java Service 一样调用它。这个设计确实舒服,尤其适合 Spring Boot 项目。
但项目稍微往前走一步,问题就来了:客服助手想用一个在线大模型,敏感内容审核想走本地模型,报表摘要又想用另一个成本更低的模型。此时如果还依赖自动装配,很容易出现启动失败、模型选错、配置难以排查的问题。
这篇文章只讲一个具体问题:LangChain4j 在 Spring Boot 多模型场景下,AI Service 应该显式绑定模型,而不是依赖自动推断。
AI Service 像 Service,但它不是普通 Service
LangChain4j 的 AI Service 思路很像 Spring Data Repository:开发者定义接口,框架在背后生成代理对象,把方法调用转换成大模型请求。
例如:
public interface ReportAssistant {
String summarize(String content);
}
配合 @AiService 后,业务代码里可以直接注入:
@Service
public class ReportService {
private final ReportAssistant reportAssistant;
public ReportService(ReportAssistant reportAssistant) {
this.reportAssistant = reportAssistant;
}
public String buildSummary(String rawReport) {
return reportAssistant.summarize(rawReport);
}
}
这就是 LangChain4j 对 Java 开发者友好的地方:它没有要求你在每个业务方法里手动拼 Prompt、调用 HTTP、解析响应,而是把“AI 调用”包装成一个接口契约。
问题也出在这里。接口看起来像普通 Service,但它背后依赖的是 ChatModel、StreamingChatModel、Chat Memory、Tools、Retrieval Augmentor 等组件。一旦 Spring 容器里有多个候选 Bean,框架就必须知道当前 AI Service 到底绑定哪一个。
单模型 Demo 里自动装配没问题;真实项目里,多模型、多工具、多检索器并存才是常态。
自动装配适合 Demo,显式布线适合项目
假设一个 Spring Boot 项目里同时接入在线模型和本地模型:
<properties>
<langchain4j.version>1.16.2</langchain4j.version>
</properties>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
</dependencies>
配置可以这样拆开:
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY}
model-name: ${OPENAI_MODEL}
ollama:
chat-model:
base-url: http://localhost:11434
model-name: ${LOCAL_MODEL}
如果只有一个 ChatModel,@AiService 可以比较轻松地自动找到它。但当容器里存在多个模型 Bean 时,自动判断就不再可靠。更工程化的做法是使用显式布线:
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;
import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
@AiService(
wiringMode = EXPLICIT,
chatModel = "openAiChatModel"
)
public interface ReportAssistant {
@UserMessage("""
请把下面的业务报表压缩成 300 字以内的摘要。
要保留关键数字、风险点和下一步建议。
{{content}}
""")
String summarize(String content);
}
再定义一个本地模型场景:
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;
import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;
@AiService(
wiringMode = EXPLICIT,
chatModel = "ollamaChatModel"
)
public interface AuditAssistant {
@UserMessage("""
判断下面这段文本是否包含敏感信息。
只返回:PASS 或 REVIEW。
{{content}}
""")
String check(String content);
}
这段代码的重点不是注解本身,而是把“哪个业务能力使用哪个模型”写成了清晰的工程约束。以后排查成本、延迟、效果问题时,不需要猜某个接口到底打到了哪个模型。
具体 Bean 名称可能会随 starter、版本和自定义配置变化,实际项目中应以官方文档和本地 Spring Bean 为准。
为什么这件事值得认真设计
多模型项目里,模型选择不是简单的技术偏好,而是业务策略。
| 场景 | 更适合的模型策略 | 关注点 |
|---|---|---|
| 报表摘要 | 在线强模型 | 质量、长文本能力 |
| 内容初筛 | 本地模型或低成本模型 | 成本、延迟、数据边界 |
| 客服回复 | 稳定在线模型 | 可用性、语气一致性 |
| 内部知识库问答 | 模型 + RAG | 召回质量、幻觉控制 |
如果所有 AI Service 都共享同一个模型,早期开发会省事,但后面会遇到三个问题。
第一,成本不可控。原本只需要低成本模型处理的任务,可能被路由到高价模型。
第二,排查困难。用户反馈“摘要质量下降”,你需要先确认它到底用了哪个模型、哪套 Prompt、有没有走检索。
第三,边界模糊。涉及内部数据、权限数据、审计数据的任务,不应该随便交给任意模型处理。
显式布线的价值,就是让这些规则沉淀在代码里,而不是只存在于某个开发者的脑子里。
Service 接口也要按业务边界拆
一个常见错误是定义一个“万能助手”:
public interface AiAssistant {
String chat(String message);
String summarize(String content);
String audit(String content);
String rewrite(String content);
}
这看起来方便,实际会让模型、Prompt、工具和权限混在一起。更合理的拆法是按业务能力拆接口:
public interface ReportAssistant {
String summarize(String content);
}
public interface AuditAssistant {
String check(String content);
}
public interface CustomerSupportAssistant {
String reply(String question);
}
这样做有几个好处。
一是模型绑定更明确。报表、审核、客服可以分别绑定不同模型。
二是测试更容易。你可以分别验证摘要质量、审核误判率、客服回答风格,而不是测一个巨大的通用入口。
三是后续扩展更自然。某个接口需要增加工具调用、记忆、RAG,不会影响其他 AI Service。
Java 后端做久了会习惯分层、限界上下文、接口隔离。AI Service 也应该遵守这些工程原则。不要因为背后是大模型,就把多年积累的设计边界丢掉。
第一版项目可以这样落地
如果团队刚开始接入 LangChain4j,不建议一上来做复杂的模型网关。第一版可以先做到三件事。
第一,每个 AI Service 只负责一个业务能力。不要把所有 AI 能力塞进一个接口。
第二,涉及多个模型时使用显式布线。哪怕当前只有两个模型,也要提前把绑定关系写清楚。
第三,把模型选择、Prompt 版本、调用日志纳入可观测范围。至少要能知道一次业务请求调用了哪个 AI Service、哪个模型、耗时多少、是否失败。
可以先不用追求“智能路由”。很多企业项目的第一阶段,最需要的不是让系统自动选择模型,而是让开发者和运维人员知道:这次请求到底发生了什么。
LangChain4j 的 AI Service 降低了 Java 项目接入大模型的门槛,但它不应该把工程边界也一起隐藏掉。接口越像普通 Service,越要把模型、工具、检索器这些背后依赖设计清楚。真正可维护的 AI 应用,不是把调用写得最短,而是让每一次调用都能被理解、被测试、被替换。
更多推荐

所有评论(0)