A Rust framework for building LLM applications with support for 8+ LLM providers, agents, RAG, BM25/hybrid search, LangGraph workflows, and multiple vector/document storage backends.
Rust
14
34 commits
updated Sep 16, 2026
A LangChain-inspired Rust framework for building LLM applications.
What it solves: Build Agents, RAG, BM25 keyword search, Hybrid retrieval, LangGraph workflows, MCP tools, A2A agent-to-agent protocols, Guardrails, multi-agent Handoffs — all in pure Rust.
The framework is engineered around a few hard rules that come out of its own design reviews. These are what make it feel different from hand-rolled LLM glue code:
| Principle | What it means in practice |
|---|---|
| Explicit over silent | No silent degradation. If an API promises X, it either delivers X or fails loudly. Batch-embedding alignment returns explicit errors instead of empty/shifted vectors; the keyword fallback for EmbeddingMatcher was removed; routing failures surface as errors, not swallowed Err(_) => {}. |
| Consumed or deleted abstractions | Every trait either has real implementors or is removed. BaseChatMemory is now implemented by all four memories, all retrievers implement RetrieverTrait, and PairwiseJudge plugs into the unified Evaluator pipeline — so users write against one abstraction, not five ad-hoc names. |
| Structured output over text parsing | Models that support tool_calls go through structured output (JSON schema / function calling). Regex-parsing model output is the last resort, not the default — it is the most common source of silent fragility. |
| Production hardening first | Tool execution has timeouts, LLM calls retry with exponential backoff, agent loops are capped (max_iterations clamped to [1, 100]), parallel actions are concurrency-limited, and CancellationToken propagates through every runnable. Eliminate the deterministic failure paths before adding features. |
| Type system enforces safety | Security properties live in types, not comments. Guardrails split InputGuardrailResult / OutputGuardrailResult so "Modify only applies to output" is enforced at compile time. |
| Composition first | Everything can be piped. Since v0.16.0, prompts, memory, native providers, parsers and RAG are all Runnable — prompt.pipe(llm).pipe(parser) compiles and runs. |
| Honest implementations | No fake backends. Empty-shell sandboxes (Wasm/E2B) were deleted; unsupported operations (e.g. Pinecone fetch-by-ID) return explicit StorageErrors instead of pretending to work. |
| Component | Description |
|---|---|
| Unified LLM access | 11 providers behind one BaseChatModel trait: OpenAI, Ollama, Anthropic Claude, Gemini, Azure, Cohere, DeepSeek, Qwen, Moonshot, Zhipu, Mistral. LLMClient::from_env() auto-detects any of the 11 from environment variables. |
| OpenAI-compatible endpoint (v0.22.4) | One generic OpenAICompatibleChat covers any base_url endpoint — keyless vLLM / LM Studio / SGLang / Ollama / internal gateways (no Authorization header is sent without a key), with GroqChat / OpenRouterChat / XaiChat presets, env constructors and extra_headers. |
| OpenAI-compatible thin wrappers | DeepSeek / Qwen / Moonshot / Zhipu / Mistral reuse the OpenAI request path; each keeps its own error variant (ProviderError::DeepSeek, etc.) so you can tell which vendor failed. New vendors are cheap to add. |
| Chat & Streaming | chat() (one full reply) and stream_chat() (first token in ~1s). Streaming chunks carry token usage (StreamChunk), so budget gates get real usage on the streaming path (v0.18). config.streaming = true makes chat() stream internally then aggregate. |
| Function Calling | bind_tools() + result.tool_calls, the native path for tool-capable models. |
| Multimodal Vision | Message::human_with_image / human_with_audio / human_with_file via schema ImageContent / AudioContent / FileContent. |
| Thinking models | Reasoning is kept in LLMResult.thinking_content and never leaked into content (DeepSeek-R1, GLM-5.2, Claude Extended Thinking). |
| OpenAI Assistants API | Stateful assistants with requires_action tool dispatch. |
| OpenAI Responses API | Typed Responses-endpoint client (openai/responses/, ~1.4k lines): web_search / file_search / code-interpreter tooling. Chat Completions remains the portable default. |
| Anthropic Extended Thinking | with_thinking for Claude reasoning. |
| Model Routing | RouterLLM with 6 strategies — Fallback / RoundRobin / LeastLatency / LatencyWeighted(beta) (EMA-latency weighted draw, deterministic SplitMix64) / LowestCost (registry-priced, blended 0.75-in/0.25-out) / InputDirected — plus per-slot ModelRateLimit admission and a shared RouterBudget USD circuit breaker (v0.22.4). Remaining models always act as fallback. |
| Cost & budgets (v0.22.4) | ModelPrice / PricingTable / shared CostTracker (run/session scopes, unknown models bill $0 and never break the loop), JSON-fetchable ModelRegistry of capabilities/prices, agent-level BudgetConfig.max_cost_usd hard gate on both invoke and stream paths, costs exported as ObsEvent::Cost. |
| Batch API | BatchClient for OpenAI / Anthropic batch inference (~50% cost reduction). |
| LLM Cache | LLMCache with TTL + true LRU eviction (hits refresh recency). |
| Structured Output | with_structured_output + StructuredOutputExt trait, JsonOutputParser fallback, and streaming structured output via PartialJsonParser. |
| Native JSON Schema (v0.21) | OpenAIChat::with_json_schema_output::<T>() sends response_format: {type: "json_schema"} (strict mode) generated from schemars 1.0 — schema-constrained decoding on the provider side; make_strict_schema enforces additionalProperties: false + full required. with_structured_output remains the portable path. |
| Token Counter | TiktokenCounter (precise) / CharRatioCounter (Chinese-friendly estimate) + TokenTrackingLLM usage stats + ModelPricing cost estimation. |
| Component | Description |
|---|---|
Unified Embeddings trait | embed_query / embed_documents / dimension / model_name, with empty-input and batch-alignment checks enforced in the trait default path. |
| Providers | OpenAI (ada-002 / 3-small / 3-large), DeepSeek, Qwen, Cohere (embed-v3.0, 4 input types), FastEmbed (local ONNX), Mock (deterministic, for tests), BagOfWords (local, always available). |
| Qwen3-Embedding (v0.21) | qwen3-embedding-0.6b / 4b / 8b (dims 1024 / 2560 / 4096) + matryoshka output via QwenEmbeddingsConfig::with_dimensions(32..=4096); the configured dimensions is passed through to the DashScope request. |
| Reliability | Exponential-backoff retries (429/5xx, max 3, 4xx not retried) with jitter and Retry-After header support (v0.21), concurrent batching (OpenAI: 2048 docs/batch, concurrency 8), and unified normalization so downstream similarity is provider-independent. |
| Local ONNX | LocalEmbeddings via the local-embeddings feature (ort). |
| Token-level embeddings (v0.21) | Optional TokenLevelEmbeddings capability trait (native async fn, statically dispatched): embed_tokens returns per-token TokenEmbedding { span, vector } with byte-offset spans. Local ONNX path shares the fastembed pipeline. |
| Late chunking (v0.21, end-to-end in v0.23) | late_chunk(&embedder, text, &LateChunkConfig) embeds the whole text once at token level, then mean-pools token vectors per chunk range into L2-normalized chunk vectors — better context retention than chunk-then-embed for long documents. late_index_in(&vector_store, &embedder, parent_key, text, &config) (v0.23) closes the loop: one token-level pass → pooled chunks → straight into any VectorStore, with deterministic {parent}:{index} ids. Runnable offline demo: cargo run -p lc-rag --example late_chunking. |
| Candle backend (v0.21) | CandleEmbeddings via the local-candle feature: pure-Rust CPU inference for BERT-family models (from_hf_hub("BAAI/bge-small-en-v1.5") or from_dir), masked mean-pooling, batch size 16. |
| Vision embeddings (v0.22.4) | VisionEmbeddings trait maps (text/image) into one shared vector space: Cohere Embed v4 (CohereVisionEmbeddings, 1536-d) and DashScope multimodal-embedding-v1 (QwenVisionEmbeddings, 1024-d), plus MockVisionEmbeddings for tests. Feeds multimodal RAG (see below). |
| Component | Description |
|---|---|
| LCEL | Runnable with four base actions — invoke / batch / stream / transform. Operators: pipe, RunnableLambda, RunnablePassthrough, RunnableParallel, RunnableBranch, RunnableBinding, RunnableWithFallbacks, RunnableAssign, with_retry, RunnableSequence. Type-erased with PhantomData — dynamic composition with compiler-checked type matches. |
| Unified composition (v0.15) | Prompts, memory, native providers, parsers and RAG are all Runnable: prompt.pipe(llm).pipe(StrOutputParser) — no glue code. RunnableWithMessageHistory wraps "LLM + memory" as one runnable (auto read history → invoke → write back). RagRunnable makes retrieval-augmented generation one link of a chain. Native OpenAIChat/QwenChat/DeepSeekChat errors are unified into LcelError. |
| Chains | BaseChain with 9 implementations: LLMChain, ConversationChain, SequentialChain, RouterChain, LLMRouterChain, RetrievalQA, ConversationRetrievalChain, plus the 4 document chains — Stuff / MapReduce / Refine / MapRerank. Chain streaming per token, ChainRunnable bridges chains into LCEL. |
| Prompts | PromptTemplate (parsed once, cached segments), ChatPromptTemplate (Runnable, outputs Vec<Message>), FewShotPromptTemplate + ExampleSelectors (LengthBasedExampleSelector). {{/}} escapes, Chinese variable names, missing variables error loudly. v0.22.4 adds PromptRegistry — versioned, named prompt storage with render-by-name and fallback, so prompt text is managed centrally instead of scattered through call sites. |
| Output Parsers | StrOutputParser, JsonOutputParser, CommaSeparatedListOutputParser, StructuredOutputParser, TypedOutputParser<T> — all tolerant of dirty model output (markdown fences, trailing commas, trailing junk). |
| Retrieval & Sessions in LCEL (v0.17) | RetrieverRunnable wraps any retriever as Runnable<String, Vec<Document>>; SessionManagerRunnable wraps persistent sessions as Runnable<(session_id, message), reply> — both compose with pipe into a chain. |
| Cancellation | CancellationToken threads through RunnableConfig into every execution. |
| Component | Description |
|---|---|
| BaseAgent / AgentExecutor | The "translator / butler" split: BaseAgent turns model output into a decision (Action / Actions / Finish), AgentExecutor is the one real loop — with tool timeouts, LLM retries, concurrency semaphore, and max_iterations clamped to [1, 100]. |
| FunctionCallingAgent | Recommended path — reads native tool_calls (requires model support). |
| ReActAgent | Text-regex thought/action loop, fallback for models without tool-calling. |
| Plan-Execute | Planner → per-step executor → replan on failure; the executor factory is configurable (no longer hardcoded to function calling). |
| DeepResearch | Multi-round research agent with sub-topic decomposition, parallel search, dedup, citation reporting. |
| RAG Agents | CorrectiveRAGAgent (self-correcting grade/rewrite/detect), AdaptiveRAG (LLM-routed retrieval), as standalone graphs. |
| Handoffs | Multi-agent handoff with max_handoff_depth (default 10) to stop A↔B ping-pong. |
| Orchestrators | Supervisor (v0.24.0 — one router LLM delegates each round to a named sub-agent or FINISH, with scratchpad feedback and a bounded-rounds one-level recursion guard), FanOutFanIn (parallel fan-out + aggregate), SequentialPipeline (serial), OrchestratorRunnable for LCEL integration. |
| Parallel tool calls (v0.24.0) | Multiple tool calls emitted in one model turn run concurrently, bounded by .with_max_concurrency(n) (default 8); observations zip back to actions in the model's call order on both invoke and stream paths. |
| Agent Hooks | Approval (on_before_tool_call allow/reject/skip), PromptInjectionHook, TokenBudgetHook, ContentFilterHook, logging. |
| Agent Gates (v0.16) | Async human-approval gate — .with_approval() (Allow / Deny / Modify; Deny feeds the reason back as an observation, Modify rewrites the arguments). Budget gate — .with_budget() with hard caps on tool calls / tokens / wall-clock duration / iterations, exceeding returns AgentError::BudgetExceeded. Both default off. |
| Cross-process resume (v0.18) | FileResumeStore persists the pending human-approval / budget-gate state to disk (atomic write); a restarted executor loads the pending point and re-enters approval instead of restarting the agent loop. |
| Context compaction (v0.21) | .with_compaction(CompactionConfig) — trigger on TurnCount / TokenCount / Any / All, compact with SlidingWindow or TokenBudget (turn-boundary truncation, no orphan tool results, min_recent_turns floor, default 2). Off by default; compaction count lands in AgentMetrics.compactions. |
| Streaming | Token-level streaming via StreamingFunctionCallingAgent + AgentStreamEvent; tool-level events via AgentExecutor::stream. |
| Web SSE (v0.22.4) | Optional axum SSE endpoint in lc-agents (sse-server feature) serving AgentStreamEvents to browsers — see the agent_sse_server example. |
| Durable checkpoints (v0.22.4) | LangGraph persistence gains three production backends behind checkpoint-sqlite (rusqlite bundled, WAL) / checkpoint-postgres (tokio-postgres) / checkpoint-redis (Lua CAS) features. Optimistic concurrency: stale writes return GraphError::CheckpointVersionConflict instead of last-write-wins. |
| Two-layer semantic memory (v0.22.4) | Episodic layer (raw per-turn observations, vector-retrieved) + semantic layer (LLM-consolidated, deduped facts) with an async background extractor — the agent accumulates durable knowledge across sessions instead of only replaying recent chat. |
| Dynamic interrupt/resume + time travel (v0.24.0) | InterruptibleNode suspends inside a node — its closure runs with resume: None, raises an InterruptRequest payload into the checkpoint, then re-enters with resume: Some(decision) via CompiledGraph::resume_with_value (even from a fresh process over a durable checkpointer; NodeInterrupt/Resumed stream events). Agent approvals converge on this one path: ApprovalGate + ApprovalDecision (Allow / Deny / Modify), so the gated tool executes exactly once and Deny performs no side effect; the non-graph ResumeStore remains for the plain executor. get_state_history() lists CheckpointInfos and fork_from(checkpoint, node, override_state) branches a new forward-only lineage off any past state. |
| Tool Policies | ToolPolicy / ToolRisk risk classification for tool access control. |
| Component | Description |
|---|---|
Unified RetrieverTrait | All retrievers implement it: SimilarityRetriever, BM25Retriever / ChunkedBM25Retriever, UnifiedHybridIndex, ParentDocumentRetriever — so any retrieval strategy plugs into the RAG pipeline. |
| RAGPipeline | RAGPipelineBuilder (llm + embeddings + vector store + retriever) → index_documents / query / query_with_sources (citation tracing). |
| Document Loaders | Text / JSON / Markdown / PDF / CSV / HTML + WebScraper / Sitemap / Docx. |
| Splitting | RecursiveCharacterSplitter (paragraph → line → sentence → char), SemanticSplitter (async semantic chunking). |
| BM25 | Keyword search with Chinese/English tokenization, ChunkedBM25Retriever parent-child structure, AutoMerging. |
| Hybrid | UnifiedHybridIndex — BM25 + vector with RRF (default) or FusionMode::Weighted linear fusion (v0.23.0), configurable min_score, plus retrieve_mmr(query, cand_k, k, λ) MMR diversity re-ranking over the fused pool (v0.23.0; standalone mmr() over (id, score, embedding) triples too). |
| Neural reranking (v0.24.0) | Hosted cross-encoders behind one AsyncReranker trait: CohereRerank (default rerank-multilingual-v3.0) and JinaRerank, driven by rerank_async(&reranker, query, results, top_n). The provider's out-of-order results[].index is mapped back to your input positions, clients bypass ambient proxies, and malformed bodies error instead of silently returning unsorted input. |
| Small-to-big retrieval (v0.24.0) | SentenceWindowRetriever — index single sentences, retrieve a deduplicated ±N-sentence window — and the public ParentDocumentRetriever — leaf-chunk hits return the entire parent document, combining precise recall with full-context answering. |
| Late-chunk dual-leg injection (v0.24.0) | UnifiedHybridIndex::add_late_chunked_document(doc, &[LateChunk]) writes token-pooled chunks to BOTH the vector index and the BM25/parent store in one call, with deterministic {parent}::{segment} ids (re-registering a parent idempotently replaces its chunk set). |
| Query Transformations | MultiQueryRetriever (decompose into multiple queries), HyDERetriever (hypothetical document), RerankingExecutor + KeywordReranker / BM25Reranker. |
| SelfQueryRetriever (v0.18) | LLM splits a natural-language query into {query, filter} via structured call, with an allowed_attributes whitelist; retrieves through similarity_search_with_filter. Composes in LCEL as a RetrieverRunnable. |
| GraphRAG | Knowledge-graph RAG with Global / Local / Hybrid modes, entity extraction, community detection. Community detection is Leiden (v0.22.4: configurable leiden_resolution / leiden_seed / max_community_levels). |
| Multimodal RAG (v0.22.4) | MultimodalChunker splits mixed text/image documents and embeds both modalities through VisionEmbeddings; MultimodalRetriever returns cross-modal hits so image content is answerable, not just text. |
| Advanced RAG | CorrectiveRAG (self-correcting), AdaptiveRAG (adaptive retrieval + structured routing decisions). |
| Contextual Retrieval (v0.21) | ContextualEnhancer — index-time transform: a small LLM writes a 1-2 sentence context per chunk, prepended to the content (original stored in metadata under contextual_context). Concurrency-limited, idempotent, fail-open (on LLM failure the original text is indexed). |
| Semantic Cache (v0.21) | CachedRetriever wraps any RetrieverTrait — exact-match hits skip the embedder entirely; otherwise a cosine-similarity lookup over cached query vectors (threshold default 0.95, FIFO max_entries 256, optional TTL, invalidate() for corpus updates). |
| Native Hybrid Search (v0.21) | NativeHybridSearch capability on QdrantVectorStore (Query API, server-side fusion, needs Qdrant ≥ 1.10): multi-branch NativeHybridQuery with FusionMethod::Rrf / Dbsf in a single round trip. Stores without the capability fail explicitly instead of silently degrading to client-side RRF. |
| Component | Description |
|---|---|
| Four memories | ConversationBufferMemory (full), ConversationBufferWindowMemory (last k turns), ConversationSummaryMemory (LLM summary), ConversationSummaryBufferMemory (summary + recent raw). All implement BaseChatMemory. |
| Semantic memory | VectorStoreRetrieverMemory — retrieval by similarity, not recency. |
| Context window | ContextWindow with Truncate / Summarize strategies and pluggable TokenCounter; System messages are always preserved. |
| Persistence | MongoPersistentMemory (feature-gated) — generic over BaseChatModel, optimistic-lock concurrent writes, session-resume summary re-injection. |
| Sessions | EventSessionManager / EventStore (v0.22.0, recommended) — event sourcing: the session is an append-only log, history is a projection; crash-safe idempotent appends, fork_session branching from any point, turn-window context, deterministic auto-compaction (snapshot past N turns, no LLM call). Legacy SessionManager / SessionStore deprecated (removed 0.23.0). |
| Component | Description |
|---|---|
| Official MCP transports (v0.22.4) | Spec-faithful clients StdioMcpClient (subprocess stdio) and StreamableMcpClient (Streamable HTTP, stateless + Mcp-Session-Id modes), and server side MCPServer::serve_streamable_http — interoperability-verified against the official TypeScript SDK 1.30.0 and Python SDK (4/4 scenarios). Includes OAuth 2.1 authorization flow (authorization server metadata, PKCE, token refresh) for remote servers requiring login. |
| MCP stateless track (v0.22.0) | 2026-07-28 single-track model: every request is a self-contained JSON-RPC HTTP POST — no handshake, no session. StatelessMcpClient carries _meta (protocol version + client identity + optional requestState), tagged with Mcp-Method / Mcp-Name routing headers so gateways route and throttle without parsing the body. The legacy handshake client (MCPClient, SSE/old-HTTP transports, streaming push) was removed in 0.22.0. |
| MCP MRTR | Multi-round tool requests: on input_required { requestState, questions } the client collects answers (MrtrAnswerProvider) and resends with the continuation token, bounded by max_round_trips (-32003 on exceed). Server-initiated interaction without a push channel. |
| MCP auth | OAuth 2.1-style: TokenValidator + StaticBearerValidator / JwtIssValidator (iss + exp) server-side; per-request bearer auth client-side (connect_with_auth); 401 → -32001. |
| MCP server | MCPServer exposes local BaseTools — in-process (handle_request), as a deployable stateless HTTP service (serve_http, example mcp_http_server), or over stdio line framing for hosts like Claude Desktop / Cursor (serve_stdio). server/discover for capability queries. |
| MCP at scale | Connection management, tool namespaces + conflict policy, static+dynamic tool discovery, per-tool timeout with hard cap, health checks + circuit breaker, per-server sandbox, sampling recursion guard, MCP Gateway (registry / pool / rate-limit / audit), multi-tenant isolation, per-method client rate limiting. |
| MCP tool adapter | MCPToolAdapter implements BaseTool — MCP tools mix seamlessly with local tools in any agent; structured errors keep {code, data}; multi-type content (image/resource) preserved. |
| A2A v1.0.1 | Agent-to-Agent protocol: AgentCard with supportedInterfaces[] — one card declares multiple (protocolVersion, transport, url) bindings (JsonRpc / HttpJson / Grpc), tenant-tagged, with client-side negotiate(). Card signing (RFC 8785-lite canonicalization + JWS HS256) protects discovery from tampering. send_task / get_task / cancel_task over HTTP. |
| A2A vs MCP | A2A orchestrates agent ↔ agent; MCP lets an agent call tools. They compose: A2A between agents, MCP below them. |
| Component | Description |
|---|---|
| Guardrails | Input/output safety rails around any agent or chain. InputGuardrailResult (Pass/Block) and OutputGuardrailResult (Pass/Block/Modify) are type-separated — Modify is compile-time impossible on input. Guardable trait lets you wrap any BaseChain. |
| Built-in guardrails | SensitiveInfoGuardrail (keywords + OpenAI-key regex + email + credit-card with Luhn check), ForbiddenWordsGuardrail, MaxLengthGuardrail. v0.22.4 adds PiiRedactionGuardrail (detect/redact PII on output) and SchemaOutputGuardrail (validate structured output against a JSON schema; fail → repair or block). |
| RAGAS evaluation (v0.22.4) | Reference-free RAG metrics in lc-evaluation: ContextPrecision, ContextRecall, AnswerRelevancy — runnable through the same EvalRunner/Report path. |
| Streaming guardrails | Two-phase: incremental keyword check (24-char sliding window) + full-output re-check. |
| Audit | AuditSink trait + FileAuditSink (JSON Lines) for violation persistence; LLM-sensitive judge for context-aware decisions. |
| GuardedAgent | Wrap an executor/chain → validate input → run → validate output; a blocked input never touches the network. |
| Retrieval Rail (v0.21) | RetrievalRail batch-scans retrieved documents for prompt injection (pattern library shared with PromptInjectionHook); GuardedRetriever wraps any RetrieverTrait with RailAction::Flag (default, tags metadata) / Redact / Drop + RailReport counts and optional audit sink. Place it inside CachedRetriever so only clean results enter the cache. |
| AI Disclosure (v0.21) | disclose() records an EU AI Act Art. 50-style transparency notice ("you are interacting with an AI system") through an AuditSink; template customizable via DisclosureConfig::with_statement with a {system} placeholder. Capability, not enforcement. |
| Evaluation | 10+ evaluators: ExactMatch, ContainsKeyword, RegexMatch, LengthCheck, Bleu, StringDistance, EmbeddingSimilarity, LLMAsJudge, PairwiseJudge, Faithfulness. EvalRunner batches all examples × all evaluators into a Report. |
| Trace → golden → compare (v0.24.0) | The lc-testkit record/replay harness now feeds evaluation: recordings sink into a golden Dataset (last user message → input, response → reference, tool results → RAG contexts) with a zero-network ReplayPredictor, and lc-evaluation::compare_reports(&baseline, &candidate, tolerance) gates any mean dropping by more than the tolerance (boundary inclusive), listing per-metric deltas and added/dropped evaluators. |
| LLM judge | StructuredJudge shared with guardrails — prefers structured output, tolerant score parsing. |
| Callbacks | CallbackHandler (3 lifecycle methods minimum) + CallbackManager dispatcher. Built-in: StdOutHandler, FileCallbackHandler, LangSmithHandler, OtelHandler. |
| Tracing | Tracer + SpanGuard (RAII), InMemory / Console / OTel backends, parent-child span tree, GenAI Semantic Conventions. OTel spans carry gen_ai.* attributes aligned with the OpenTelemetry GenAI semconv (v0.21): gen_ai.system / gen_ai.request.model / gen_ai.response.finish_reason / token usage incl. cache-read and reasoning extensions, plus gen_ai.operation.name = "retrieve" for retrieval spans. |
| Component | Description |
|---|---|
| Built-in tools | Calculator, SimpleMathTool, DateTimeTool, URLFetchTool, WikipediaTool, DuckDuckGoSearchTool, PythonREPLTool. |
| Hosted search & browser (v0.22.4) | HostedSearchTool with Tavily / Serper / Exa backends (API key from env, one uniform tool interface — no scraping fragility). CdpBrowserTool drives a real Chrome over the DevTools Protocol (navigate/click/fill/extract) behind the browser-cdp feature for pages that require JavaScript execution. |
#[tool] macro | Define a tool from a plain function — auto-converted to BaseTool; StructuredTool gives typed in/out with automatic JSON. |
| Sandbox | SandboxTool + LocalSandbox (subprocess + timeout). Tool-code execution is isolated — the Python blacklist is documented as noise filtering, not a security boundary. |
| Extended tools | HTTPTool, FileTool (sandboxed), SQLTool (read-only, sqlite-storage feature), ComputerUseTool (screen interaction). |
| Security | SSRF protection (is_private_ip) on URL/HTTP tools with per-hop DNS resolution, all-answers validation, and IP pinning that closes the DNS-rebinding TOCTOU window (v0.22.4); path sandboxing; risk classification via ToolPolicy. |
| Component | Description |
|---|---|
Unified VectorStore trait | add_documents, similarity_search, similarity_search_with_min_score, similarity_search_with_filter (MetadataFilter with Eq/Ne/Gt/Gte/Lt/Lte/In/Nin + And/Or, v0.18), similarity_search_text (auto-embeds if the store owns an embedder, else explicit error), embed_query, get_document, delete_document, count, clear. |
| Backends | InMemory, FileVectorStore (atomic write, fixed dim), ChunkedVectorStore (parent-child source retrieval), Qdrant, ChromaDB, LanceDB, Neo4j, Pinecone, Redis, MongoDB, SQLite, PGVector (typed PGVectorStore via the pgvector-storage feature). |
| Honest errors | VectorStoreError distinguishes DocumentNotFound / EmbeddingError / StorageError / ConnectionError; missing features fail loudly instead of silently degrading (e.g. Qdrant without the feature → ConnectionError, not in-memory fallback). |
langchainrust is a 23-crate workspace with a single facade crate langchainrust (in crates/lc) that re-exports the public API. Layers depend downward — lc-shared / lc-schema sit at the bottom and are depended on by everyone, which is exactly how the circular-dependency problem is solved.
┌──────────────────────────────────────┐
│ langchainrust (facade, crates/lc) │
└──────────────────┬───────────────────┘
│
┌──────────────┬───────────────────┼───────────────────┬──────────────┐
Protocol Quality Intelligence Composition Providers
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ lc-mcp │ │ lc-guardrails │ │ lc-agents │ │ lc-chains │ │ lc-providers │
│ lc-a2a │ │ lc-evaluation │ │ lc-rag │ │ lc-langgraph │ │ lc-embeddings │
│ │ │ lc-callbacks │ │ lc-vector-stores │ │ │ │ lc-prompts │
│ │ │ lc-observability │ │ │ │ │ │ lc-tools │
└─────────┬──────────┘ └──────────┬─────────┘ └──────────┬─────────┘ └──────────┬─────────┘ └──────────┬─────────┘
└───────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘
│
┌─────────────────────────────────┴──────────────────────────────────────┐
│ Core & Foundation │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐ │
│ │ lc-core │ │ lc-schema│ │ lc-shared │ │
│ │ Runnable │ │ Message │ │ Document / ToolCall / │ │
│ │ LCEL │ │ types │ │ TextSplitter │ │
│ └──────────┘ └──────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
(lc-memory, lc-sessions, lc-testkit and lc-tools-derive are omitted from the diagram for clarity; the crate table below lists all 23.)
| Crate | Role |
|---|---|
| lc-core | Execution layer: Runnable / LCEL operators, BaseChatModel/BaseLanguageModel, BaseTool/ToolRegistry, output parsers, structured output, token counter, LLMCache, RouterLLM (+ ModelRegistry pricing/capabilities, ModelRateLimit, RouterBudget), cost ledger (CostTracker, ModelPrice, PricingTable, ObsEvent::Cost), CancellationToken, StructuredJudge, BatchClient, cosine_similarity. |
| lc-schema | Message (content + role + multimodal attachments), MessageType, ImageContent/AudioContent/FileContent. |
| lc-shared | Cross-crate foundation types: Document, VectorDocument, SearchResult, ChunkDocument, ToolCall/FunctionCall, TextSplitter — breaks the dependency cycle. |
| lc-providers | 11 LLM vendors behind BaseChatModel; LLMClient (auto-detect), ProviderError (per-vendor variants), ChatModelWrapper (error normalization for mixed routing). |
| lc-prompts | PromptTemplate, ChatPromptTemplate (Runnable), FewShotPromptTemplate, ExampleSelectors. |
| lc-tools | Built-in tool library + #[tool] proc macro (lc-tools-derive), sandbox. |
| lc-embeddings | Embeddings trait + 7 providers, retries, concurrency, normalization. |
| lc-chains | BaseChain + 9 chains, ChainRunnable bridge into LCEL. |
| lc-langgraph | StateGraph, conditional/FanOut/FanIn edges, Reducers, Checkpointer (memory/file + SQLite/Postgres/Redis durable backends, OCC conflict errors), GraphPersistence, Subgraph, dynamic injection; v0.24 adds in-node dynamic interrupt/resume (InterruptibleNode, resume_with_value), checkpoint snapshots() state history and fork_from time travel. |
| lc-agents | ReAct / FunctionCalling / PlanExecute / CRAG / AdaptiveRAG / DeepResearch / Handoffs / Orchestrators / Hooks + human-approval gate (ApprovalHandler) / budget gate (BudgetConfig); v0.24 adds the Supervisor sub-agent router, graph-path ApprovalGate (approval-as-interrupt convergence) and bounded parallel tool calls. |
| lc-memory | Buffer/Window/Summary/SummaryBuffer memories, ContextWindow, MongoPersistentMemory, two-layer semantic memory (episodic + consolidated facts, background extractor). |
| lc-sessions | EventSessionManager + EventStore event-sourced multi-turn lifecycle (recommended); legacy SessionManager/SessionStore deprecated. |
| lc-rag | RetrieverTrait (Similarity/BM25/UnifiedHybrid), RAGPipeline, MultiQuery/HyDE/Reranking, GraphRAG; v0.24 adds hosted neural rerankers (AsyncReranker Cohere/Jina), SentenceWindowRetriever / public ParentDocumentRetriever, and late-chunk dual-leg injection (MMR + weighted fusion landed in v0.23.0). |
| lc-vector-stores | VectorStore trait + InMemory/File/Chunked/Qdrant/ChromaDB/LanceDB/Neo4j/Pinecone/Redis/Mongo/SQLite/PGVector backends. |
| lc-mcp | MCP client/server: official stdio + Streamable HTTP transports (with OAuth 2.1), the framework's own stateless HTTP track, tool adapter, MRTR, Gateway. |
| lc-a2a | A2A protocol server/client. |
| lc-evaluation | Rule evaluators + LLM judges, EvalRunner + Report; v0.24 adds compare_reports baseline/candidate regression gating (ReportComparison, per-metric deltas, added/dropped evaluators). |
| lc-guardrails | Input/output guardrails, Guardable, streaming guardrails, audit sinks. |
| lc-callbacks | CallbackHandler/CallbackManager + StdOut/File/LangSmith/OTel + Tracer/SpanGuard. |
| lc-observability | MetricsSink / ObsEvent observation bus with JsonLinesSink (JSONL files) and MongoSink (behind observability-mongodb). |
| lc-testkit | Record/replay test harness: RecordingProvider records real LLM exchanges to JSONL, ReplayProvider replays them offline with zero network — framework tests run without API keys. Phase 2 (v0.17): tool definition recording (bind_tools), out-of-order replay (ReplayStrategy::{Fifo, ByToolName}), agent-level offline replay, and chain scenarios transcribed from online tests. Phase 3 (v0.18): strict message-signature replay (ReplayStrategy::Exact). Phase 4 (v0.24): trace → golden dataset bridge (golden_dataset, write_golden_jsonl, ReplayPredictor, replay_golden_from_file) closing the record→score→regression-gate loop. |
[dependencies]
langchainrust = "0.24.0"
tokio = { version = "1.0", features = ["full"] }
# Optional features — vector stores & storage
langchainrust = { version = "0.24.0", features = ["qdrant-integration"] } # Qdrant vector DB
langchainrust = { version = "0.24.0", features = ["mongodb-persistence"] } # MongoDB storage (memory + vector store + checkpoints)
langchainrust = { version = "0.24.0", features = ["redis-storage"] } # Redis vector store
langchainrust = { version = "0.24.0", features = ["sqlite-storage"] } # SQLite vector store (+ SQLTool)
langchainrust = { version = "0.24.0", features = ["pgvector-storage"] } # PGVector (requires user-configured sqlx/pgvector deps)
# Durable LangGraph checkpointers (v0.22.4)
langchainrust = { version = "0.24.0", features = ["checkpoint-sqlite"] } # rusqlite bundled, WAL — zero extra infra
langchainrust = { version = "0.24.0", features = ["checkpoint-postgres"] } # tokio-postgres
langchainrust = { version = "0.24.0", features = ["checkpoint-redis"] } # Redis with Lua CAS
# Local embeddings (vision/Cohere/Qwen multimodal embeddings need no feature)
langchainrust = { version = "0.24.0", features = ["local-embeddings"] } # Local ONNX embeddings (ort)
langchainrust = { version = "0.24.0", features = ["fastembed"] } # FastEmbed ONNX models
langchainrust = { version = "0.24.0", features = ["local-candle"] } # Pure-Rust Candle BERT embeddings
# Observability
langchainrust = { version = "0.24.0", features = ["opentelemetry"] } # OpenTelemetry tracing spans
langchainrust = { version = "0.24.0", features = ["otlp"] } # OTLP HTTP/JSON exporter (v0.22.4)
langchainrust = { version = "0.24.0", features = ["observability"] } # MetricsSink + JsonLinesSink (v0.22.4)
langchainrust = { version = "0.24.0", features = ["observability-mongodb"] } # MongoDB observation sink
# Tools & memory
langchainrust = { version = "0.24.0", features = ["browser-cdp"] } # CDP browser tool (v0.22.4)
langchainrust = { version = "0.24.0", features = ["vectorstore-memory"] } # VectorStoreRetrieverMemory (semantic memory)
langchainrust = { version = "0.24.0", features = ["experimental"] } # Experimental features
# PineconeStore / FileVectorStore / hosted search (Tavily, Serper, Exa) require no feature flag.
# The axum SSE agent endpoint is gated by lc-agents' own `sse-server` feature (see examples/agent_sse_server.rs).
Note on MSRV: Rust 1.85+ required.
use langchainrust::{OpenAIChat, OpenAIConfig, BaseChatModel};
use langchainrust::schema::Message;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = OpenAIConfig {
api_key: std::env::var("OPENAI_API_KEY")?,
base_url: "https://api.openai.com/v1".to_string(),
model: "gpt-4o-mini".to_string(),
..Default::default()
};
let llm = OpenAIChat::new(config);
let response = llm.chat(vec![
Message::system("You are a helpful assistant."),
Message::human("What is Rust?"),
], None).await?;
println!("{}", response.content);
Ok(())
}
use langchainrust::{
DeepSeekChat, MoonshotChat, ZhipuChat, QwenChat,
AnthropicChat, OllamaChat,
};
let deepseek = DeepSeekChat::from_env_result()?;
let moonshot = MoonshotChat::with_model("moonshot-v1-128k")?; // reads key from env, returns Result
let claude = AnthropicChat::from_env_result()?;
let ollama = OllamaChat::new("llama3.2");
use langchainrust::{
ChatPromptTemplate, Message, OpenAIChat, OpenAIConfig, RunnableExt, StrOutputParser,
};
use std::collections::HashMap;
let llm = OpenAIChat::new(OpenAIConfig {
api_key: std::env::var("OPENAI_API_KEY")?,
base_url: "https://api.openai.com/v1".to_string(),
model: "gpt-4o-mini".to_string(),
..Default::default()
});
// prompt.pipe(llm).pipe(parser) — everything is a Runnable (v0.15)
let prompt = ChatPromptTemplate::from_messages([
Message::system("你是一个简洁的 Rust 助手。"),
Message::human("{question}"),
]);
let chain = prompt.pipe(llm).pipe(StrOutputParser::new());
let mut vars = HashMap::new();
vars.insert("question".to_string(), "一句话说明什么是 Rust".to_string());
let answer = chain.invoke(vars, None).await?;
println!("{answer}");
For the full five-way composition — prompt + memory + LLM + parser + RAG in one program — see lcel_compose.
use langchainrust::{BM25Retriever, Document};
let mut retriever = BM25Retriever::new();
retriever.add_documents_sync(vec![
Document::new("Rust is a systems programming language"),
Document::new("Python is a scripting language"),
]);
let results = retriever.search("systems programming", 3);
for result in results {
println!("Document: {}", result.document.content);
println!("Score: {}", result.score);
}
More examples in 中文使用指南 or Usage Guide.
The crates/lc/examples/ directory provides 42 runnable examples covering core functionality:
| Category | Examples | Requires API Key |
|---|---|---|
| basic | chat / streaming / multi_provider / token_counter / quick_start / responses_api / batch_api / sandbox | Yes |
| agent | function_calling / multi_tool / assistants / handoffs / plan_execute / deep_research / extended_thinking | Yes |
| agent SSE | agent_sse_server (axum + SSE, v0.22.4) | Yes (AGENT_SSE_API_KEY) |
| rag | bm25_search / document_loaders / file_vectorstore / semantic_splitter / adaptive_rag / corrective_rag / graph_rag | No |
| langgraph | basic_graph / conditional_edge | No |
| memory | buffer_memory / context_window / sessions / vectorstore_memory | No |
| chains | llm_chain / sequential_chain | Yes |
| lcel | lcel_pipe / lcel_compose | pipe: No / compose: Yes |
| evaluation | evaluation / ragas_eval (RAGAS metrics, v0.22.4) | evaluation: No / ragas_eval: Yes |
| guardrails | guardrails | No |
| mcp | mcp_http_server / mcp_stdio_server (stateless track), mcp_server (server primitives) | No |
| a2a | a2a_http_server | Yes |
| otel | otel_tracing / otlp_tracing (OTLP exporter, v0.22.4; needs --features otlp) | No |
Examples requiring API keys read from environment variables:
export OPENAI_API_KEY="your-key"
cargo run --example basic_chat
Examples without API keys (BM25 / LangGraph / Memory / Loader) can run directly — great for quick exploration.
Some hard-won guidance from the framework's design reviews:
LocalEmbeddings without the local-embeddings feature is a Bag-of-Words fallback — don't use it for real semantic retrieval. Enable the feature or use an API provider.EmptyVectorInBatch / BatchMismatch instead of empty slots — treat them as failures, don't skip them.len/4 heuristic over-counts Chinese; ContextWindow uses TiktokenCounter when available.last_summary_error() reports the failure); it never silently wipes history.{"error":{"code":401,...}} in the body — check the body, not just the status code. Agent-card discovery is intentionally public.MCPError::connection_lost() on the next call; restarting the subprocess is the caller's job. MRTR round trips are bounded by max_round_trips (-32003), and method rate limits fail fast with -32002.get_document / get_embedding / clear return explicit StorageErrors; count uses describe_index_stats. Don't design around those ops with Pinecone.LocalSandbox.EventSessionManager accepts a BaseMemory via with_memory (or per-session with_memory_factory) for persistent multi-turn apps. The legacy SessionManager is deprecated and removed in 0.23.0.CostTracker records usage for models missing from the PricingTable at zero cost — register the model price explicitly if the USD budget gate must actually constrain it; otherwise the gate silently never trips on that model.GraphError::CheckpointVersionConflict — re-read and retry, never last-write-wins (SQLite/Postgres/Redis backends all use compare-and-swap).| Docs | Content |
|---|---|
| 中文使用指南 | 所有组件的详细用法(中文) |
| Usage Guide | Detailed usage for all components |
| API Docs | Rust API documentation |
| Changelog | Release history and breaking changes |
cargo test
Contributions welcome! See CONTRIBUTING.md.
MIT or Apache-2.0, at your option.
34 commits
Rust
99.3%
A Rust framework for building LLM applications with support for 8+ LLM providers, agents, RAG, BM25/hybrid search, LangGraph workflows, and multiple vector/document storage backends.
Rust
14
34 commits
updated Sep 16, 2026
A LangChain-inspired Rust framework for building LLM applications.
What it solves: Build Agents, RAG, BM25 keyword search, Hybrid retrieval, LangGraph workflows, MCP tools, A2A agent-to-agent protocols, Guardrails, multi-agent Handoffs — all in pure Rust.
The framework is engineered around a few hard rules that come out of its own design reviews. These are what make it feel different from hand-rolled LLM glue code:
| Principle | What it means in practice |
|---|---|
| Explicit over silent | No silent degradation. If an API promises X, it either delivers X or fails loudly. Batch-embedding alignment returns explicit errors instead of empty/shifted vectors; the keyword fallback for EmbeddingMatcher was removed; routing failures surface as errors, not swallowed Err(_) => {}. |
| Consumed or deleted abstractions | Every trait either has real implementors or is removed. BaseChatMemory is now implemented by all four memories, all retrievers implement RetrieverTrait, and PairwiseJudge plugs into the unified Evaluator pipeline — so users write against one abstraction, not five ad-hoc names. |
| Structured output over text parsing | Models that support tool_calls go through structured output (JSON schema / function calling). Regex-parsing model output is the last resort, not the default — it is the most common source of silent fragility. |
| Production hardening first | Tool execution has timeouts, LLM calls retry with exponential backoff, agent loops are capped (max_iterations clamped to [1, 100]), parallel actions are concurrency-limited, and CancellationToken propagates through every runnable. Eliminate the deterministic failure paths before adding features. |
| Type system enforces safety | Security properties live in types, not comments. Guardrails split InputGuardrailResult / OutputGuardrailResult so "Modify only applies to output" is enforced at compile time. |
| Composition first | Everything can be piped. Since v0.16.0, prompts, memory, native providers, parsers and RAG are all Runnable — prompt.pipe(llm).pipe(parser) compiles and runs. |
| Honest implementations | No fake backends. Empty-shell sandboxes (Wasm/E2B) were deleted; unsupported operations (e.g. Pinecone fetch-by-ID) return explicit StorageErrors instead of pretending to work. |
| Component | Description |
|---|---|
| Unified LLM access | 11 providers behind one BaseChatModel trait: OpenAI, Ollama, Anthropic Claude, Gemini, Azure, Cohere, DeepSeek, Qwen, Moonshot, Zhipu, Mistral. LLMClient::from_env() auto-detects any of the 11 from environment variables. |
| OpenAI-compatible endpoint (v0.22.4) | One generic OpenAICompatibleChat covers any base_url endpoint — keyless vLLM / LM Studio / SGLang / Ollama / internal gateways (no Authorization header is sent without a key), with GroqChat / OpenRouterChat / XaiChat presets, env constructors and extra_headers. |
| OpenAI-compatible thin wrappers | DeepSeek / Qwen / Moonshot / Zhipu / Mistral reuse the OpenAI request path; each keeps its own error variant (ProviderError::DeepSeek, etc.) so you can tell which vendor failed. New vendors are cheap to add. |
| Chat & Streaming | chat() (one full reply) and stream_chat() (first token in ~1s). Streaming chunks carry token usage (StreamChunk), so budget gates get real usage on the streaming path (v0.18). config.streaming = true makes chat() stream internally then aggregate. |
| Function Calling | bind_tools() + result.tool_calls, the native path for tool-capable models. |
| Multimodal Vision | Message::human_with_image / human_with_audio / human_with_file via schema ImageContent / AudioContent / FileContent. |
| Thinking models | Reasoning is kept in LLMResult.thinking_content and never leaked into content (DeepSeek-R1, GLM-5.2, Claude Extended Thinking). |
| OpenAI Assistants API | Stateful assistants with requires_action tool dispatch. |
| OpenAI Responses API | Typed Responses-endpoint client (openai/responses/, ~1.4k lines): web_search / file_search / code-interpreter tooling. Chat Completions remains the portable default. |
| Anthropic Extended Thinking | with_thinking for Claude reasoning. |
| Model Routing | RouterLLM with 6 strategies — Fallback / RoundRobin / LeastLatency / LatencyWeighted(beta) (EMA-latency weighted draw, deterministic SplitMix64) / LowestCost (registry-priced, blended 0.75-in/0.25-out) / InputDirected — plus per-slot ModelRateLimit admission and a shared RouterBudget USD circuit breaker (v0.22.4). Remaining models always act as fallback. |
| Cost & budgets (v0.22.4) | ModelPrice / PricingTable / shared CostTracker (run/session scopes, unknown models bill $0 and never break the loop), JSON-fetchable ModelRegistry of capabilities/prices, agent-level BudgetConfig.max_cost_usd hard gate on both invoke and stream paths, costs exported as ObsEvent::Cost. |
| Batch API | BatchClient for OpenAI / Anthropic batch inference (~50% cost reduction). |
| LLM Cache | LLMCache with TTL + true LRU eviction (hits refresh recency). |
| Structured Output | with_structured_output + StructuredOutputExt trait, JsonOutputParser fallback, and streaming structured output via PartialJsonParser. |
| Native JSON Schema (v0.21) | OpenAIChat::with_json_schema_output::<T>() sends response_format: {type: "json_schema"} (strict mode) generated from schemars 1.0 — schema-constrained decoding on the provider side; make_strict_schema enforces additionalProperties: false + full required. with_structured_output remains the portable path. |
| Token Counter | TiktokenCounter (precise) / CharRatioCounter (Chinese-friendly estimate) + TokenTrackingLLM usage stats + ModelPricing cost estimation. |
| Component | Description |
|---|---|
Unified Embeddings trait | embed_query / embed_documents / dimension / model_name, with empty-input and batch-alignment checks enforced in the trait default path. |
| Providers | OpenAI (ada-002 / 3-small / 3-large), DeepSeek, Qwen, Cohere (embed-v3.0, 4 input types), FastEmbed (local ONNX), Mock (deterministic, for tests), BagOfWords (local, always available). |
| Qwen3-Embedding (v0.21) | qwen3-embedding-0.6b / 4b / 8b (dims 1024 / 2560 / 4096) + matryoshka output via QwenEmbeddingsConfig::with_dimensions(32..=4096); the configured dimensions is passed through to the DashScope request. |
| Reliability | Exponential-backoff retries (429/5xx, max 3, 4xx not retried) with jitter and Retry-After header support (v0.21), concurrent batching (OpenAI: 2048 docs/batch, concurrency 8), and unified normalization so downstream similarity is provider-independent. |
| Local ONNX | LocalEmbeddings via the local-embeddings feature (ort). |
| Token-level embeddings (v0.21) | Optional TokenLevelEmbeddings capability trait (native async fn, statically dispatched): embed_tokens returns per-token TokenEmbedding { span, vector } with byte-offset spans. Local ONNX path shares the fastembed pipeline. |
| Late chunking (v0.21, end-to-end in v0.23) | late_chunk(&embedder, text, &LateChunkConfig) embeds the whole text once at token level, then mean-pools token vectors per chunk range into L2-normalized chunk vectors — better context retention than chunk-then-embed for long documents. late_index_in(&vector_store, &embedder, parent_key, text, &config) (v0.23) closes the loop: one token-level pass → pooled chunks → straight into any VectorStore, with deterministic {parent}:{index} ids. Runnable offline demo: cargo run -p lc-rag --example late_chunking. |
| Candle backend (v0.21) | CandleEmbeddings via the local-candle feature: pure-Rust CPU inference for BERT-family models (from_hf_hub("BAAI/bge-small-en-v1.5") or from_dir), masked mean-pooling, batch size 16. |
| Vision embeddings (v0.22.4) | VisionEmbeddings trait maps (text/image) into one shared vector space: Cohere Embed v4 (CohereVisionEmbeddings, 1536-d) and DashScope multimodal-embedding-v1 (QwenVisionEmbeddings, 1024-d), plus MockVisionEmbeddings for tests. Feeds multimodal RAG (see below). |
| Component | Description |
|---|---|
| LCEL | Runnable with four base actions — invoke / batch / stream / transform. Operators: pipe, RunnableLambda, RunnablePassthrough, RunnableParallel, RunnableBranch, RunnableBinding, RunnableWithFallbacks, RunnableAssign, with_retry, RunnableSequence. Type-erased with PhantomData — dynamic composition with compiler-checked type matches. |
| Unified composition (v0.15) | Prompts, memory, native providers, parsers and RAG are all Runnable: prompt.pipe(llm).pipe(StrOutputParser) — no glue code. RunnableWithMessageHistory wraps "LLM + memory" as one runnable (auto read history → invoke → write back). RagRunnable makes retrieval-augmented generation one link of a chain. Native OpenAIChat/QwenChat/DeepSeekChat errors are unified into LcelError. |
| Chains | BaseChain with 9 implementations: LLMChain, ConversationChain, SequentialChain, RouterChain, LLMRouterChain, RetrievalQA, ConversationRetrievalChain, plus the 4 document chains — Stuff / MapReduce / Refine / MapRerank. Chain streaming per token, ChainRunnable bridges chains into LCEL. |
| Prompts | PromptTemplate (parsed once, cached segments), ChatPromptTemplate (Runnable, outputs Vec<Message>), FewShotPromptTemplate + ExampleSelectors (LengthBasedExampleSelector). {{/}} escapes, Chinese variable names, missing variables error loudly. v0.22.4 adds PromptRegistry — versioned, named prompt storage with render-by-name and fallback, so prompt text is managed centrally instead of scattered through call sites. |
| Output Parsers | StrOutputParser, JsonOutputParser, CommaSeparatedListOutputParser, StructuredOutputParser, TypedOutputParser<T> — all tolerant of dirty model output (markdown fences, trailing commas, trailing junk). |
| Retrieval & Sessions in LCEL (v0.17) | RetrieverRunnable wraps any retriever as Runnable<String, Vec<Document>>; SessionManagerRunnable wraps persistent sessions as Runnable<(session_id, message), reply> — both compose with pipe into a chain. |
| Cancellation | CancellationToken threads through RunnableConfig into every execution. |
| Component | Description |
|---|---|
| BaseAgent / AgentExecutor | The "translator / butler" split: BaseAgent turns model output into a decision (Action / Actions / Finish), AgentExecutor is the one real loop — with tool timeouts, LLM retries, concurrency semaphore, and max_iterations clamped to [1, 100]. |
| FunctionCallingAgent | Recommended path — reads native tool_calls (requires model support). |
| ReActAgent | Text-regex thought/action loop, fallback for models without tool-calling. |
| Plan-Execute | Planner → per-step executor → replan on failure; the executor factory is configurable (no longer hardcoded to function calling). |
| DeepResearch | Multi-round research agent with sub-topic decomposition, parallel search, dedup, citation reporting. |
| RAG Agents | CorrectiveRAGAgent (self-correcting grade/rewrite/detect), AdaptiveRAG (LLM-routed retrieval), as standalone graphs. |
| Handoffs | Multi-agent handoff with max_handoff_depth (default 10) to stop A↔B ping-pong. |
| Orchestrators | Supervisor (v0.24.0 — one router LLM delegates each round to a named sub-agent or FINISH, with scratchpad feedback and a bounded-rounds one-level recursion guard), FanOutFanIn (parallel fan-out + aggregate), SequentialPipeline (serial), OrchestratorRunnable for LCEL integration. |
| Parallel tool calls (v0.24.0) | Multiple tool calls emitted in one model turn run concurrently, bounded by .with_max_concurrency(n) (default 8); observations zip back to actions in the model's call order on both invoke and stream paths. |
| Agent Hooks | Approval (on_before_tool_call allow/reject/skip), PromptInjectionHook, TokenBudgetHook, ContentFilterHook, logging. |
| Agent Gates (v0.16) | Async human-approval gate — .with_approval() (Allow / Deny / Modify; Deny feeds the reason back as an observation, Modify rewrites the arguments). Budget gate — .with_budget() with hard caps on tool calls / tokens / wall-clock duration / iterations, exceeding returns AgentError::BudgetExceeded. Both default off. |
| Cross-process resume (v0.18) | FileResumeStore persists the pending human-approval / budget-gate state to disk (atomic write); a restarted executor loads the pending point and re-enters approval instead of restarting the agent loop. |
| Context compaction (v0.21) | .with_compaction(CompactionConfig) — trigger on TurnCount / TokenCount / Any / All, compact with SlidingWindow or TokenBudget (turn-boundary truncation, no orphan tool results, min_recent_turns floor, default 2). Off by default; compaction count lands in AgentMetrics.compactions. |
| Streaming | Token-level streaming via StreamingFunctionCallingAgent + AgentStreamEvent; tool-level events via AgentExecutor::stream. |
| Web SSE (v0.22.4) | Optional axum SSE endpoint in lc-agents (sse-server feature) serving AgentStreamEvents to browsers — see the agent_sse_server example. |
| Durable checkpoints (v0.22.4) | LangGraph persistence gains three production backends behind checkpoint-sqlite (rusqlite bundled, WAL) / checkpoint-postgres (tokio-postgres) / checkpoint-redis (Lua CAS) features. Optimistic concurrency: stale writes return GraphError::CheckpointVersionConflict instead of last-write-wins. |
| Two-layer semantic memory (v0.22.4) | Episodic layer (raw per-turn observations, vector-retrieved) + semantic layer (LLM-consolidated, deduped facts) with an async background extractor — the agent accumulates durable knowledge across sessions instead of only replaying recent chat. |
| Dynamic interrupt/resume + time travel (v0.24.0) | InterruptibleNode suspends inside a node — its closure runs with resume: None, raises an InterruptRequest payload into the checkpoint, then re-enters with resume: Some(decision) via CompiledGraph::resume_with_value (even from a fresh process over a durable checkpointer; NodeInterrupt/Resumed stream events). Agent approvals converge on this one path: ApprovalGate + ApprovalDecision (Allow / Deny / Modify), so the gated tool executes exactly once and Deny performs no side effect; the non-graph ResumeStore remains for the plain executor. get_state_history() lists CheckpointInfos and fork_from(checkpoint, node, override_state) branches a new forward-only lineage off any past state. |
| Tool Policies | ToolPolicy / ToolRisk risk classification for tool access control. |
| Component | Description |
|---|---|
Unified RetrieverTrait | All retrievers implement it: SimilarityRetriever, BM25Retriever / ChunkedBM25Retriever, UnifiedHybridIndex, ParentDocumentRetriever — so any retrieval strategy plugs into the RAG pipeline. |
| RAGPipeline | RAGPipelineBuilder (llm + embeddings + vector store + retriever) → index_documents / query / query_with_sources (citation tracing). |
| Document Loaders | Text / JSON / Markdown / PDF / CSV / HTML + WebScraper / Sitemap / Docx. |
| Splitting | RecursiveCharacterSplitter (paragraph → line → sentence → char), SemanticSplitter (async semantic chunking). |
| BM25 | Keyword search with Chinese/English tokenization, ChunkedBM25Retriever parent-child structure, AutoMerging. |
| Hybrid | UnifiedHybridIndex — BM25 + vector with RRF (default) or FusionMode::Weighted linear fusion (v0.23.0), configurable min_score, plus retrieve_mmr(query, cand_k, k, λ) MMR diversity re-ranking over the fused pool (v0.23.0; standalone mmr() over (id, score, embedding) triples too). |
| Neural reranking (v0.24.0) | Hosted cross-encoders behind one AsyncReranker trait: CohereRerank (default rerank-multilingual-v3.0) and JinaRerank, driven by rerank_async(&reranker, query, results, top_n). The provider's out-of-order results[].index is mapped back to your input positions, clients bypass ambient proxies, and malformed bodies error instead of silently returning unsorted input. |
| Small-to-big retrieval (v0.24.0) | SentenceWindowRetriever — index single sentences, retrieve a deduplicated ±N-sentence window — and the public ParentDocumentRetriever — leaf-chunk hits return the entire parent document, combining precise recall with full-context answering. |
| Late-chunk dual-leg injection (v0.24.0) | UnifiedHybridIndex::add_late_chunked_document(doc, &[LateChunk]) writes token-pooled chunks to BOTH the vector index and the BM25/parent store in one call, with deterministic {parent}::{segment} ids (re-registering a parent idempotently replaces its chunk set). |
| Query Transformations | MultiQueryRetriever (decompose into multiple queries), HyDERetriever (hypothetical document), RerankingExecutor + KeywordReranker / BM25Reranker. |
| SelfQueryRetriever (v0.18) | LLM splits a natural-language query into {query, filter} via structured call, with an allowed_attributes whitelist; retrieves through similarity_search_with_filter. Composes in LCEL as a RetrieverRunnable. |
| GraphRAG | Knowledge-graph RAG with Global / Local / Hybrid modes, entity extraction, community detection. Community detection is Leiden (v0.22.4: configurable leiden_resolution / leiden_seed / max_community_levels). |
| Multimodal RAG (v0.22.4) | MultimodalChunker splits mixed text/image documents and embeds both modalities through VisionEmbeddings; MultimodalRetriever returns cross-modal hits so image content is answerable, not just text. |
| Advanced RAG | CorrectiveRAG (self-correcting), AdaptiveRAG (adaptive retrieval + structured routing decisions). |
| Contextual Retrieval (v0.21) | ContextualEnhancer — index-time transform: a small LLM writes a 1-2 sentence context per chunk, prepended to the content (original stored in metadata under contextual_context). Concurrency-limited, idempotent, fail-open (on LLM failure the original text is indexed). |
| Semantic Cache (v0.21) | CachedRetriever wraps any RetrieverTrait — exact-match hits skip the embedder entirely; otherwise a cosine-similarity lookup over cached query vectors (threshold default 0.95, FIFO max_entries 256, optional TTL, invalidate() for corpus updates). |
| Native Hybrid Search (v0.21) | NativeHybridSearch capability on QdrantVectorStore (Query API, server-side fusion, needs Qdrant ≥ 1.10): multi-branch NativeHybridQuery with FusionMethod::Rrf / Dbsf in a single round trip. Stores without the capability fail explicitly instead of silently degrading to client-side RRF. |
| Component | Description |
|---|---|
| Four memories | ConversationBufferMemory (full), ConversationBufferWindowMemory (last k turns), ConversationSummaryMemory (LLM summary), ConversationSummaryBufferMemory (summary + recent raw). All implement BaseChatMemory. |
| Semantic memory | VectorStoreRetrieverMemory — retrieval by similarity, not recency. |
| Context window | ContextWindow with Truncate / Summarize strategies and pluggable TokenCounter; System messages are always preserved. |
| Persistence | MongoPersistentMemory (feature-gated) — generic over BaseChatModel, optimistic-lock concurrent writes, session-resume summary re-injection. |
| Sessions | EventSessionManager / EventStore (v0.22.0, recommended) — event sourcing: the session is an append-only log, history is a projection; crash-safe idempotent appends, fork_session branching from any point, turn-window context, deterministic auto-compaction (snapshot past N turns, no LLM call). Legacy SessionManager / SessionStore deprecated (removed 0.23.0). |
| Component | Description |
|---|---|
| Official MCP transports (v0.22.4) | Spec-faithful clients StdioMcpClient (subprocess stdio) and StreamableMcpClient (Streamable HTTP, stateless + Mcp-Session-Id modes), and server side MCPServer::serve_streamable_http — interoperability-verified against the official TypeScript SDK 1.30.0 and Python SDK (4/4 scenarios). Includes OAuth 2.1 authorization flow (authorization server metadata, PKCE, token refresh) for remote servers requiring login. |
| MCP stateless track (v0.22.0) | 2026-07-28 single-track model: every request is a self-contained JSON-RPC HTTP POST — no handshake, no session. StatelessMcpClient carries _meta (protocol version + client identity + optional requestState), tagged with Mcp-Method / Mcp-Name routing headers so gateways route and throttle without parsing the body. The legacy handshake client (MCPClient, SSE/old-HTTP transports, streaming push) was removed in 0.22.0. |
| MCP MRTR | Multi-round tool requests: on input_required { requestState, questions } the client collects answers (MrtrAnswerProvider) and resends with the continuation token, bounded by max_round_trips (-32003 on exceed). Server-initiated interaction without a push channel. |
| MCP auth | OAuth 2.1-style: TokenValidator + StaticBearerValidator / JwtIssValidator (iss + exp) server-side; per-request bearer auth client-side (connect_with_auth); 401 → -32001. |
| MCP server | MCPServer exposes local BaseTools — in-process (handle_request), as a deployable stateless HTTP service (serve_http, example mcp_http_server), or over stdio line framing for hosts like Claude Desktop / Cursor (serve_stdio). server/discover for capability queries. |
| MCP at scale | Connection management, tool namespaces + conflict policy, static+dynamic tool discovery, per-tool timeout with hard cap, health checks + circuit breaker, per-server sandbox, sampling recursion guard, MCP Gateway (registry / pool / rate-limit / audit), multi-tenant isolation, per-method client rate limiting. |
| MCP tool adapter | MCPToolAdapter implements BaseTool — MCP tools mix seamlessly with local tools in any agent; structured errors keep {code, data}; multi-type content (image/resource) preserved. |
| A2A v1.0.1 | Agent-to-Agent protocol: AgentCard with supportedInterfaces[] — one card declares multiple (protocolVersion, transport, url) bindings (JsonRpc / HttpJson / Grpc), tenant-tagged, with client-side negotiate(). Card signing (RFC 8785-lite canonicalization + JWS HS256) protects discovery from tampering. send_task / get_task / cancel_task over HTTP. |
| A2A vs MCP | A2A orchestrates agent ↔ agent; MCP lets an agent call tools. They compose: A2A between agents, MCP below them. |
| Component | Description |
|---|---|
| Guardrails | Input/output safety rails around any agent or chain. InputGuardrailResult (Pass/Block) and OutputGuardrailResult (Pass/Block/Modify) are type-separated — Modify is compile-time impossible on input. Guardable trait lets you wrap any BaseChain. |
| Built-in guardrails | SensitiveInfoGuardrail (keywords + OpenAI-key regex + email + credit-card with Luhn check), ForbiddenWordsGuardrail, MaxLengthGuardrail. v0.22.4 adds PiiRedactionGuardrail (detect/redact PII on output) and SchemaOutputGuardrail (validate structured output against a JSON schema; fail → repair or block). |
| RAGAS evaluation (v0.22.4) | Reference-free RAG metrics in lc-evaluation: ContextPrecision, ContextRecall, AnswerRelevancy — runnable through the same EvalRunner/Report path. |
| Streaming guardrails | Two-phase: incremental keyword check (24-char sliding window) + full-output re-check. |
| Audit | AuditSink trait + FileAuditSink (JSON Lines) for violation persistence; LLM-sensitive judge for context-aware decisions. |
| GuardedAgent | Wrap an executor/chain → validate input → run → validate output; a blocked input never touches the network. |
| Retrieval Rail (v0.21) | RetrievalRail batch-scans retrieved documents for prompt injection (pattern library shared with PromptInjectionHook); GuardedRetriever wraps any RetrieverTrait with RailAction::Flag (default, tags metadata) / Redact / Drop + RailReport counts and optional audit sink. Place it inside CachedRetriever so only clean results enter the cache. |
| AI Disclosure (v0.21) | disclose() records an EU AI Act Art. 50-style transparency notice ("you are interacting with an AI system") through an AuditSink; template customizable via DisclosureConfig::with_statement with a {system} placeholder. Capability, not enforcement. |
| Evaluation | 10+ evaluators: ExactMatch, ContainsKeyword, RegexMatch, LengthCheck, Bleu, StringDistance, EmbeddingSimilarity, LLMAsJudge, PairwiseJudge, Faithfulness. EvalRunner batches all examples × all evaluators into a Report. |
| Trace → golden → compare (v0.24.0) | The lc-testkit record/replay harness now feeds evaluation: recordings sink into a golden Dataset (last user message → input, response → reference, tool results → RAG contexts) with a zero-network ReplayPredictor, and lc-evaluation::compare_reports(&baseline, &candidate, tolerance) gates any mean dropping by more than the tolerance (boundary inclusive), listing per-metric deltas and added/dropped evaluators. |
| LLM judge | StructuredJudge shared with guardrails — prefers structured output, tolerant score parsing. |
| Callbacks | CallbackHandler (3 lifecycle methods minimum) + CallbackManager dispatcher. Built-in: StdOutHandler, FileCallbackHandler, LangSmithHandler, OtelHandler. |
| Tracing | Tracer + SpanGuard (RAII), InMemory / Console / OTel backends, parent-child span tree, GenAI Semantic Conventions. OTel spans carry gen_ai.* attributes aligned with the OpenTelemetry GenAI semconv (v0.21): gen_ai.system / gen_ai.request.model / gen_ai.response.finish_reason / token usage incl. cache-read and reasoning extensions, plus gen_ai.operation.name = "retrieve" for retrieval spans. |
| Component | Description |
|---|---|
| Built-in tools | Calculator, SimpleMathTool, DateTimeTool, URLFetchTool, WikipediaTool, DuckDuckGoSearchTool, PythonREPLTool. |
| Hosted search & browser (v0.22.4) | HostedSearchTool with Tavily / Serper / Exa backends (API key from env, one uniform tool interface — no scraping fragility). CdpBrowserTool drives a real Chrome over the DevTools Protocol (navigate/click/fill/extract) behind the browser-cdp feature for pages that require JavaScript execution. |
#[tool] macro | Define a tool from a plain function — auto-converted to BaseTool; StructuredTool gives typed in/out with automatic JSON. |
| Sandbox | SandboxTool + LocalSandbox (subprocess + timeout). Tool-code execution is isolated — the Python blacklist is documented as noise filtering, not a security boundary. |
| Extended tools | HTTPTool, FileTool (sandboxed), SQLTool (read-only, sqlite-storage feature), ComputerUseTool (screen interaction). |
| Security | SSRF protection (is_private_ip) on URL/HTTP tools with per-hop DNS resolution, all-answers validation, and IP pinning that closes the DNS-rebinding TOCTOU window (v0.22.4); path sandboxing; risk classification via ToolPolicy. |
| Component | Description |
|---|---|
Unified VectorStore trait | add_documents, similarity_search, similarity_search_with_min_score, similarity_search_with_filter (MetadataFilter with Eq/Ne/Gt/Gte/Lt/Lte/In/Nin + And/Or, v0.18), similarity_search_text (auto-embeds if the store owns an embedder, else explicit error), embed_query, get_document, delete_document, count, clear. |
| Backends | InMemory, FileVectorStore (atomic write, fixed dim), ChunkedVectorStore (parent-child source retrieval), Qdrant, ChromaDB, LanceDB, Neo4j, Pinecone, Redis, MongoDB, SQLite, PGVector (typed PGVectorStore via the pgvector-storage feature). |
| Honest errors | VectorStoreError distinguishes DocumentNotFound / EmbeddingError / StorageError / ConnectionError; missing features fail loudly instead of silently degrading (e.g. Qdrant without the feature → ConnectionError, not in-memory fallback). |
langchainrust is a 23-crate workspace with a single facade crate langchainrust (in crates/lc) that re-exports the public API. Layers depend downward — lc-shared / lc-schema sit at the bottom and are depended on by everyone, which is exactly how the circular-dependency problem is solved.
┌──────────────────────────────────────┐
│ langchainrust (facade, crates/lc) │
└──────────────────┬───────────────────┘
│
┌──────────────┬───────────────────┼───────────────────┬──────────────┐
Protocol Quality Intelligence Composition Providers
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ lc-mcp │ │ lc-guardrails │ │ lc-agents │ │ lc-chains │ │ lc-providers │
│ lc-a2a │ │ lc-evaluation │ │ lc-rag │ │ lc-langgraph │ │ lc-embeddings │
│ │ │ lc-callbacks │ │ lc-vector-stores │ │ │ │ lc-prompts │
│ │ │ lc-observability │ │ │ │ │ │ lc-tools │
└─────────┬──────────┘ └──────────┬─────────┘ └──────────┬─────────┘ └──────────┬─────────┘ └──────────┬─────────┘
└───────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘
│
┌─────────────────────────────────┴──────────────────────────────────────┐
│ Core & Foundation │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐ │
│ │ lc-core │ │ lc-schema│ │ lc-shared │ │
│ │ Runnable │ │ Message │ │ Document / ToolCall / │ │
│ │ LCEL │ │ types │ │ TextSplitter │ │
│ └──────────┘ └──────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
(lc-memory, lc-sessions, lc-testkit and lc-tools-derive are omitted from the diagram for clarity; the crate table below lists all 23.)
| Crate | Role |
|---|---|
| lc-core | Execution layer: Runnable / LCEL operators, BaseChatModel/BaseLanguageModel, BaseTool/ToolRegistry, output parsers, structured output, token counter, LLMCache, RouterLLM (+ ModelRegistry pricing/capabilities, ModelRateLimit, RouterBudget), cost ledger (CostTracker, ModelPrice, PricingTable, ObsEvent::Cost), CancellationToken, StructuredJudge, BatchClient, cosine_similarity. |
| lc-schema | Message (content + role + multimodal attachments), MessageType, ImageContent/AudioContent/FileContent. |
| lc-shared | Cross-crate foundation types: Document, VectorDocument, SearchResult, ChunkDocument, ToolCall/FunctionCall, TextSplitter — breaks the dependency cycle. |
| lc-providers | 11 LLM vendors behind BaseChatModel; LLMClient (auto-detect), ProviderError (per-vendor variants), ChatModelWrapper (error normalization for mixed routing). |
| lc-prompts | PromptTemplate, ChatPromptTemplate (Runnable), FewShotPromptTemplate, ExampleSelectors. |
| lc-tools | Built-in tool library + #[tool] proc macro (lc-tools-derive), sandbox. |
| lc-embeddings | Embeddings trait + 7 providers, retries, concurrency, normalization. |
| lc-chains | BaseChain + 9 chains, ChainRunnable bridge into LCEL. |
| lc-langgraph | StateGraph, conditional/FanOut/FanIn edges, Reducers, Checkpointer (memory/file + SQLite/Postgres/Redis durable backends, OCC conflict errors), GraphPersistence, Subgraph, dynamic injection; v0.24 adds in-node dynamic interrupt/resume (InterruptibleNode, resume_with_value), checkpoint snapshots() state history and fork_from time travel. |
| lc-agents | ReAct / FunctionCalling / PlanExecute / CRAG / AdaptiveRAG / DeepResearch / Handoffs / Orchestrators / Hooks + human-approval gate (ApprovalHandler) / budget gate (BudgetConfig); v0.24 adds the Supervisor sub-agent router, graph-path ApprovalGate (approval-as-interrupt convergence) and bounded parallel tool calls. |
| lc-memory | Buffer/Window/Summary/SummaryBuffer memories, ContextWindow, MongoPersistentMemory, two-layer semantic memory (episodic + consolidated facts, background extractor). |
| lc-sessions | EventSessionManager + EventStore event-sourced multi-turn lifecycle (recommended); legacy SessionManager/SessionStore deprecated. |
| lc-rag | RetrieverTrait (Similarity/BM25/UnifiedHybrid), RAGPipeline, MultiQuery/HyDE/Reranking, GraphRAG; v0.24 adds hosted neural rerankers (AsyncReranker Cohere/Jina), SentenceWindowRetriever / public ParentDocumentRetriever, and late-chunk dual-leg injection (MMR + weighted fusion landed in v0.23.0). |
| lc-vector-stores | VectorStore trait + InMemory/File/Chunked/Qdrant/ChromaDB/LanceDB/Neo4j/Pinecone/Redis/Mongo/SQLite/PGVector backends. |
| lc-mcp | MCP client/server: official stdio + Streamable HTTP transports (with OAuth 2.1), the framework's own stateless HTTP track, tool adapter, MRTR, Gateway. |
| lc-a2a | A2A protocol server/client. |
| lc-evaluation | Rule evaluators + LLM judges, EvalRunner + Report; v0.24 adds compare_reports baseline/candidate regression gating (ReportComparison, per-metric deltas, added/dropped evaluators). |
| lc-guardrails | Input/output guardrails, Guardable, streaming guardrails, audit sinks. |
| lc-callbacks | CallbackHandler/CallbackManager + StdOut/File/LangSmith/OTel + Tracer/SpanGuard. |
| lc-observability | MetricsSink / ObsEvent observation bus with JsonLinesSink (JSONL files) and MongoSink (behind observability-mongodb). |
| lc-testkit | Record/replay test harness: RecordingProvider records real LLM exchanges to JSONL, ReplayProvider replays them offline with zero network — framework tests run without API keys. Phase 2 (v0.17): tool definition recording (bind_tools), out-of-order replay (ReplayStrategy::{Fifo, ByToolName}), agent-level offline replay, and chain scenarios transcribed from online tests. Phase 3 (v0.18): strict message-signature replay (ReplayStrategy::Exact). Phase 4 (v0.24): trace → golden dataset bridge (golden_dataset, write_golden_jsonl, ReplayPredictor, replay_golden_from_file) closing the record→score→regression-gate loop. |
[dependencies]
langchainrust = "0.24.0"
tokio = { version = "1.0", features = ["full"] }
# Optional features — vector stores & storage
langchainrust = { version = "0.24.0", features = ["qdrant-integration"] } # Qdrant vector DB
langchainrust = { version = "0.24.0", features = ["mongodb-persistence"] } # MongoDB storage (memory + vector store + checkpoints)
langchainrust = { version = "0.24.0", features = ["redis-storage"] } # Redis vector store
langchainrust = { version = "0.24.0", features = ["sqlite-storage"] } # SQLite vector store (+ SQLTool)
langchainrust = { version = "0.24.0", features = ["pgvector-storage"] } # PGVector (requires user-configured sqlx/pgvector deps)
# Durable LangGraph checkpointers (v0.22.4)
langchainrust = { version = "0.24.0", features = ["checkpoint-sqlite"] } # rusqlite bundled, WAL — zero extra infra
langchainrust = { version = "0.24.0", features = ["checkpoint-postgres"] } # tokio-postgres
langchainrust = { version = "0.24.0", features = ["checkpoint-redis"] } # Redis with Lua CAS
# Local embeddings (vision/Cohere/Qwen multimodal embeddings need no feature)
langchainrust = { version = "0.24.0", features = ["local-embeddings"] } # Local ONNX embeddings (ort)
langchainrust = { version = "0.24.0", features = ["fastembed"] } # FastEmbed ONNX models
langchainrust = { version = "0.24.0", features = ["local-candle"] } # Pure-Rust Candle BERT embeddings
# Observability
langchainrust = { version = "0.24.0", features = ["opentelemetry"] } # OpenTelemetry tracing spans
langchainrust = { version = "0.24.0", features = ["otlp"] } # OTLP HTTP/JSON exporter (v0.22.4)
langchainrust = { version = "0.24.0", features = ["observability"] } # MetricsSink + JsonLinesSink (v0.22.4)
langchainrust = { version = "0.24.0", features = ["observability-mongodb"] } # MongoDB observation sink
# Tools & memory
langchainrust = { version = "0.24.0", features = ["browser-cdp"] } # CDP browser tool (v0.22.4)
langchainrust = { version = "0.24.0", features = ["vectorstore-memory"] } # VectorStoreRetrieverMemory (semantic memory)
langchainrust = { version = "0.24.0", features = ["experimental"] } # Experimental features
# PineconeStore / FileVectorStore / hosted search (Tavily, Serper, Exa) require no feature flag.
# The axum SSE agent endpoint is gated by lc-agents' own `sse-server` feature (see examples/agent_sse_server.rs).
Note on MSRV: Rust 1.85+ required.
use langchainrust::{OpenAIChat, OpenAIConfig, BaseChatModel};
use langchainrust::schema::Message;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = OpenAIConfig {
api_key: std::env::var("OPENAI_API_KEY")?,
base_url: "https://api.openai.com/v1".to_string(),
model: "gpt-4o-mini".to_string(),
..Default::default()
};
let llm = OpenAIChat::new(config);
let response = llm.chat(vec![
Message::system("You are a helpful assistant."),
Message::human("What is Rust?"),
], None).await?;
println!("{}", response.content);
Ok(())
}
use langchainrust::{
DeepSeekChat, MoonshotChat, ZhipuChat, QwenChat,
AnthropicChat, OllamaChat,
};
let deepseek = DeepSeekChat::from_env_result()?;
let moonshot = MoonshotChat::with_model("moonshot-v1-128k")?; // reads key from env, returns Result
let claude = AnthropicChat::from_env_result()?;
let ollama = OllamaChat::new("llama3.2");
use langchainrust::{
ChatPromptTemplate, Message, OpenAIChat, OpenAIConfig, RunnableExt, StrOutputParser,
};
use std::collections::HashMap;
let llm = OpenAIChat::new(OpenAIConfig {
api_key: std::env::var("OPENAI_API_KEY")?,
base_url: "https://api.openai.com/v1".to_string(),
model: "gpt-4o-mini".to_string(),
..Default::default()
});
// prompt.pipe(llm).pipe(parser) — everything is a Runnable (v0.15)
let prompt = ChatPromptTemplate::from_messages([
Message::system("你是一个简洁的 Rust 助手。"),
Message::human("{question}"),
]);
let chain = prompt.pipe(llm).pipe(StrOutputParser::new());
let mut vars = HashMap::new();
vars.insert("question".to_string(), "一句话说明什么是 Rust".to_string());
let answer = chain.invoke(vars, None).await?;
println!("{answer}");
For the full five-way composition — prompt + memory + LLM + parser + RAG in one program — see lcel_compose.
use langchainrust::{BM25Retriever, Document};
let mut retriever = BM25Retriever::new();
retriever.add_documents_sync(vec![
Document::new("Rust is a systems programming language"),
Document::new("Python is a scripting language"),
]);
let results = retriever.search("systems programming", 3);
for result in results {
println!("Document: {}", result.document.content);
println!("Score: {}", result.score);
}
More examples in 中文使用指南 or Usage Guide.
The crates/lc/examples/ directory provides 42 runnable examples covering core functionality:
| Category | Examples | Requires API Key |
|---|---|---|
| basic | chat / streaming / multi_provider / token_counter / quick_start / responses_api / batch_api / sandbox | Yes |
| agent | function_calling / multi_tool / assistants / handoffs / plan_execute / deep_research / extended_thinking | Yes |
| agent SSE | agent_sse_server (axum + SSE, v0.22.4) | Yes (AGENT_SSE_API_KEY) |
| rag | bm25_search / document_loaders / file_vectorstore / semantic_splitter / adaptive_rag / corrective_rag / graph_rag | No |
| langgraph | basic_graph / conditional_edge | No |
| memory | buffer_memory / context_window / sessions / vectorstore_memory | No |
| chains | llm_chain / sequential_chain | Yes |
| lcel | lcel_pipe / lcel_compose | pipe: No / compose: Yes |
| evaluation | evaluation / ragas_eval (RAGAS metrics, v0.22.4) | evaluation: No / ragas_eval: Yes |
| guardrails | guardrails | No |
| mcp | mcp_http_server / mcp_stdio_server (stateless track), mcp_server (server primitives) | No |
| a2a | a2a_http_server | Yes |
| otel | otel_tracing / otlp_tracing (OTLP exporter, v0.22.4; needs --features otlp) | No |
Examples requiring API keys read from environment variables:
export OPENAI_API_KEY="your-key"
cargo run --example basic_chat
Examples without API keys (BM25 / LangGraph / Memory / Loader) can run directly — great for quick exploration.
Some hard-won guidance from the framework's design reviews:
LocalEmbeddings without the local-embeddings feature is a Bag-of-Words fallback — don't use it for real semantic retrieval. Enable the feature or use an API provider.EmptyVectorInBatch / BatchMismatch instead of empty slots — treat them as failures, don't skip them.len/4 heuristic over-counts Chinese; ContextWindow uses TiktokenCounter when available.last_summary_error() reports the failure); it never silently wipes history.{"error":{"code":401,...}} in the body — check the body, not just the status code. Agent-card discovery is intentionally public.MCPError::connection_lost() on the next call; restarting the subprocess is the caller's job. MRTR round trips are bounded by max_round_trips (-32003), and method rate limits fail fast with -32002.get_document / get_embedding / clear return explicit StorageErrors; count uses describe_index_stats. Don't design around those ops with Pinecone.LocalSandbox.EventSessionManager accepts a BaseMemory via with_memory (or per-session with_memory_factory) for persistent multi-turn apps. The legacy SessionManager is deprecated and removed in 0.23.0.CostTracker records usage for models missing from the PricingTable at zero cost — register the model price explicitly if the USD budget gate must actually constrain it; otherwise the gate silently never trips on that model.GraphError::CheckpointVersionConflict — re-read and retry, never last-write-wins (SQLite/Postgres/Redis backends all use compare-and-swap).| Docs | Content |
|---|---|
| 中文使用指南 | 所有组件的详细用法(中文) |
| Usage Guide | Detailed usage for all components |
| API Docs | Rust API documentation |
| Changelog | Release history and breaking changes |
cargo test
Contributions welcome! See CONTRIBUTING.md.
MIT or Apache-2.0, at your option.
34 commits
Rust
99.3%