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);
}
}
关键优势
- 类型安全: 编译时检查,避免运行时错误
- 简洁直观: 无需手动构建消息对象
- 易于测试: 可以轻松 Mock 接口
- 声明式: 通过注解配置行为
系统消息与角色定义
使用 @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 应用 |
最佳实践
-
接口命名清晰: 使用描述性的接口和方法名
javainterface CustomerSupportAgent { } // ✅ 好 interface Agent { } // ❌ 不够清晰 -
充分使用 @Description: 帮助模型理解字段含义
java@Description("用户的出生日期,格式:YYYY-MM-DD") private LocalDate birthDate; -
合理设置响应格式 : 对于结构化输出,使用
json_schema模式javaChatLanguageModel model = OpenAiChatModel.builder() .responseFormat("json_schema") .strictJsonSchema(true) .build(); -
记忆管理: 根据场景选择合适的记忆策略
java// 按消息数量限制 MessageWindowChatMemory.withMaxMessages(10) // 按 Token 数量限制 TokenWindowChatMemory.withMaxTokens(1000, tokenizer) -
错误处理: 添加适当的异常处理
javatry { String response = assistant.chat(message); return response; } catch (Exception e) { log.error("AI服务调用失败", e); return "抱歉,服务暂时不可用"; }
下一步学习
- 05-对话记忆管理 - 深入学习记忆机制
- 06-工具与函数调用 - 扩展 AI 能力
- 07-RAG检索增强生成 - 接入外部知识库
参考资料
- 示例代码:
tutorials/src/main/java/_08_AIServiceExamples.java - 官方文档: https://docs.langchain4j.dev/tutorials/ai-services