Accessing static runtime context in workflow nodes
In a LangGraph workflow node, static runtime context is accessed through a Runtime parameter with the type Runtime[ContextSchema]. The runtime object can be used to access static context via runtime.context and other utilities like the active store and stream writer.
Static runtime context in tools
Tools can access static runtime context by accepting a ToolRuntime parameter with the type ToolRuntime[ContextSchema]. The context is then accessed via runtime.context.user_name or similar field references.
Static runtime context in LangGraph
Static runtime context represents immutable data like user metadata, tools, and database connections that are passed to an application at the start of a run via the context argument to invoke or stream. This data does not change during execution.
Dynamic runtime context in agents using state
Dynamic runtime context is managed through the LangGraph state object and represents mutable data that evolves during a single run. This includes conversation history, intermediate results, and values derived from tools or LLM outputs. In LangGraph, the state object acts as short-term memory during a run. An agent can have a CustomState extending AgentState that includes additional fields beyond the standard messages field.
Accessing dynamic context in agent middleware
In an agent's middleware with @dynamic_prompt decorator, dynamic context is accessed via request.state which allows reading state values. The middleware receives a ModelRequest object that contains the state.
Context engineering definition and dimensions
Context engineering is the practice of building dynamic systems that provide the right information and tools in the right format so that an AI application can accomplish a task. Context can be characterized along two key dimensions: by mutability (static context for immutable data like user metadata and database connections, or dynamic context for mutable data like conversation history) and by lifetime (runtime context for single run data, or cross-conversation context for data persisting across multiple conversations).
Updating state in workflow nodes
In a LangGraph workflow node, state is updated by returning a dictionary with the fields to update. Only the fields specified in the return dictionary are merged into the state; the function receives the full state as input.
Three ways LangGraph manages context
LangGraph provides three ways to manage context: static runtime context (immutable user metadata, tools, database connections passed at startup via context argument to invoke/stream, static mutability, single run lifetime), dynamic runtime context or state (mutable data evolving during a single run, accessible via LangGraph state object, dynamic mutability, single run lifetime), and dynamic cross-conversation context or store (persistent data shared across conversations, accessible via LangGraph store, dynamic mutability, cross-conversation lifetime).
Runtime context vs LLM context and context window
Runtime context refers to local context and data that dependencies need to run. It does not refer to the LLM context (data passed into the LLM's prompt) or the context window (the maximum number of tokens that can be passed to the LLM). Runtime context is a form of dependency injection that can optimize the LLM context by providing dependencies like database connections, user IDs, or API clients to tools and nodes at runtime rather than hardcoding them.
Dynamic cross-conversation context with LangGraph store
Dynamic cross-conversation context represents persistent, mutable data that spans across multiple conversations or sessions and is managed through the LangGraph store. This includes user profiles, preferences, and historical interactions. The LangGraph store acts as long-term memory across multiple runs and can be used to read or update persistent facts like user profiles and preferences.
Static runtime context passed to invoke with context argument
Static runtime context is passed to graph.invoke() using the context parameter as a dictionary or object. For example: graph.invoke({"messages": [{"role": "user", "content": "hi!"}]}, context={"user_name": "John Smith"}).
JavaScript config for static context
In JavaScript, static immutable data like user metadata or API keys is passed using config with a key called 'configurable' which is reserved for this purpose. For example: await graph.invoke({ messages: [{role: "user", content: "hi!"}] }, { configurable: { user_id: "user_123" } }).
Enabling memory for state persistence
Memory can be enabled to persist the agent's state across multiple invocations. Without memory enabled, the state is scoped only to a single run. Details on how to enable memory are provided in the memory guide.
When to use LangGraph
Use LangGraph when you need fine-grained, low-level control over agent orchestration, need durable execution for long-running stateful agents, are building complex workflows that combine deterministic and agentic steps, or need production-ready infrastructure for agent deployment.
LangChain is an agent framework
LangChain is an agent framework that provides abstractions like structured content blocks, the agent loop, and middleware. It is built on top of LangGraph, but users do not need to know LangGraph to use LangChain. LangChain abstractions are designed to be easy to get started with while still providing the flexibility needed for advanced use cases.
LangGraph is an agent runtime
LangGraph is a low-level orchestration framework and runtime for building, managing, and deploying long-running, stateful agents. It provides durable execution, streaming, human-in-the-loop capabilities, persistence, and low-level control over agent orchestration.
Deep Agents SDK is an agent harness
The Deep Agents SDK is an opinionated, batteries-included agent harness built on top of LangGraph that adds planning capabilities, file systems for context management, the ability to spawn subagents, and other features. It is designed for complex, multi-step tasks that require planning and decomposition.
When to use LangChain
Use LangChain when you want to quickly build agents and autonomous applications, need standard abstractions for models, tools, and agent loops, want an easy-to-use framework that still provides flexibility, or are building straightforward agent applications without complex orchestration needs.
When to use Deep Agents SDK
Use the Deep Agents SDK when you are building agents that run over long time periods, building agents that need to handle complex multi-step tasks, want to use predefined tools such as filesystem operations and bash execution, or want to use predefined prompts and subagents.
Agent framework value: abstractions and integrations
Agent frameworks like LangChain provide value through abstractions and integrations that make it easier to build with LLMs.
Agent runtime value: durable execution, streaming, HITL, persistence
Agent runtimes like LangGraph provide value through durable execution (agents persist through failures and resume), streaming support, human-in-the-loop capabilities, and persistence for state management.
Agent harness value: predefined tools, prompts, subagents, planning
Agent harnesses like the Deep Agents SDK provide value through predefined tools, prompts, subagents, planning capabilities with to-do lists, task delegation, file system access, and token management for conversation history and tool results.
LangChain 1.0 is built on top of LangGraph
LangChain 1.0 is built on top of LangGraph, with agent frameworks generally being higher level and running on agent runtimes.
Feature comparison: Skills
LangChain provides skills via multi-agent skills. Deep Agents provides skills via Deep Agents skills. LangGraph does not have a skills feature listed.
Feature comparison: Subagents
LangGraph provides subagents via subgraphs. LangChain provides subagents via multi-agent subagents. Deep Agents provides subagents via Deep Agents subagents.
Feature comparison: Human-in-the-loop
LangGraph provides human-in-the-loop via interrupts. LangChain provides human-in-the-loop via human-in-the-loop middleware. Deep Agents provides human-in-the-loop via an interrupt_on parameter.
Feature comparison: Streaming
LangGraph provides streaming via LangGraph streaming features. LangChain provides streaming via agent streaming. Deep Agents provides streaming via Deep Agents event-streaming features.
CalaRetriever configuration
CalaRetriever can be configured with the API key via environment variable CALA_API_KEY or passed directly to the constructor with the api_key parameter.
CalaRetriever modes and endpoints
CalaRetriever implements BaseRetriever and supports three modes: 'search' (default, POST /v1/knowledge/search) for open-ended natural language questions returning synthesized answers with citations; 'query' (POST /v1/knowledge/query) for structured dot-notation lookups like 'OpenAI.founded.year'; 'entities' (GET /v1/entities) for discovering entities by name before deeper queries.
CalaRetriever parameters table
CalaRetriever accepts the following parameters: api_key (SecretStr, default: $CALA_API_KEY) for your Cala API key; mode (str, default: 'search') one of 'search', 'query', 'entities'; k (int, default: 5) for maximum number of documents to return; timeout (int, default: 30) for HTTP request timeout in seconds.
CalaRetriever search mode example
from langchain_cala import CalaRetriever
retriever = CalaRetriever(api_key="your-api-key")
docs = retriever.invoke("Which EU AI startups raised funding in 2024?")
for doc in docs:
print(doc.page_content)
print(doc.metadata) # includes 'verified', 'source', 'explainability'
CalaRetriever query mode example
retriever = CalaRetriever(api_key="your-api-key", mode="query")
docs = retriever.invoke("Mistral.founded.year")
CalaRetriever entity discovery example
retriever = CalaRetriever(api_key="your-api-key", mode="entities")
docs = retriever.invoke("Factorial HR")
CalaRetriever in RAG chain example
from langchain_cala import CalaRetriever
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
retriever = CalaRetriever(api_key="your-api-key")
prompt = ChatPromptTemplate.from_template(
"Answer the question based only on the following context:\n\n{context}\n\nQuestion: {question}"
)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| ChatOpenAI()
| StrOutputParser()
)
chain.invoke("Who are the key players in European AI infrastructure?")
Cala returns verified entity data with traceability
Cala returns verified entity data with full source traceability, unlike web-search retrievers. Every document response includes a 'verified' metadata field and a citation chain, making it compatible with EU AI Act Article 13 explainability requirements for high-risk AI deployments.
CalaRetriever installation
Install Cala integration with `pip install langchain-cala`. Get your API key at console.cala.ai.
CharacterTextSplitter with metadata JavaScript example
const metadatas = [{"document": 1}, {"document": 2}]
const documents = splitter.createDocuments(
[{ pageContent: stateOfTheUnion }, { pageContent: stateOfTheUnion }],
{ metadatas: metadatas }
);
console.log(documents[0]);
This propagates metadata associated with each input document to the output chunks.
CharacterTextSplitter.splitText JavaScript example
splitter.splitText(stateOfTheUnion)[0]
Returns plain string chunks directly, without wrapping in Document objects.
CharacterTextSplitter basic concept
Character-based splitting divides text using a specified character sequence (default: "\n\n"), with chunk length measured by the number of characters.
CharacterTextSplitter.split_text vs create_documents
CharacterTextSplitter offers two methods: .split_text() returns plain string chunks; .create_documents() returns LangChain Document objects, useful when metadata needs to be preserved for downstream tasks.
CharacterTextSplitter Python installation
Install with: pip install -qU langchain-text-splitters
CharacterTextSplitter JavaScript installation
Install with npm: npm install @langchain/textsplitters; pnpm: pnpm install @langchain/textsplitters; yarn: yarn add @langchain/textsplitters; bun: bun add @langchain/textsplitters
CharacterTextSplitter Python constructor parameters
CharacterTextSplitter accepts: separator (string, default "\n\n"), chunk_size (int, character count for chunks), chunk_overlap (int, overlap between chunks), length_function (callable, default len), is_separator_regex (bool, default False, whether separator is a regex pattern).
CharacterTextSplitter Python example
from langchain_text_splitters import CharacterTextSplitter
with open("state_of_the_union.txt") as f:
state_of_the_union = f.read()
text_splitter = CharacterTextSplitter(
separator="\n\n",
chunk_size=1000,
chunk_overlap=200,
length_function=len,
is_separator_regex=False,
)
texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
CharacterTextSplitter JavaScript example
import { CharacterTextSplitter } from "@langchain/textsplitters";
import { readFileSync } from "fs";
const stateOfTheUnion = readFileSync("state_of_the_union.txt", "utf8");
const splitter = new CharacterTextSplitter({
separator: "\n\n",
chunkSize: 1000,
chunkOverlap: 200,
});
const texts = splitter.createDocuments([{ pageContent: stateOfTheUnion }]);
console.log(texts[0]);
CharacterTextSplitter with metadata Python example
metadatas = [{"document": 1}, {"document": 2}]
documents = text_splitter.create_documents(
[state_of_the_union, state_of_the_union], metadatas=metadatas
)
print(documents[0])
This propagates metadata associated with each input document to the output chunks.
TypeScript text splitter example
Example of splitting TypeScript code:
const TS_CODE = `
function helloWorld(): void {
console.log("Hello, World!");
}
// Call the function
helloWorld();
`;
const tsSplitter = RecursiveCharacterTextSplitter.fromLanguage(
"ts",
{ chunkSize: 60, chunkOverlap: 0 }
);
const tsDocs = tsSplitter.createDocuments([{ pageContent: TS_CODE }]);
This produces three documents, with the opening brace on its own in the first chunk due to the small chunk size.
RecursiveCharacterTextSplitter supported languages
RecursiveCharacterTextSplitter supports language-specific code splitting with prebuilt separator lists. Supported languages in Python (langchain_text_splitters.Language enum) are: cpp, go, java, kotlin, js, ts, php, proto, python, rst, ruby, rust, scala, swift, markdown, latex, html, sol, csharp, cobol, c, lua, perl, haskell, elixir, powershell, visualbasic6. JavaScript/TypeScript (SupportedTextSplitterLanguages type) supports: cpp, go, java, js, php, proto, python, rst, ruby, rust, scala, swift, markdown, latex, html, sol.
RecursiveCharacterTextSplitter.get_separators_for_language (Python)
Call RecursiveCharacterTextSplitter.get_separators_for_language(Language.LANGUAGE_NAME) to view the list of separators used for a given language. For example, RecursiveCharacterTextSplitter.get_separators_for_language(Language.PYTHON) returns ["\nclass ", "\ndef ", "\n\tdef ", "\n\n", "\n", " ", ""].
RecursiveCharacterTextSplitter.from_language (Python)
Create a language-specific text splitter by calling RecursiveCharacterTextSplitter.from_language(language=Language.LANGUAGE_NAME, chunk_size=SIZE, chunk_overlap=OVERLAP). Pass a Language enum value to tailor the splitter to that language's syntax.
RecursiveCharacterTextSplitter.getSeparatorsForLanguage (JavaScript/TypeScript)
Call RecursiveCharacterTextSplitter.getSeparatorsForLanguage(language_string) in JavaScript/TypeScript to view the list of separators for a given language.
RecursiveCharacterTextSplitter.fromLanguage (JavaScript/TypeScript)
Create a language-specific text splitter in JavaScript/TypeScript by calling RecursiveCharacterTextSplitter.fromLanguage(language_string, { chunkSize: SIZE, chunkOverlap: OVERLAP }). Pass a supported language string to tailor the splitter to that language's syntax.
Python text splitter example
Example of splitting Python code:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
PYTHON_CODE = """
def hello_world():
print("Hello, World!")
# Call the function
hello_world()
"""
python_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON, chunk_size=50, chunk_overlap=0
)
python_docs = python_splitter.create_documents([PYTHON_CODE])
This produces two documents with the function definition in the first chunk and the function call in the second.
JavaScript text splitter example
Example of splitting JavaScript code:
const JS_CODE = `
function helloWorld() {
console.log("Hello, World!");
}
// Call the function
helloWorld();
`;
const jsSplitter = RecursiveCharacterTextSplitter.fromLanguage(
"js",
{ chunkSize: 60, chunkOverlap: 0 }
);
const jsDocs = jsSplitter.createDocuments([{ pageContent: JS_CODE }]);
This produces two documents with the function definition in the first chunk and the function call in the second.
Markdown text splitter example
Example of splitting Markdown text:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
markdown_text = """
# 🦜️🔗 LangChain
⚡ Building applications with LLMs through composability ⚡
## What is LangChain?
# Hopefully this code block isn't split
LangChain is a framework for...
As an open-source project in a rapidly developing field, we are extremely open to contributions.
"""
md_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.MARKDOWN, chunk_size=60, chunk_overlap=0
)
md_docs = md_splitter.create_documents([markdown_text])
This respects markdown headers as split boundaries.
HTML text splitter example
Example of splitting HTML text:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
html_text = """
<!DOCTYPE html>
<html>
<head>
<title>🦜️🔗 LangChain</title>
<style>
body {
font-family: Arial, sans-serif;
}
h1 {
color: darkblue;
}
</style>
</head>
<body>
<div>
<h1>🦜️🔗 LangChain</h1>
<p>⚡ Building applications with LLMs through composability ⚡</p>
</div>
<div>
As an open-source project in a rapidly developing field, we are extremely open to contributions.
</div>
</body>
</html>
"""
html_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.HTML, chunk_size=60, chunk_overlap=0
)
html_docs = html_splitter.create_documents([html_text])
This respects HTML tag boundaries for splitting.
Solidity text splitter example
Example of splitting Solidity code:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
SOL_CODE = """
pragma solidity ^0.8.20;
contract HelloWorld {
function add(uint a, uint b) pure public returns(uint) {
return a + b;
}
}
"""
sol_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.SOL, chunk_size=128, chunk_overlap=0
)
sol_docs = sol_splitter.create_documents([SOL_CODE])
This produces two documents with the pragma statement and the contract definition separated.
C# text splitter example
Example of splitting C# code:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
C_CODE = """
using System;
class Program
{
static void Main()
{
int age = 30; // Change the age value as needed
// Categorize the age without any console output
if (age < 18)
{
// Age is under 18
}
else if (age >= 18 && age < 65)
{
// Age is an adult
}
else
{
// Age is a senior citizen
}
}
}
"""
c_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.CSHARP, chunk_size=128, chunk_overlap=0
)
c_docs = c_splitter.create_documents([C_CODE])
This respects C# class and method boundaries.
Haskell text splitter example
Example of splitting Haskell code:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
HASKELL_CODE = """
main :: IO ()
main = do
putStrLn "Hello, World!"
-- Some sample functions
add :: Int -> Int -> Int
add x y = x + y
"""
haskell_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.HASKELL, chunk_size=50, chunk_overlap=0
)
haskell_docs = haskell_splitter.create_documents([HASKELL_CODE])
This produces four documents respecting Haskell's function definitions and type signatures.
PHP text splitter example
Example of splitting PHP code:
from langchain_text_splitters import Language, RecursiveCharacterTextSplitter
PHP_CODE = """<?php
namespace foo;
class Hello {
public function __construct() { }
}
function hello() {
echo "Hello World!";
}
interface Human {
public function breath();
}
trait Foo { }
enum Color
{
case Red;
case Blue;
}"""
php_splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PHP, chunk_size=50, chunk_overlap=0
)
php_docs = php_splitter.create_documents([PHP_CODE])
This respects PHP class, function, interface, trait, and enum boundaries.