跳到正文
GitHub·· 3 小时前AI 评分60

Swiftide 开源 Rust 框架,提供智能体、类型化任务图与 RAG 流水线

bosun-ai/swiftide

AI 导读

bosun-ai 开源 Swiftide,一个用 Rust 构建 LLM 应用的框架,包含智能体运行循环、类型化任务图和流式 RAG 索引与查询流水线。智能体支持函数工具、生命周期钩子、MCP 工具箱和人工审批,任务图在编译期强类型并支持并行分支与暂停恢复。

正文

CI Coverage Status Crate Badge Docs Badge Contributors Stargazers Discord MIT License LinkedIn

Swiftide is an opinionated framework for building LLM applications. It gives you an agent harness, typed task graphs for orchestration, and streaming, composable indexing/query pipelines for RAG.

Swiftide composition overview

Table of Contents

Why Swiftide

  • Build agents that loop over LLM calls, tool calls, lifecycle hooks, and stop conditions.
  • Compose prompt steps, agents, command executors, and domain-specific Rust code in typed task graphs.
  • Fan out work into parallel branches and join typed results back into one task output.
  • Pause and resume agents or tasks for human approval, external callbacks, or persisted state.
  • Bring tools from local Rust functions, custom Tool implementations, or MCP servers.
  • Stream large indexing and retrieval workloads through loaders, transformers, embedders, caches, and storage backends.
  • Trace agent, task, and pipeline execution with tracing, metrics, and Langfuse support.

The core primitives provide the shared interaction model. Around them, use pipelines for data flows, agents for tool loops, and tasks for graphs of typed hand-offs.

Quick Start

Swiftide keeps default dependencies light. Start with the agent harness and add the integrations your application needs.

cargo add swiftide --features swiftide-agents,openai
cargo add anyhow
cargo add tokio --features macros,rt-multi-thread

If using OpenAI, set the API key expected by the OpenAI-compatible integration:

export OPENAI_API_KEY=...

Agent Harness

Use the agent harness to call a model, run tools, and control when an agent stops. Add tools as Rust functions or Tool implementations, and use hooks to run logic during the agent lifecycle.

AgentContext manages conversation history and gives tools access to a ToolExecutor. Use the local executor or run commands in an isolated environment with the Docker executor.

use anyhow::Result;
use swiftide::{
    agents,
    chat_completion::{ToolOutput, errors::ToolError},
    traits::AgentContext,
};

#[swiftide::tool(
    description = "Looks up a Swiftide concept",
    param(name = "concept", description = "Concept to explain")
)]
async fn explain_concept(
    _context: &dyn AgentContext,
    concept: &str,
) -> Result<ToolOutput, ToolError> {
    let explanation = match concept {
        "tasks" => "Tasks compose typed nodes into explicit workflows.",
        "agents" => "Agents run LLM completions, tools, hooks, and stop conditions.",
        "pipelines" => "Pipelines stream data through indexing and retrieval steps.",
        _ => "Swiftide composes agents, task graphs, tools, and RAG pipelines.",
    };

    Ok(explanation.into())
}

#[tokio::main]
async fn main() -> Result<()> {
    let openai = swiftide::integrations::openai::OpenAI::builder()
        .default_prompt_model("gpt-4o-mini")
        .build()?;

    agents::Agent::builder()
        .llm(&openai)
        .tools([explain_concept()])
        .on_new_message(|_, message| {
            println!("{message}");
            Box::pin(async { Ok(()) })
        })
        .limit(8)
        .build()?
        .query("Explain Swiftide tasks and agents in one paragraph.")
        .await?;

    Ok(())
}

The agent calls the model, exposes explain_concept as a tool, prints new messages, and stops within the configured turn limit. By default all agents have a tool to stop the loop. This can be customized.

Agent capabilities include:

  • function tools through #[swiftide::tool], derived tools, or manual Tool implementations
  • lifecycle hooks before and after completions, tools, messages, streaming chunks, start, and stop
  • local or custom ToolExecutor implementations for command/file access
  • human-in-the-loop approval via ApprovalRequired and feedback-aware contexts
  • structured stop and failure payloads with custom JSON schemas
  • MCP toolboxes that load tools at runtime
  • streaming responses and reasoning-item handling for providers that support them

Start with examples/hello_agents.rs, then look at the human approval, MCP, streaming, resume, and structured-output examples.

Agent Tools and Hooks

Use swiftide-agents-contrib to add file tools, plans, context hooks, and lazy executors to your agents. Choose the features you need and register the components on your agent.

Feature on swiftide What it provides
agents-contrib-file-tools Read file pages or selected lines with ReadFile, replace text with ExactReplace, and edit files with ApplyPatch.
agents-contrib-planning Track steps and progress with UpdatePlan.
agents-contrib-context Shorten large tool outputs with ToolSummarizer and summarize long conversations with ContextCompression.
agents-contrib-lazy-executor Start an executor when the agent first needs it with LazyExecutor.
cargo add swiftide --features agents-contrib-file-tools,agents-contrib-planning

Import components from swiftide::agents_contrib, for example swiftide::agents_contrib::tools::ReadFile registers read_file; add .with_line_numbers() for read_file_with_line_numbers. Both accept file_name, optional one-based offset, and optional limit. Reads default to 2,000 lines, truncate long lines at 2,000 characters, and refuse windows above the 100,000-character budget. Partial pages explain how to continue. Contrib features are off by default. See the crate guide for examples, defaults, and the features to use when depending on the contrib crate directly.

Typed Task Graphs

Tasks are Swiftide's orchestration layer. A task is a typed graph of TaskNode steps. Each node has an input type, output type, and error type; transitions decide where the output goes next.

Tasks are strongly typed at build time. It allows you to compose agents, other swiftide components, and functions to create complex automations.

From examples/tasks.rs.

use swiftide::{
    prompt::Prompt,
    tasks::{Task, TaskRunOutcome, Transition},
    traits::SimplePrompt,
};
use std::sync::Arc;

let prompt_model: Arc<dyn SimplePrompt> = Arc::new(openai.clone());
let briefing_agent = BriefingAgent::new(agent);
let mut task: Task<Prompt, String> = Task::new();

let brief = task.register_node(prompt_model.clone());
let decide = task.register_node(briefing_agent);
let render = task.register_node(prompt_model);

task.starts_with(brief);
task.register_transition(brief, move |short_brief| {
    decide.transitions_with(short_brief)
})?;
task.register_transition(decide, move |decision: BriefingDecision| {
    Transition::next(
        &render,
        Prompt::from("Write a hand-off note for {{audience}}: {{summary}}")
            .with_context_value("audience", decision.audience)
            .with_context_value("summary", decision.summary),
    )
})?;
task.register_transition(render, task.transitions_to_finish())?;

match task.run(Prompt::from("Summarize the rollout plan")).await? {
    TaskRunOutcome::Completed(note) => println!("{note}"),
    TaskRunOutcome::Paused => println!("Task paused"),
}

Task capabilities include:

  • closure nodes for small glue steps and TaskNode implementations for domain logic
  • typed NodeId handles, transitions, and join payloads
  • static fan-out with explicit joins
  • sequential or parallel branch execution
  • pause, resume, and reset support
  • adapters for prompt-like Swiftide primitives, chat completions, and tool executors
  • TaskAgent for the simple case where an agent should run as a task node

See examples/tasks.rs for a prompt plus custom agent workflow, and examples/tasks_fanout.rs for fan-out and join.

RAG Pipelines

Swiftide includes first-class indexing and querying pipelines for retrieval-augmented generation. Pipelines are streaming and composable: load data, transform it, embed it, cache it, store it, then retrieve and answer with a typed query flow.

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

async fn index(openai: swiftide::integrations::openai::OpenAI) -> anyhow::Result<()> {
    let qdrant = Qdrant::builder()
        .collection_name("swiftide-code")
        .vector_size(1536)
        .batch_size(50)
        .build()?;

    indexing::Pipeline::from_loader(FileLoader::new(".").with_extensions(&["rs"]))
        .with_default_llm_client(openai.clone())
        .then_chunk(ChunkCode::try_for_language_and_chunk_size("rust", 10..2048)?)
        .then(MetadataQACode::default())
        .then_in_batch(Embed::new(openai))
        .then_store_with(qdrant)
        .run()
        .await?;

    Ok(())
}

Indexing supports loaders, caches, chunkers, transformers, batch transformers, embedders, and storage backends. Query pipelines support query transformation, retrieval, response transformation, answer generation, hybrid search, reranking patterns, and evaluation.

Integrations

Swiftide integrations are feature-gated so application builds stay intentional.

Area Supported integrations
LLM providers OpenAI and Azure OpenAI, Anthropic, Gemini, OpenRouter, AWS Bedrock Converse API, Groq, Ollama, Dashscope
Tooling MCP toolboxes, local command execution, custom tool executors
Storage and retrieval Qdrant, Redis, LanceDB, PgVector, DuckDB, Redb
Loading data Files, scraping, Fluvio, Kafka, Parquet, executor-backed file streams
Code and text processing Markdown, text splitting, tree-sitter code chunking and metadata
Observability tracing, metrics, Langfuse

Examples

The examples has a variety of examples.

More background is available on the Bosun blog, including posts about tasks, streaming agents, human-in-the-loop flows, and Rust performance for AI tools.

Project Status

Swiftide is pre-1.0. APIs can change while the agent harness and task graph APIs settle around production use. The current API docs and examples are the most reliable source of exact signatures.

Swiftide is part of the bosun.ai project.

Contributing

Contributions are welcome. Read CONTRIBUTING.md, open an issue for design discussion, file a bug report, or propose a feature. Join the Discord for a faster feedback loop.

Before opening a pull request:

  1. Run the focused checks for the crates you changed.
  2. Run cargo +nightly fmt --all -- --check.
  3. Run cargo clippy --workspace --all-targets --all-features -- -D warnings when touching shared behavior.
  4. Add or update examples, tests, or rustdoc when behavior changes.

AI-generated code is welcome and should be reviewed like any other code. Keep abstractions small, keep domain logic separate from plumbing, and pay attention to allocations in indexing, querying, and task execution paths.

AI agents can refer to AGENTS.md for workspace layout, commands, and expectations.

Core Team Members

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

来源:GitHub · github.com