Docs   Quickstart

In the rapidly evolving landscape of artificial intelligence (AI), Large Language Models (LLMs) have emerged as powerful tools for building sophisticated AI applications. However, harnessing the full potential of LLMs often requires navigating complex APIs, managing different providers, and implementing intricate workflows. This is where Rig comes in – a comprehensive Rust library designed to transform how developers build LLM-powered applications.

The Challenge of Building LLM Applications

Before diving into Rig’s capabilities, let’s consider the challenges developers face when building LLM applications:

  1. API Complexity: Each LLM provider has its own API, requiring developers to learn and manage multiple interfaces.
  2. Workflow Management: Implementing advanced AI workflows, such as Retrieval-Augmented Generation (RAG), involves multiple steps and can be error-prone.
  3. Performance and Scalability: Ensuring optimal performance and scalability in LLM applications can be challenging, especially as projects grow in complexity.
  4. Type Safety and Error Handling: Maintaining type safety and robust error handling across different LLM interactions is crucial but often difficult.

Enter Rig: A Game-Changer for LLM Application Development

Rig is more than just an API wrapper; it’s a comprehensive framework that addresses these challenges head-on. By providing high-level abstractions and a unified interface, Rig simplifies the development process, allowing you to focus on building innovative AI solutions rather than wrestling with implementation details.

Whether you’re a seasoned Rust developer or new to the language, Rig offers a range of features designed to make your LLM application development smoother, faster, and more enjoyable.

Getting Started with Rig

Let’s dive into a simple example to demonstrate how easy it is to get started with Rig:

use rig::{completion::Prompt, providers::openai};
 
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    // Initialize the OpenAI client using environment variables
    let openai_client = openai::Client::from_env();
    
    // Create a GPT-4 model instance
    let gpt4 = openai_client.model("gpt-4").build();
    
    // Send a prompt to GPT-4 and await the response
    let response = gpt4.prompt("Explain quantum computing in one sentence.").await?;
    
    // Print the response
    println!("GPT-4: {}", response);
    
    Ok(())
}

This simple example demonstrates how Rig abstracts away the complexities of interacting with OpenAI’s API, allowing you to focus on the core logic of your application.

To include Rig in your project, add the following to your Cargo.toml:

[dependencies]
rig-core = "0.0.6"
tokio = { version = "1.34.0", features = ["full"] }

💡 Tip: Don’t forget to set the OPENAI_API_KEY environment variable before running your application.

Key Features and Developer Experience

Rig combines Rust’s powerful type system and performance with intuitive abstractions tailored for AI development. Let’s explore some of its key features:

1. Unified and Intuitive API

One of Rig’s standout features is its consistent interface across different LLM providers:

// Using OpenAI
let gpt4 = openai_client.model("gpt-4").build();
let response = gpt4.prompt("Hello, GPT-4!").await?;
 
// Using Cohere
let command = cohere_client.model("command").build();
let response = command.prompt("Hello, Cohere!").await?;

This unified API design ensures that switching between providers or adding new ones to your project is seamless, reducing cognitive load and improving code maintainability.

2. Advanced Abstractions for Complex Workflows

Rig shines when it comes to implementing complex AI workflows. For example, creating a Retrieval-Augmented Generation (RAG) system typically involves multiple steps:

  1. Generating embeddings for documents
  2. Storing these embeddings in a vector database
  3. Retrieving relevant context based on user queries
  4. Augmenting the LLM prompt with this context

With Rig, this entire process can be condensed into a few lines of code:

let rag_agent = openai_client.context_rag_agent("gpt-4")
    .preamble("You are a helpful assistant.")
    .dynamic_context(2, vector_store.index(embedding_model))
    .build();
 
let response = rag_agent.prompt("What is the capital of France?").await?;

This high-level abstraction allows developers to implement advanced AI systems quickly and efficiently, without getting bogged down in the implementation details.

3. Type-Safe Development

Leveraging Rust’s strong type system, Rig provides compile-time guarantees and better auto-completion, enhancing the developer experience:

#[derive(serde::Deserialize, JsonSchema)]
struct Person {
    name: String,
    age: u8,
}
 
let extractor = openai_client.extractor::<Person>("gpt-4").build();
let person: Person = extractor.extract("John Doe is 30 years old").await?;

This type-safe approach helps catch errors early in the development process and makes refactoring and maintenance easier.

4. Extensibility and Integration

Rig’s flexible architecture allows for easy customization and seamless integration with Rust’s growing AI ecosystem:

impl VectorStore for MyCustomStore {
    // Implementation details...
}
 
let my_store = MyCustomStore::new();
let rag_agent = openai_client.context_rag_agent("gpt-4")
    .dynamic_context(2, my_store.index(embedding_model))
    .build();

This extensibility ensures that Rig can grow with your project’s needs and integrate with other tools in your AI development stack.

Advanced Features: RAG Systems and Beyond

Let’s explore a more comprehensive example of a RAG system with Rig, showcasing its ability to handle complex AI workflows:

use rig::{
    completion::Prompt,
    embeddings::EmbeddingsBuilder,
    providers::openai::Client,
    vector_store::{in_memory_store::InMemoryVectorStore, VectorStore},
};
 
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    // Initialize OpenAI client and embedding model
    let openai_client = Client::from_env();
    let embedding_model = openai_client.embedding_model("text-embedding-ada-002");
 
    // Create and populate vector store
    let mut vector_store = InMemoryVectorStore::default();
    let embeddings = EmbeddingsBuilder::new(embedding_model.clone())
        .simple_document("doc1", "Rig is a Rust library for building LLM applications.")
        .simple_document("doc2", "Rig supports OpenAI and Cohere as LLM providers.")
        .build()
        .await?;
    vector_store.add_documents(embeddings).await?;
 
    // Create and use RAG agent
    let rag_agent = openai_client.context_rag_agent("gpt-4")
        .preamble("You are an assistant that answers questions about Rig.")
        .dynamic_context(1, vector_store.index(embedding_model))
        .build();
 
    let response = rag_agent.prompt("What is Rig?").await?;
    println!("RAG Agent: {}", response);
 
    Ok(())
}

This example demonstrates how Rig abstracts the complexity of creating a RAG system, handling embedding generation, vector storage, and context retrieval efficiently. With just a few lines of code, you’ve implemented a sophisticated AI system that can provide context-aware responses.

But Rig’s capabilities extend beyond RAG systems. Its flexible architecture allows for the implementation of various AI workflows, including:

  • Multi-agent systems for complex problem-solving
  • AI-powered data analysis and extraction
  • Automated content generation and summarization
  • And much more!