SDK-Leitfäden
Rust
Nutzen Sie async-openai mit api14: API-Basis über OpenAIConfig setzen, Chat, Streaming, Tool Calling, strukturierte Ausgabe, Embeddings und Fehler in Rust.
Nutzen Sie async-openai mit api14. Konfigurieren Sie die API-Basis mit OpenAIConfig::with_api_base und übergeben Sie Modell-IDs wie openai/gpt-5-mini.
Installation
cargo add async-openai futures serde_json
cargo add tokio --features full
export API14_API_KEY="sk-api14-..."
Konfiguration
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);
Lesen Sie den Schlüssel wie oben aus der Umgebung, statt ihn fest einzucodieren. Um zwischen Staging und Produktion zu wechseln, lesen Sie die Base URL auf dieselbe Weise, zum Beispiel 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}"),
}
}
Siehe 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()); // Ihre Funktion
messages.push(ChatCompletionRequestToolMessageArgs::default()
.tool_call_id(call.id)
.content(result)
.build()?
.into());
}
}
Siehe Tool Calling.
Strukturierte Ausgabe
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("{}"))?;
Siehe Strukturierte Ausgaben.
Bildeingabe
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()?;
Senden Sie es mit google/gemini-2.5-flash oder einem anderen Modell mit image-Eingabe. Siehe Vision & Dateien.
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());
Endpunkte, für die das Crate keinen Typ hat (Videoaufträge, Rerank), können mit reqwest aufgerufen werden, siehe die HTTP-Beispiele im Codeblock unten.
Fehler
Gateway-Fehler werden zu OpenAIError::ApiError geparst; verzweigen Sie nach dem maschinenlesbaren code:
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}"),
}
Siehe Fehler.
Timeouts und Wiederholungen
async-openai wartet bereits mit Backoff und wiederholt 429 rate_limited-Antworten. Das Standard-Backoff versucht es bis zu 15 Minuten lang, was für die meisten Apps zu lang und bei daily_limit_reached sinnlos ist. Begrenzen Sie es und geben Sie dem HTTP-Client ein Timeout (cargo add backoff reqwest, passend zu den von async-openai verwendeten Versionen):
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());
Siehe Rate Limits.
Alle Fähigkeiten
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);