1. 引言

在前面的文章中,我们深入探讨了 LangChain4j 中的 Tools 机制,了解了如何让大模型调用本地方法。然而,在实际开发中,我们往往需要将 ChatLanguageModel、ChatMessage、ChatMemory、Tools 等多个组件整合起来,才能构建一个功能完整的智能体应用。如果每次都要手动编排这些组件,开发效率会非常低下。

LangChain4j 提供了一个强大的上层抽象——AiServices,它通过代理模式,将这些基础组件无缝整合,让我们能够以极低的代码量快速构建出功能强大的 AI 服务。本文将带你从零开始,一步步掌握 AiServices 的核心用法,并深入其源码,理解其背后的工作原理。

2. 什么是 AiServices?

简单来说,AiServices 是 LangChain4j 提供的一个服务构建器,它允许你通过定义一个 Java 接口来描述 AI 服务的行为,然后自动生成该接口的代理实现。这个代理对象会负责与大模型进行交互,并自动处理消息的组装、记忆的管理以及工具的调用。

核心优势:

  • 极简开发:通过接口定义,告别繁琐的底层 API 调用。
  • 组件整合:轻松整合 ChatMemoryToolsSystemMessage 等核心组件。
  • 多用户支持:内置对多用户会话隔离的支持。

3. 快速入门:构建你的第一个 AiServices 代理

让我们从一个最简单的例子开始。假设我们想让大模型扮演一个作家,根据给定的题目写一篇短文。

首先,定义一个接口:

interface Writer {
    String write(String topic);
}

然后,使用 AiServices 创建代理并调用:

ChatLanguageModel model = ModelUtil.getZhipuAIModel(); // 获取模型,过程略

Writer writer = AiServices.create(Writer.class, model);
String content = writer.write("我最感谢的人");
System.out.println(content);

运行这段代码,大模型就会根据“我最感谢的人”这个题目,生成一篇短文。这就是 AiServices 的第一个作用:通过接口代理,快速完成与大模型的交互。

4. 进阶用法:整合核心组件

上面的例子虽然简单,但生成的作文往往比较粗糙。接下来,我们将逐步整合 @SystemMessageChatMemoryTools,让我们的“作家”变得更智能。

4.1 通过 @SystemMessage 增加系统提示词

为了让大模型更好地理解我们的需求,我们可以通过 @SystemMessage 注解来设定系统提示词。

interface Writer {
    @SystemMessage("你是一名作家,根据输入的题目写一篇200字以内的作文")
    String write(String topic);
}

这样,每次调用 write() 方法时,LangChain4j 都会自动将 SystemMessage 和用户输入的 UserMessage 组合发送给大模型,从而得到更符合预期的结果。

你还可以通过 @V 注解,让系统提示词支持动态参数:

interface Writer {
    @SystemMessage("你是一名作家,写一篇作文,题目是{{title}},字数不超过{{count}}个字")
    String write(@UserMessage String message, @V("title") String title, @V("count") Long count);
}

注意:当方法参数使用了 @V 注解后,必须有一个参数带有 @UserMessage 注解,或者方法只有一个参数时,该参数默认作为 UserMessage 处理。

4.2 整合 ChatMemory 和 Tools

AiServices 提供了一个 Builder 组件,可以方便地整合 ChatMemoryTools

interface Assistant {
    String chat(@MemoryId Long userId, @UserMessage String message);
}

@Tool("获取当前日期")
public static String dateUtil() {
    return LocalDateTime.now().toString();
}

public static void main(String[] args) {
    ChatLanguageModel model = ModelUtil.getZhipuAIModel();
    ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
    ToolSpecification toolSpecification = ToolSpecifications.toolSpecificationFrom(
        UserAiService.class.getMethod("dateUtil")
    );

    Assistant assistant = AiServices.builder(Assistant.class)
            .chatLanguageModel(model)
            .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
            .tools(toolSpecification)
            .build();

    // 与用户1的交互
    System.out.println(">>>" + assistant.chat(1L, "你好,我是楼兰"));
    System.out.println(">>>" + assistant.chat(1L, "我的名字是什么"));

    // 与用户2的交互
    System.out.println(">>>" + assistant.chat(2L, "你好,我是老王"));
    System.out.println(">>>" + assistant.chat(2L, "我的名字是什么"));
}

关键点

  • @MemoryId:用于标识不同的用户会话。AiServices 会根据 memoryId 自动管理不同用户的聊天记录,实现多用户隔离。
  • chatMemoryProvider:相比于直接设置 chatMemory,使用 chatMemoryProvider 可以更灵活地为每个用户创建独立的记忆空间。

5. AiServices 重点源码解读

理解源码有助于我们更好地掌握 AiServices 的细节。其核心在于 JDK 动态代理。

5.1 代理对象的创建

AiServices 创建服务接口代理对象的核心方法在 DefaultAiServices 中,它通过 JDK 的 Proxy.newProxyInstance 创建接口代理。

// dev.langchain4j.service.DefaultAiServices#build
Object proxyInstance = Proxy.newProxyInstance(
    context.aiServiceClass.getClassLoader(),
    new Class<?>[]{context.aiServiceClass},
    new InvocationHandler() {
        // 核心业务方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // ... 处理 @SystemMessage, @UserMessage, ChatMemory, Tools 等
        }
    }
);

5.2 核心执行流程

当调用代理对象的方法时,InvocationHandlerinvoke 方法会被触发,其大致流程如下:

  1. 解析注解:解析方法上的 @SystemMessage@UserMessage@V 等注解,以及参数上的 @MemoryId@V 等注解。
  2. 构建消息:根据注解和传入的参数,构建 SystemMessageUserMessage 对象。
  3. 管理记忆:根据 @MemoryIdChatMemoryProvider 中获取或创建对应的 ChatMemory 对象,并将历史消息加载到上下文中。
  4. 准备工具:获取通过 Builder 注册的 ToolSpecification 列表。
  5. 调用模型:将消息、记忆和工具信息一并发送给 ChatLanguageModel
  6. 处理工具调用:如果模型返回了工具调用请求,则执行对应的本地方法,并将结果作为新的消息再次发送给模型,直到模型返回最终文本结果。
  7. 保存记忆:将本次交互的消息保存到 ChatMemory 中。
  8. 返回结果:将模型的最终文本结果返回给调用方。

6. 总结

AiServices 是 LangChain4j 框架中一个极其重要的组件,它通过代理模式极大地简化了 AI 应用的开发流程。通过本文的学习,你应该已经掌握了:

  • 如何使用 AiServices.create() 快速创建 AI 代理。
  • 如何通过 @SystemMessage@V 注解定制提示词。
  • 如何使用 Builder 整合 ChatMemoryTools,并实现多用户会话隔离。
  • AiServices 基于 JDK 动态代理的核心工作原理。

掌握了 AiServices,你就拥有了快速构建复杂智能体应用的利器。你可以将生成的代理对象保存到 Spring 的 IOC 容器中,轻松构建出功能完整的 AI 服务。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐