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需要令牌,可在官网生成:

ChatGPT 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提供的tokenizersopenai-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获取。


原始标题:OpenAI API Client in Java | Baeldung