Usamos cookies. Cookies e o armazenamento do navegador mantêm você conectado e lembram suas preferências. Com sua permissão, também medimos como o site é usado. Você pode a qualquer momento. Veja nossa política de cookies.

Rust

Guias de SDK

Rust

Use o crate async-openai com a api14: configure a base da API com OpenAIConfig, faça chat, streaming, tool calling, saída estruturada e trate erros em Rust.

Use o async-openai com a api14. Configure a base da API com OpenAIConfig::with_api_base e passe ids de modelo como openai/gpt-5-mini.

Instalação

cargo add async-openai futures serde_json
cargo add tokio --features full
export API14_API_KEY="sk-api14-..."

Configuração

use async_openai::{config::OpenAIConfig, Client};

let config = OpenAIConfig::new()
    .with_api_base("https://api14.com/api/v1")
    .with_api_key(std::env::var("API14_API_KEY")?);
let client = Client::with_config(config);

Leia a chave do ambiente, como acima, em vez de deixá-la fixa no código. Para alternar entre staging e produção, leia a URL base da mesma forma, por exemplo std::env::var("API14_BASE_URL").unwrap_or("https://api14.com/api/v1".into()).

Chat

use async_openai::{
    config::OpenAIConfig,
    types::{ChatCompletionRequestUserMessageArgs, CreateChatCompletionRequestArgs},
    Client,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = OpenAIConfig::new()
        .with_api_base("https://api14.com/api/v1")
        .with_api_key(std::env::var("API14_API_KEY")?);
    let client = Client::with_config(config);

    let request = CreateChatCompletionRequestArgs::default()
        .model("openai/gpt-5-mini")
        .messages([ChatCompletionRequestUserMessageArgs::default()
            .content("Explain vector databases in two sentences.")
            .build()?
            .into()])
        .build()?;

    let response = client.chat().create(request).await?;
    if let Some(content) = &response.choices[0].message.content {
        println!("{content}");
    }
    Ok(())
}

Streaming

use futures::StreamExt;

let request = CreateChatCompletionRequestArgs::default()
    .model("anthropic/claude-sonnet-4.5")
    .messages([ChatCompletionRequestUserMessageArgs::default()
        .content("Write a haiku about APIs.")
        .build()?
        .into()])
    .build()?;

let mut stream = client.chat().create_stream(request).await?;
while let Some(result) = stream.next().await {
    match result {
        Ok(chunk) => {
            for choice in chunk.choices {
                if let Some(text) = choice.delta.content {
                    print!("{text}");
                }
            }
        }
        Err(err) => eprintln!("stream error: {err}"),
    }
}

Veja Streaming.

Tool calling

use async_openai::types::{
    ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage,
    ChatCompletionRequestToolMessageArgs, ChatCompletionToolArgs, ChatCompletionToolType,
    FunctionObjectArgs,
};
use serde_json::{json, Value};

let tools = vec![ChatCompletionToolArgs::default()
    .r#type(ChatCompletionToolType::Function)
    .function(FunctionObjectArgs::default()
        .name("get_weather")
        .description("Current weather for a city")
        .parameters(json!({
            "type": "object",
            "properties": { "city": { "type": "string" } },
            "required": ["city"]
        }))
        .build()?)
    .build()?];

let mut messages: Vec<ChatCompletionRequestMessage> = vec![ChatCompletionRequestUserMessageArgs::default()
    .content("What's the weather in Istanbul?")
    .build()?
    .into()];

loop {
    let request = CreateChatCompletionRequestArgs::default()
        .model("openai/gpt-5-mini")
        .messages(messages.clone())
        .tools(tools.clone())
        .build()?;
    let message = client.chat().create(request).await?.choices.remove(0).message;

    let Some(calls) = message.tool_calls else {
        println!("{}", message.content.unwrap_or_default());
        break;
    };
    messages.push(ChatCompletionRequestAssistantMessageArgs::default()
        .tool_calls(calls.clone())
        .build()?
        .into());
    for call in calls {
        let args: Value = serde_json::from_str(&call.function.arguments)?;
        let result = get_weather(args["city"].as_str().unwrap_or_default()); // sua função
        messages.push(ChatCompletionRequestToolMessageArgs::default()
            .tool_call_id(call.id)
            .content(result)
            .build()?
            .into());
    }
}

Veja Tool calling.

Saída estruturada

use async_openai::types::{ResponseFormat, ResponseFormatJsonSchema};

let request = CreateChatCompletionRequestArgs::default()
    .model("openai/gpt-5-mini")
    .messages([ChatCompletionRequestUserMessageArgs::default()
        .content("Extract: Ada Lovelace, born 1815.")
        .build()?
        .into()])
    .response_format(ResponseFormat::JsonSchema {
        json_schema: ResponseFormatJsonSchema {
            name: "person".into(),
            description: None,
            strict: Some(true),
            schema: Some(json!({
                "type": "object",
                "properties": { "name": { "type": "string" }, "born": { "type": "integer" } },
                "required": ["name", "born"],
                "additionalProperties": false
            })),
        },
    })
    .build()?;

let response = client.chat().create(request).await?;
let person: Value = serde_json::from_str(response.choices[0].message.content.as_deref().unwrap_or("{}"))?;

Veja Saídas estruturadas.

Entrada de imagem

use async_openai::types::{
    ChatCompletionRequestMessageContentPartImageArgs, ChatCompletionRequestMessageContentPartTextArgs,
    ImageUrlArgs,
};

let message = ChatCompletionRequestUserMessageArgs::default()
    .content(vec![
        ChatCompletionRequestMessageContentPartTextArgs::default()
            .text("What is in this picture?")
            .build()?
            .into(),
        ChatCompletionRequestMessageContentPartImageArgs::default()
            .image_url(ImageUrlArgs::default().url("https://example.com/photo.jpg").build()?)
            .build()?
            .into(),
    ])
    .build()?;

Envie com google/gemini-2.5-flash ou outro modelo com entrada image. Veja Visão e arquivos.

Embeddings

use async_openai::types::CreateEmbeddingRequestArgs;

let request = CreateEmbeddingRequestArgs::default()
    .model("openai/text-embedding-3-small")
    .input(["The quick brown fox", "Lorem ipsum"])
    .build()?;
let response = client.embeddings().create(request).await?;
println!("{}", response.data[0].embedding.len());

Endpoints para os quais o crate não tem tipo (jobs de vídeo, rerank) podem ser chamados com reqwest; veja os exemplos HTTP no bloco de código abaixo.

Erros

Os erros do gateway são interpretados como OpenAIError::ApiError; trate pelo code legível por máquina:

use async_openai::error::OpenAIError;

match client.chat().create(request).await {
    Ok(response) => println!("{:?}", response.choices[0].message.content),
    Err(OpenAIError::ApiError(err)) => match err.code.as_deref() {
        Some("insufficient_balance") => eprintln!("Balance too low, add funds"),
        Some("rate_limited") | Some("daily_limit_reached") => eprintln!("Slow down: {}", err.message),
        _ => eprintln!("API error: {}", err.message),
    },
    Err(other) => eprintln!("{other}"),
}

Veja Erros.

Timeouts e novas tentativas

O async-openai já faz backoff e repete respostas 429 rate_limited. O backoff padrão continua tentando por até 15 minutos, o que é longo demais para a maioria dos apps e inútil para daily_limit_reached. Limite-o e dê um timeout ao cliente HTTP (cargo add backoff reqwest, nas versões que o async-openai usa):

use std::time::Duration;

let http = reqwest::Client::builder()
    .timeout(Duration::from_secs(120))
    .build()?;

let client = Client::with_config(config)
    .with_http_client(http)
    .with_backoff(backoff::ExponentialBackoffBuilder::new()
        .with_max_elapsed_time(Some(Duration::from_secs(90)))
        .build());

Veja Limites de taxa.

Todos os recursos

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api14.com/api/v1",
  apiKey: process.env.API14_API_KEY,
});

const result = await client.chat.completions.create({
  "model": "openai/gpt-5-mini",
  "messages": [
    {
      "role": "user",
      "content": "Explain vector databases in two sentences."
    }
  ]
});
console.log(result.choices[0].message.content);