LangChain component ecosystem layers
LangChain components are organized in five interconnected layers: Input processing (transforms raw data into structured documents using document loaders and text splitters), Embedding & storage (converts text into vector representations and stores them in vector stores), Retrieval (finds relevant information by embedding user queries and matching against stored vectors), Generation (uses chat models to create responses, optionally with tools), and Orchestration (coordinates everything through agents and memory systems).
Input processing layer components
The input processing layer transforms raw data into structured documents. It consists of: text input as raw data source, document loaders that ingest data, text splitters that break content into manageable chunks, and documents as the structured output.
Embedding and storage layer components
The embedding and storage layer converts text into searchable vector representations. It takes documents from input processing, applies embedding models to generate vectors, and stores these vectors in vector stores for later retrieval.
Retrieval layer components
The retrieval layer finds relevant information based on user queries. A user query is embedded using the same embedding models, converted to a query vector, then retrievers search vector stores using this vector to return relevant context for generation.
Generation layer components
The generation layer uses AI models to create responses. Chat models serve as the core component, optionally calling tools to gather information, receiving tool results back for incorporation into responses. Relevant context from the retrieval layer is provided to the chat model, which produces the final AI response.
Orchestration layer components
The orchestration layer coordinates all other components through agents and memory systems. Agents orchestrate chat models, tools, retrievers, and memory to manage complex workflows and maintain context across interactions.
Models category purpose and components
The Models category handles AI reasoning and generation. Key components include chat models, LLMs, and embedding models. Use cases include text generation, reasoning, and semantic understanding.
Tools category purpose and components
The Tools category provides external capabilities for AI agents. Key components include APIs and databases. Use cases include web search, data access, and computations.
Agents category purpose and components
The Agents category handles orchestration and reasoning. Key components include ReAct agents and tool calling agents. Use cases include nondeterministic workflows and decision making.
Memory category purpose and components
The Memory category preserves context across interactions. Key components include message history and custom state. Use cases include conversations and stateful interactions.
Retrievers category purpose and components
The Retrievers category provides information access capabilities. Key components include vector retrievers and web retrievers. Use cases include RAG (Retrieval-Augmented Generation) and knowledge base search.
Document processing category purpose and components
The Document processing category handles data ingestion. Key components include loaders, splitters, and transformers. Use cases include PDF processing and web scraping.
Vector Stores category purpose and components
The Vector Stores category provides semantic search capabilities. Key components include Chroma, Pinecone, and FAISS. Use cases include similarity search and embeddings storage.
Declarative generative UI overview and spectrum position
Declarative generative UI sits in the middle of the generative UI spectrum. The agent emits a structured specification, and the frontend composes the interface from a catalog of components registered ahead of time. Instead of rendering text responses in chat bubbles, the agent output becomes the UI itself: forms, cards, dashboards, and more.
Component catalog as guardrail in declarative generative UI
The catalog is the guardrail that makes declarative generative UI safe. The agent can arrange and combine components freely but cannot step outside the set you approve. This balances creativity against predictability. It trades pixel-perfection for breadth, which suits secondary interactions, internal tools, and dashboards where showing something useful matters more than exact control.
Use cases for declarative generative UI
Use declarative generative UI for the long tail of your product, where the agent can compose layouts you did not fully anticipate while staying inside a set of components you approve. It is suited for secondary interactions, internal tools, and dashboards. For high-traffic or brand-critical surfaces that must be exact, move toward controlled generative UI. For interfaces created outside your application, move toward open-ended generative UI.
Declarative generative UI workflow steps
The declarative generative UI workflow has four steps: (1) Define a catalog by declaring what components the AI can use with typed props, (2) Prompt the AI by describing the UI you want in natural language, (3) AI generates a spec—a JSON document describing the component tree, (4) Render safely with json-render's Renderer using your components.
Define component catalog with Zod schema and descriptions
The catalog describes every component the AI is allowed to use. Each component has a Zod schema for its props and a description that the AI reads to understand when to use it. Example: a Card component with optional title and padding props described as 'A card container with optional title and padding'.
Component catalog definition example with json-render
Example of defining a catalog using json-render's `defineCatalog`. The catalog includes components like Card, Stack, TextInput, and Button. Each component has a description and Zod-validated props:
```ts
import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { z } from "zod";
const catalog = defineCatalog(schema, {
components: {
Card: {
description: "A card container with optional title and padding",
props: z.object({
title: z.string().optional(),
padding: z.enum(["sm", "md", "lg"]).optional(),
}),
},
Stack: {
description: "Layout children vertically or horizontally with consistent spacing",
props: z.object({
direction: z.enum(["vertical", "horizontal"]).optional(),
gap: z.enum(["sm", "md", "lg"]).optional(),
}),
},
TextInput: {
description: "A text input field with optional label and placeholder",
props: z.object({
label: z.string().optional(),
placeholder: z.string().optional(),
type: z.enum(["text", "email", "password", "number", "textarea"]).optional(),
}),
},
Button: {
description: "A clickable button with label and style variants",
props: z.object({
label: z.string(),
variant: z.enum(["primary", "secondary", "ghost", "link"]).optional(),
fullWidth: z.boolean().optional(),
}),
},
},
actions: {},
});
```
Keep component catalogs focused
Keep catalogs focused by including only components the AI needs for the use case. A smaller, more focused catalog produces better results than a kitchen-sink approach that includes everything.
Build component registry for type-safe rendering
The registry maps each catalog component to its actual rendering implementation. Use `defineRegistry` to get type-safe bindings between the catalog props and your component functions, ensuring the props passed at runtime match the catalog schema.
Component registry React implementation example
Example of defining a registry in React using json-render's `defineRegistry`:
```tsx
import { defineRegistry, Renderer, JSONUIProvider } from "@json-render/react";
const { registry } = defineRegistry(catalog, {
components: {
Card: ({ props, children }) => (
<div className="card">
{props.title && <h2>{props.title}</h2>}
{children}
</div>
),
Stack: ({ props, children }) => (
<div className={`stack stack-${props.direction ?? "vertical"} gap-${props.gap ?? "md"}`}>
{children}
</div>
),
TextInput: ({ props }) => (
<div>
{props.label && <label>{props.label}</label>}
<input type={props.type ?? "text"} placeholder={props.placeholder} />
</div>
),
Button: ({ props }) => (
<button className={props.variant ?? "primary"}>
{props.label}
</button>
),
},
});
```
Connect declarative generative UI to LangChain agent with useStream
The agent uses structured output to return a json-render spec. Set up `useStream` with the agent's assistant ID, then extract the spec from the AI message's `tool_calls`. The raw spec is accessed via `aiMessage?.tool_calls?.[0]?.args`.
Extract generative UI spec from agent in React
Example of extracting the spec from an agent response in React:
```tsx
import { useStream } from "@langchain/react";
import { AIMessage } from "langchain";
function GenerativeUI() {
const stream = useStream<typeof myAgent>({
apiUrl: "http://localhost:2024",
assistantId: "generative_ui",
});
const aiMessage = stream.messages.find(AIMessage.isInstance);
const rawSpec = aiMessage?.tool_calls?.[0]?.args;
}
```
JSONUIProvider required context setup
The `JSONUIProvider` is required to set up json-render's internal context providers for state, visibility, validation, and actions. The `Renderer` component must be rendered inside a `JSONUIProvider` to access these internal contexts.
A2UI as alternative to json-render for declarative generative UI
A2UI is Google's declarative, streaming-first generative UI specification integrated via CopilotKit as an alternative to json-render. Like json-render, A2UI composes interfaces from components you register, keeping the agent inside guardrails you define. A2UI comes in two variants: Dynamic schema (secondary model generates full interface including schema, data, and layout) and Fixed schema (component tree defined on frontend, agent streams only data into it).
Best practice: descriptive component descriptions
Use descriptive component descriptions in your catalog. The AI uses these descriptions to understand when to use each component. Clear descriptions lead to better UI generation.
Best practice: style generative UI with design tokens
Use CSS custom properties when styling components in your registry so rendered components adapt to light and dark themes automatically.
AI Elements component library overview
AI Elements is a composable, shadcn/ui-based component library for AI chat interfaces. Components include Conversation, Message, Tool, Reasoning, and PromptInput, designed to drop into React projects and wire to stream.messages with minimal code.
AI Elements installation via CLI
AI Elements components are installed via CLI and added as editable source files into your project in shadcn/ui registry style. Install with: npm install @langchain/react && npx ai-elements@latest add conversation message prompt-input tool reasoning suggestion
AI Elements Conversation component scroll management
Wrap messages in the Conversation component which manages scroll behavior so new messages auto-scroll into view. Include ConversationContent for message rendering and ConversationScrollButton for manual scroll control.
AI Elements components are editable source files
AI Elements components ship in your project as editable source files, not as an external package dependency. This allows you to change anything without forking.
assistant-ui overview
assistant-ui is a headless React UI framework for AI chat. It provides a full runtime layer including thread management, message branching, and attachment handling that connects to the @useStream hook via the useExternalStoreRuntime adapter.
assistant-ui integration workflow
Integration with LangChain involves three steps: (1) stream with @useStream to connect to an agent and get reactive messages, loading state, and submit/cancel callbacks; (2) adapt with useExternalStoreRuntime to bridge stream.messages into assistant-ui's runtime format by converting BaseMessage[] to ThreadMessageLike[]; (3) provide the runtime by wrapping the UI in AssistantRuntimeProvider and rendering any assistant-ui thread component.
assistant-ui installation
Install assistant-ui with: bun add @assistant-ui/react @assistant-ui/react-markdown
useExternalStoreRuntime adapter configuration
The useExternalStoreRuntime adapter accepts four parameters: messages (the converted ThreadMessageLike[] from stream.messages), onNew (callback to handle new messages via stream.submit), onCancel (callback to stop the stream), and convertMessage (identity function to pass messages through).
BaseMessage to ThreadMessageLike conversion for HumanMessage
When converting HumanMessage instances to ThreadMessageLike format, create an object with role set to 'user' and content as an array with a single text block containing msg.text.
BaseMessage to ThreadMessageLike conversion for AIMessage
When converting AIMessage instances to ThreadMessageLike format: (1) extract reasoning tokens from msg.contentBlocks and add them as content with type 'reasoning'; (2) convert each tool call from msg.tool_calls to a content part with type 'tool-call', including toolCallId, toolName, and args; (3) extract and add the text response if present; (4) wrap all parts in a ThreadMessageLike with role 'assistant'.
BaseMessage to ThreadMessageLike conversion for ToolMessage
When converting ToolMessage instances, attach the tool result to the preceding assistant message by matching the tool_call_id with the toolCallId of the corresponding tool-call content part, then set the result property on that part.
assistant-ui Thread customisation
Customise the default Thread UI by overriding component slots. The Thread.Root wrapper contains ThreadMessages and Composer components. ThreadMessages accepts a components object with UserMessage, AssistantMessage, and ToolFallback properties to replace default rendering.
Message conversion memoisation best practice
Wrap toThreadMessages(stream.messages) in useMemo to avoid re-running the conversion on every render, which improves performance.
assistant-ui attachment handling
Handle attachments using CompositeAttachmentAdapter with SimpleImageAttachmentAdapter for image uploads, and extend with custom adapters for other file types.
assistant-ui message branching with LangGraph
assistant-ui has built-in message branching support via MessageBranch. Pair edits with useMessageMetadata and forkFrom when you need LangGraph checkpoint forks to create branching conversations.
assistant-ui thread persistence
Persist threadId using the onThreadId callback and pass it back into @useStream on page load to reconnect to the same thread, enabling session continuity.
useStream hook integration example
Example showing wiring useStream to assistant-ui: call useStream with apiUrl and assistantId parameters, define onNew callback to extract text from message content and call stream.submit with human message type, convert stream.messages to ThreadMessageLike format with useMemo, create runtime with useExternalStoreRuntime passing messages, onNew, onCancel callbacks, wrap in AssistantRuntimeProvider and render Thread component.
useStream is UI-agnostic reactive state hook
The useStream hook returns plain reactive state with messages, tool calls, loading flags, values, and thread metadata that can be wired to any visual layer. It is designed to be UI-agnostic and framework-independent.
Frontend integration libraries for LangChain agents
Four main React integration libraries work with LangChain frontends: CopilotKit (full chat runtime with structured generative UI), AI Elements (composable shadcn/ui-based components), assistant-ui (headless React framework with runtime layer), and OpenUI (generative UI library for dashboards). All four work well with LangChain agents, and the latter three connect directly to useStream.
CopilotKit integration approach
CopilotKit provides a full AI chat runtime with structured generative UI support. Implementation involves adding a custom CopilotKit endpoint to a LangGraph deployment, then rendering dynamic component trees in React.
AI Elements integration approach
AI Elements provides composable shadcn/ui-based components for AI chat. Components like Conversation, Message, Tool, and Reasoning can be dropped in and wired directly to stream.messages.
assistant-ui integration approach
assistant-ui is a headless React framework with a full runtime layer. Integration is done by bridging useStream to AssistantRuntimeProvider via the useExternalStoreRuntime adapter.
OpenUI integration approach
OpenUI is a generative UI library that lets agents produce complete, interactive dashboards in a declarative component DSL. It is purpose-built for data-rich, report-style UIs and agents output openui-lang text.
Frontend library comparison table
Comparison across four frontend libraries:
| Criteria | CopilotKit | AI Elements | assistant-ui | OpenUI |
|---------|-----------|-----------|----------|--------|
| Best for | Full chat runtime plus structured generative UI | Chat with rich message types | Full-featured chat with minimal setup | Generated dashboards and reports |
| UI style | CopilotKit chat shell + custom message renderers | Composable shadcn/ui components | Headless slots + default theme | Prebuilt component library with declarative DSL |
| Customisation | Custom backend endpoint, agent context, and renderers | Edit source files directly | Override component slots | Theme via CSS custom properties |
| Streaming UX | Runtime-managed chat stream with structured assistant payloads | Component-level progressive render | Built-in thread management | Hoisting — shell appears immediately, data fills in |
| Tool calls | Via CopilotKit runtime and custom renderers | Tool / ToolHeader / ToolOutput | Custom via message slots | Inline in the generated UI |
| Agent format | Structured assistant responses plus optional Markdown | Any stream.messages | Any stream.messages | Agent outputs openui-lang text |
When to use CopilotKit for frontend integration
CopilotKit is especially useful when you want a richer runtime layer and a dedicated endpoint that can sit alongside a LangGraph deployment.
Open-ended generative UI definition
Open-ended generative UI is at the agent-created end of the generative UI spectrum. The interface is authored outside your application, such as by an MCP server, and your frontend renders it inside a sandbox. Neither the developer nor the agent writes the components; a third party ships them and the application hosts them.
Open-ended generative UI advantages
Open-ended generative UI gives the widest expressive range because the agent owns the canvas. A capability can arrive with its own interface already built, allowing you to surface interactive tools you never implemented without requiring frontend code. It suits one-off visualizations and bespoke answers where a result that is surprising and good enough beats one that is predictable.
Open-ended generative UI drawbacks
Open-ended generative UI is the most experimental approach, the least deterministic, slower, and more expensive to run. Untrusted UI is the hardest to make consistent, accessible, and safe, so it must be isolated from the rest of your application.
When to use open-ended generative UI
Use open-ended generative UI when you want to surface capabilities and interfaces that live outside your application and evolve independently of it, such as tools published by an ecosystem of MCP servers. When you need to guarantee branding, accessibility, or layout, move back along the spectrum toward declarative or controlled generative UI where your application owns the components.
Sandboxing for open-ended generative UI safety
Because the interface in open-ended generative UI comes from a third party, treat it as untrusted. Render it in an isolated context, such as a sandboxed iframe, and constrain what it can access so a misbehaving or malicious app cannot reach the rest of your page or your users' data. Sandboxing contains the expressive range rather than limiting it and makes the open end of the spectrum usable in production.
LangChain frontend SDKs architecture
LangChain frontend SDKs follow a bidirectional architecture where a createAgent backend streams state to a frontend via the SDK stream API. The backend produces a compiled LangGraph graph that exposes a streaming API. On the frontend, the stream handle connects to that API and provides reactive state including messages, tool calls, interrupts, values, and thread metadata that can be rendered with any framework.
Frontend SDK integration with component libraries
The stream API exposed by LangChain frontend SDKs is UI-agnostic and can be used with any component library or generative UI framework. Component libraries can own the presentation layer while LangChain's SDK owns the agent runtime state, resumability, interrupts, and checkpoint semantics.