Langchain4J 实战教程(三):AI Services 核心详解
2025-05-10·4 分钟阅读
Langchain4J 实战教程(三):AI Services 核心详解
前言
AI Services 是 Langchain4J 最核心、最强大的特性。它采用声明式编程范式,让开发者只需定义接口,框架自动处理 LLM 调用的所有细节。本章将深入探索 AI Services 的工作原理和高级用法,助你构建更智能的 AI 应用。
AI Services 概述
核心理念
┌─────────────────────────────────────────────────────────────┐
│ AI Services 核心理念 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 传统方式:命令式编程 │
│ ───────────────────── │
│ • 手动构建消息 │
│ • 手动调用模型 │
│ • 手动解析响应 │
│ • 手动管理记忆 │
│ • 代码量大,容易出错 │
│ │
│ AI Services:声明式编程 │
│ ───────────────────── │
│ • 定义接口 + 注解 │
│ • 框架自动实现 │
│ • 自动处理所有细节 │
│ • 代码简洁,类型安全 │
│ │
│ 接口定义 ──→ 框架实现 ──→ 直接使用 │
│ │
└─────────────────────────────────────────────────────────────┘
工作原理
┌─────────────────────────────────────────────────────────────────┐
│ AI Services 工作原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 用户代码 Langchain4J 框架 │
│ ──────── ──────────────── │
│ │
│ Assistant assistant = ┌─────────────────────┐ │
│ AiServices.builder( │ 动态代理生成 │ │
│ Assistant.class │ (Proxy) │ │
│ ) └──────────┬──────────┘ │
│ .chatLanguageModel(model) │ │
│ .build(); ┌──────────▼──────────┐ │
│ │ 解析注解 │ │
│ assistant.chat("Hello"); │ @SystemMessage │ │
│ │ │ @UserMessage │ │
│ │ │ @Tool │ │
│ │ └──────────┬──────────┘ │
│ │ ┌──────────▼──────────┐ │
│ │ │ 构建提示词 │ │
│ │ │ + 系统消息 │ │
│ │ │ + 用户消息 │ │
│ │ │ + 历史记忆 │ │
│ │ │ + 工具描述 │ │
│ │ └──────────┬──────────┘ │
│ │ ┌──────────▼──────────┐ │
│ └────────────────────►│ 调用 LLM │ │
│ │ │ │
│ └──────────┬──────────┘ │
│ ┌──────────▼──────────┐ │
│ │ 解析响应 │ │
│ │ + 工具调用处理 │ │
│ │ + 类型转换 │ │
│ └──────────┬──────────┘ │
│ ┌──────────▼──────────┐ │
│ String response = ◄─────────────────────── 返回结果 │
│ │
└─────────────────────────────────────────────────────────────────┘
基础用法
简单接口
interface SimpleAssistant {
String chat(String message);
}
// 使用
SimpleAssistant assistant = AiServices.builder(SimpleAssistant.class)
.chatLanguageModel(chatModel)
.build();
String response = assistant.chat("Hello!");
系统消息注解
使用 @SystemMessage 定义 AI 的角色和行为:
interface ProfessionalAssistant {
@SystemMessage("""
你是一个专业的技术顾问,具有以下特点:
1. 回答简洁明了,避免冗余
2. 提供具体的代码示例
3. 必要时给出最佳实践建议
4. 如果不确定,诚实告知
""")
String chat(String message);
}
用户消息注解
使用 @UserMessage 定义用户消息模板:
interface TemplateAssistant {
@UserMessage("""
请解释以下技术概念:{{concept}}
要求:
1. 给出简单定义
2. 说明应用场景
3. 提供代码示例
""")
String explain(@V("concept") String concept);
}
// 使用
String response = assistant.explain("Java Stream API");
方法参数注解
interface AdvancedAssistant {
String chat(
@MemoryId String conversationId,
@UserMessage String message
);
@UserMessage("翻译以下{{sourceLang}}文本为{{targetLang}}:{{text}}")
String translate(
@V("sourceLang") String sourceLang,
@V("targetLang") String targetLang,
@V("text") String text
);
}
高级注解
@SystemMessage 高级用法
interface SystemMessageAssistant {
// 从资源文件加载系统消息
@SystemMessage(fromResource = "/prompts/system-prompt.txt")
String chat(String message);
// 动态系统消息
@SystemMessage("你是一个{{role}},请用{{style}}的风格回答")
String chatWithRole(
@V("role") String role,
@V("style") String style,
@UserMessage String message
);
}
/prompts/system-prompt.txt:
你是一个经验丰富的软件架构师。
你的职责是帮助开发者解决技术难题,提供架构建议。
回答时请:
1. 先分析问题的核心
2. 给出多种解决方案
3. 推荐最佳方案并说明理由
@UserMessage 模板功能
interface UserMessageAssistant {
// 基础模板
@UserMessage("分析以下代码的问题:{{code}}")
String analyzeCode(@V("code") String code);
// 复杂模板
@UserMessage("""
任务:{{task}}
输入数据:
{{input}}
输出要求:
- 格式:{{format}}
- 语言:{{language}}
""")
String process(
@V("task") String task,
@V("input") String input,
@V("format") String format,
@V("language") String language
);
// 使用资源文件
@UserMessage(fromResource = "/prompts/analyze-prompt.txt")
String analyze(@V("content") String content);
}
@Moderation 内容审核
interface SafeAssistant {
@Moderate // 自动审核用户输入是否合规
String chat(String message);
}
// 自定义审核模型
SafeAssistant assistant = AiServices.builder(SafeAssistant.class)
.chatLanguageModel(chatModel)
.moderationModel(OpenAiModerationModel.withApiKey(apiKey))
.build();
返回类型
字符串返回
interface StringAssistant {
String chat(String message);
}
结构化输出
interface StructuredAssistant {
record PersonInfo(
String name,
int age,
List<String> skills,
String email
) {}
// 返回 Java 对象
PersonInfo extractPerson(@UserMessage String text);
// 返回列表
List<String> extractKeywords(@UserMessage String text);
// 返回枚举
enum Sentiment { POSITIVE, NEGATIVE, NEUTRAL }
Sentiment analyzeSentiment(@UserMessage String text);
}
流式返回
interface StreamingAssistant {
// 返回 TokenStream
TokenStream chatStream(String message);
// 返回 CompletableFuture(适合异步场景)
@UserMessage("生成一篇关于{{topic}}的文章")
CompletableFuture<String> generateArticle(@V("topic") String topic);
}
// 使用
TokenStream stream = assistant.chatStream("Hello");
stream.onNext(token -> System.out.print(token))
.onComplete(response -> System.out.println("\n完成!"))
.onError(Throwable::printStackTrace)
.start();
结果包装
interface ResponseAssistant {
// 返回 Response 包装,包含元数据
Response<AiMessage> chatWithMetadata(String message);
// 使用
Response<AiMessage> response = assistant.chatWithMetadata("Hello");
String content = response.content().text();
TokenUsage tokens = response.tokenUsage(); // Token 使用量
FinishReason finishReason = response.finishReason(); // 结束原因
}
Chat Memory 集成
单一会话记忆
interface MemoryAssistant {
String chat(@MemoryId String conversationId, String message);
}
// 为每个对话提供独立的记忆
MemoryAssistant assistant = AiServices.builder(MemoryAssistant.class)
.chatLanguageModel(chatModel)
.chatMemoryProvider(id -> MessageWindowChatMemory.withMaxMessages(10))
.build();
// 不同用户有独立的对话历史
assistant.chat("user-1", "我叫张三");
assistant.chat("user-2", "我叫李四");
assistant.chat("user-1", "我叫什么?"); // AI 知道是张三
assistant.chat("user-2", "我叫什么?"); // AI 知道是李四
记忆策略选择
// 消息窗口记忆 - 保留最近 N 条消息
ChatMemory windowMemory = MessageWindowChatMemory.withMaxMessages(20);
// Token 窗口记忆 - 保留最近 N 个 Token
ChatMemory tokenMemory = TokenWindowChatMemory.withMaxTokens(4000);
// 持久化记忆
ChatMemoryStore store = new PersistentChatMemoryStore();
ChatMemory persistentMemory = PersistentChatMemory.builder()
.storeId("conversation-123")
.store(store)
.maxMessages(50)
.build();
记忆提供者配置
MemoryAssistant assistant = AiServices.builder(MemoryAssistant.class)
.chatLanguageModel(chatModel)
// 方式1:使用提供者函数(推荐)
.chatMemoryProvider(id -> MessageWindowChatMemory.withMaxMessages(10))
// 方式2:使用单一记忆实例
// .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();
Tools 集成
定义工具
class WeatherTools {
private final WeatherService weatherService;
public WeatherTools(WeatherService weatherService) {
this.weatherService = weatherService;
}
@Tool("获取指定城市的当前天气信息")
public String getCurrentWeather(
@P("城市名称,如:北京、上海") String city,
@P(value = "温度单位", required = false) String unit
) {
return weatherService.fetchWeather(city, unit);
}
@Tool("获取未来几天的天气预报")
public String getWeatherForecast(
@P("城市名称") String city,
@P("预报天数,1-7") int days
) {
return weatherService.fetchForecast(city, days);
}
}
集成工具
interface SmartAssistant {
@SystemMessage("""
你是一个智能助手。
当用户询问天气相关问题时,使用天气工具获取实时数据。
用自然语言回答用户问题。
""")
String chat(@UserMessage String message);
}
SmartAssistant assistant = AiServices.builder(SmartAssistant.class)
.chatLanguageModel(chatModel)
.tools(new WeatherTools(weatherService))
.build();
// 使用 - AI 会自动判断何时调用工具
String response = assistant.chat("北京今天天气怎么样?");
// AI 会自动调用 getCurrentWeather("北京", null) 获取数据
工具执行配置
SmartAssistant assistant = AiServices.builder(SmartAssistant.class)
.chatLanguageModel(chatModel)
.tools(new WeatherTools(weatherService))
// 配置工具执行器
.toolExecutor((toolName, args) -> {
log.info("执行工具: {} with args: {}", toolName, args);
// 自定义执行逻辑
return executeTool(toolName, args);
})
// 配置最大工具调用次数(防止循环)
.maxSequentialToolsInvocations(10)
.build();
RAG 集成
内容检索器
interface RAGAssistant {
@SystemMessage("""
你是一个知识库助手。
基于提供的知识库内容回答问题。
如果知识库中没有相关信息,请诚实告知。
""")
String chat(@UserMessage String question);
}
// 创建内容检索器
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(5) // 返回最多 5 个相关文档
.minScore(0.7) // 最低相似度分数
.build();
RAGAssistant assistant = AiServices.builder(RAGAssistant.class)
.chatLanguageModel(chatModel)
.contentRetriever(retriever)
.build();
增强器(Augmentor)
// 自定义 RAG 增强器
class CustomAugmentor implements Augmentor {
@Override
public AugmentedMessage augment(UserMessage userMessage) {
// 1. 检索相关内容
List<Content> contents = retrieveRelevantContent(userMessage);
// 2. 构建增强消息
return AugmentedMessage.builder()
.userMessage(userMessage)
.contents(contents)
.build();
}
}
RAGAssistant assistant = AiServices.builder(RAGAssistant.class)
.chatLanguageModel(chatModel)
.augmentor(new CustomAugmentor())
.build();
完整示例
智能客服机器人
// 1. 定义接口
interface CustomerServiceBot {
@SystemMessage("""
你是电商平台的客服机器人。
职责:
1. 解答商品相关问题
2. 处理订单查询(使用订单工具)
3. 处理物流查询(使用物流工具)
4. 处理退换货咨询
规则:
- 友好、专业的态度
- 无法处理的问题建议转人工客服
""")
String chat(@MemoryId String sessionId, @UserMessage String message);
}
// 2. 定义工具
class ServiceTools {
private final OrderService orderService;
private final LogisticsService logisticsService;
private final ProductService productService;
@Tool("查询订单状态和详情")
public String queryOrder(@P("订单号") String orderId) {
Order order = orderService.getOrder(orderId);
return formatOrderInfo(order);
}
@Tool("查询物流信息")
public String queryLogistics(@P("运单号") String trackingNumber) {
LogisticsInfo info = logisticsService.track(trackingNumber);
return formatLogisticsInfo(info);
}
@Tool("查询商品信息")
public String queryProduct(@P("商品名称或关键词") String keyword) {
List<Product> products = productService.search(keyword);
return formatProducts(products);
}
@Tool("创建退货申请")
public String createReturnRequest(
@P("订单号") String orderId,
@P("退货原因") String reason
) {
ReturnRequest request = orderService.createReturn(orderId, reason);
return "退货申请已创建,退货单号:" + request.getId();
}
}
// 3. 配置服务
@Configuration
public class BotConfig {
@Bean
public CustomerServiceBot customerServiceBot(
ChatLanguageModel chatModel,
OrderService orderService,
LogisticsService logisticsService,
ProductService productService) {
return AiServices.builder(CustomerServiceBot.class)
.chatLanguageModel(chatModel)
.chatMemoryProvider(id -> MessageWindowChatMemory.withMaxMessages(20))
.tools(new ServiceTools(orderService, logisticsService, productService))
.build();
}
}
// 4. 使用
@Service
public class CustomerService {
private final CustomerServiceBot bot;
public String handleMessage(String sessionId, String message) {
return bot.chat(sessionId, message);
}
}
测试用例
@SpringBootTest
class CustomerServiceBotTest {
@Autowired
private CustomerServiceBot bot;
@Test
void testOrderQuery() {
String response = bot.chat("session-1", "帮我查一下订单 ORD123456");
assertNotNull(response);
assertTrue(response.contains("订单") || response.contains("ORD123456"));
}
@Test
void testMemory() {
bot.chat("session-2", "我叫张三");
String response = bot.chat("session-2", "我叫什么?");
assertTrue(response.contains("张三"));
}
}
调试技巧
启用日志
<!-- logback.xml -->
<logger name="dev.langchain4j" level="DEBUG"/>
<logger name="dev.langchain4j.service" level="TRACE"/>
使用监听器
CustomerServiceBot bot = AiServices.builder(CustomerServiceBot.class)
.chatLanguageModel(chatModel)
.tools(new ServiceTools())
.listeners(new ChatMemoryListener() {
@Override
public void onMessageAdded(ChatMessage message) {
log.debug("Message added: {}", message);
}
})
.build();
查看生成的提示词
// 使用 debug 模式查看构建的完整提示词
AiServices.builder(Assistant.class)
.chatLanguageModel(chatModel)
.build();
// 日志会显示发送给 LLM 的完整消息
小结
本章我们学习了:
- AI Services 核心理念:声明式接口定义,框架自动实现
- 工作原理:动态代理、注解解析、提示词构建
- 高级注解:@SystemMessage、@UserMessage、@Moderation
- 返回类型:字符串、结构化输出、流式响应
- Chat Memory:单一会话、多会话、持久化记忆
- Tools 集成:定义工具、自动调用、执行配置
- RAG 集成:内容检索器、增强器
练习
- 创建一个支持多语言的翻译助手
- 实现一个带天气查询功能的对话机器人
- 构建一个知识库问答系统
参考资料
下一章预告
在下一章《模型集成》中,我们将深入探索:
- OpenAI 模型的高级配置
- Anthropic Claude 模型集成
- Google Gemini 模型集成
- 国内大模型集成
- 本地模型 Ollama 集成
- 模型选择最佳实践
敬请期待!
教程系列持续更新中,欢迎关注!
相关文章
Langchain4J 实战教程(九):可观测性与生产部署
2025-07-06·4 分钟阅读
深入掌握 Langchain4J 应用的可观测性建设、性能优化、安全实践及生产环境部署策略,构建企业级 AI 应用。
Langchain4J 实战教程(八):Tools 与 Agent 开发
2025-06-23·4 分钟阅读
深入掌握 Function Calling 和 Agent 开发的核心技术,学习工具定义、多工具协作及复杂 Agent 系统的设计与实现。
Langchain4J 实战教程(七):RAG 检索增强生成
2025-06-11·4 分钟阅读
深入掌握 RAG 检索增强生成的核心技术,学习文档处理、向量嵌入、相似度检索及完整 RAG 系统的实现方法。