# Turbine LLM Turbine LLM is a unified Rust library that provides a single, consistent interface for interacting with multiple Large Language Model providers including OpenAI, Anthropic, Google Gemini, and Groq. The library abstracts away provider-specific API differences, allowing developers to switch between providers with minimal code changes while maintaining full type safety and proper error handling through Rust's type system. Built with async/await using Tokio, Turbine LLM offers high-performance operations with support for both text and structured JSON responses. The library uses a clean builder pattern for constructing requests, making it simple to add messages, set parameters like temperature and token limits, and configure output formats. Each provider requires only its corresponding API key as an environment variable, and the unified interface ensures consistent behavior regardless of which provider is selected. ## API Reference ### Creating a Client Initialize a TurbineClient for any supported provider by specifying the provider enum and ensuring the corresponding API key environment variable is set. ```rust use turbine_llm::{TurbineClient, Provider}; #[tokio::main] async fn main() -> Result<(), Box> { // Set environment variable: export OPENAI_API_KEY="sk-..." let openai_client = TurbineClient::new(Provider::OpenAI)?; // Set environment variable: export ANTHROPIC_API_KEY="sk-ant-..." let anthropic_client = TurbineClient::new(Provider::Anthropic)?; // Set environment variable: export GEMINI_API_KEY="..." let gemini_client = TurbineClient::new(Provider::Gemini)?; // Set environment variable: export GROQ_API_KEY="..." let groq_client = TurbineClient::new(Provider::Groq)?; Ok(()) } ``` ### Basic Text Generation Send a simple request to generate text with a user message and system prompt, controlling output length with max_tokens. ```rust use turbine_llm::{TurbineClient, LLMRequest, Message, Provider}; #[tokio::main] async fn main() -> Result<(), Box> { let client = TurbineClient::new(Provider::OpenAI)?; let request = LLMRequest::new("gpt-4o-mini") .with_system_prompt("You are a helpful assistant.") .with_message(Message::user("Explain what Rust is in 2-3 sentences.")) .with_max_tokens(150); let response = client.send_request(&request).await?; println!("Response: {}", response.content); println!("Token usage: {} input, {} output", response.usage.input_tokens, response.usage.output_tokens ); Ok(()) } ``` ### JSON Output Mode Request structured JSON responses from any provider by setting the output format, useful for extracting structured data from LLM responses. ```rust use turbine_llm::{TurbineClient, LLMRequest, Message, OutputFormat, Provider}; #[tokio::main] async fn main() -> Result<(), Box> { let client = TurbineClient::new(Provider::Anthropic)?; let request = LLMRequest::new("claude-3-5-sonnet-20241022") .with_system_prompt("Return all data as valid JSON.") .with_message(Message::user( "Give me info about Paris with keys: name, country, population, famous_landmarks (array)" )) .with_output_format(OutputFormat::Json); let response = client.send_request(&request).await?; // Response will be JSON string like: // {"name":"Paris","country":"France","population":2161000,"famous_landmarks":["Eiffel Tower","Louvre","Notre-Dame"]} println!("{}", response.content); // Parse JSON if needed let parsed: serde_json::Value = serde_json::from_str(&response.content)?; println!("City: {}", parsed["name"]); Ok(()) } ``` ### Multi-turn Conversations Build conversational contexts by chaining multiple messages with alternating user and assistant roles, maintaining conversation history. ```rust use turbine_llm::{TurbineClient, LLMRequest, Message, Provider}; #[tokio::main] async fn main() -> Result<(), Box> { let client = TurbineClient::new(Provider::Gemini)?; let messages = vec![ Message::user("Hello! My name is Alice and I love programming."), Message::assistant( "Hello Alice! It's great to meet you. Programming is wonderful! What languages do you enjoy?" ), Message::user("I really like Rust! What's my name again?"), ]; let request = LLMRequest::new("gemini-2.0-flash-exp") .with_system_prompt("You are a friendly assistant with good memory.") .with_messages(messages) .with_max_tokens(100); let response = client.send_request(&request).await?; // Response will remember: "Your name is Alice!" println!("{}", response.content); Ok(()) } ``` ### Temperature and Sampling Control Adjust response randomness and creativity using temperature and top_p parameters for fine-grained control over generation behavior. ```rust use turbine_llm::{TurbineClient, LLMRequest, Message, Provider}; #[tokio::main] async fn main() -> Result<(), Box> { let client = TurbineClient::new(Provider::Groq)?; // Low temperature for deterministic, focused responses let deterministic_request = LLMRequest::new("llama-3.3-70b-versatile") .with_message(Message::user("What is 2+2?")) .with_temperature(0.1) .with_max_tokens(50); let response1 = client.send_request(&deterministic_request).await?; println!("Deterministic: {}", response1.content); // High temperature for creative, varied responses let creative_request = LLMRequest::new("llama-3.3-70b-versatile") .with_message(Message::user("Write a creative tagline for a coffee shop")) .with_temperature(1.5) .with_top_p(0.95) .with_max_tokens(50); let response2 = client.send_request(&creative_request).await?; println!("Creative: {}", response2.content); Ok(()) } ``` ### Error Handling Handle common errors including missing API keys, network failures, and invalid responses with proper error types. ```rust use turbine_llm::{TurbineClient, LLMRequest, Message, Provider, TurbineError}; #[tokio::main] async fn main() { let client_result = TurbineClient::new(Provider::OpenAI); match client_result { Ok(client) => { let request = LLMRequest::new("gpt-4o-mini") .with_message(Message::user("Hello!")); match client.send_request(&request).await { Ok(response) => { println!("Success: {}", response.content); }, Err(TurbineError::HttpError(e)) => { eprintln!("Network error: {}", e); }, Err(TurbineError::ApiError(msg)) => { eprintln!("API returned error: {}", msg); }, Err(TurbineError::InvalidResponse(msg)) => { eprintln!("Invalid response: {}", msg); }, Err(e) => { eprintln!("Other error: {}", e); } } }, Err(TurbineError::ApiKeyNotFound(provider)) => { eprintln!("Missing API key for {}", provider); eprintln!("Set environment variable: export OPENAI_API_KEY=\"your-key\""); }, Err(e) => { eprintln!("Initialization error: {}", e); } } } ``` ### Provider Switching Dynamically switch between providers at runtime while using the same request structure and API interface. ```rust use turbine_llm::{TurbineClient, LLMRequest, Message, Provider}; async fn query_with_provider(provider: Provider, model: &str) -> Result> { let client = TurbineClient::new(provider)?; let request = LLMRequest::new(model) .with_system_prompt("You are a helpful assistant.") .with_message(Message::user("What is the capital of France?")) .with_max_tokens(50); let response = client.send_request(&request).await?; Ok(response.content) } #[tokio::main] async fn main() -> Result<(), Box> { // Same query across different providers let openai_response = query_with_provider(Provider::OpenAI, "gpt-4o-mini").await?; println!("OpenAI: {}", openai_response); let anthropic_response = query_with_provider(Provider::Anthropic, "claude-3-5-haiku-20241022").await?; println!("Anthropic: {}", anthropic_response); let gemini_response = query_with_provider(Provider::Gemini, "gemini-2.0-flash-exp").await?; println!("Gemini: {}", gemini_response); let groq_response = query_with_provider(Provider::Groq, "mixtral-8x7b-32768").await?; println!("Groq: {}", groq_response); Ok(()) } ``` ### Building Complex Requests Combine all available parameters to create sophisticated requests with precise control over model behavior and output. ```rust use turbine_llm::{TurbineClient, LLMRequest, Message, OutputFormat, Provider}; #[tokio::main] async fn main() -> Result<(), Box> { let client = TurbineClient::new(Provider::Anthropic)?; let request = LLMRequest::new("claude-3-5-sonnet-20241022") .with_system_prompt("You are a technical writer. Output valid JSON only.") .with_message(Message::user("Create a product description for noise-cancelling headphones")) .with_max_tokens(500) .with_temperature(0.8) .with_top_p(0.9) .with_output_format(OutputFormat::Json); let response = client.send_request(&request).await?; println!("Generated JSON: {}", response.content); println!("Tokens: {} in, {} out", response.usage.input_tokens, response.usage.output_tokens ); Ok(()) } ``` ### Message Construction Helpers Use convenient helper methods to create messages with different roles for cleaner, more readable code. ```rust use turbine_llm::{Message, LLMRequest}; fn build_conversation() -> LLMRequest { // Three ways to create messages let msg1 = Message::user("What's the weather?"); let msg2 = Message::assistant("I don't have access to weather data."); let msg3 = Message::system("You are a helpful assistant."); // Or use the generic constructor let msg4 = Message::new("user", "Tell me a joke"); LLMRequest::new("gpt-4o-mini") .with_message(msg1) .with_message(msg2) .with_message(msg4) } #[tokio::main] async fn main() -> Result<(), Box> { use turbine_llm::{TurbineClient, Provider}; let client = TurbineClient::new(Provider::OpenAI)?; let request = build_conversation(); let response = client.send_request(&request).await?; println!("{}", response.content); Ok(()) } ``` ## Integration Patterns and Use Cases Turbine LLM excels in applications requiring provider flexibility and consistent LLM interfaces. Common use cases include building AI chatbots with conversation history, generating structured data extraction pipelines where JSON output ensures predictable parsing, creating content generation systems with temperature control for balancing creativity and consistency, and implementing fallback systems that automatically switch providers when one experiences downtime or rate limits. The library's async architecture makes it ideal for web servers handling multiple concurrent LLM requests. Integration patterns typically involve wrapping TurbineClient in application-specific service layers that manage provider selection logic, implement retry mechanisms with exponential backoff, cache responses to reduce API costs, and parse JSON outputs into strongly-typed Rust structs. The provider-agnostic design enables A/B testing different models, implementing cost optimization strategies by routing queries to cheaper providers when appropriate, and building model evaluation frameworks that compare outputs across providers. With support for multi-turn conversations and system prompts, Turbine LLM provides everything needed for production-grade AI applications.