Назад в блог

API и SDKИнструкция

Первый запрос на Java через openai-java: base URL, ключ, usage

Рабочая программа на Java 8+: openai-java с адресом CheapTokens, один chat completion и вывод ответа, finish_reason и расхода токенов.

Автор: CheapTokens TeamОпубликовано 4 мин чтения

Код на Java, направляющий openai-java на API CheapTokens
Содержание
  1. Добавьте зависимость
  2. Ключ и base URL — вне кода
  3. Программа
  4. Явные значения через билдер
  5. Три ошибки, которые встретятся первыми
  6. Сколько стоит один запрос

Чтобы обратиться к CheapTokens из Java, оставьте официальный SDK openai-java и поменяйте три вещи: base URL (https://api.cheaptokens.dev/v1), ключ API и id модели, который передаётся обычной строкой String. Программа ниже отправляет один chat completion и печатает ответ, finish_reason и расход токенов. Нужна Java 8 или новее.

Если у вас уже есть сервис на Spring, который ходит в OpenAI, миграция — это всё: новый клиент и новые классы запроса не нужны.

Добавьте зависимость#

В README SDK (github.com/openai/openai-java, проверено 4 ноября 2026) указана версия 4.99.0, группа com.openai, артефакт openai-java. Дату релиза README не приводит, так что перед копированием загляните в репозиторий за свежей версией.

Подключите openai-java к сборке

Maven

xml
<dependency>
  <groupId>com.openai</groupId>
  <artifactId>openai-java</artifactId>
  <version>4.99.0</version>
</dependency>

Gradle

kotlin
implementation("com.openai:openai-java:4.99.0")

Нейтральные к фреймворкам артефакты работают на Java 8+, так что старый корпоративный JDK не помеха.

Ключ и base URL — вне кода#

SDK читает две переменные окружения: OPENAI_API_KEY и OPENAI_BASE_URL. OpenAIOkHttpClient.fromEnv() подхватывает обе, поэтому ключ не попадает в исходники. (Системные свойства openai.apiKey и openai.baseUrl тоже работают и приоритетнее переменных.)

bash
export OPENAI_API_KEY="your-cheaptokens-key"
export OPENAI_BASE_URL="https://api.cheaptokens.dev/v1"

Адрес SDK по умолчанию — https://api.openai.com/v1. Пропустите вторую строку, и запрос уйдёт туда с ключом CheapTokens, которого там не знают. Так можно получить 401 при первом запуске. Где хранить ключ и как не отдать его git, читайте в статье как безопасно хранить API-ключ.

Две переменные окружения и команда запуска в терминале
Ключ и base URL берутся из окружения, а не из исходника

Программа#

Создайте FirstRequest.java:

java
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;

public class FirstRequest {
  public static void main(String[] args) {
    OpenAIClient client = OpenAIOkHttpClient.fromEnv();

    ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
        .model("deepseek-ai/DeepSeek-V4-Flash-0731")
        .addUserMessage("Explain in two sentences what a token is.")
        .maxCompletionTokens(300L)
        .build();

    ChatCompletion completion = client.chat().completions().create(params);
    ChatCompletion.Choice choice = completion.choices().get(0);

    System.out.println(choice.message().content().orElse("(no text)"));
    System.out.println("finish_reason: " + choice.finishReason());
    completion.usage().ifPresent(u ->
        System.out.println("input " + u.promptTokens()
            + ", output " + u.completionTokens()));
  }
}

На несколько строк стоит посмотреть внимательнее.

  • .model("deepseek-ai/DeepSeek-V4-Flash-0731"). В примерах README SDK — типизированные константы вроде ChatModel.GPT_5_2, но у билдера есть и перегрузка model(String), так что подойдёт любой id. Берите полный id из документации CheapTokens: короткое deepseek-v4-flash-0731 — так подписаны цены на сайте; API ждёт полный id с префиксом deepseek-ai/. Не уверены в id? Получите список моделей через GET /v1/models.
  • .maxCompletionTokens(300L). Потолок длины ответа, тип long. DeepSeek-V4-Flash отдаёт до 32 768 токенов за ответ, так что 300 — выбор ради короткой демонстрации, а не предел модели.
  • content() — это Optional. Поэтому в программе orElse. У ответа, состоящего только из вызовов инструментов, текста нет.
  • usage() тоже Optional. ifPresent печатает его, когда сервер его прислал.

Соберите и запустите так, как это делает ваша сборка (mvn compile exec:java -Dexec.mainClass=FirstRequest или задача JavaExec в Gradle). Вы получите объяснение токена, затем строку finish_reason: … со словом stop, затем строку с числом входных и выходных токенов. Если в finish_reason стоит length, ответ упёрся в ваш лимит 300 токенов и был обрезан: увеличьте число (почему так бывает).

usage() возвращает число токенов промпта, ответа и общее (promptTokens(), completionTokens(), totalTokens()).

Явные значения через билдер#

Тестам или сервису с несколькими клиентами иногда нужны явные значения. Тот же клиент, собранный вручную:

java
OpenAIClient client = OpenAIOkHttpClient.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .baseUrl("https://api.cheaptokens.dev/v1")
    .build();

Всё после этой строки, параметры и вызов create, остаётся как выше. Ключ и здесь читайте из окружения: строка в .java-файле окажется в репозитории.

Код на Java, openai-java, адрес CheapTokens и модель
Ваш код говорит с SDK; кто ответит, решает только base URL

Три ошибки, которые встретятся первыми#

Найдите пары

Сопоставьте симптом и причину

  • 401 Unauthorizedключ пуст или неверен, либо запрос ушёл на api.openai.com, потому что OPENAI_BASE_URL не задан
  • 404 Not Foundв base URL нет /v1 или такого id модели не существует
  • finish_reason равен lengthmaxCompletionTokens меньше, чем нужно ответу

Пустую переменную окружения легко проглядеть в IDE: конфигурация запуска из панели может не наследовать переменные, которые вы экспортировали в терминале. Если ключ «задан», а 401 всё равно приходит, добавьте переменные прямо в конфигурацию запуска. Подробнее об этих кодах: ошибка 401 или 404: ключ, base URL, id модели.

Сколько стоит один запрос#

Раз вы печатаете usage, запрос можно оценить в деньгах до масштабирования. Допустим, ваш сервис отправляет около 200 входных токенов и получает 300 обратно. По сегодняшним ценам такой запрос на DeepSeek-V4-Flash стоит $0.000033. Вход и выход оплачиваются вместе, и в сумме это дешевле, чем на OpenRouter. Таблица повторяет расчёт для 1 000 запросов по нашим моделям:

Модель За запрос 1 000 запросов OpenRouter, 1 000 запросов
GLM-5.3-Flash $0.000016 $0.016 $0.0316
DeepSeek-V4-Flash $0.000033 $0.033 $0.056
MiniMax-M2.7 $0.000055 $0.055 $0.66

200 входных и 300 выходных токенов на запрос. Цены за 1M токенов актуальны и меняются вместе с нашими тарифами; столбец OpenRouter показывает справочные цены для той же нагрузки.

Теперь подставьте свой трафик. Подвиньте ползунки к числам из вашей первой напечатанной строки usage:

Калькулятор стоимости

Сервис поддержки: 2 000 запросов в день

Входные токены на запрос: 200 · Выходные токены на запрос: 300 · Запросов в день: 2 000

МодельВ деньВ месяц
GLM-5.3-Flash$0.032$0.96
DeepSeek-V4-Flash$0.066$1.98
MiniMax-M2.7$0.11$3.30

Если нужен длинный ответ или другая нагрузка: у DeepSeek-V4-Flash контекст 380K и одна цена в любое время суток; GLM-5.3-Flash (zai-org/GLM-5.3-Flash) встаёт в ту же программу вместо неё — меняете id, и всё. Актуальные цены всех моделей — на странице цен, а тот же запрос на других языках — в документации. Пишете на Go? Смотрите версию для openai-go.