Langchain4j中AIService学习

1. 什么是 AiServices?

AiServices 是 LangChain4j 提供的一种 "高层级声明式抽象"

它的核心思想是:

你只需要定义一个 Java 接口 (Interface),并加上简单的注解。LangChain4j 框架会在运行时利用 动态代理 技术,自动帮你生成这个接口的实现类。

对比一下:

  • 以前 (ChatLanguageModel): 你得手动写:"请把这句话翻译成英文:" + text

  • 现在 (AiServices): 你定义一个方法 String translate(String text),框架自动帮你填 Prompt,发请求,解析结果。

2. AiServices 有什么好处?

  1. 代码解耦 (Clean Code): 业务逻辑(接口)和 AI 实现细节彻底分离。你不需要在业务代码里到处拼接字符串。

  2. 类型安全 (Structured Output): AI 不再只能返回 String。它可以直接返回 booleanDateEnumList 甚至自定义的 Person 对象。框架会自动提示 AI 输出 JSON 并帮你反序列化。

  3. 功能集成 (All-in-One): 它不仅仅是对话,它把 RAG (知识库)ChatMemory (记忆)Tools (工具调用)Audit (审计) 全部整合在一起。你只需要在构建时配置一下,接口就立刻拥有了这些能力。

3. 核心注解与方法

在使用 AiServices 时,我们主要打交道的是以下几个注解:

注解 作用 示例
@SystemMessage 给 AI 设定"人设"或"系统指令"。 @SystemMessage("你是一个专业的法律顾问")
@UserMessage 定义发给 AI 的具体 Prompt 模板。 @UserMessage("请将 {``{text}} 翻译成 {``{lang}}")
@V 绑定方法参数到模板变量中。 translate(@V("text") String t, @V("lang") String l)
@MemoryId 区分不同用户的记忆(多轮对话用)。 chat(@MemoryId int userId, String msg)

4. 实战 Demo:打造一个"情感分析与翻译助手"

我们继续在你现有的 AiTest 类基础上扩展。这次我们不直接调用 chatLanguageModel.generate,而是创建一个接口。

第一步:定义接口 (在同一个文件或新建文件)

这个接口定义了我们希望 AI 完成的两个功能:

  1. 翻译功能(带参数模板)。

  2. 情感分析功能(要求返回布尔值,看看 AI 是不是真的懂类型转换)。

java 复制代码
// 定义一个内部接口方便测试,实际开发中建议单独建文件
interface SmartAssistant {

    // 功能 1: 简单的对话,设定人设
    @SystemMessage("你是一个说话像古代诗人的助手")
    String chat(String userMessage);

    // 功能 2: 带参数的模板
    // {{message}} 和 {{language}} 会被参数自动替换
    @UserMessage("请将以下内容:'{{message}}' 翻译成目标语言:{{language}}")
    String translate(@dev.langchain4j.service.V("message") String message, 
                     @dev.langchain4j.service.V("language") String language);

    // 功能 3: 结构化输出 (直接返回 boolean)
    @UserMessage("以下这段话是正面的积极评价吗?请只回答 true 或 false:{{text}}")
    boolean isPositive(@dev.langchain4j.service.V("text") String text);
}
第二步:编写测试用例 (AiServicesTest)

将以下代码添加到你的测试类中(或者替换原来的 test 方法)。我们会复用你之前配置好的 apiKey 等变量。

java 复制代码
package com.qcby.langchain4jdemo;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices; // 引入核心类
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class AiServicesTest {

    @Value("${aliyun.ai.key}")
    private String apiKey;

    @Value("${aliyun.ai.apiUrl}")
    private String url;

    @Value("${aliyun.ai.model}")
    private String modelName;

    // 1. 定义接口 (实际项目中通常放在单独的 .java 文件里)
    interface SmartAssistant {
        
        @SystemMessage("你是一个精通多国语言的翻译官,但在闲聊时非常幽默。")
        String chat(String msg);

        @UserMessage("请将这段文字 '{{msg}}' 翻译成 {{lang}},只输出翻译结果,不要废话。")
        String translate(@V("msg") String message, @V("lang") String targetLanguage);

        @UserMessage("请判断这句话的情感是否是积极的?文本:{{text}}")
        boolean analyzeSentiment(@V("text") String text); // 注意返回值是 boolean
    }

    @Test
    public void testAiService() {
        // 2. 准备底层模型 (和之前一样)
        ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey(apiKey)
                .baseUrl(url)
                .modelName(modelName)
                .build();

        // 3. 【核心步骤】创建 AiService 代理实例
        // 这一步相当于 MyBatis 的 SqlSession.getMapper(UserMapper.class)
        SmartAssistant assistant = AiServices.builder(SmartAssistant.class)
                .chatLanguageModel(model) // 绑定模型引擎
                .build();

        // 4. 像调用普通 Java 方法一样调用 AI
        System.out.println("--- 测试 1: 闲聊 ---");
        String chatResult = assistant.chat("你好,你会写代码吗?");
        System.out.println(chatResult);

        System.out.println("\n--- 测试 2: 翻译 (参数替换) ---");
        String transResult = assistant.translate("Hello World", "中文");
        System.out.println("翻译结果: " + transResult);

        System.out.println("\n--- 测试 3: 结构化输出 (Boolean) ---");
        boolean isHappy = assistant.analyzeSentiment("LangChain4j 真是太好用了,我爱死它了!");
        boolean isSad = assistant.analyzeSentiment("今天的代码全是 Bug,我很绝望。");
        
        System.out.println("第一句是积极的吗? " + isHappy);
        System.out.println("第二句是积极的吗? " + isSad);
    }
}

5. 代码深度解析

当你运行 assistant.translate("Hello World", "中文") 时,LangChain4j 在后台默默做了这些事:

  1. 模板解析: 它读取 @UserMessage 注解,发现里面有两个变量 {``{msg}}{``{lang}}

  2. 参数填充: 它把你的参数 "Hello World" 填入 {``{msg}},把 "中文" 填入 {``{lang}}

  3. Prompt 构建: 最终生成的 Prompt 是:请将这段文字 'Hello World' 翻译成 中文,只输出翻译结果,不要废话。

  4. 发送请求: 带着 @SystemMessage 定义的人设,把 Prompt 发给阿里云。

  5. 结果解析: 拿到 AI 的回复字符串,直接返回给你。

而对于 analyzeSentiment 方法:

  • AI 可能返回了 "Yes""True""是的"

  • AiServices 会尝试把这些自然语言自动解析成 Java 的 boolean 值 (true/false)。

下一步建议

一旦你跑通了这个 Demo,你就掌握了 LangChain4j 最核心的用法。

接下来的进阶玩法是:

  • ChatMemory : 现在的 SmartAssistant 是没记性的,你上一句说你是谁,下一句它就忘了。你可以给 builder 加上 .chatMemory(...)

  • Structured Output (POJO) : 尝试定义一个 Person 类,让 AI 从一段文本里提取姓名和年龄,直接返回 Person 对象。

相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习