1. 概述
随着生成式AI(尤其是ChatGPT)的普及,许多语言都开始提供与OpenAI API交互的库。Java也不例外。本文将介绍*openai-java*——一个简化OpenAI API通信的客户端库。由于完整覆盖整个库不现实,我们将通过构建一个连接ChatGPT的控制台工具来演示核心功能。
2. 依赖配置
首先需要导入项目依赖。这些库可在Maven仓库中找到:三个模块分别处理不同交互场景:
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>service</artifactId>
<version>0.18.2</version>
</dependency>
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>api</artifactId>
<version>0.18.2</version>
</dependency>
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>client</artifactId>
<version>0.18.2</version>
</dependency>
⚠️ 注意:虽然名称包含GPT3,但同样支持GPT4。
3. Baeldung学习助手
我们将构建一个工具,基于Baeldung平台的文章生成学习路径。互联网资源虽丰富,但信息筛选却日益困难——本工具通过ChatGPT在Baeldung文章海洋中导航,解决学习路径规划问题。
4. OpenAI API令牌
连接OpenAI API需要令牌,可在官网生成:
务必保护令牌安全。openai-java示例使用环境变量存储——生产环境需更安全方案,但小型实验足够。
开发时可通过IDE配置环境变量(如IntelliJ IDEA的配置方式)。令牌分两类:
- 个人令牌:直接使用
- 服务账户令牌:用于机器人/应用连接OpenAI项目
本例使用个人令牌即可。
5. OpenAiService核心类
OpenAiService是API入口点,通过其实例与ChatGPT交互。创建时需传入令牌:
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
5.1. 构建请求对象
使用ChatCompletionRequest创建请求,最小配置仅需消息和模型:
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest
.builder()
.model(GPT_3_5_TURBO_0301.getName())
.messages(messages)
.build();
逐步解析关键参数:
5.2. 模型选择
**模型选择直接影响效果和成本**,需合理权衡:
- 简单任务(如文本清理)无需高级模型
- 复杂任务需更强能力模型
推荐使用ModelEnum而非硬编码名称:
@Getter
@AllArgsConstructor
public enum ModelEnum {
GPT_3_5_TURBO("gpt-3.5-turbo"),
GPT_3_5_TURBO_0301("gpt-3.5-turbo-0301"),
GPT_4("gpt-4"),
GPT_4_0314("gpt-4-0314"),
GPT_4_32K("gpt-4-32k"),
GPT_4_32K_0314("gpt-4-32k-0314"),
GPT_4_1106_preview("gpt-4-1106-preview");
private String name;
}
✅ 虽未包含所有模型,但足够使用。未列出的模型可通过String名称指定。
5.3. 消息处理
消息通过ChatMessage类构建,需指定角色和内容:
List<ChatMessage> messages = new ArrayList<>();
ChatMessage systemMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), PROMPT);
messages.add(systemMessage);
核心机制:
- 发送的是消息集合(类似邮件线程而非单条消息)
- 通过追加消息维护对话上下文
- 本质是无状态服务,需显式传递历史消息
替代方案:使用助手API存储消息线程,避免重复传输历史。
5.4. 角色定义
角色是ChatGPT理解上下文的关键,用于标识消息来源。ChatMessages支持四种角色:
public enum ChatMessageRole {
SYSTEM("system"),
USER("user"),
ASSISTANT("assistant"),
FUNCTION("function");
private final String value;
ChatMessageRole(final String value) {
this.value = value;
}
public String value() {
return value;
}
}
角色含义:
SYSTEM
:初始上下文/提示词USER
:用户消息ASSISTANT
:ChatGPT回复FUNCTION
:可调用函数标识
5.5. 令牌管理
此处"令牌"指文本处理单元(非API访问令牌),用于:
- 限制输入/输出信息量
- 控制成本
通过maxTokens
约束响应长度:
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest
.builder()
.model(MODEL)
.maxTokens(MAX_TOKENS)
.messages(messages)
.build();
⚠️ 默认值可能产生超长响应导致费用激增,建议显式配置。响应后可统计消耗:
long usedTokens = result.getUsage().getTotalTokens();
System.out.println("Total tokens used: " + usedTokens);
5.6. 令牌化处理
为预估请求大小,可使用OpenAI提供的tokenizers。openai-java封装了TikTokensUtil,通过模型名和消息计算令牌数。
5.7. 多选项控制
通过n()
方法控制单次请求返回的响应数量(默认1):
ChatCompletionRequest request = ChatCompletionRequest
.builder()
.n(2) // 返回两个候选响应
// ...其他配置
.build();
⚠️ 所有选项的令牌消耗均会计费。
5.8. 随机性与偏见控制
通过以下参数调整输出:
logitBias()
:增加/减少特定令牌出现概率(非绝对控制)topP()
和temperature()
:控制响应随机性
本例保持默认值即可。
6. 学习路径生成实战
完整实现代码:
public static void main(String[] args) {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
List<ChatMessage> messages = new ArrayList<>();
ChatMessage systemMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), PROMPT);
messages.add(systemMessage);
System.out.print(GREETING);
Scanner scanner = new Scanner(System.in);
ChatMessage firstMsg = new ChatMessage(ChatMessageRole.USER.value(), scanner.nextLine());
messages.add(firstMsg);
while (true) {
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest
.builder()
.model(GPT_3_5_TURBO_0301.getName())
.messages(messages)
.build();
ChatCompletionResult result = service.createChatCompletion(chatCompletionRequest);
long usedTokens = result.getUsage().getTotalTokens();
ChatMessage response = result.getChoices().get(0).getMessage();
messages.add(response);
System.out.println(response.getContent());
System.out.println("Total tokens used: " + usedTokens);
System.out.print("Anything else?\n");
String nextLine = scanner.nextLine();
if (nextLine.equalsIgnoreCase("exit")) {
System.exit(0);
}
messages.add(new ChatMessage(ChatMessageRole.USER.value(), nextLine));
}
}
运行示例交互:
Hello!
What do you want to learn?
输入学习主题:
$ I would like to learn about binary trees.
工具返回学习路径:
Great! Here's a suggested order for Baeldung's articles on binary trees:
1. Introduction to Binary Trees: https://www.baeldung.com/java-binary-tree-intro
2. Implementing a Binary Tree in Java: https://www.baeldung.com/java-binary-tree
3. Depth First Traversal of Binary Tree: https://www.baeldung.com/java-depth-first-binary-tree-traversal
4. Breadth First Traversal of Binary Tree: https://www.baeldung.com/java-breadth-first-binary-tree-traversal
5. Finding the Maximum Element in a Binary Tree: https://www.baeldung.com/java-binary-tree-maximum-element
6. Binary Search Trees in Java: https://www.baeldung.com/java-binary-search-tree
7. Deleting from a Binary Search Tree: https://www.baeldung.com/java-binary-search-tree-delete
I hope this helps you out!
Total tokens used: 288
Anything else?
踩坑提醒:返回结果中仅1篇文章真实存在,其余为AI生成的虚构链接。这揭示了生成式AI的核心局限——难以验证信息真实性。作为开发者,需始终对AI输出保持审慎,关键信息必须人工复核。
7. 总结
AI工具极大提升了应用开发效率,从邮件处理到教育优化均有应用。Java提供多种方式接入OpenAI API,openai-java是其中优秀选择。
但需谨记:生成式模型虽表现强大,本质是概率预测而非事实验证。开发者应:
- 对关键信息进行二次验证
- 为模型提供充足上下文以提升可靠性
本文完整代码可在GitHub获取。