fix: correct route function to return 'b' instead of 'a' when not terminating
This fixes a bug in the graph API how-to where the route function incorrectly returned 'a'. Now it correctly returns 'b' as intended.
* Add more details about database for deployment types. Clarify that deployment type cannot be changed.
* Add note about Development type disk capacity.
* Migrate to `uv`
* Format `pyproject.toml` files properly
* Remove upper bounds on dependencies, and bounds on dev dependencies
(we should be using latest)
* Move to hatch for packaing
In the future we should:
* Set up dependabot / automate lockfile updates and tests
* Add tests for min compatible versions (I'll do this right after merge)
* Use dynamic versioning
* Bump `pydantic` to v2.11.4 in the lockfile, we have some tests failing
On line 586, the check_query function should use
check_query_system_prompt. Instead, small mistake it is using the
generate_query_system_prompt prompt which is obviously incorrect.
- remove match_cached_writes from PregelRunner args (now called by
PregelLoop internally)
- this will be helpful when implementing distributed runner classes
- remove match_cached_writes from PregelRunner args (now called by PregelLoop internally)
- this will be helpful when implementing distributed runner classes
[gitmcp.io](https://gitmcp.io/) provides easy access to the latest
langgraph docs through a remote, free, open-source MCP. It's supported
by all major clients (including the new claude.ai web client). It
enables two access points -
- Empower AI agents (e.g., Cursor) with live documentation context to
prevent hallucinations.
- Chat with the documentation in the browser via the embedded chat
This PR proposes adding a new badge to help users make the most of
Langgraph's documentation with GitMCP. The badge is
[customizable](https://github.com/idosal/git-mcp?tab=readme-ov-file#-gitmcp-badge).
The count is a live count of users accessing Langgraph's documentation
through GitMCP.
Example:
[](https://gitmcp.io/langchain-ai/langgraph)
You can see a demo with Langgraph's GitHub pages at gitmcp.io.
Please let us know what you think :)
# PR Summary
This small PR resolves the error formatting in
`libs/langgraph/langgraph/pregel/algo.py` so the `proc.channels` will be
evaluated in the message.
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
- Turn on strict mode to fail docs build if there are any internal
broken anchor links.
- Fix broken anchor links.
- Delete storm tutorial that has fake markdown inside it (we'll figure
out how to deal with it later)
- BaseCache interface defines the base class for cache storage adapters
- FileCache implements BaseCache with filesystem-backed storage
- Provide default cache key implementation which hashes args with pickle
- Update PregelExecutableTask with cache_key property for tasks that
opt-in to caching
- Update PregelLoop, PregelRunner to get/set from cache as appropriate
TODO
- [x] Call match_cached_writes in async PregelRunner
- [ ] Implement RedisCache to use in LGP
- [x] Add more tests
Because we were propagating the task ID config key, the stream mode was
always overridden as "values", meaning the token, etc. callback handlers
were never added within the remote graphs.
---------
Signed-off-by: William Fu-Hinthorn <13333726+hinthornw@users.noreply.github.com>
I was having trouble following this section of the docs and I realized
it is because the incorrect tools is included in the tools list.
`update_user_info` was defined earlier in the file but never used.
Also moving over any logic from `langchain-core` to here as we slowly
drop `langchain-core` dependency.
Pydantic v1 is no longer undergoing active maintenance and v2 has been
out for almost 2 years, so it seems like an appropriate time to drop v1
scar tissue.
Manual pass to apply a few heuristics:
* Boost conceptual pages
* Deboost (is that a word?) index pages that list all content
* Prefer Agents pages if search query contains the word "agent"
* Add tags for a few selected pages
* Adding support for mapping interrupt ids -> resume values with the
`Command.resume_map` argument, like:
```py
resume_map = {
i.interrupt_id: f"human input for prompt {i.value}"
for i in parent_graph.get_state(thread_config).interrupts
}
parent_graph.invoke(Command(resume=resume_map), config=thread_config)
```
* Adds an `interrupts` attribute on `StateSnapshot` so that we can
access that directly rather than having to do
`get_state(thread_config).tasks` and then iterate over tasks to find
interrupts
* Deprecates undocumented feature where (if interrupting a graph from
the level of an interrupt), you could pass a dict mapping task ids ->
resume values. Now we recommend and endorse the `interrupt_id` approach
above.
I'll note, from an internal perspective, I would love if we didn't have
to pass around this map, but it seems like the best way right now to
make the necessary resume information necessary at different levels in a
graph with subgraphs.
Fix https://github.com/langchain-ai/langgraph/issues/4028
Slotted to be included in our v0.4.0 release early next week!
A few notes:
* We shouldn't be using `tool.poetry.dependencies`, that's deprecated -
waiting for a future PR to address this big change though.
* We should remove upper bounds for all deps unless strictly necessary.
We want to deprecate `TavilySearchResults` in langchain-community in
favor of `TavilySearch` in langchain-tavily.
Also update quickstart to use `init_chat_model`.
This PR does a few things:
1. Surfaces interrupts when `stream_mode='values'` (particularly
relevant for `invoke`, where this is the default behavior)
2. Adds an `interrupt_id` property to the `Interrupt` dataclass so that
interrupts can effectively be mapped to resumes
3. Minor docs updates to reflect the new pattern (no need for a special
section on interrupts with `invoke` and `ainvoke`)
* In a different PR (the one with the multiple resume values), as it's
more relevant there: add an `interrupts` property to `StateSnapshot` so
that `interrupts` can easily be iterated over if users are attempting to
map interrupts to resumes.
I **don't** recommend we release this until we have multi-resumes
working.
## Example
We have the following setup where we're sending multiple prompts to the
child graph, which uses `interrupt`:
```py
def child_graph(state):
human_input = interrupt(state["prompt"])
return {
"human_inputs": [human_input],
}
```
<img width="142" alt="Screenshot 2025-04-23 at 10 01 12 AM"
src="https://github.com/user-attachments/assets/c6238bf1-54ad-4e48-ab0b-60a0bfc18485"
/>
Old behavior:
```py
initial_input = {"prompts": ["a", "b"]}
print(parent_graph.invoke(input=initial_input,config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': []}
print(parent_graph.invoke(Command(resume="hello 1"),config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1']}
print(parent_graph.invoke(Command(resume="hello 2"),config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1', 'hello 2']}
```
New behavior:
```py
initial_input = {"prompts": ["a", "b"]}
print(parent_graph.invoke(input=initial_input,config=thread_config,stream_mode="values"))
"""
{
"prompts": ["a", "b"],
"human_inputs": [],
"__interrupt__": [
Interrupt(
value="a",
resumable=True,
ns=["child_graph:38d43a18-a5e7-8ab2-ca83-9d80f6e9ca83"]
),
Interrupt(
value="b",
resumable=True,
ns=["child_graph:dad810e8-738e-9f90-41cd-30c0091eb79b"]
)
]
}
"""
print(parent_graph.invoke(Command(resume="hello 1"),config=thread_config,stream_mode="values"))
"""
{
"prompts": ["a", "b"],
"human_inputs": ["hello 1"],
"__interrupt__": [
Interrupt(
value="b",
resumable=True,
ns=["child_graph:dad810e8-738e-9f90-41cd-30c0091eb79b"]
)
]
}
"""
print(parent_graph.invoke(Command(resume="hello 2"),config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1', 'hello 2']}
```
Using this argument, you can get more customization since you can do
`langgraph build` or directly `docker build` your image and then re-use
the `langgraph up --image my-image` and have it also spin up redis &
postgres for you.
Easier then writing your own compose file
- It now executes the same pregel algo as when the graph is executed
(without running any user code in nodes or conditional edges) to
discover all the edges
- This means we now support drawing the graph for all Pregel instances,
not just StateGraph
- This is done in preparation for new edge/node type coming in separate
PR
- Known changes
- custom labels on conditional edges to END are no longer displayed
- It now executes the same pregel algo as when the graph is executed (without running any user code in nodes or conditional edges) to discover all the edges
- This means we now support drawing the graph for all Pregel instances, not just StateGraph
If the state schema uses validators, skip the model construct
optimization.
For context, pydantic state can be significantly slower to run than
typed dict and dataclass states due to the full recursive validation.
We have some optimizations to reduce the impact of this (using cached
validators with model_construct), but this doesn't handle things like
field_validator.
We prefer correctness over performance, obviously.
Resolves: https://github.com/langchain-ai/langgraph/issues/4074
Signed-off-by: William Fu-Hinthorn <13333726+hinthornw@users.noreply.github.com>
The configuration expects the key "fields", not "text_fields": I had
failed to update across all implementations in the original PR
Thank you to Vincent Min for the fix!
---------
Co-authored-by: Vincent Min <93780551+VMinB12@users.noreply.github.com>
- Deletes all data associated with a thread_id
- Implemented in InMemory, Sqlite and Postgres checkpointers
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
- attached to every node to handle command/send return values
- used to be a full blown conditional edge, can be simpler by doing all
of it in a single function
- attached to every node to handle command/send return values
- used to be a full blown conditional edge, can be simpler by doing all of it in a single function
- Uses new `install-node.sh` script already used for Python Gen UI
- Add default `node_version` / `python_version` based on provided
`graphs`
Closes#4115
- This provides a new mode of execution where only the last checkpoint
is saved
- We save the last checkpoint no matter how the agent run is terminated
(success, error, interrupt, etc)
- This cuts down on cpu time spent on checkpointing, while not losing
any resilience benefits, given individual task writes are still saved
- If an error occurs and the run is retried, any tasks that completed
successfully before will be skipped (as currently)
- checkpoint_during=True is useful when you want to time-travel to inner
steps of a run
- The default value will remain the current behavior, ie.
checkpoint_during=True
If you're deploying with langgraph API, you don't need to manually
define a checkpointer. For folks who already know they'll be developing
with the api server, I'd like to save everyone time by making this more
clear in the docs on checkpointing.
- This provides a new mode of execution where only the last checkpoint is saved
- We save the last checkpoint no matter how the agent run is terminated (success, error, interrupt, etc)
- This cuts down on cpu time spent on checkpointing, while not losing any resilience benefits, given individual task writes are still saved
- If an error occurs and the run is retried, any tasks that completed successfully before will be skipped (as currently)
- checkpoint_during=True is useful when you want to time-travel to inner steps of a run
- The default value will remain the current behavior, ie. checkpoint_during=True
…entation.
This commit fixes a syntax error in the "langchain-ai.github"
documentation. The function called "some_node_inside_alice" was missing
a colon (:) after the function, which is required for valid Python
syntax.
### Summary
This is a large refactor of the content for the LangGraph Platform
deployment options. Although there are a lot of changes, I do feel
fairly confident that this is safe to merge and won't have any negative
impact related to confusion around deployment options. However, please
review thoroughly (i.e. run the docs locally).
### Goals and Non-Goals
Just wanted to explicitly state goals and non-goals so that we're clear
about what needs to be done now versus what can be done in a smaller
follow-up PR.
Goals
1. Add new content for the new deployment options (Self-Hosted Data
Plane, Self-Hosted Control Plane).
1. Hide old content for deprecated deployment options (BYOC).
1. Create a pair of "conceptual" and "how-to" pages for each deployment
option. As much as possible, the pages should have consistent headings.
1. Introduce the terms "control plane" and "data plane" and define them
plainly without hiding/abstracting information.
Non-Goals
1. Do not change the navigation of the existing deployment options. As
much as possible, update content in-place or add new pages. Changing the
navigation is a bigger task that can be done later.
1. Do not remove old content for deprecated deployment options. We may
need to refer to this later. There are only ~2 pages (I think).
### Next Steps
1. Update the architecture diagrams for each deployment option. Commit
Excalidraw file to source control.
1. Create a "how-to" page for the Control Plane UI. This page pertains
to 3/4 deployment options. Most of the content lives in the "how-to"
page for Cloud SaaS deployment.
1. Document required RBAC permissions for K8s for Self-Hosted Data Plane
and Self-Hosted Control Plane (and update links).
1. Figure out how to consolidate plan information.
1. Figure out where to document licensing, telemetry, custom
Postgres/Redis.
1. Update autoscaling content.
- When checkpointing is disabled don't call create_checkpoint in
PregelLoop
- In local_read apply writes directly to copies of updated channels
- Add BaseChannel.copy() method to create channel copies with less
overhead
- When checkpointing is disabled don't call create_checkpoint in PregelLoop
- In local_read apply writes directly to copies of updated channels
- Add BaseChannel.copy() method to create channel copies with less overhead
- This mirrors the work done earlier on BaseChannel.get()
- Comparing to a sentinel value is significantly faster than raising and
catching an exception
- This mirrors the work done earlier on BaseChannel.get()
- Comparing to a sentinel value is significantly faster than raising and catching an exception
- If the value to serialize is None we can use encode it in the string
type, and skip msgpack encoding
- Use None value for edge/branch channels in StateGraph
### Summary
1. Update API spec.
2. Clarify how to specify `requirements.txt` in `dependencies` list.
3. Clarify deletion policy for database.
4. Clarify resource allocation for `Production` type deployments.
5. Update supported Python versions.
- Used to be 2 channels per node, it is now one per node, which is the
minimum
- Now both hard edges, conditional edges, entrypoint and conditional
entrypoint all use the same channel to trigger a node
- Used to be 2 channels per node, it is now one per node, which is the minimum
- Now both hard edges, conditional edges, entrypoint and conditional entrypoint all use the same channel to trigger a node
- Used to be 2 channels per node, it is now one per node, which is the minimum
- Now both hard edges, conditional edges, entrypoint and conditional entrypoint all use the same channel to trigger a node
This PR fixes the return type annotation of the `update` method from
`None` to `bool`, as the method returns a boolean value indicating
whether self.values has changed
Co-authored-by: kakaogames <kakaogames@Justin-MacBook-Pro.local>
This pull request includes changes to add version admonitions to the
documentation and update the styling for these admonitions. The most
important changes include the addition of version information to the
documentation, updates to the CSS for version admonitions, and
modifications to the `mkdocs.yml` configuration file to include the new
stylesheets.
this should solve this #3991
---------
Co-authored-by: Eugene Yurtsev <eugene@langchain.dev>
This PR only allows this in the HTTP client.
I can follow up with a PR to allow throughout the entire API.
The use case is to allow instantiating the client once (w/ a single connection pool), but allowing changing api keys and any other headers at run time
- Added a validator to sanitize 'name' fields and prevent
string_pattern_mismatch errors.
- Replaced deprecated `dict` method with `model_dump` in line with
Pydantic v2.0 migration guidelines.
- Updated gen_perspectives_chain and gen_queries_chain to ensure
compatibility with structured output and include raw data where needed.
This allows use of fast_llm across the notebook.
---------
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
**Description:**
Make AsyncSqliteSaver examples workable.
**Issue:**
For "Usage within StateGraph" example,
SyntaxError: 'async with' outside async function
For "Raw usage" example
KeyError: 'checkpoint_ns' and KeyError: 'id'
**Dependencies:**
N/A
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
- This makes our checkpoint benchmarks more closely resemble the
behavior of our prod checkpointers
- Also found and fixed a bug w multiple subgraphs in same node
accidentally sharing checkpoints
- This makes our checkpoint benchmarks more closely resemble the behavior of our prod checkpointers
- Also found and fixed a bug w multiple subgraphs in same node accidentally sharing checkpoints
- When there are no values in checkpoint no need to run through all the
PULL candidates
- When there are input writes save updated_channels to use on the next
call to prepare_next_tasks
- RunnableCallable: Skip signature checks for internal callables where
we know the signatures ahead of time
- PregelNode: Avoid redoing subgraphs serarch when copying it
- CompiledStateGraph: Avoid copying PregelNode when attaching writers
- RunnableCallable: Skip signature checks for internal callables where we know the signatures ahead of time
- PregelNode: Avoid redoing subgraphs serarch when copying it
- CompiledStateGraph: Avoid copying PregelNode when attaching writers
- When there are no values in checkpoint no need to run through all the PULL candidates
- When there are input writes save updated_channels to use on the next call to prepare_next_tasks
Leverage information about which channels were updated in the previous
step to determine which tasks should be triggered. This can result in
significant speed up in prepare_next_tasks in some situations.
Includes:
- Explicit unsetting of runnable context var
- Weakref for PregelExecutableTask
both to reduce the chance of keeping a reference to an internal object
and preventing garbage collection
## Description
The documentation for working with Pydantic and graph State recommends
to use `AnyMessage` when working with LangChain types, but the code
example uses `BaseMessage`.
Includes:
- Explicit unsetting of runnable context var
- Weakref for PregelExecutableTask
both to reduce the chance of keeping a reference to an internal object and preventing
garbage collection
This method is useful for recreating a thread from a list of checkpoint writes. A new method is needed to clone a checkpoint that has been created from multiple writes (functional API, map-reduce)
Port of https://github.com/langchain-ai/langgraphjs/pull/969
Current text in the doc is incorrect:
```
Use the search tool to ask the user where they are, then look up the weather there
```
The search tool is not the one to use. Instead should just tell the
model to ask the user.
In addition, an important step is missing and makes the code seem less
impactful:
```python
location = interrupt("Please provide your location:")
```
The question to ask the human is actually coming from the LLM, there is
no need to hardcode it:
```python
...
location = interrupt(ask.question)
```
Before merging, someone who validates this should push an update to cell
outputs. I cleared it out from my branch because it made too many
updates to the file and would make it harder to review.
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
This pull request corrects a couple of typographical errors in the
documentation.
---------
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: Vadym Barda <vadym@langchain.dev>
* Document that `check_same_thread` as an option when creating sqlite
connection.
* Document why it's OK to do that.
---------
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
- sequential(2000) goes from 8.4s to 4.1s
- replace UUID(str).bytes with faster binascii.unhexlify, and do it only
once per step
- find only the first active trigger, instead of the full list
- use a dedicated function for checking active trigger
## Description
This PR enhances the state-model documentation by adding comprehensive
examples for advanced Pydantic usage in LangGraph. It addresses issue
#2745 regarding the need for better documentation of Pydantic schema
behavior.
### Changes
- Added new section on Advanced Pydantic Model Usage
- Added examples for serialization behavior with nested models
- Added section on runtime type coercion with examples
- Added documentation for proper message type handling (BaseMessage vs
AnyMessage)
- Updated Pydantic error URLs to latest version
### Related Issues
Closes#2745
### Testing
- All notebook cells have been executed and outputs verified
- Examples demonstrate proper usage patterns
- Error cases are properly documented
### Documentation
The changes are documentation-focused and include:
- New examples for complex Pydantic models
- Runtime coercion behavior examples
- Message type handling best practices
### Reviewers
@eyurtsev
- sequential(2000) goes from 8.4s to 4.7s
- replace UUID(str).bytes with simpler str.encode()
- find only the first active trigger, instead of the full list
- use a dedicated function for checking active trigger
- Was O(n^2) due to individual channels created for every conditional
edge, including the default cond edge created for Command
- Now using a single channel per node for all conditional edge / command
triggers, reducing to linear complexity
- Improves run time on sequential(200) from 1.8s to 0.14s
When searching for subgraphs do not attempt to search function non
locals for RunnableCallables as this captures unwanted reference to
surrounding variables.
- Previously the global resume value was passed to subgraphs without
being consumed
- This would result in two parallel subgraph calls being able to use the
same resume value
- Note this behavior can't be implemented over the wire, that will be
fixed in future PR
Closes#3398
- Was O(n^2) due to individual channels created for every conditional edge, including the default cond edge created for Command
- Now using a single channel per node for all conditional edge / command triggers, reducing to linear complexity
- Improves run time on sequential(200) from 1.8s to 0.14s
- Previously the global resume value was passed to subgraphs without being consumed
- This would result in two parallel subgraph calls being able to use the same resume value
- Note this behavior can't be implemented over the wire, that will be fixed in future PR
- Need to use a single operation to check if present and remove item
from list
- This doesn't fix the separate issue that parallel tasks claiming a
single interrupt value have somewhat undefined behavior (in the sense
that they will race to be the first to take it). That will be fixed in a
future PR
Closes#3875
- Need to use a single operation to check if present and remove item from list
- This doesn't fix the separate issue that parallel tasks claiming a single interrupt value have somewhat undefined behavior (in the sense that they will race to be the first to take it). That will be fixed in a future PR
- no dependency on any particular encryption lib (there is no py stdlib
encryption lib)
- works with any modern checkpointer, ie. those which use dumps_typed
and loads_typed methods to serialize data
- uses the default msg pack serializer, but also works with any custom
serializer
- backwards compatible with unencrypted data in same storage (will just
be read unencrypted)
- providing easy constructor to use AES encryption through pycriptodome
library, one single line of code to add it in
- other encryption libraries or algorithms (even assymetric ones) can be
used by implementing the two-method CipherProtocol interface
- cipher name (eg. aes) is stored with encrypted payload for forwards
compatibility
```py
import sqlite3
from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
from langgraph.checkpoint.sqlite import SqliteSaver
# will read AES key from env var LANGGRAPH_AES_KEY
serde = EncryptedSerializer.from_pycryptodome_aes()
# works with any other checkpointer, including custom ones
checkpointer = SqliteSaver(sqlite3.connect('...'), serde=serde)
```
- no dependency on any particular encryption lib (there is no py stdlib encryption lib)
- works with any modern checkpointer, ie. those which use dumps_typed and loads_typed methods to serialize data
- backwards compatible with unencrypted data in same storage (will just be read unencrypted)
- providing easy constructor to use AES encryption through pycriptodome library, one single line of code to add it in
- other encryption libraries or algorithms (even assymetric ones) can be used by implementing the two-method CipherProtocol interface
- cipher name (eg. aes) is stored with encrypted payload for forwards compatibility
- remove usage of require_at_least_one_of, we shouldn't be enforcing
presence of keys in inputs/updates, an empty dict is a valid
input/update
- ensure that values that were explcitly set/assigned in pydantic model
are saved even if equal to default value
- remove usage of require_at_least_one_of, we shouldn't be enforcing presence of keys in inputs/updates, an empty dict is a valid input/update
- ensure that values that were explcitly set/assigned in pydantic model are saved even if equal to default value
Since we are demonstrating thread-level memory not human-in-the-loop, a
string is more straightforward and reliable than AssertionError(), when
dealing with 'Unknown Location'.
if ! diff -q schemas/schema.json schemas/schema.current.json > /dev/null; then
echo "Error: Langgraph.json configuration schema has changed. Please run 'poetry run python generate_schema.py' in the libs/cli directory and commit the changes."
echo "Error: Langgraph.json configuration schema has changed. Please run 'uv run python generate_schema.py' in the libs/cli directory and commit the changes."
Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic, and more – LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents.
> [!NOTE]
> Looking for the JS version? See the [JS repo](https://github.com/langchain-ai/langgraphjs) and the [JS docs](https://langchain-ai.github.io/langgraphjs/).
## Get started
## Overview
Install LangGraph:
[LangGraph](https://langchain-ai.github.io/langgraph/) is a library for building
stateful, multi-actor applications with LLMs, used to create agent and multi-agent
workflows. Check out an introductory tutorial [here](https://langchain-ai.github.io/langgraph/tutorials/introduction/).
LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain.
### Why use LangGraph?
LangGraph powers [production-grade agents](https://www.langchain.com/built-with-langgraph), trusted by Linkedin, Uber, Klarna, GitLab, and many more. LangGraph provides fine-grained control over both the flow and state of your agent applications. It implements a central [persistence layer](https://langchain-ai.github.io/langgraph/concepts/persistence/), enabling features that are common to most agent architectures:
- **Memory**: LangGraph persists arbitrary aspects of your application's state,
supporting memory of conversations and other updates within and across user
interactions;
- **Human-in-the-loop**: Because state is checkpointed, execution can be interrupted
and resumed, allowing for decisions, validation, and corrections at key stages via
human input.
Standardizing these components allows individuals and teams to focus on the behavior
of their agent, instead of its supporting infrastructure.
Through [LangGraph Platform](#langgraph-platform), LangGraph also provides tooling for
the development, deployment, debugging, and monitoring of your applications.
LangGraph integrates seamlessly with
[LangChain](https://python.langchain.com/docs/introduction/) and
[LangSmith](https://docs.smith.langchain.com/) (but does not require them).
To learn more about LangGraph, check out our first LangChain Academy
course, *Introduction to LangGraph*, available for free
[LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform) is infrastructure for deploying LangGraph agents. It is a commercial solution for deploying agentic applications to production, built on the open-source LangGraph framework. The LangGraph Platform consists of several components that work together to support the development, deployment, debugging, and monitoring of LangGraph applications: [LangGraph Server](https://langchain-ai.github.io/langgraph/concepts/langgraph_server) (APIs), [LangGraph SDKs](https://langchain-ai.github.io/langgraph/concepts/sdk) (clients for the APIs), [LangGraph CLI](https://langchain-ai.github.io/langgraph/concepts/langgraph_cli) (command line tool for building the server), and [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio) (UI/debugger).
See deployment options [here](https://langchain-ai.github.io/langgraph/concepts/deployment_options/)
(includes a free tier).
Here are some common issues that arise in complex deployments, which LangGraph Platform addresses:
- **Streaming support**: LangGraph Server provides [multiple streaming modes](https://langchain-ai.github.io/langgraph/concepts/streaming) optimized for various application needs
- **Background runs**: Runs agents asynchronously in the background
- **Support for long running agents**: Infrastructure that can handle long running processes
- **[Double texting](https://langchain-ai.github.io/langgraph/concepts/double_texting)**: Handle the case where you get two messages from the user before the agent can respond
- **Handle burstiness**: Task queue for ensuring requests are handled consistently without loss, even under heavy loads
## Installation
```shell
```
pip install -U langgraph
```
## Example
Let's build a tool-calling [ReAct-style](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-implementation) agent that uses a search tool!
```shell
pip install langchain-anthropic
```
```shell
exportANTHROPIC_API_KEY=sk-...
```
Optionally, we can set up [LangSmith](https://docs.smith.langchain.com/) for best-in-class observability.
```shell
exportLANGSMITH_TRACING=true
exportLANGSMITH_API_KEY=lsv2_sk_...
```
The simplest way to create a tool-calling agent in LangGraph is to use `create_react_agent`:
<details open>
<summary>High-level implementation</summary>
Then, create an agent [using prebuilt components](https://langchain-ai.github.io/langgraph/agents/agents/):
```python
# pip install -qU "langchain[anthropic]" to call the model
fromlanggraph.prebuiltimportcreate_react_agent
fromlanggraph.checkpoint.memoryimportMemorySaver
fromlangchain_anthropicimportChatAnthropic
fromlangchain_core.toolsimporttool
# Define the tools for the agent to use
@tool
defsearch(query:str):
"""Call to surf the web."""
# This is a placeholder, but don't tell the LLM that...
{"messages":[{"role":"user","content":"what is the weather in sf"}]},
config={"configurable":{"thread_id":42}}
)
final_state["messages"][-1].content
```
```
"Based on the search results, I can tell you that the current weather in San Francisco is:\n\nTemperature: 60 degrees Fahrenheit\nConditions: Foggy\n\nSan Francisco is known for its microclimates and frequent fog, especially during the summer months. The temperature of 60°F (about 15.5°C) is quite typical for the city, which tends to have mild temperatures year-round. The fog, often referred to as "Karl the Fog" by locals, is a characteristic feature of San Francisco\'s weather, particularly in the mornings and evenings.\n\nIs there anything else you\'d like to know about the weather in San Francisco or any other location?"
```
Now when we pass the same <code>"thread_id"</code>, the conversation context is retained via the saved state (i.e. stored list of messages)
```python
final_state=app.invoke(
{"messages":[{"role":"user","content":"what about ny"}]},
config={"configurable":{"thread_id":42}}
)
final_state["messages"][-1].content
```
```
"Based on the search results, I can tell you that the current weather in New York City is:\n\nTemperature: 90 degrees Fahrenheit (approximately 32.2 degrees Celsius)\nConditions: Sunny\n\nThis weather is quite different from what we just saw in San Francisco. New York is experiencing much warmer temperatures right now. Here are a few points to note:\n\n1. The temperature of 90°F is quite hot, typical of summer weather in New York City.\n2. The sunny conditions suggest clear skies, which is great for outdoor activities but also means it might feel even hotter due to direct sunlight.\n3. This kind of weather in New York often comes with high humidity, which can make it feel even warmer than the actual temperature suggests.\n\nIt's interesting to see the stark contrast between San Francisco's mild, foggy weather and New York's hot, sunny conditions. This difference illustrates how varied weather can be across different parts of the United States, even on the same day.\n\nIs there anything else you'd like to know about the weather in New York or any other location?"
```
</details>
> [!TIP]
> LangGraph is a **low-level** framework that allows you to implement any custom agent
architectures. Click on the low-level implementation below to see how to implement a
# If the LLM makes a tool call, then we route to the "tools" node
iflast_message.tool_calls:
return"tools"
# Otherwise, we stop (reply to the user)
returnEND
# Define the function that calls the model
defcall_model(state:MessagesState):
messages=state['messages']
response=model.invoke(messages)
# We return a list, because this will get added to the existing list
return{"messages":[response]}
# Define a new graph
workflow=StateGraph(MessagesState)
# Define the two nodes we will cycle between
workflow.add_node("agent",call_model)
workflow.add_node("tools",tool_node)
# Set the entrypoint as `agent`
# This means that this node is the first one called
workflow.add_edge(START,"agent")
# We now add a conditional edge
workflow.add_conditional_edges(
# First, we define the start node. We use `agent`.
# This means these are the edges taken after the `agent` node is called.
"agent",
# Next, we pass in the function that will determine which node is called next.
should_continue,
agent=create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_weather],
prompt="You are a helpful assistant"
)
# We now add a normal edge from `tools` to `agent`.
# This means that after `tools` is called, `agent` node is called next.
workflow.add_edge("tools",'agent')
# Initialize memory to persist state between graph runs
checkpointer=MemorySaver()
# Finally, we compile it!
# This compiles it into a LangChain Runnable,
# meaning you can use it as you would any other runnable.
# Note that we're (optionally) passing the memory when compiling the graph
app=workflow.compile(checkpointer=checkpointer)
# Use the agent
final_state=app.invoke(
{"messages":[{"role":"user","content":"what is the weather in sf"}]},
config={"configurable":{"thread_id":42}}
# Run the agent
agent.invoke(
{"messages":[{"role":"user","content":"what is the weather in sf"}]}
)
final_state["messages"][-1].content
```
<b>Step-by-step Breakdown</b>:
For more information, see the [Quickstart](https://langchain-ai.github.io/langgraph/agents/agents/). Or, to learn how to build an [agent workflow](https://langchain-ai.github.io/langgraph/concepts/low_level/) with a customizable architecture, long-term memory, and other complex task handling, see the [LangGraph basics tutorials](https://langchain-ai.github.io/langgraph/tutorials/get-started/1-build-basic-chatbot/).
<details>
<summary>Initialize the model and tools.</summary>
<ul>
<li>
We use <code>ChatAnthropic</code> as our LLM. <strong>NOTE:</strong> we need to make sure the model knows that it has these tools available to call. We can do this by converting the LangChain tools into the format for OpenAI tool calling using the <code>.bind_tools()</code> method.
</li>
<li>
We define the tools we want to use - a search tool in our case. It is really easy to create your own tools - see documentation here on how to do that <a href="https://python.langchain.com/docs/how_to/custom_tools/">here</a>.
</li>
</ul>
</details>
## Core benefits
<details>
<summary>Initialize graph with state.</summary>
LangGraph provides low-level supporting infrastructure for *any* long-running, stateful workflow or agent. LangGraph does not abstract prompts or architecture, and provides the following central benefits:
<ul>
<li>We initialize graph (<code>StateGraph</code>) by passing state schema (in our case <code>MessagesState</code>)</li>
<li><code>MessagesState</code> is a prebuilt state schema that has one attribute -- a list of LangChain <code>Message</code> objects, as well as logic for merging the updates from each node into the state.</li>
</ul>
</details>
- [Durable execution](https://langchain-ai.github.io/langgraph/concepts/durable_execution/): Build agents that persist through failures and can run for extended periods, automatically resuming from exactly where they left off.
- [Human-in-the-loop](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/): Seamlessly incorporate human oversight by inspecting and modifying agent state at any point during execution.
- [Comprehensive memory](https://langchain-ai.github.io/langgraph/concepts/memory/): Create truly stateful agents with both short-term working memory for ongoing reasoning and long-term persistent memory across sessions.
- [Debugging with LangSmith](http://www.langchain.com/langsmith): Gain deep visibility into complex agent behavior with visualization tools that trace execution paths, capture state transitions, and provide detailed runtime metrics.
- [Production-ready deployment](https://langchain-ai.github.io/langgraph/concepts/deployment_options/): Deploy sophisticated agent systems confidently with scalable infrastructure designed to handle the unique challenges of stateful, long-running workflows.
<details>
<summary>Define graph nodes.</summary>
## LangGraph’s ecosystem
There are two main nodes we need:
While LangGraph can be used standalone, it also integrates seamlessly with any LangChain product, giving developers a full suite of tools for building agents. To improve your LLM application development, pair LangGraph with:
<ul>
<li>The <code>agent</code> node: responsible for deciding what (if any) actions to take.</li>
<li>The <code>tools</code> node that invokes tools: if the agent decides to take an action, this node will then execute that action.</li>
</ul>
</details>
- [LangSmith](http://www.langchain.com/langsmith) — Helpful for agent evals and observability. Debug poor-performing LLM app runs, evaluate agent trajectories, gain visibility in production, and improve performance over time.
- [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform) — Deploy and scale agents effortlessly with a purpose-built deployment platform for long running, stateful workflows. Discover, reuse, configure, and share agents across teams — and iterate quickly with visual prototyping in [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/).
- [LangChain](https://python.langchain.com/docs/introduction/) – Provides integrations and composable components to streamline LLM application development.
<details>
<summary>Define entry point and graph edges.</summary>
> [!NOTE]
> Looking for the JS version of LangGraph? See the [JS repo](https://github.com/langchain-ai/langgraphjs) and the [JS docs](https://langchain-ai.github.io/langgraphjs/).
First, we need to set the entry point for graph execution - <code>agent</code> node.
## Additional resources
Then we define one normal and one conditional edge. Conditional edge means that the destination depends on the contents of the graph's state (<code>MessagesState</code>). In our case, the destination is not known until the agent (LLM) decides.
- [Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.).
- [Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components.
- [Examples](https://langchain-ai.github.io/langgraph/tutorials/overview/): Guided examples on getting started with LangGraph.
- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course.
- [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted.
- [Case studies](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship AI applications at scale.
<ul>
<li>Conditional edge: after the agent is called, we should either:
<ul>
<li>a. Run tools if the agent said to take an action, OR</li>
<li>b. Finish (respond to the user) if the agent did not ask to run tools</li>
</ul>
</li>
<li>Normal edge: after the tools are invoked, the graph should always return to the agent to decide what to do next</li>
</ul>
</details>
## Acknowledgements
<details>
<summary>Compile the graph.</summary>
<ul>
<li>
When we compile the graph, we turn it into a LangChain
which automatically enables calling <code>.invoke()</code>, <code>.stream()</code> and <code>.batch()</code>
with your inputs
</li>
<li>
We can also optionally pass checkpointer object for persisting state between graph runs, and enabling memory,
human-in-the-loop workflows, time travel and more. In our case we use <code>MemorySaver</code> -
a simple in-memory checkpointer
</li>
</ul>
</details>
<details>
<summary>Execute the graph.</summary>
<ol>
<li>LangGraph adds the input message to the internal state, then passes the state to the entrypoint node, <code>"agent"</code>.</li>
<li>The <code>"agent"</code> node executes, invoking the chat model.</li>
<li>The chat model returns an <code>AIMessage</code>. LangGraph adds this to the state.</li>
<li>Graph cycles the following steps until there are no more <code>tool_calls</code> on <code>AIMessage</code>:
<ul>
<li>If <code>AIMessage</code> has <code>tool_calls</code>, <code>"tools"</code> node executes</li>
<li>The <code>"agent"</code> node executes again and returns <code>AIMessage</code></li>
</ul>
</li>
<li>Execution progresses to the special <code>END</code> value and outputs the final state. And as a result, we get a list of all our chat messages as output.</li>
</ol>
</details>
</details>
## Documentation
* [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Learn to build with LangGraph through guided examples.
* [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Accomplish specific things within LangGraph, from streaming, to adding memory & persistence, to common design patterns (branching, subgraphs, etc.), these are the place to go if you want to copy and run a specific code snippet.
* [Conceptual Guides](https://langchain-ai.github.io/langgraph/concepts/high_level/): In-depth explanations of the key concepts and principles behind LangGraph, such as nodes, edges, state and more.
* [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Review important classes and methods, simple examples of how to use the graph and checkpointing APIs, higher-level prebuilt components and more.
* [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform): LangGraph Platform is a commercial solution for deploying agentic applications in production, built on the open-source LangGraph framework.
## Resources
* [Built with LangGraph](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications.
## Contributing
For more information on how to contribute, see [here](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md).
LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.