Почему Rust и ИИ — это не фантастика, а рабочий инструмент
Когда мы слышим «искусственный интеллект» и «Rust» в одном предложении, обычно представляем себе сложные нейросети, написанные на Python. Но что, если я скажу вам, что Rust может стать отличным бэкендом для взаимодействия с ChatGPT? Без медленного Python, без зависимостей вроде TensorFlow — просто чистый, быстрый, безопасный код, который общается с OpenAI API.
В этой статье мы не будем учить нейросеть с нуля — мы сделаем кое-что более практичное: напишем на Rust программу, которая отправляет запросы к ChatGPT и получает ответы. А затем научим её генерировать код, документацию и даже исправлять ошибки. Звучит как магия? На самом деле — это всего лишь пара крейтов и правильный API-ключ.
Если вы когда-нибудь хотели добавить в свой Rust-проект «мозги» в виде языковой модели — вы попали по адресу. Поехали!
Что нам понадобится: инструменты и подготовка
Прежде чем писать код, давайте разберёмся, что потребуется для интеграции ChatGPT в Rust-приложение.
Необходимые компоненты
- Rust — установленный компилятор (rustc) и менеджер пакетов Cargo. Если у вас ещё нет Rust —
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - API-ключ OpenAI — зарегистрируйтесь на platform.openai.com, создайте ключ и положите его в переменную окружения
OPENAI_API_KEY - Библиотеки Rust — мы будем использовать крейты
reqwest(для HTTP-запросов),serdeиserde_json(для работы с JSON),tokio(асинхронный рантайм)
Создаём проект
cargo new rust_chatgpt
cd rust_chatgpt
Добавим зависимости в Cargo.toml:
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Теперь можно запускать cargo build — зависимости подтянутся автоматически.
Пишем первый запрос к ChatGPT на Rust
Самый простой способ «поговорить» с ChatGPT — отправить POST-запрос на эндпоинт https://api.openai.com/v1/chat/completions. Rust с его строгой типизацией идеально подходит для этой задачи: мы чётко опишем структуру запроса и ответа, и компилятор проверит нас на каждом шагу.
Структуры данных для API
OpenAI API ожидает JSON с определённой схемой. Опишем её с помощью serde:
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct ChatRequest {
model: String,
messages: Vec<Message>,
temperature: f32,
}
#[derive(Serialize, Deserialize, Clone)]
struct Message {
role: String,
content: String,
}
#[derive(Deserialize)]
struct ChatResponse {
choices: Vec<Choice>,
}
#[derive(Deserialize)]
struct Choice {
message: Message,
}
Обратите внимание: Message используется и для отправки, и для получения — поэтому мы добавили оба атрибута Serialize и Deserialize.
Асинхронный запрос
Теперь напишем функцию, которая отправляет сообщение и возвращает ответ от ChatGPT:
use std::env;
async fn ask_chatgpt(prompt: &str) -> Result<String, Box<dyn std::error::Error>> {
let api_key = env::var("OPENAI_API_KEY")
.expect("Переменная OPENAI_API_KEY не установлена");
let client = reqwest::Client::new();
let request_body = ChatRequest {
model: "gpt-4o-mini".to_string(), // быстрая и дешёвая модель
messages: vec![
Message {
role: "system".to_string(),
content: "Ты — ассистент, который помогает программистам на Rust.".to_string(),
},
Message {
role: "user".to_string(),
content: prompt.to_string(),
},
],
temperature: 0.7,
};
let response = client
.post("https://api.openai.com/v1/chat/completions")
.header("Authorization", format!("Bearer {}", api_key))
.json(&request_body)
.send()
.await?
.json::<ChatResponse>()
.await?;
Ok(response.choices[0].message.content.clone())
}
Ключевые моменты:
- Используем
reqwest::Client— он эффективнее, чем создавать новый клиент на каждый запрос - API-ключ читаем из переменной окружения — никогда не храните ключи в коде!
- Системное сообщение задаёт тон ответа модели — можно настроить под свои нужды
Запускаем в main
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let answer = ask_chatgpt("Напиши пример функции на Rust, которая сортирует вектор чисел").await?;
println!("ChatGPT ответил:\n{}", answer);
Ok(())
}
Запустите cargo run — и через пару секунд вы увидите сгенерированный код от ChatGPT прямо в терминале. Работает!
Продвинутые сценарии: генерация кода и документации
Просто «поболтать» с нейросетью — это весело, но давайте сделаем что-то полезное для реальной разработки. ChatGPT отлично справляется с задачами, которые отнимают время у программиста: написание boilerplate-кода, генерация документации, рефакторинг и поиск ошибок.
Генератор Rust-функций по описанию
Представьте: вы описываете, что должна делать функция, а ChatGPT пишет код. Реализуем это:
async fn generate_rust_function(description: &str) -> Result<String, Box<dyn std::error::Error>> {
let prompt = format!(
"Напиши на Rust функцию, которая {}.
Используй идиоматичный Rust, обработку ошибок через Result,
и добавь комментарии на русском языке.",
description
);
ask_chatgpt(&prompt).await
}
// Пример использования:
let func = generate_rust_function("принимает строку и возвращает количество гласных в ней").await?;
println!("{}", func);
Результат может выглядеть так:
fn count_vowels(text: &str) -> usize {
let vowels = ['a', 'e', 'i', 'o', 'u', 'а', 'е', 'ё', 'и', 'о', 'у', 'ы', 'э', 'ю', 'я'];
text.chars().filter(|c