LangChain4j 与 OpenAI 深度集成:Function Calling、JSON Mode 与结构化输出
前言
OpenAI 的 API 提供了强大的 Function Calling、JSON Mode、Assistants API 等高级特性,LangChain4j 1.4.0 通过深度集成将这些能力无缝融入 Java 生态。本文将详细介绍如何使用 LangChain4j 调用 OpenAI 的完整功能栈。
一、Function Calling 完整链路
1.1 @Tool 注解定义工具
java
import dev.langchain4j.service.tool.Tool;
public class WeatherTools {
@Tool("查询指定城市的天气预报")
public String getWeather(String city) {
// 模拟 API 调用
return city + "今天气温 25°C,晴转多云";
}
@Tool("查询股票实时价格")
public String getStockPrice(
@P("股票代码,例如:AAPL, TSLA") String symbol
) {
// 模拟 API 调用
return symbol + " 当前股价 $150.25";
}
@Tool("计算两个数的和")
public double add(double a, double b) {
return a + b;
}
}
1.2 参数自动映射
java
public class ComplexTools {
@Tool("创建订单")
public String createOrder(
@P("商品名称") String productName,
@P("数量") int quantity,
@P("收货地址") String address,
@P(value = "备注", required = false) String note
) {
return String.format(
"订单已创建:%s x %d,地址:%s,备注:%s",
productName, quantity, address, note
);
}
// 支持复杂对象
record OrderItem(String name, int quantity, double price) {}
@Tool("批量创建订单")
public String batchCreateOrder(@P("订单列表") List<OrderItem> items) {
double total = items.stream()
.mapToDouble(item -> item.quantity() * item.price())
.sum();
return String.format(
"批量订单已创建,共 %d 件商品,总金额:%.2f",
items.size(), total
);
}
}
1.3 Function Calling 流程
java
import dev.langchain4j.service.AiService;
@AiService
public interface Assistant {
String chat(String message);
}
public class FunctionCallingExample {
public static void main(String[] args) {
// 1. 创建 OpenAI 模型
OpenAiChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4")
.build();
// 2. 创建 AI Service
Assistant assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(model)
.tools(new WeatherTools(), new StockTools())
.build();
// 3. 调用
String response = assistant.chat("北京今天天气如何?");
System.out.println(response);
// 输出: "北京今天气温 25°C,晴转多云"
}
}
1.4 Function Calling 流程图
┌─────────────────────────────────────────────────────────────┐
│ Function Calling 执行流程 │
└─────────────────────────────────────────────────────────────┘
用户 AI Service OpenAI
│ │ │
│ 1. "北京天气如何?" │ │
├─────────────────────────>│ │
│ │ 2. 构建请求(包含工具Schema)│
│ ├───────────────────────────>│
│ │ { │
│ │ "tools": [ │
│ │ { │
│ │ "name": "getWeather",│
│ │ "description": "...",│
│ │ "parameters": {...} │
│ │ } │
│ │ ] │
│ │ } │
│ │ │
│ │ 3. LLM 分析需要调用工具 │
│ │<───────────────────────────┤
│ │ { │
│ │ "tool_calls": [ │
│ │ { │
│ │ "id": "call_123", │
│ │ "function": { │
│ │ "name": "getWeather",│
│ │ "arguments": "{\"city\":\"北京\"}"│
│ │ } │
│ │ } │
│ │ ] │
│ │ } │
│ │ │
│ │ 4. 执行工具 getWeather("北京") │
│ │<───────────────────────────┤
│ │ │
│ │ 5. 返回工具执行结果 │
│ ├───────────────────────────>│
│ │ { │
│ │ "tool_call_id": "call_123",│
│ │ "role": "tool", │
│ │ "content": "北京今天25°C"│
│ │ } │
│ │ │
│ │ 6. LLM 基于工具结果生成最终回答 │
│ │<───────────────────────────┤
│ 7. "北京今天气温 25°C" │ │
│<─────────────────────────┤ │
│ │ │
└──────────────────────────┴───────────────────────────┘
1.5 并行工具执行(1.4.0 新特性)
java
@AiService
public interface ConcurrentAssistant {
@UserMessage("同时查询{{city1}}和{{city2}}的天气")
String queryWeather(
@P("城市1") String city1,
@P("城市2") String city2
);
}
// LangChain4j 1.4.0 会并发调用两次 getWeather
String response = assistant.queryWeather("北京", "上海");
// AI 会同时发送两个工具调用请求,提高效率
二、JSON Mode 强制输出
2.1 启用 JSON Mode
java
OpenAiChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o")
.responseFormat("json_object") // 强制 JSON 输出
.build();
String jsonResponse = model.generate("请返回一个用户对象,包含 name 和 age");
// 输出: {"name": "张三", "age": 25}
2.2 JSON Schema 验证
java
import dev.langchain4j.model.output.structured.Description;
public class User {
private String name;
@Description("用户年龄,范围 0-120")
private int age;
@Description("用户邮箱,必须包含 @")
private String email;
// getters and setters
}
@AiService
public interface JsonAssistant {
User extractUser(String text);
}
// 使用
User user = assistant.extractUser("我叫张三,25岁,邮箱是zhangsan@example.com");
// 自动验证 Schema
2.3 结构化数据提取
java
public class NewsExtractor {
public record News(
String title,
String summary,
String author,
LocalDateTime publishTime,
List<String> tags
) {}
@AiService
public interface NewsAssistant {
@UserMessage("从以下文本中提取新闻信息:\n{{it}}")
News extractNews(String text);
}
// 使用
String text = """
北京时间 2024-08-28 10:00,科技日报报道,
LangChain4j 1.4.0 正式发布,带来了 Agentic 增强、
MCP 流式传输等新特性。作者:张三。
标签:AI、Java、开源
""";
News news = assistant.extractNews(text);
// news.title() == "LangChain4j 1.4.0 正式发布"
// news.author() == "张三"
// news.tags() == ["AI", "Java", "开源"]
}
2.4 JSON Mode 流程图
┌─────────────────────────────────────────────────────────────┐
│ JSON Mode 执行流程 │
└─────────────────────────────────────────────────────────────┘
┌─────────┐ ┌──────────────┐ ┌─────────────┐ ┌───────┐
│ 用户 │ -> │ @AiService │ -> │ OpenAI │ -> │ LLM │
│ 输入文本 │ -> │ 接口代理 │ -> │ API │ -> │ gpt-4 │
└─────────┘ └──────────────┘ └─────────────┘ └───────┘
│ │ │ │
│ 1. 调用方法 │ 2. 构建 JSON │ 3. 发送请求 │ 4. 返回
│ extractUser() │ Schema 提示 │ responseFormat │ JSON
│ │ │: "json_object"│
└────────────────┴──────────────────┴───────────────┘
│
5. JSON 解析
6. 映射到 POJO
7. 返回给用户
JSON Mode 优势:
- 强制 JSON 输出,无需额外解析
- 支持 JSON Schema 验证
- 自动处理复杂嵌套结构
三、Assistants API 支持
3.1 创建 Assistant
java
import dev.langchain4j.model.openai.assistant.*;
// 1. 创建 Assistant
Assistant assistant = OpenAiAssistant.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.description("客服助手,回答产品相关问题")
.instructions("你是一个友好的客服助手,用简洁的语言回答问题")
.model(OpenAiChatModelName.GPT_4O)
.tools(new CustomerServiceTools()) // 注册工具
.build();
// 2. 创建 Thread
Thread thread = assistant.createThread();
// 3. 添加消息
thread.addUserMessage("我想了解产品价格");
// 4. 运行 Assistant
Run run = thread.run();
// 5. 等待完成
Run completedRun = run.awaitCompletion();
// 6. 获取响应
List<AssistantMessage> messages = thread.messages();
String response = messages.get(messages.size() - 1).text();
3.2 文件操作
java
// 上传文件
File file = new File("product_manual.pdf");
FileId fileId = assistant.uploadFile(file);
// 创建带文件的 Assistant
Assistant fileAssistant = OpenAiAssistant.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.instructions("基于上传的文件回答问题")
.files(fileId)
.build();
// 使用文件
Thread thread = fileAssistant.createThread();
thread.addUserMessage("产品手册中提到哪些功能?");
thread.run().awaitCompletion();
3.3 多轮对话管理
java
// 创建 Thread
Thread thread = assistant.createThread();
// 多轮对话
thread.addUserMessage("什么是 LangChain4j?");
thread.run().awaitCompletion();
System.out.println(thread.lastMessage().text());
thread.addUserMessage("它支持哪些模型?");
thread.run().awaitCompletion();
System.out.println(thread.lastMessage().text());
thread.addUserMessage("如何快速开始?");
thread.run().awaitCompletion();
System.out.println(thread.lastMessage().text());
// Thread 自动管理历史消息
四、图像输入
4.1 单图输入
java
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiChatModelName;
// 创建支持视觉的模型
ChatLanguageModel visionModel = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(OpenAiChatModelName.GPT_4O)
.build();
// 图文混合输入
UserMessage message = UserMessage.from(
ImageContent.from("https://example.com/screenshot.png"),
TextContent.from("请解释这张截图中的错误信息")
);
String response = visionModel.generate(message);
4.2 多图对比
java
UserMessage comparison = UserMessage.from(
TextContent.from("对比这两张图片的差异:"),
ImageContent.from("https://example.com/before.png"),
ImageContent.from("https://example.com/after.png")
);
String diff = visionModel.generate(comparison);
4.3 Base64 图像
java
// 从文件读取
byte[] imageBytes = Files.readAllBytes(Paths.get("diagram.png"));
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
UserMessage message = UserMessage.from(
ImageContent.from("data:image/png;base64," + base64Image),
TextContent.from("请分析这个架构图")
);
String analysis = visionModel.generate(message);
4.4 图像处理流程图
┌─────────────────────────────────────────────────────────────┐
│ 图像处理流程 │
└─────────────────────────────────────────────────────────────┘
┌─────────┐ ┌──────────────┐ ┌─────────────┐ ┌───────┐
│ 图像源 │ -> │ ImageContent │ -> │ UserMessage │ -> │ GPT-4 │
│ URL/ │ -> │ 创建 │ -> │ 构建图文 │ -> │ Vision │
│ Base64 │ -> │ │ -> │ 混合消息 │ -> │ API │
└─────────┘ └──────────────┘ └─────────────┘ └───────┘
│ │ │ │
│ 1. 加载图像 │ 2. 创建 │ 3. 构建消息 │ 4. 视觉
│ ImageContent UserMessage │ 理解
└────────────────┴──────────────────┴───────────────┘
│
5. 返回文字描述
6. 分析图像内容
支持的操作:
- 图像描述(Image Captioning)
- OCR 文字识别
- 图表分析
- 代码截图解释
- 图像对比
五、完整实战示例
5.1 智能客服系统
java
@AiService
public interface CustomerServiceAssistant {
// 查询订单
@Tool("查询订单状态")
String queryOrder(@P("订单号") String orderId);
// 退换货
@Tool("处理退换货请求")
String processReturn(
@P("订单号") String orderId,
@P("退换货原因") String reason
);
// 聊天
String chat(@UserMessage String message);
}
public class CustomerServiceSystem {
private final CustomerServiceAssistant assistant;
public CustomerServiceSystem() {
OpenAiChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o")
.responseFormat("json_object") // JSON Mode
.build();
this.assistant = AiServices.builder(CustomerServiceAssistant.class)
.chatLanguageModel(model)
.tools(new OrderTools(), new ReturnTools())
.build();
}
public String handleCustomerRequest(String message) {
return assistant.chat(message);
}
}
// 使用
CustomerServiceSystem system = new CustomerServiceSystem();
// 场景 1:查询订单
String response1 = system.handleCustomerRequest("查询订单号 123456");
// AI 会自动调用 queryOrder("123456")
// 场景 2:退换货
String response2 = system.handleCustomerRequest(
"我要退货,订单号 123456,原因是商品有瑕疵"
);
// AI 会自动调用 processReturn("123456", "商品有瑕疵")
// 场景 3:普通聊天
String response3 = system.handleCustomerRequest("你们的工作时间是什么?");
// AI 直接回答
六、常见问题
Q1: Function Calling 失败怎么办?
A: 检查以下几点:
java
// 1. 确保 @Tool 注解描述清晰
@Tool("查询天气,参数为城市名称(中文或英文)")
String getWeather(String city);
// 2. 使用 @P 注解描述参数
@Tool("创建订单")
String createOrder(
@P("商品名称,必填") String productName,
@P("数量,必填,正整数") int quantity
);
// 3. 检查模型是否支持工具调用
OpenAiChatModel.builder()
.modelName("gpt-4") // gpt-4 和 gpt-3.5-turbo 支持
.build();
Q2: JSON Mode 返回非 JSON 怎么办?
A: LangChain4j 会自动重试,也可以手动修复:
java
AiServices.builder(Assistant.class)
.chatLanguageModel(model)
.jsonRepairStrategy(JsonRepairStrategy.AUTO_FIX)
.build();
Q3: 如何处理图像中的文字识别?
A: 使用 GPT-4 Vision 的 OCR 能力:
java
UserMessage message = UserMessage.from(
ImageContent.from("screenshot.png"),
TextContent.from("请识别图片中的所有文字")
);
String text = visionModel.generate(message);
七、小结
本文深入介绍了 LangChain4j 与 OpenAI 的深度集成,包括:
- Function Calling:@Tool 注解、参数映射、并行执行
- JSON Mode:强制 JSON 输出、Schema 验证、结构化数据提取
- Assistants API:创建 Assistant、Thread 管理、文件操作
- 图像输入:单图/多图输入、Base64 编码、视觉理解
- 完整实战:智能客服系统集成
核心思想: 通过 LangChain4j 的抽象层,无缝使用 OpenAI 的所有高级特性。
下一步学习:
- 文章 6:《LangChain4j 本地模型与 Ollama:私有化部署的零成本方案》
参考文献:
- LangChain4j 官方文档:https://docs.langchain4j.dev/integrations/language-models/open-ai/
- OpenAI API 文档:https://platform.openai.com/docs/api-reference/chat
- OpenAI Assistants API:https://platform.openai.com/docs/assistants/overview