【Langchain4j-Java AI开发】04-AI 服务核心模式

LangChain4j AI 服务核心模式

概述

AI Services 是 LangChain4j 的核心设计模式,它允许你通过定义 Java 接口来声明式地构建 AI 应用。本教程将全面介绍 AI Services 的各种使用模式。

基础 AI Service

最简单的 AI Service

代码示例 (参考:tutorials/src/main/java/_08_AIServiceExamples.java

java 复制代码
package dev.langchain4j.example;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;

import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI;

public class SimpleAiServiceExample {

    // 1. 定义接口
    interface Assistant {
        String chat(String message);
    }

    public static void main(String[] args) {

        // 2. 创建模型
        ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey(System.getenv("OPENAI_API_KEY"))
                .modelName(GPT_4_O_MINI)
                .build();

        // 3. 创建 AI Service 实例
        Assistant assistant = AiServices.create(Assistant.class, model);

        // 4. 像调用普通方法一样使用
        String answer = assistant.chat("什么是 LangChain4j?");

        System.out.println(answer);
    }
}

关键优势

  1. 类型安全: 编译时检查,避免运行时错误
  2. 简洁直观: 无需手动构建消息对象
  3. 易于测试: 可以轻松 Mock 接口
  4. 声明式: 通过注解配置行为

系统消息与角色定义

使用 @SystemMessage 定义 AI 角色

java 复制代码
import dev.langchain4j.service.SystemMessage;

interface Chef {
    @SystemMessage("你是一位专业的中餐厨师,拥有 20 年烹饪经验。请用友好且专业的语气回答问题。")
    String answer(String question);
}

// 使用
Chef chef = AiServices.create(Chef.class, model);
String answer = chef.answer("如何做宫保鸡丁?");

多行系统消息

java 复制代码
interface TechnicalWriter {
    @SystemMessage({
            "你是一位资深的技术文档工程师。",
            "你擅长将复杂的技术概念解释得通俗易懂。",
            "你的文档结构清晰、逻辑严谨、示例丰富。",
            "请始终使用中文回答。"
    })
    String writeDocumentation(String topic);
}

带变量的系统消息

java 复制代码
interface Translator {
    @SystemMessage("你是一位专业的翻译,精通 {{sourceLanguage}} 和 {{targetLanguage}}。")
    @UserMessage("将以下 {{sourceLanguage}} 文本翻译成 {{targetLanguage}}:{{text}}")
    String translate(
            @V("text") String text,
            @V("sourceLanguage") String sourceLanguage,
            @V("targetLanguage") String targetLanguage
    );
}

// 使用
Translator translator = AiServices.create(Translator.class, model);
String result = translator.translate("Hello World", "English", "Chinese");
// 输出: 你好世界

结构化输出

返回枚举类型

代码示例 (参考:tutorials/src/main/java/_08_AIServiceExamples.java:104-129

java 复制代码
package dev.langchain4j.example;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.UserMessage;

import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI;

public class SentimentAnalysisExample {

    // 定义情感枚举
    enum Sentiment {
        POSITIVE,    // 积极
        NEUTRAL,     // 中性
        NEGATIVE     // 消极
    }

    interface SentimentAnalyzer {
        @UserMessage("分析以下文本的情感倾向:{{it}}")
        Sentiment analyzeSentimentOf(String text);

        @UserMessage("文本 {{it}} 是否具有积极情感?")
        boolean isPositive(String text);
    }

    public static void main(String[] args) {

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

        SentimentAnalyzer analyzer = AiServices.create(SentimentAnalyzer.class, model);

        // 返回枚举
        Sentiment sentiment1 = analyzer.analyzeSentimentOf("这个产品太棒了!");
        System.out.println(sentiment1);  // POSITIVE

        Sentiment sentiment2 = analyzer.analyzeSentimentOf("这个服务真糟糕。");
        System.out.println(sentiment2);  // NEGATIVE

        // 返回布尔值
        boolean isPositive = analyzer.isPositive("今天天气不错");
        System.out.println(isPositive);  // true
    }
}

返回列表类型

java 复制代码
interface IssueAnalyzer {
    @UserMessage("分析以下评论中提到的问题类别:{{it}}")
    List<IssueCategory> analyzeReview(String review);
}

enum IssueCategory {
    MAINTENANCE_ISSUE,      // 维护问题
    SERVICE_ISSUE,          // 服务问题
    COMFORT_ISSUE,          // 舒适度问题
    CLEANLINESS_ISSUE,      // 清洁问题
    CONNECTIVITY_ISSUE      // 连接问题
}

// 使用
IssueAnalyzer analyzer = AiServices.create(IssueAnalyzer.class, model);
String review = "房间的空调不工作,WiFi信号很弱,而且床单不够干净。";
List<IssueCategory> issues = analyzer.analyzeReview(review);
// 输出: [MAINTENANCE_ISSUE, CONNECTIVITY_ISSUE, CLEANLINESS_ISSUE]

提取数字类型

代码示例 (参考:tutorials/src/main/java/_08_AIServiceExamples.java:168-200

java 复制代码
import java.math.BigDecimal;
import java.math.BigInteger;

interface NumberExtractor {

    @UserMessage("从文本中提取数字:{{it}}")
    int extractInt(String text);

    @UserMessage("从文本中提取数字:{{it}}")
    long extractLong(String text);

    @UserMessage("从文本中提取数字:{{it}}")
    double extractDouble(String text);

    @UserMessage("从文本中提取数字:{{it}}")
    BigDecimal extractBigDecimal(String text);
}

// 使用
NumberExtractor extractor = AiServices.create(NumberExtractor.class, model);
String text = "这个项目预算是 1,250,000 元人民币";
int amount = extractor.extractInt(text);
System.out.println(amount);  // 1250000

提取日期和时间

java 复制代码
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

interface DateTimeExtractor {

    @UserMessage("从文本中提取日期:{{it}}")
    LocalDate extractDate(String text);

    @UserMessage("从文本中提取时间:{{it}}")
    LocalTime extractTime(String text);

    @UserMessage("从文本中提取完整日期时间:{{it}}")
    LocalDateTime extractDateTime(String text);
}

// 使用
DateTimeExtractor extractor = AiServices.create(DateTimeExtractor.class, model);

LocalDate date = extractor.extractDate("会议安排在2024年3月15日");
System.out.println(date);  // 2024-03-15

LocalTime time = extractor.extractTime("下午3点30分开始");
System.out.println(time);  // 15:30:00

提取复杂对象(POJO)

定义数据类

java 复制代码
package dev.langchain4j.example;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.output.structured.Description;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.UserMessage;

import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI;

public class PersonExtractionExample {

    // 定义 Person 类,使用 @Description 注解描述字段
    static class Person {
        @Description("人的名字")
        private String firstName;

        @Description("人的姓氏")
        private String lastName;

        @Description("人的年龄,单位:岁")
        private int age;

        @Description("人所在的城市")
        private String city;

        // Constructors, getters, setters, toString()
        public Person() {}

        public String getFirstName() { return firstName; }
        public void setFirstName(String firstName) { this.firstName = firstName; }

        public String getLastName() { return lastName; }
        public void setLastName(String lastName) { this.lastName = lastName; }

        public int getAge() { return age; }
        public void setAge(int age) { this.age = age; }

        public String getCity() { return city; }
        public void setCity(String city) { this.city = city; }

        @Override
        public String toString() {
            return "Person{" +
                    "firstName='" + firstName + '\'' +
                    ", lastName='" + lastName + '\'' +
                    ", age=" + age +
                    ", city='" + city + '\'' +
                    '}';
        }
    }

    interface PersonExtractor {
        @UserMessage("从以下文本中提取人物信息:{{it}}")
        Person extractPersonFrom(String text);
    }

    public static void main(String[] args) {

        ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey(System.getenv("OPENAI_API_KEY"))
                .modelName(GPT_4_O_MINI)
                .responseFormat("json_schema")  // 使用 JSON Schema 模式
                .strictJsonSchema(true)          // 严格模式
                .build();

        PersonExtractor extractor = AiServices.create(PersonExtractor.class, model);

        String text = "我叫张伟,今年28岁,目前在北京工作。";
        Person person = extractor.extractPersonFrom(text);

        System.out.println(person);
        // 输出: Person{firstName='伟', lastName='张', age=28, city='北京'}
    }
}

提取复杂嵌套对象

java 复制代码
static class Address {
    @Description("街道地址")
    private String street;

    @Description("城市")
    private String city;

    @Description("邮政编码")
    private String zipCode;

    // getters and setters...
}

static class Employee {
    @Description("员工姓名")
    private String name;

    @Description("职位")
    private String position;

    @Description("部门")
    private String department;

    @Description("家庭地址")
    private Address address;  // 嵌套对象

    @Description("技能列表")
    private List<String> skills;

    // getters and setters...
}

interface EmployeeExtractor {
    @UserMessage("从以下简历中提取员工信息:{{it}}")
    Employee extractEmployee(String resume);
}

// 使用
EmployeeExtractor extractor = AiServices.create(EmployeeExtractor.class, model);
String resume = """
    姓名:李明
    职位:高级Java工程师
    部门:技术研发部
    地址:北京市朝阳区建国路88号,邮编100022
    技能:Java, Spring Boot, Kubernetes, MySQL
    """;

Employee employee = extractor.extractEmployee(resume);
System.out.println(employee.getName());  // 李明
System.out.println(employee.getAddress().getCity());  // 北京市
System.out.println(employee.getSkills());  // [Java, Spring Boot, Kubernetes, MySQL]

Builder 模式(完整配置)

基础 Builder

java 复制代码
Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(chatModel)
        .build();

完整配置示例

java 复制代码
package dev.langchain4j.example;

import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;

import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI;

public class FullBuilderExample {

    interface Assistant {
        String chat(String message);
    }

    static class Calculator {
        @Tool("计算两个数的和")
        int add(int a, int b) {
            return a + b;
        }
    }

    public static void main(String[] args) {

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

        Assistant assistant = AiServices.builder(Assistant.class)
                .chatModel(model)                                      // 设置模型
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))  // 添加记忆
                .tools(new Calculator())                               // 添加工具
                // .contentRetriever(contentRetriever)                 // 添加检索器(RAG)
                .build();

        String answer = assistant.chat("5 加 3 等于多少?");
        System.out.println(answer);
    }
}

多用户会话管理

使用 @MemoryId 隔离不同用户

java 复制代码
package dev.langchain4j.example;

import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;

import java.util.HashMap;
import java.util.Map;

import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI;

public class MultiUserExample {

    interface Assistant {
        String chat(@MemoryId int memoryId, @UserMessage String message);
    }

    public static void main(String[] args) {

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

        // 创建共享的内存存储
        ChatMemoryStore store = new InMemoryChatMemoryStore();

        Assistant assistant = AiServices.builder(Assistant.class)
                .chatModel(model)
                .chatMemoryProvider(memoryId -> MessageWindowChatMemory.builder()
                        .id(memoryId)
                        .maxMessages(10)
                        .chatMemoryStore(store)
                        .build())
                .build();

        // 用户1的对话
        System.out.println("=== 用户1 ===");
        String response1 = assistant.chat(1, "我叫张三");
        System.out.println(response1);

        String response2 = assistant.chat(1, "我叫什么名字?");
        System.out.println(response2);  // 你叫张三

        // 用户2的对话(完全独立)
        System.out.println("\n=== 用户2 ===");
        String response3 = assistant.chat(2, "我叫李四");
        System.out.println(response3);

        String response4 = assistant.chat(2, "我叫什么名字?");
        System.out.println(response4);  // 你叫李四

        // 用户1的记忆仍然保留
        System.out.println("\n=== 用户1(再次) ===");
        String response5 = assistant.chat(1, "我之前说我叫什么?");
        System.out.println(response5);  // 你之前说你叫张三
    }
}

结构化提示词(StructuredPrompt)

使用类组织复杂提示词

java 复制代码
import dev.langchain4j.model.input.structured.StructuredPrompt;

@StructuredPrompt({
        "为以下产品创建营销文案:",
        "",
        "产品名称: {{name}}",
        "产品类别: {{category}}",
        "目标用户: {{targetAudience}}",
        "核心卖点: {{keyFeatures}}",
        "价格: {{price}}",
        "",
        "要求:",
        "- 标题吸引人",
        "- 突出核心优势",
        "- 包含行动号召",
        "- 字数在{{wordCount}}字以内"
})
static class CreateMarketingCopy {
    private String name;
    private String category;
    private String targetAudience;
    private String keyFeatures;
    private String price;
    private int wordCount;

    // Constructor, getters, setters...
}

interface MarketingAssistant {
    String createCopy(CreateMarketingCopy prompt);
}

// 使用
CreateMarketingCopy prompt = new CreateMarketingCopy(
        "智能手表X1",
        "可穿戴设备",
        "年轻职场人士",
        "超长续航、健康监测、NFC支付",
        "¥1,299",
        200
);

MarketingAssistant assistant = AiServices.create(MarketingAssistant.class, model);
String copy = assistant.createCopy(prompt);

总结与最佳实践

AI Service 使用场景

场景 推荐方案 示例
简单对话 AiServices.create() 聊天机器人
需要记忆 Builder + chatMemory 客服系统
需要工具 Builder + tools 数据查询助手
需要 RAG Builder + contentRetriever 文档问答
多用户 @MemoryId + ChatMemoryProvider SaaS 应用

最佳实践

  1. 接口命名清晰: 使用描述性的接口和方法名

    java 复制代码
    interface CustomerSupportAgent { }  // ✅ 好
    interface Agent { }                  // ❌ 不够清晰
  2. 充分使用 @Description: 帮助模型理解字段含义

    java 复制代码
    @Description("用户的出生日期,格式:YYYY-MM-DD")
    private LocalDate birthDate;
  3. 合理设置响应格式 : 对于结构化输出,使用 json_schema 模式

    java 复制代码
    ChatLanguageModel model = OpenAiChatModel.builder()
            .responseFormat("json_schema")
            .strictJsonSchema(true)
            .build();
  4. 记忆管理: 根据场景选择合适的记忆策略

    java 复制代码
    // 按消息数量限制
    MessageWindowChatMemory.withMaxMessages(10)
    
    // 按 Token 数量限制
    TokenWindowChatMemory.withMaxTokens(1000, tokenizer)
  5. 错误处理: 添加适当的异常处理

    java 复制代码
    try {
        String response = assistant.chat(message);
        return response;
    } catch (Exception e) {
        log.error("AI服务调用失败", e);
        return "抱歉,服务暂时不可用";
    }

下一步学习

参考资料

相关推荐
好奇龙猫2 小时前
【人工智能学习-AI-MIT公开课-第5. 搜索:最优、分支限界、A**】
人工智能·学习
白日做梦Q2 小时前
预训练模型微调(Finetune)实战:策略、技巧及常见误区规避
人工智能·python·神经网络·机器学习·计算机视觉
刘宇涵492 小时前
Javalength
java
历程里程碑2 小时前
双指针巧解LeetCode接雨水难题
java·开发语言·数据结构·c++·python·flask·排序算法
阿星AI工作室2 小时前
这一年,让我人生事业开挂的13个认知
人工智能
玄同7652 小时前
Python 流程控制:LLM 批量推理与 API 限流处理
服务器·人工智能·python·深度学习·自然语言处理·数据挖掘·知识图谱
Dev7z2 小时前
基于Matlab实现GRACE卫星重力数据的全球水储量变化估算与分析
人工智能·算法·matlab
IT_陈寒2 小时前
Vue3性能优化实战:7个被低估的Composition API技巧让渲染提速40%
前端·人工智能·后端
qualifying2 小时前
JAVAEE——多线程(2)
java·开发语言