openai-api-rs для Rust: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

openai-api-rs для Rust: полное руководство с примерами

Библиотека openai-api-rs — это современный, асинхронный и типобезопасный клиент для OpenAI API, написанный на языке Rust. Она предоставляет разработчикам удобный интерфейс для взаимодействия с моделями GPT (включая GPT-4, GPT-3.5), DALL-E (генерация изображений), Whisper (распознавание речи), а также для работы с эмбеддингами, модерацией контента и управлением файлами. Библиотека полностью поддерживает потоковую передачу (streaming) ответов, что критически важно для создания интерактивных чат-приложений и ассистентов с низкой задержкой.

Зачем использовать Rust для работы с OpenAI API? Rust обеспечивает высочайшую производительность и безопасность памяти без сборщика мусора. Это делает openai-api-rs идеальным выбором для высоконагруженных серверных приложений, ботов для Telegram/Discord, систем обработки естественного языка в реальном времени и встраиваемых устройств. Благодаря строгой системе типов Rust, многие ошибки (например, неправильный формат запроса) отлавливаются на этапе компиляции, а не в рантайме. Библиотека построена на базе reqwest и tokio, что гарантирует эффективную работу с асинхронными операциями ввода-вывода.

На образовательном сайте PythonLib мы рассматриваем эту библиотеку, чтобы показать, как экосистема Rust может быть использована для задач машинного обучения и NLP. Даже если вы пишете на Python, понимание Rust-клиентов поможет вам лучше осознать внутреннее устройство API-запросов и принципы обработки потоковых данных. Библиотека активно поддерживается сообществом, имеет подробную документацию и покрыта тестами.

Установка

Для установки библиотеки openai-api-rs в ваш проект на Rust, выполните команду в терминале в корневой директории проекта:

cargo add openai-api-rs

Эта команда добавит последнюю версию библиотеки в файл Cargo.toml. Если вы предпочитаете ручное редактирование, добавьте следующую строку в раздел [dependencies]:

[dependencies]
openai-api-rs = "0.2"  # Проверьте актуальную версию на crates.io

Также вам понадобится асинхронный рантайм. Рекомендуется использовать tokio:

cargo add tokio --features full

Не забудьте установить переменную окружения OPENAI_API_KEY с вашим ключом API от OpenAI. Это можно сделать в терминале:

export OPENAI_API_KEY="sk-ваш_ключ_здесь"

Или передавать ключ напрямую в код (не рекомендуется для продакшена).

Быстрый старт

Минимальный рабочий пример: отправка простого запроса к модели GPT-3.5 и вывод ответа в консоль.

use openai_api_rs::v1::api::Client;
use openai_api_rs::v1::chat_completion::{ChatCompletionRequest, Message};
use std::env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Создаем клиент, используя API ключ из переменной окружения
    let client = Client::new(env::var("OPENAI_API_KEY")?);

    // Формируем запрос
    let request = ChatCompletionRequest::new(
        "gpt-3.5-turbo".to_string(),
        vec![Message {
            role: "user".to_string(),
            content: "Напиши короткое стихотворение о Rust".to_string(),
        }],
    );

    // Отправляем запрос и получаем ответ
    let response = client.chat_completion(request).await?;

    // Извлекаем текст ответа
    if let Some(choice) = response.choices.first() {
        println!("Ответ: {}", choice.message.content);
    }

    Ok(())
}

Запустите программу командой cargo run. Вы должны увидеть сгенерированное стихотворение. Этот пример демонстрирует базовую механику: создание клиента, формирование запроса и обработка ответа.

Основные методы и структуры

Ниже представлены ключевые методы библиотеки openai-api-rs. Каждый метод сопровождается сигнатурой, описанием и рабочим примером кода.

1. Client::new(api_key: String) -> Client

Что делает: Создает новый экземпляр клиента для взаимодействия с OpenAI API. Принимает API-ключ в качестве строки. Клиент будет использоваться для всех последующих запросов.

use openai_api_rs::v1::api::Client;

let client = Client::new("sk-...".to_string());
// или через переменную окружения:
let client = Client::new(std::env::var("OPENAI_API_KEY").unwrap());

2. client.chat_completion(request: ChatCompletionRequest) -> Result<ChatCompletionResponse>

Что делает: Отправляет запрос к чат-модели (GPT-3.5, GPT-4). Принимает структуру ChatCompletionRequest, содержащую модель, список сообщений и опциональные параметры (температура, max_tokens и т.д.). Возвращает ответ с выборками (choices).

use openai_api_rs::v1::chat_completion::{ChatCompletionRequest, Message};

let request = ChatCompletionRequest::new(
    "gpt-4".to_string(),
    vec![
        Message { role: "system".to_string(), content: "Ты — полезный ассистент.".to_string() },
        Message { role: "user".to_string(), content: "Расскажи про Rust".to_string() },
    ],
);

let response = client.chat_completion(request).await?;
println!("{}", response.choices[0].message.content);

3. client.chat_completion_stream(request: ChatCompletionRequest) -> impl Stream<Item = Result<ChatCompletionChunk>>

Что делает: Отправляет запрос к чат-модели в потоковом режиме (streaming). Ответ приходит частями (chunks) по мере генерации текста. Возвращает асинхронный поток (Stream), который можно обрабатывать по мере поступления данных. Идеально для создания эффекта печатающегося текста.

use futures_util::StreamExt;
use openai_api_rs::v1::chat_completion::ChatCompletionRequest;

let request = ChatCompletionRequest::new(
    "gpt-3.5-turbo".to_string(),
    vec![Message { role: "user".to_string(), content: "Напиши историю из 3 предложений".to_string() }],
);

let mut stream = client.chat_completion_stream(request).await?;
while let Some(chunk) = stream.next().await {
    let chunk = chunk?;
    if let Some(delta) = chunk.choices.first().and_then(|c| c.delta.content.as_ref()) {
        print!("{}", delta);
    }
}

4. client.create_image(request: ImageGenerationRequest) -> Result<ImageResponse>

Что делает: Генерирует изображение на основе текстового описания (prompt) с использованием модели DALL-E. Принимает структуру ImageGenerationRequest, где можно указать размер, количество изображений и стиль. Возвращает URL или base64-кодированное изображение.

use openai_api_rs::v1::image::{ImageGenerationRequest, ImageSize};

let request = ImageGenerationRequest::new(
    "Кот в космосе, цифровая живопись".to_string(),
    ImageSize::S1024x1024,
    1,
);

let response = client.create_image(request).await?;
if let Some(url) = response.data.first().and_then(|d| d.url.as_ref()) {
    println!("URL изображения: {}", url);
}

5. client.create_embedding(request: EmbeddingRequest) -> Result<EmbeddingResponse>

Что делает: Создает векторное представление (эмбеддинг) для входного текста. Эмбеддинги используются для поиска по смыслу, кластеризации и классификации текстов. Модель по умолчанию — text-embedding-ada-002.

use openai_api_rs::v1::embedding::EmbeddingRequest;

let request = EmbeddingRequest::new(
    "text-embedding-ada-002".to_string(),
    "Rust — это язык системного программирования".to_string(),
);

let response = client.create_embedding(request).await?;
let embedding = &response.data[0].embedding;
println!("Размерность эмбеддинга: {}", embedding.len()); // 1536 для ada-002

6. client.create_transcription(request: AudioTranscriptionRequest) -> Result<TranscriptionResponse>

Что делает: Транскрибирует аудиофайл в текст с помощью модели Whisper. Поддерживает форматы: flac, m4a, mp3, mp4, mpeg, mpga, oga, ogg, wav, webm. Принимает путь к файлу и опционально язык.

use openai_api_rs::v1::audio::{AudioTranscriptionRequest, AudioInput};

let request = AudioTranscriptionRequest::new(
    AudioInput::File("speech.mp3".to_string()),
    "whisper-1".to_string(),
);

let response = client.create_transcription(request).await?;
println!("Транскрипция: {}", response.text);

7. client.create_moderation(request: ModerationRequest) -> Result<ModerationResponse>

Что делает: Проверяет текст на наличие нежелательного контента (ненависть, насилие, сексуальный контент и т.д.). Возвращает флаги по каждой категории и общий флаг flagged. Полезно для фильтрации пользовательского ввода.

use openai_api_rs::v1::moderation::ModerationRequest;

let request = ModerationRequest::new("Я тебя ненавижу!".to_string());
let response = client.create_moderation(request).await?;
println!("Флаг: {}", response.results[0].flagged); // true, если контент нарушает правила

8. client.list_models() -> Result<ListModelsResponse>

Что делает: Получает список всех доступных моделей OpenAI. Возвращает информацию о каждой модели: ID, владелец, дата создания и т.д. Полезно для динамического выбора модели в приложении.

let response = client.list_models().await?;
for model in response.data {
    println!("ID: {}, Владелец: {}", model.id, model.owned_by);
}

9. client.retrieve_model(model_id: &str) -> Result<Model>

Что делает: Получает детальную информацию о конкретной модели по её ID. Возвращает структуру Model с полями: id, object, created, owned_by, permission, root, parent.

let model = client.retrieve_model("gpt-4").await?;
println!("Модель: {}, создана: {}", model.id, model.created);

10. client.delete_model(model_id: &str) -> Result<DeleteModelResponse>

Что делает: Удаляет тонко настроенную (fine-tuned) модель. Работает только с моделями, созданными пользователем. Возвращает статус удаления. Внимание: это действие необратимо.

let response = client.delete_model("ft:gpt-3.5-turbo:my-org::custom_id").await?;
println!("Удалено: {}", response.deleted);

Реальный практический пример: Чат-бот с историей и потоковым выводом

В этом примере мы создадим консольный чат-бот, который сохраняет историю диалога и выводит ответы в реальном времени (streaming). Пользователь может вводить сообщения, а бот отвечает, учитывая контекст предыдущих сообщений. Для выхода из чата введите "exit".

use openai_api_rs::v1::api::Client;
use openai_api_rs::v1::chat_completion::{ChatCompletionRequest, Message};
use futures_util::StreamExt;
use std::env;
use std::io::{self, Write};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Инициализация клиента
    let api_key = env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY не установлен");
    let client = Client::new(api_key);

    // История диалога: начинаем с системного сообщения
    let mut messages: Vec<Message> = vec![
        Message {
            role: "system".to_string(),
            content: "Ты — дружелюбный ассистент. Отвечай кратко и по делу.".to_string(),
        },
    ];

    println!("Чат-бот запущен. Введите 'exit' для выхода.\n");

    loop {
        // Ввод пользователя
        print!("Вы: ");
        io::stdout().flush()?;
        let mut user_input = String::new();
        io::stdin().read_line(&mut user_input)?;
        let user_input = user_input.trim().to_string();

        if user_input.eq_ignore_ascii_case("exit") {
            println!("До свидания!");
            break;
        }

        // Добавляем сообщение пользователя в историю
        messages.push(Message {
            role: "user".to_string(),
            content: user_input,
        });

        // Формируем запрос с потоковым выводом
        let request = ChatCompletionRequest::new(
            "gpt-3.5-turbo".to_string(),
            messages.clone(), // передаем всю историю
        );

        print!("Бот: ");
        io::stdout().flush()?;

        let mut full_response = String::new();
        let mut stream = client.chat_completion_stream(request).await?;

        // Обрабатываем потоковые чанки
        while let Some(chunk) = stream.next().await {
            let chunk = chunk?;
            if let Some(delta) = chunk.choices.first()
                .and_then(|c                    

Рекомендаций