Usiamo i cookie. Cookie e memoria del browser ti mantengono connesso e ricordano le tue preferenze. Con il tuo consenso misuriamo anche come viene usato il sito. Puoi in qualsiasi momento. Consulta la nostra cookie policy.

Rust

Guide agli SDK

Rust

Usa async-openai con api14 in Rust: configurazione con with_api_base, chat, streaming, strumenti, output strutturato, embeddings, errori e retry con backoff.

Usa async-openai con api14. Configura la base dell'API con OpenAIConfig::with_api_base e passa id di modello come openai/gpt-5-mini.

Installazione

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

Configurazione

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);

Leggi la chiave dall'ambiente come sopra invece di scriverla nel codice. Per passare tra staging e produzione, leggi allo stesso modo il base URL, ad esempio 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}"),
    }
}

Vedi 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()); // la tua funzione
        messages.push(ChatCompletionRequestToolMessageArgs::default()
            .tool_call_id(call.id)
            .content(result)
            .build()?
            .into());
    }
}

Vedi Tool calling.

Output strutturato

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("{}"))?;

Vedi Output strutturati.

Input di immagini

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()?;

Invialo con google/gemini-2.5-flash o con un altro modello che accetta input image. Vedi Visione e file.

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());

Gli endpoint per cui il crate non ha un tipo (job video, rerank) possono essere chiamati con reqwest: vedi gli esempi HTTP nel blocco di codice qui sotto.

Errori

Gli errori del gateway vengono analizzati in OpenAIError::ApiError; distingui i casi in base al code leggibile da macchina:

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}"),
}

Vedi Errori.

Timeout e retry

async-openai applica già backoff e ripete le risposte 429 rate_limited. Il suo backoff predefinito continua a provare fino a 15 minuti, troppo per la maggior parte delle app e inutile per daily_limit_reached. Limitalo e dai un timeout al client HTTP (cargo add backoff reqwest, con le stesse versioni usate da async-openai):

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());

Vedi Limiti di frequenza.

Tutte le funzionalità

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);