第5章:在LangChain中如何使用AI Services

这篇文章详细介绍了 LangChain4j 中的 AI Services 概念,展示了如何通过高层次的抽象来简化与大语言模型(LLM)的交互。AI Services 的核心思想是隐藏底层复杂性,让开发者专注于业务逻辑,同时支持聊天记忆、工具调用和 RAG 等高级功能。通过示例和代码片段,文章展示了如何定义和使用 AI Services,以及如何将它们组合起来构建复杂的 LLM 驱动的应用程

AI Services | LangChain4j

引言

到目前为止,我们已经介绍了低层次的组件,例如 ChatLanguageModel、ChatMessage 和 ChatMemory 等。在这一层次上工作非常灵活,给你完全的自由,但这也迫使你编写大量的样板代码(boilerplate code)。由于基于 LLM 的应用程序通常不仅需要单个组件,而是多个组件协同工作(例如,提示词模板、聊天记忆、LLM、输出解析器、RAG 组件:嵌入模型和存储),并且通常涉及多次交互,因此协调它们变得更加繁琐。

解决方案

我们希望你专注于业务逻辑,而不是底层实现细节。因此,LangChain4j 提出了两个高层次的概念来帮助实现这一点:AI Services 和 Chains。

  1. Chains(已废弃)
    Chains 的概念源自 Python 的 LangChain(在引入 LCEL 之前)。其想法是为每个常见用例提供一个 Chain,例如聊天机器人、RAG 等。Chains 结合了多个低层次组件,并协调它们之间的交互。然而,它们的主要问题是,如果你需要自定义某些内容,它们会显得过于僵化。LangChain4j 目前只实现了两个 Chains(ConversationalChain 和 ConversationalRetrievalChain),并且目前不计划添加更多。
  2. AI Services
    我们提出了另一种解决方案,称为 AI Services,专为 Java 设计。其想法是将与 LLM 和其他组件交互的复杂性隐藏在一个简单的 API 后面。
    这种方法类似于 Spring Data JPA 或 Retrofit:你声明性地定义一个接口,指定所需的 API,而 LangChain4j 提供一个实现该接口的对象(代理)。你可以将 AI Service 视为应用程序服务层的一个组件,它提供 AI 服务,因此得名。

AI Services 处理最常见的操作:

  • 为 LLM 格式化输入。
  • 解析 LLM 的输出。
    它们还支持更高级的功能:
  • 聊天记忆(Chat Memory)。
  • 工具(Tools)。
  • RAG(Retrieval-Augmented Generation,检索增强生成)。

AI Services 可以用于构建支持来回交互的状态化聊天机器人,也可以用于自动化每个 LLM 调用都是独立的流程。

AI Service初探

最简单的 AI Service 示例

首先,我们定义一个接口,其中包含一个名为 chat 的方法,该方法接受一个 String 类型的输入并返回一个 String 类型的输出:

interface Assistant {
   
    String chat(String userMessage);
}

然后,我们创建低层次组件。这些组件将在 AI Service 的底层使用。在这个例子中,我们只需要 ChatLanguageModel:

ChatLanguageModel model = OpenAiChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName(GPT_4_O_MINI)
    .build();

最后,我们使用 AiServices 类创建 AI Service 的实例:

Assistant assistant = AiServices.create(Assistant.class, model);

注意:在 Quarkus 和 Spring Boot 应用程序中,自动配置会处理 Assistant 的创建。这意味着你不需要调用 AiServices.create(…),只需在需要的地方注入/自动装配 Assistant 即可。
现在我们可以使用 Assistant:

String answer = assistant.chat("Hello");
System.out.println(answer); // 输出:Hello, how can I help you?

工作原理

你将接口的 Class 和低层次组件提供给 AiServices,AiServices 会创建一个实现该接口的代理对象。目前,它使用反射实现,但我们也在考虑其他替代方案。这个代理对象处理所有输入和输出的转换。在这个例子中,输入是一个单独的 String,但我们使用的是接受 ChatMessage 作为输入的 ChatLanguageModel。因此,AiService 会自动将其转换为 UserMessage 并调用 ChatLanguageModel。由于 chat 方法的输出类型是 String,因此在从 chat 方法返回之前,ChatLanguageModel 返回的 AiMessage 将被转换为 String。

在 Quarkus 和 Spring Boot 应用程序中使用 AI Services

LangChain4j 提供了 Quarkus 扩展和 Spring Boot 启动器,极大地简化了在这些框架中使用 AI Services 的过程。

@SystemMessage

现在,我们来看一个更复杂的例子。我们将强制 LLM 使用俚语回答。这通常是通过在

SystemMessage 中提供指令来实现的:
interface Friend {
   
    @SystemMessage("You are a good friend of mine. Answer using slang.")
    String chat(String userMessage);
}
Friend friend = AiServices.create(Friend.class, model);
String answer = friend.chat("Hello"); // 输出:Hey! What's up?

在这个例子中,我们添加了 @SystemMessage 注解,并指定了我们想要使用的系统提示模板。这将在后台被转换为 SystemMessage,并与 UserMessage 一起发送给 LLM。
@SystemMessage 也可以从资源文件中加载提示模板:

@SystemMessage(fromResource = "my-prompt-template.txt")

系统消息提供者(System Message Provider)

系统消息也可以通过系统消息提供者动态定义:

Friend friend = AiServices.builder(Friend.class)
    .chatLanguageModel(model)
    .systemMessageProvider(chatMemoryId -> "You are a good friend of mine. Answer using slang.")
    .build();

你可以根据聊天记忆 ID(用户或对话)提供不同的系统消息。

@UserMessage

假设我们使用的模型不支持系统消息,或者我们只想使用 UserMessage 来实现:

interface Friend {
   
    @UserMessage("You are a good friend of mine. Answer using slang. {
   {it}}")
    String chat(String userMessage);
}
Friend friend = AiServices.create(Friend.class, model);
String answer = friend.chat("Hello"); // 输出:Hey! What's shakin'?

我们将 @SystemMessage 替换为 @UserMessage,并指定了一个包含变量 it 的提示模板,该变量指向方法的唯一参数。
你也可以使用 @V 注解为提示模板变量指定自定义名称:

interface Friend {
   
    @UserMessage("You are a good friend of mine. Answer using slang. {
   {message}}")
    String chat(@V("message") String userMessage);
}

注意:在使用 LangChain4j 的 Quarkus 或 Spring Boot 应用程序中,@V 注解不是必需的。只有在 Java 编译时未启用 -parameters 选项时,才需要使用它。
@UserMessage 也可以从资源文件中加载提示模板:

@UserMessage(fromResource = "my-prompt-template.txt")

有效的 AI Service 方法示例

以下是一些有效的 AI Service 方法示例:

使用 UserMessage

String chat(String userMessage);

String chat(@UserMessage String userMessage);

String chat(@UserMessage String userMessage, @V("country") String country); // userMessage 包含 "{
   {country}}" 模板变量

@UserMessage("What is the capital of Germany?")
String chat();

@UserMessage("What is the capital of {
   {it}}?")
String chat(String country);

@UserMessage("What is the capital of {
   {country}}?")
String chat(@V("country") String country);

@UserMessage("
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起学开源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值