Java开发者必知:AIService让LLM调用更简单 - 教程

目录

1. 背景:为什么需要 AIService

2. 概念:AIService 是什么、不是什么

2.1 定义

2.2 核心职责

2.3 与 Chain 的区别

3. 架构:三层模型与关键组件

3.1 接口层

3.2 代理层

3.3 组件层

4. 源码:一次代理调用的完整生命周期

5. 实战:10 行代码跑通第一个 AI 接口

5.1 依赖引入

5.2 定义接口

5.3 启动与调用

6. 进阶:聊天记忆、工具调用与 RAG 编排

6.1 聊天记忆

6.2 工具调用

6.3 RAG 编排

7. 工程化:SpringBoot 集成与多环境配置

7.1 自动配置

7.2 多模型切换

7.3 可观测性

8. 性能与可靠性:线程池、重试与限流

9. 常见错误与排查思路


1. 背景:为什么需要 AIService

在 LLM 进入工程化元年后,Java 开发者最常遇到的三类需求是:

  1. 快速验证“ Prompt 是否可行”,不想写冗余的 HTTP 调用与 JSON 解析;

  2. 让 LLM 记住多轮对话,并在下一次请求中保持上下文;

  3. 把 LLM 输出自动映射到业务对象,而不是手写正则去“扒”字段。

如果直接基于最底层的 ChatLanguageModel 编程,开发者需要重复完成“参数拼装—网络 IO—异常处理—结果反序列化—业务后处理”整条链路。LangChain4j 团队将这一整套样板逻辑下沉到框架内部,并暴露出声明式接口,即 AIService。它的定位等同于 Spring Data JPA:把“如何存取”做成动态代理,把“存取什么”留给业务注解。

2. 概念:AIService 是什么、不是什么

2.1 定义

AIService 是 LangChain4j 提供的高级抽象,它通过 JDK 动态代理机制,在运行时为开发者定义的接口生成实现类,将“对 LLM 的一次调用”包装成普通 Java 方法。

2.2 核心职责

  • 输入格式化:把 Java 形参转换成 LLM 可消化的 SystemMessage + UserMessage;

  • 输出解析:把 LLM 返回的 AiMessage 反序列化成 Java 返回值;

  • 中间层扩展:在两次网络 IO 之间插入记忆、工具、 moderation 等切面逻辑。

2.3 与 Chain 的区别

LangChain4j 早期曾提供 ConversationalChain 等“链”式组件,但链对自定义节点顺序高度敏感,扩展点固化。AIService 采用“接口即服务”思路,把编排决策权交还给开发者,因而被官方定位为未来主推模式。

3. 架构:三层模型与关键组件

3.1 接口层

开发者只需定义一个普通 Java 接口,并通过注解声明系统提示、用户消息、记忆隔离 ID 等元数据。

3.2 代理层

DefaultAiServices 在启动阶段通过 Proxy.newProxyInstance 生成实现类;方法被调用时,由 InvocationHandler 把“Java 反射元数据”翻译成“ChatMessage 列表”,再交给下层 ChatLanguageModel。

3.3 组件层

包含 ChatLanguageModel、ChatMemory、ContentModerator、Tool 等 SPI。代理层以组合模式引用它们,实现“调用-记忆-审查-工具”一条闭环。

4. 源码:一次代理调用的完整生命周期

以下流程基于 0.35 版本 DefaultAiServices#invoke 阅读得出:

  1. 拦截接口方法,提取 @SystemMessage、@UserMessage、@MemoryId、@V 等注解;

  2. 将模板变量替换为实际参数,生成 SystemMessage 和 UserMessage;

  3. 如果配置了 ChatMemory,则按 memoryId 取出历史消息,与新消息合并;

  4. 调用 ChatLanguageModel.generate(List<ChatMessage>

  5. 若返回类型为 String,直接取 content;若为 POJO,则通过 JsonSchema 解析;

  6. 将本轮对话写回 ChatMemory,供下一次请求使用;

  7. 如果方法标注 @Moderate,则额外调用 ModerationModel 进行内容合规校验。

5. 实战:10 行代码跑通第一个 AI 接口

5.1 依赖引入


  dev.langchain4j
  langchain4j-open-ai
  0.35

5.2 定义接口

public interface Assistant {
    @SystemMessage("你是一名资深技术博主,用中文回答。")
    String chat(@UserMessage String question);
}

5.3 启动与调用

ChatLanguageModel model = OpenAiChatModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .modelName("gpt-4o-mini")
        .build();
Assistant assistant = AiServices.create(Assistant.class, model);
String answer = assistant.chat("AIService 的核心价值是什么?");
System.out.println(answer);

运行结果示例:

AIService 的核心价值在于“隐藏交互复杂度,让开发者专注业务语义”……

至此,第一行 AI 代码完成,总代码量(含 main)不超过 30 行。

6. 进阶:聊天记忆、工具调用与 RAG 编排

6.1 聊天记忆

ChatMemory memory = MessageWindowChatMemory.builder()
        .maxMessages(10)
        .build();
Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(model)
        .chatMemory(memory)
        .build();

相同 memory 实例在多轮调用中自动维护上下文;若需用户级隔离,可配置 ChatMemoryProvider 并结合 @MemoryId。

6.2 工具调用

class WeatherService {
    @Tool("获取城市气温")
    double getTemperature(@P("城市") String city) { … }
}
AiServices.builder(Assistant.class)
        .tools(new WeatherService())
        .build();

当用户提问“今天北京多少度”时,LLM 会生成工具调用指令,框架负责反射执行并把结果回传给模型,完成闭环决策。

6.3 RAG 编排

通过集成 EmbeddingStore 与 ContentRetriever,AIService 可在生成阶段自动检索私有知识库,把相关段落插入 SystemMessage,实现“检索增强生成”。得益于代理层的设计,业务接口无需任何改动,仅替换底层组件即可。

7. 工程化:SpringBoot 集成与多环境配置

7.1 自动配置

LangChain4j 提供 langchain4j-spring-boot-starter,在 application.yml 中声明模型参数后,可直接注入 Assistant Bean,省去 AiServices.create() 样板。

7.2 多模型切换

利用 Spring Profile 定义不同环境的 modelName、baseUrl、timeout;运行时通过 @ConditionalOnProperty 动态装配 ChatLanguageModel,实现“同一套代码,开发环境走 4o-mini,生产环境走 4o”。

7.3 可观测性

框架内置 Metrics 接口,可扩展 Micrometer;在 InvocationHandler 中埋点记录“输入 token 数/输出 token 数/方法耗时”,对接 Prometheus 后,可在 Grafana 面板实时观察 LLM 调用成本。

8. 性能与可靠性:线程池、重试与限流

  • 线程池:ChatLanguageModel 默认同步阻塞,建议用 Supplier<CompletableFuture>

  • 重试:OpenAiChatModel 支持 backoff 策略,可配置 maxRetries、retryDelay;

  • 限流:LLM 按 token 计费,需在网关层或 SDK 层做 QPS + token 双维度限流,防止提示注入攻击导致账单爆炸。

9. 常见错误与排查思路

现象根因排查要点
java.lang.IllegalConfiguration: moderationModel is null接口方法加 @Moderate 却未注入 ModerationModel检查 AiServices.builder().moderationModel() 是否缺失
返回内容被截断超过模型 maxTokens显式设置 OpenAiChatModel#maxTokens,或改用流式 StreamingChatModel
多轮对话“失忆”忘记配置 ChatMemory确认 AiServices.builder().chatMemory() 已绑定,且 Controller 层未每次 new 新实例
工具调用报 NoSuchMethodException工具方法参数未加 @P 注解

        AIService 通过“声明式接口 + 动态代理”把 LLM 的交互复杂度下沉到框架层,让 Java 工程师能以最小成本享受生成式 AI 的能力。

posted @ 2025-11-12 10:16  yangykaifa  阅读(6)  评论(0)    收藏  举报