Swiftide

Swiftide is a Rust library for building LLM applications. It supports everything from simple prompt completions to fast, streaming indexing and querying pipelines, and building composable agents that use tools or call other agents.

High level features

  • Simple primitives for common LLM tasks
  • Streaming indexing and querying pipelines
  • Composable agents and pipelines
  • Modular, extendable API with minimal abstractions
  • Integrations with popular LLMs and storage providers
  • Built-in pipeline transformations (or bring your own)
  • Graph-like workflows with Tasks
  • Langfuse support

Installation

Install Swiftide with Qdrant, OpenAI, and Redis support:

cargo add swiftide --features=qdrant,openai,redis

Note that Swiftide comes barebones by default, so you need to enable features for the integrations you want to use.


Indexing Example (Step by Step)

This example indexes .rs files using Swiftide with Qdrant as vector storage.

use swiftide::{
    indexing,
    indexing::LanguageModelWithBackOff,
    indexing::loaders::FileLoader,
    indexing::transformers::{ChunkCode, Embed, MetadataQACode},
    integrations::{self, qdrant::Qdrant, redis::Redis},
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt::init();

    // 1. Set up OpenAI client for embedding and prompt models
    let openai_client = integrations::openai::OpenAI::builder()
        .default_embed_model("text-embedding-3-small")
        .default_prompt_model("gpt-3.5-turbo")
        .build()?;

    // 3. Set up Redis for caching which files/chunks are already processed
    let redis_url = std::env::var("REDIS_URL")
        .as_deref()
        .unwrap_or("redis://localhost:6379")
        .to_owned();

    indexing::Pipeline::from_loader(FileLoader::new(".").with_extensions(&["rs"]))
        // 4. Skip files/chunks already indexed (cached in Redis)
        .filter_cached(Redis::try_from_url(redis_url, "swiftide-examples")?)
        // 5. Generate metadata Q&A for code chunks, using LLM
        .then(MetadataQACode::new(openai_client.clone()))
        // 6. Split code into chunks suitable for embedding
        .then_chunk(ChunkCode::try_for_language_and_chunk_size("rust", 10..2048)?)
        // 7. Embed code+metadata in batches
        .then_in_batch(Embed::new(openai_client.clone()).with_batch_size(10))
        // 8. Store results in a Qdrant collection
        .then_store_with(
            Qdrant::builder()
                .batch_size(50)
                .vector_size(1536)
                .collection_name("swiftide-examples")
                .build()?,
        )
        // 9. Run the pipeline asynchronously
        .run()
        .await?;
    Ok(())
}

Hybrid Search Example

Below is a streamlined workflow for hybrid dense/sparse search using Qdrant.

use swiftide::{
    indexing::{
        self, EmbeddedField,
        loaders::FileLoader,
        transformers::{self, ChunkCode, MetadataQACode},
    },
    integrations::{fastembed::FastEmbed, openai, qdrant::Qdrant},
    query::{self, answers, query_transformers, search_strategies::HybridSearch},
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt::init();

    // 1. Create fastembed (dense/sparse) clients
    let batch_size = 64;
    let fastembed_sparse = FastEmbed::try_default_sparse().unwrap().to_owned();
    let fastembed = FastEmbed::try_default().unwrap().to_owned();

    // 2. Use a compact OpenAI prompt model for metadata Q&A generation
    let openai = openai::OpenAI::builder()
        .default_prompt_model("gpt-4o-mini")
        .build()
        .unwrap();

    // 3. Set up Qdrant for both dense and sparse vectors
    let qdrant = Qdrant::builder()
        .batch_size(batch_size)
        .vector_size(384)
        .with_vector(EmbeddedField::Combined)
        .with_sparse_vector(EmbeddedField::Combined)
        .collection_name("swiftide-hybrid-example")
        .build()?;

    indexing::Pipeline::from_loader(FileLoader::new("swiftide-core/").with_extensions(&["rs"]))
        .then_chunk(ChunkCode::try_for_language_and_chunk_size("rust", 10..2048)?)
        .then(MetadataQACode::from_client(openai.clone()).build().unwrap())
        .then_in_batch(transformers::SparseEmbed::new(fastembed_sparse.clone()).with_batch_size(batch_size))
        .then_in_batch(transformers::Embed::new(fastembed.clone()).with_batch_size(batch_size))
        .then_store_with(qdrant.clone())
        .run()
        .await?;

    // 4. Run a hybrid search pipeline
    let openai = openai::OpenAI::builder()
        .default_prompt_model("gpt-4o")
        .build()
        .unwrap();

    let query_pipeline = query::Pipeline::from_search_strategy(
        HybridSearch::default()
            .with_top_n(20)
            .with_top_k(20)
            .to_owned(),
    )
    .then_transform_query(query_transformers::GenerateSubquestions::from_client(openai.clone()))
    .then_transform_query(query_transformers::Embed::from_client(fastembed.clone()))
    .then_transform_query(query_transformers::SparseEmbed::from_client(fastembed_sparse.clone()))
    .then_retrieve(qdrant.clone())
    .then_answer(answers::Simple::from_client(openai.clone()));

    let answer = query_pipeline
        .query("What are the different pipelines in Swiftide and how do they work?")
        .await
        .unwrap();

    println!("{}", answer.answer());
}

Further reading

Was this page useful?

Thank you for your feedback! 🙏

We are sorry to hear that. 😔 You can edit this page on GitHub, or create a GitHub issue.