atliliw/langchainrust

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

See the code
agent-framework
ai
ai-agents
langchain
langgraph
llm
mcp
multi-agent
rag
rust

README

langchainrust

Rust License Crates.io Documentation CI Crates.io Downloads

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.


Design Principles

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:

PrincipleWhat it means in practice
Explicit over silentNo 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 abstractionsEvery 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 parsingModels 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 firstTool 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 safetySecurity properties live in types, not comments. Guardrails split InputGuardrailResult / OutputGuardrailResult so "Modify only applies to output" is enforced at compile time.
Composition firstEverything can be piped. Since v0.16.0, prompts, memory, native providers, parsers and RAG are all Runnableprompt.pipe(llm).pipe(parser) compiles and runs.
Honest implementationsNo 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.

Core Features

LLM & Providers

ComponentDescription
Unified LLM access11 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 wrappersDeepSeek / 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 & Streamingchat() (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 Callingbind_tools() + result.tool_calls, the native path for tool-capable models.
Multimodal VisionMessage::human_with_image / human_with_audio / human_with_file via schema ImageContent / AudioContent / FileContent.
Thinking modelsReasoning is kept in LLMResult.thinking_content and never leaked into content (DeepSeek-R1, GLM-5.2, Claude Extended Thinking).
OpenAI Assistants APIStateful assistants with requires_action tool dispatch.
OpenAI Responses APITyped Responses-endpoint client (openai/responses/, ~1.4k lines): web_search / file_search / code-interpreter tooling. Chat Completions remains the portable default.
Anthropic Extended Thinkingwith_thinking for Claude reasoning.
Model RoutingRouterLLM 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 APIBatchClient for OpenAI / Anthropic batch inference (~50% cost reduction).
LLM CacheLLMCache with TTL + true LRU eviction (hits refresh recency).
Structured Outputwith_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 CounterTiktokenCounter (precise) / CharRatioCounter (Chinese-friendly estimate) + TokenTrackingLLM usage stats + ModelPricing cost estimation.

Embeddings

ComponentDescription
Unified Embeddings traitembed_query / embed_documents / dimension / model_name, with empty-input and batch-alignment checks enforced in the trait default path.
ProvidersOpenAI (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.
ReliabilityExponential-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 ONNXLocalEmbeddings 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).

Composition: Chains & LCEL

ComponentDescription
LCELRunnable 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.
ChainsBaseChain 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.
PromptsPromptTemplate (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 ParsersStrOutputParser, 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.
CancellationCancellationToken threads through RunnableConfig into every execution.

Agents & Multi-Agent

ComponentDescription
BaseAgent / AgentExecutorThe "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].
FunctionCallingAgentRecommended path — reads native tool_calls (requires model support).
ReActAgentText-regex thought/action loop, fallback for models without tool-calling.
Plan-ExecutePlanner → per-step executor → replan on failure; the executor factory is configurable (no longer hardcoded to function calling).
DeepResearchMulti-round research agent with sub-topic decomposition, parallel search, dedup, citation reporting.
RAG AgentsCorrectiveRAGAgent (self-correcting grade/rewrite/detect), AdaptiveRAG (LLM-routed retrieval), as standalone graphs.
HandoffsMulti-agent handoff with max_handoff_depth (default 10) to stop A↔B ping-pong.
OrchestratorsSupervisor (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 HooksApproval (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.
StreamingToken-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 PoliciesToolPolicy / ToolRisk risk classification for tool access control.

Retrieval & RAG

ComponentDescription
Unified RetrieverTraitAll retrievers implement it: SimilarityRetriever, BM25Retriever / ChunkedBM25Retriever, UnifiedHybridIndex, ParentDocumentRetriever — so any retrieval strategy plugs into the RAG pipeline.
RAGPipelineRAGPipelineBuilder (llm + embeddings + vector store + retriever) → index_documents / query / query_with_sources (citation tracing).
Document LoadersText / JSON / Markdown / PDF / CSV / HTML + WebScraper / Sitemap / Docx.
SplittingRecursiveCharacterSplitter (paragraph → line → sentence → char), SemanticSplitter (async semantic chunking).
BM25Keyword search with Chinese/English tokenization, ChunkedBM25Retriever parent-child structure, AutoMerging.
HybridUnifiedHybridIndex — 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 TransformationsMultiQueryRetriever (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.
GraphRAGKnowledge-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 RAGCorrectiveRAG (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.

Memory & Sessions

ComponentDescription
Four memoriesConversationBufferMemory (full), ConversationBufferWindowMemory (last k turns), ConversationSummaryMemory (LLM summary), ConversationSummaryBufferMemory (summary + recent raw). All implement BaseChatMemory.
Semantic memoryVectorStoreRetrieverMemory — retrieval by similarity, not recency.
Context windowContextWindow with Truncate / Summarize strategies and pluggable TokenCounter; System messages are always preserved.
PersistenceMongoPersistentMemory (feature-gated) — generic over BaseChatModel, optimistic-lock concurrent writes, session-resume summary re-injection.
SessionsEventSessionManager / 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).

Protocols: MCP & A2A

ComponentDescription
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 MRTRMulti-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 authOAuth 2.1-style: TokenValidator + StaticBearerValidator / JwtIssValidator (iss + exp) server-side; per-request bearer auth client-side (connect_with_auth); 401 → -32001.
MCP serverMCPServer 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 scaleConnection 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 adapterMCPToolAdapter 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.1Agent-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 MCPA2A orchestrates agent ↔ agent; MCP lets an agent call tools. They compose: A2A between agents, MCP below them.

Quality: Guardrails, Evaluation, Observability

ComponentDescription
GuardrailsInput/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 guardrailsSensitiveInfoGuardrail (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 guardrailsTwo-phase: incremental keyword check (24-char sliding window) + full-output re-check.
AuditAuditSink trait + FileAuditSink (JSON Lines) for violation persistence; LLM-sensitive judge for context-aware decisions.
GuardedAgentWrap 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.
Evaluation10+ 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 judgeStructuredJudge shared with guardrails — prefers structured output, tolerant score parsing.
CallbacksCallbackHandler (3 lifecycle methods minimum) + CallbackManager dispatcher. Built-in: StdOutHandler, FileCallbackHandler, LangSmithHandler, OtelHandler.
TracingTracer + 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.

Tools

ComponentDescription
Built-in toolsCalculator, 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] macroDefine a tool from a plain function — auto-converted to BaseTool; StructuredTool gives typed in/out with automatic JSON.
SandboxSandboxTool + LocalSandbox (subprocess + timeout). Tool-code execution is isolated — the Python blacklist is documented as noise filtering, not a security boundary.
Extended toolsHTTPTool, FileTool (sandboxed), SQLTool (read-only, sqlite-storage feature), ComputerUseTool (screen interaction).
SecuritySSRF 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.

Vector Stores

ComponentDescription
Unified VectorStore traitadd_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.
BackendsInMemory, 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 errorsVectorStoreError distinguishes DocumentNotFound / EmbeddingError / StorageError / ConnectionError; missing features fail loudly instead of silently degrading (e.g. Qdrant without the feature → ConnectionError, not in-memory fallback).

Architecture

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.)

CrateRole
lc-coreExecution 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-schemaMessage (content + role + multimodal attachments), MessageType, ImageContent/AudioContent/FileContent.
lc-sharedCross-crate foundation types: Document, VectorDocument, SearchResult, ChunkDocument, ToolCall/FunctionCall, TextSplitter — breaks the dependency cycle.
lc-providers11 LLM vendors behind BaseChatModel; LLMClient (auto-detect), ProviderError (per-vendor variants), ChatModelWrapper (error normalization for mixed routing).
lc-promptsPromptTemplate, ChatPromptTemplate (Runnable), FewShotPromptTemplate, ExampleSelectors.
lc-toolsBuilt-in tool library + #[tool] proc macro (lc-tools-derive), sandbox.
lc-embeddingsEmbeddings trait + 7 providers, retries, concurrency, normalization.
lc-chainsBaseChain + 9 chains, ChainRunnable bridge into LCEL.
lc-langgraphStateGraph, 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-agentsReAct / 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-memoryBuffer/Window/Summary/SummaryBuffer memories, ContextWindow, MongoPersistentMemory, two-layer semantic memory (episodic + consolidated facts, background extractor).
lc-sessionsEventSessionManager + EventStore event-sourced multi-turn lifecycle (recommended); legacy SessionManager/SessionStore deprecated.
lc-ragRetrieverTrait (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-storesVectorStore trait + InMemory/File/Chunked/Qdrant/ChromaDB/LanceDB/Neo4j/Pinecone/Redis/Mongo/SQLite/PGVector backends.
lc-mcpMCP client/server: official stdio + Streamable HTTP transports (with OAuth 2.1), the framework's own stateless HTTP track, tool adapter, MRTR, Gateway.
lc-a2aA2A protocol server/client.
lc-evaluationRule evaluators + LLM judges, EvalRunner + Report; v0.24 adds compare_reports baseline/candidate regression gating (ReportComparison, per-metric deltas, added/dropped evaluators).
lc-guardrailsInput/output guardrails, Guardable, streaming guardrails, audit sinks.
lc-callbacksCallbackHandler/CallbackManager + StdOut/File/LangSmith/OTel + Tracer/SpanGuard.
lc-observabilityMetricsSink / ObsEvent observation bus with JsonLinesSink (JSONL files) and MongoSink (behind observability-mongodb).
lc-testkitRecord/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.

Installation

[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.


Quick Start

1. Basic chat

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(())
}

2. Multi-provider — same interface, swap config

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");

3. LCEL — compose everything into one chain

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.

4. BM25 keyword search (no API key)

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.


Examples

The crates/lc/examples/ directory provides 42 runnable examples covering core functionality:

CategoryExamplesRequires API Key
basicchat / streaming / multi_provider / token_counter / quick_start / responses_api / batch_api / sandboxYes
agentfunction_calling / multi_tool / assistants / handoffs / plan_execute / deep_research / extended_thinkingYes
agent SSEagent_sse_server (axum + SSE, v0.22.4)Yes (AGENT_SSE_API_KEY)
ragbm25_search / document_loaders / file_vectorstore / semantic_splitter / adaptive_rag / corrective_rag / graph_ragNo
langgraphbasic_graph / conditional_edgeNo
memorybuffer_memory / context_window / sessions / vectorstore_memoryNo
chainsllm_chain / sequential_chainYes
lcellcel_pipe / lcel_composepipe: No / compose: Yes
evaluationevaluation / ragas_eval (RAGAS metrics, v0.22.4)evaluation: No / ragas_eval: Yes
guardrailsguardrailsNo
mcpmcp_http_server / mcp_stdio_server (stateless track), mcp_server (server primitives)No
a2aa2a_http_serverYes
otelotel_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.


Production Considerations

Some hard-won guidance from the framework's design reviews:

  • Don't rely on silent keyword fallbacks. 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.
  • Embedding batch alignment errors are explicit. Missing or shifted vectors now return EmptyVectorInBatch / BatchMismatch instead of empty slots — treat them as failures, don't skip them.
  • Chinese text: prefer Tiktoken-based token counting. The len/4 heuristic over-counts Chinese; ContextWindow uses TiktokenCounter when available.
  • Summary memory: old summaries survive LLM failure. A failed summary leaves the previous summary and raw messages intact (last_summary_error() reports the failure); it never silently wipes history.
  • MCP / A2A auth is at the JSON-RPC layer. Bearer-token auth returns HTTP 200 with {"error":{"code":401,...}} in the body — check the body, not just the status code. Agent-card discovery is intentionally public.
  • MCP failure semantics differ by transport. The stateless HTTP track has no handshake or heartbeat — an unreachable server fails the request immediately, so there is no reconnect to wait on. The stdio transport has no reconnect at all: a child exit / pipe EOF surfaces as 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.
  • Pinecone intentionally lacks fetch-by-ID. get_document / get_embedding / clear return explicit StorageErrors; count uses describe_index_stats. Don't design around those ops with Pinecone.
  • SQLTool is read-only by default, use parameterized queries. The Python blacklist is noise-filtering, not a security boundary — isolate real code execution with LocalSandbox.
  • Summary memory and sessions need no special wiring. 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.
  • Unknown model prices bill $0, they don't crash the run. 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.
  • Checkpoint writes are optimistic. Concurrent stale writes against the same LangGraph checkpoint return GraphError::CheckpointVersionConflict — re-read and retry, never last-write-wins (SQLite/Postgres/Redis backends all use compare-and-swap).

Documentation

DocsContent
中文使用指南所有组件的详细用法(中文)
Usage GuideDetailed usage for all components
API DocsRust API documentation
ChangelogRelease history and breaking changes

Testing

cargo test

Contributing

Contributions welcome! See CONTRIBUTING.md.


License

MIT or Apache-2.0, at your option.

Contributors

atliliw

34 commits

atliliw/langchainrust

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

See the code
agent-framework
ai
ai-agents
langchain
langgraph
llm
mcp
multi-agent
rag
rust

README

langchainrust

Rust License Crates.io Documentation CI Crates.io Downloads

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.


Design Principles

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:

PrincipleWhat it means in practice
Explicit over silentNo 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 abstractionsEvery 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 parsingModels 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 firstTool 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 safetySecurity properties live in types, not comments. Guardrails split InputGuardrailResult / OutputGuardrailResult so "Modify only applies to output" is enforced at compile time.
Composition firstEverything can be piped. Since v0.16.0, prompts, memory, native providers, parsers and RAG are all Runnableprompt.pipe(llm).pipe(parser) compiles and runs.
Honest implementationsNo 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.

Core Features

LLM & Providers

ComponentDescription
Unified LLM access11 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 wrappersDeepSeek / 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 & Streamingchat() (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 Callingbind_tools() + result.tool_calls, the native path for tool-capable models.
Multimodal VisionMessage::human_with_image / human_with_audio / human_with_file via schema ImageContent / AudioContent / FileContent.
Thinking modelsReasoning is kept in LLMResult.thinking_content and never leaked into content (DeepSeek-R1, GLM-5.2, Claude Extended Thinking).
OpenAI Assistants APIStateful assistants with requires_action tool dispatch.
OpenAI Responses APITyped Responses-endpoint client (openai/responses/, ~1.4k lines): web_search / file_search / code-interpreter tooling. Chat Completions remains the portable default.
Anthropic Extended Thinkingwith_thinking for Claude reasoning.
Model RoutingRouterLLM 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 APIBatchClient for OpenAI / Anthropic batch inference (~50% cost reduction).
LLM CacheLLMCache with TTL + true LRU eviction (hits refresh recency).
Structured Outputwith_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 CounterTiktokenCounter (precise) / CharRatioCounter (Chinese-friendly estimate) + TokenTrackingLLM usage stats + ModelPricing cost estimation.

Embeddings

ComponentDescription
Unified Embeddings traitembed_query / embed_documents / dimension / model_name, with empty-input and batch-alignment checks enforced in the trait default path.
ProvidersOpenAI (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.
ReliabilityExponential-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 ONNXLocalEmbeddings 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).

Composition: Chains & LCEL

ComponentDescription
LCELRunnable 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.
ChainsBaseChain 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.
PromptsPromptTemplate (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 ParsersStrOutputParser, 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.
CancellationCancellationToken threads through RunnableConfig into every execution.

Agents & Multi-Agent

ComponentDescription
BaseAgent / AgentExecutorThe "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].
FunctionCallingAgentRecommended path — reads native tool_calls (requires model support).
ReActAgentText-regex thought/action loop, fallback for models without tool-calling.
Plan-ExecutePlanner → per-step executor → replan on failure; the executor factory is configurable (no longer hardcoded to function calling).
DeepResearchMulti-round research agent with sub-topic decomposition, parallel search, dedup, citation reporting.
RAG AgentsCorrectiveRAGAgent (self-correcting grade/rewrite/detect), AdaptiveRAG (LLM-routed retrieval), as standalone graphs.
HandoffsMulti-agent handoff with max_handoff_depth (default 10) to stop A↔B ping-pong.
OrchestratorsSupervisor (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 HooksApproval (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.
StreamingToken-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 PoliciesToolPolicy / ToolRisk risk classification for tool access control.

Retrieval & RAG

ComponentDescription
Unified RetrieverTraitAll retrievers implement it: SimilarityRetriever, BM25Retriever / ChunkedBM25Retriever, UnifiedHybridIndex, ParentDocumentRetriever — so any retrieval strategy plugs into the RAG pipeline.
RAGPipelineRAGPipelineBuilder (llm + embeddings + vector store + retriever) → index_documents / query / query_with_sources (citation tracing).
Document LoadersText / JSON / Markdown / PDF / CSV / HTML + WebScraper / Sitemap / Docx.
SplittingRecursiveCharacterSplitter (paragraph → line → sentence → char), SemanticSplitter (async semantic chunking).
BM25Keyword search with Chinese/English tokenization, ChunkedBM25Retriever parent-child structure, AutoMerging.
HybridUnifiedHybridIndex — 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 TransformationsMultiQueryRetriever (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.
GraphRAGKnowledge-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 RAGCorrectiveRAG (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.

Memory & Sessions

ComponentDescription
Four memoriesConversationBufferMemory (full), ConversationBufferWindowMemory (last k turns), ConversationSummaryMemory (LLM summary), ConversationSummaryBufferMemory (summary + recent raw). All implement BaseChatMemory.
Semantic memoryVectorStoreRetrieverMemory — retrieval by similarity, not recency.
Context windowContextWindow with Truncate / Summarize strategies and pluggable TokenCounter; System messages are always preserved.
PersistenceMongoPersistentMemory (feature-gated) — generic over BaseChatModel, optimistic-lock concurrent writes, session-resume summary re-injection.
SessionsEventSessionManager / 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).

Protocols: MCP & A2A

ComponentDescription
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 MRTRMulti-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 authOAuth 2.1-style: TokenValidator + StaticBearerValidator / JwtIssValidator (iss + exp) server-side; per-request bearer auth client-side (connect_with_auth); 401 → -32001.
MCP serverMCPServer 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 scaleConnection 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 adapterMCPToolAdapter 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.1Agent-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 MCPA2A orchestrates agent ↔ agent; MCP lets an agent call tools. They compose: A2A between agents, MCP below them.

Quality: Guardrails, Evaluation, Observability

ComponentDescription
GuardrailsInput/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 guardrailsSensitiveInfoGuardrail (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 guardrailsTwo-phase: incremental keyword check (24-char sliding window) + full-output re-check.
AuditAuditSink trait + FileAuditSink (JSON Lines) for violation persistence; LLM-sensitive judge for context-aware decisions.
GuardedAgentWrap 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.
Evaluation10+ 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 judgeStructuredJudge shared with guardrails — prefers structured output, tolerant score parsing.
CallbacksCallbackHandler (3 lifecycle methods minimum) + CallbackManager dispatcher. Built-in: StdOutHandler, FileCallbackHandler, LangSmithHandler, OtelHandler.
TracingTracer + 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.

Tools

ComponentDescription
Built-in toolsCalculator, 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] macroDefine a tool from a plain function — auto-converted to BaseTool; StructuredTool gives typed in/out with automatic JSON.
SandboxSandboxTool + LocalSandbox (subprocess + timeout). Tool-code execution is isolated — the Python blacklist is documented as noise filtering, not a security boundary.
Extended toolsHTTPTool, FileTool (sandboxed), SQLTool (read-only, sqlite-storage feature), ComputerUseTool (screen interaction).
SecuritySSRF 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.

Vector Stores

ComponentDescription
Unified VectorStore traitadd_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.
BackendsInMemory, 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 errorsVectorStoreError distinguishes DocumentNotFound / EmbeddingError / StorageError / ConnectionError; missing features fail loudly instead of silently degrading (e.g. Qdrant without the feature → ConnectionError, not in-memory fallback).

Architecture

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.)

CrateRole
lc-coreExecution 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-schemaMessage (content + role + multimodal attachments), MessageType, ImageContent/AudioContent/FileContent.
lc-sharedCross-crate foundation types: Document, VectorDocument, SearchResult, ChunkDocument, ToolCall/FunctionCall, TextSplitter — breaks the dependency cycle.
lc-providers11 LLM vendors behind BaseChatModel; LLMClient (auto-detect), ProviderError (per-vendor variants), ChatModelWrapper (error normalization for mixed routing).
lc-promptsPromptTemplate, ChatPromptTemplate (Runnable), FewShotPromptTemplate, ExampleSelectors.
lc-toolsBuilt-in tool library + #[tool] proc macro (lc-tools-derive), sandbox.
lc-embeddingsEmbeddings trait + 7 providers, retries, concurrency, normalization.
lc-chainsBaseChain + 9 chains, ChainRunnable bridge into LCEL.
lc-langgraphStateGraph, 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-agentsReAct / 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-memoryBuffer/Window/Summary/SummaryBuffer memories, ContextWindow, MongoPersistentMemory, two-layer semantic memory (episodic + consolidated facts, background extractor).
lc-sessionsEventSessionManager + EventStore event-sourced multi-turn lifecycle (recommended); legacy SessionManager/SessionStore deprecated.
lc-ragRetrieverTrait (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-storesVectorStore trait + InMemory/File/Chunked/Qdrant/ChromaDB/LanceDB/Neo4j/Pinecone/Redis/Mongo/SQLite/PGVector backends.
lc-mcpMCP client/server: official stdio + Streamable HTTP transports (with OAuth 2.1), the framework's own stateless HTTP track, tool adapter, MRTR, Gateway.
lc-a2aA2A protocol server/client.
lc-evaluationRule evaluators + LLM judges, EvalRunner + Report; v0.24 adds compare_reports baseline/candidate regression gating (ReportComparison, per-metric deltas, added/dropped evaluators).
lc-guardrailsInput/output guardrails, Guardable, streaming guardrails, audit sinks.
lc-callbacksCallbackHandler/CallbackManager + StdOut/File/LangSmith/OTel + Tracer/SpanGuard.
lc-observabilityMetricsSink / ObsEvent observation bus with JsonLinesSink (JSONL files) and MongoSink (behind observability-mongodb).
lc-testkitRecord/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.

Installation

[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.


Quick Start

1. Basic chat

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(())
}

2. Multi-provider — same interface, swap config

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");

3. LCEL — compose everything into one chain

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.

4. BM25 keyword search (no API key)

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.


Examples

The crates/lc/examples/ directory provides 42 runnable examples covering core functionality:

CategoryExamplesRequires API Key
basicchat / streaming / multi_provider / token_counter / quick_start / responses_api / batch_api / sandboxYes
agentfunction_calling / multi_tool / assistants / handoffs / plan_execute / deep_research / extended_thinkingYes
agent SSEagent_sse_server (axum + SSE, v0.22.4)Yes (AGENT_SSE_API_KEY)
ragbm25_search / document_loaders / file_vectorstore / semantic_splitter / adaptive_rag / corrective_rag / graph_ragNo
langgraphbasic_graph / conditional_edgeNo
memorybuffer_memory / context_window / sessions / vectorstore_memoryNo
chainsllm_chain / sequential_chainYes
lcellcel_pipe / lcel_composepipe: No / compose: Yes
evaluationevaluation / ragas_eval (RAGAS metrics, v0.22.4)evaluation: No / ragas_eval: Yes
guardrailsguardrailsNo
mcpmcp_http_server / mcp_stdio_server (stateless track), mcp_server (server primitives)No
a2aa2a_http_serverYes
otelotel_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.


Production Considerations

Some hard-won guidance from the framework's design reviews:

  • Don't rely on silent keyword fallbacks. 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.
  • Embedding batch alignment errors are explicit. Missing or shifted vectors now return EmptyVectorInBatch / BatchMismatch instead of empty slots — treat them as failures, don't skip them.
  • Chinese text: prefer Tiktoken-based token counting. The len/4 heuristic over-counts Chinese; ContextWindow uses TiktokenCounter when available.
  • Summary memory: old summaries survive LLM failure. A failed summary leaves the previous summary and raw messages intact (last_summary_error() reports the failure); it never silently wipes history.
  • MCP / A2A auth is at the JSON-RPC layer. Bearer-token auth returns HTTP 200 with {"error":{"code":401,...}} in the body — check the body, not just the status code. Agent-card discovery is intentionally public.
  • MCP failure semantics differ by transport. The stateless HTTP track has no handshake or heartbeat — an unreachable server fails the request immediately, so there is no reconnect to wait on. The stdio transport has no reconnect at all: a child exit / pipe EOF surfaces as 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.
  • Pinecone intentionally lacks fetch-by-ID. get_document / get_embedding / clear return explicit StorageErrors; count uses describe_index_stats. Don't design around those ops with Pinecone.
  • SQLTool is read-only by default, use parameterized queries. The Python blacklist is noise-filtering, not a security boundary — isolate real code execution with LocalSandbox.
  • Summary memory and sessions need no special wiring. 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.
  • Unknown model prices bill $0, they don't crash the run. 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.
  • Checkpoint writes are optimistic. Concurrent stale writes against the same LangGraph checkpoint return GraphError::CheckpointVersionConflict — re-read and retry, never last-write-wins (SQLite/Postgres/Redis backends all use compare-and-swap).

Documentation

DocsContent
中文使用指南所有组件的详细用法(中文)
Usage GuideDetailed usage for all components
API DocsRust API documentation
ChangelogRelease history and breaking changes

Testing

cargo test

Contributing

Contributions welcome! See CONTRIBUTING.md.


License

MIT or Apache-2.0, at your option.

Contributors

atliliw

34 commits

Languages

Rust

99.3%