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 对象。

相关推荐
龙文浩_8 小时前
Attention Mechanism: From Theory to Code
人工智能·深度学习·神经网络·学习·自然语言处理
爱上好庆祝10 小时前
svg图片
前端·css·学习·html·css3
嵌入式小企鹅10 小时前
蓝牙学习系列(八):BLE L2CAP 协议详解
网络·学习·蓝牙·ble·协议栈·l2cap
jiayong2311 小时前
第 8 课:开始引入组合式函数
前端·javascript·学习
格鸰爱童话12 小时前
向AI学习项目技能(五)
java·学习
技术人生黄勇12 小时前
拆解 Hermes Agent:开源 Agent 里唯一的闭环学习系统
学习
凉、介12 小时前
别再把 PCIe 的 inbound/outbound、iATU 和 eDMA 混为一谈
linux·笔记·学习·嵌入式·pcie
speop13 小时前
TASK01 | Reasoning Kindom
学习
2301_8227032014 小时前
鸿蒙flutter三方库实战——教育与学习平台:Flutter Markdown
学习·算法·flutter·华为·harmonyos·鸿蒙
码喽7号14 小时前
vue学习四:Axios网络请求
前端·vue.js·学习