diff --git a/README.md b/README.md index ec9967659..26550f5b4 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ While LangGraph can be used standalone, it also integrates seamlessly with any L - [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 Forum](https://forum.langchain.com/): Connect with the community and share all of your technical questions, ideas, and feedback. - [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. diff --git a/docs/_scripts/notebook_hooks.py b/docs/_scripts/notebook_hooks.py index db31e41ce..81882d397 100644 --- a/docs/_scripts/notebook_hooks.py +++ b/docs/_scripts/notebook_hooks.py @@ -3,6 +3,7 @@ Lifecycle events: https://www.mkdocs.org/dev-guide/plugins/#events """ +import json import logging import os import posixpath @@ -15,8 +16,8 @@ from mkdocs.structure.files import Files, File from mkdocs.structure.pages import Page from _scripts.generate_api_reference_links import update_markdown_with_imports -from _scripts.notebook_convert import convert_notebook from _scripts.link_map import JS_LINK_MAP +from _scripts.notebook_convert import convert_notebook logger = logging.getLogger(__name__) logging.basicConfig() @@ -100,10 +101,6 @@ REDIRECT_MAP = { "how-tos/create-react-agent-memory.ipynb": "agents/memory.md", "how-tos/create-react-agent-system-prompt.ipynb": "agents/context.md#prompts", "how-tos/create-react-agent-structured-output.ipynb": "agents/agents.md#structured-output", - # Time-travel - "how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.md", - # breakpoints - "how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "how-tos/human_in_the_loop/breakpoints.md", # misc "prebuilt.md": "agents/prebuilt.md", "reference/prebuilt.md": "reference/agents.md", @@ -125,6 +122,11 @@ REDIRECT_MAP = { "how-tos/review-tool-calls-functional.ipynb": "how-tos/use-functional-api.md", "how-tos/create-react-agent-hitl.ipynb": "how-tos/human_in_the_loop/add-human-in-the-loop.md", "agents/human-in-the-loop.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md", + "how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "how-tos/human_in_the_loop/breakpoints.md", + "concepts/breakpoints.md": "concepts/human_in_the_loop.md", + "how-tos/human_in_the_loop/breakpoints.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md", + "cloud/how-tos/human_in_the_loop_breakpoint.md": "cloud/how-tos/add-human-in-the-loop.md", + "how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.md", } @@ -356,12 +358,16 @@ def _on_page_markdown_with_config( def on_page_markdown(markdown: str, page: Page, **kwargs: Dict[str, Any]): - return _on_page_markdown_with_config( - markdown, - page, - add_api_references=True, - **kwargs, + finalized_markdown = ( + _on_page_markdown_with_config( + markdown, + page, + add_api_references=True, + **kwargs, + ) ) + page.meta["original_markdown"] = finalized_markdown + return finalized_markdown # redirects @@ -431,20 +437,51 @@ height="0" width="0" style="display:none;visibility:hidden"> else: return html # fallback if no found +def _inject_markdown_into_html(html: str, page: Page) -> str: + """Inject the original markdown content into the HTML page as JSON.""" + original_markdown = page.meta.get("original_markdown", "") + if not original_markdown: + return html + markdown_data = { + "markdown": original_markdown, + "title": page.title or "Page Content", + "url": page.url or "", + } -def on_post_page(output: str, page: Page, config: MkDocsConfig) -> str: + # Properly escape the JSON for HTML + json_content = json.dumps(markdown_data, ensure_ascii=False) + + json_content = ( + json_content.replace("{json_content}' + ) + + # Insert before if it exists, otherwise before + if "" not in html: + raise ValueError( + "HTML does not contain tag. Cannot inject markdown content." + ) + return html.replace("", f"{script_content}") + +def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str: """Inject Google Tag Manager noscript tag immediately after . Args: - output: The HTML output of the page. + html: The HTML output of the page. page: The page instance. config: The MkDocs configuration object. Returns: modified HTML output with GTM code injected. """ - return _inject_gtm(output) - + html = _inject_markdown_into_html(html, page) + return _inject_gtm(html) # Create HTML files for redirects after site dir has been built def on_post_build(config): diff --git a/docs/docs/agents/evals.md b/docs/docs/agents/evals.md index 74fdb5a63..ead956dd5 100644 --- a/docs/docs/agents/evals.md +++ b/docs/docs/agents/evals.md @@ -15,7 +15,7 @@ To evaluate your agent's performance you can use `LangSmith` [evaluations](https def evaluator(*, outputs: dict, reference_outputs: dict): # compare agent outputs against reference outputs output_messages = outputs["messages"] - reference_messages = reference["messages"] + reference_messages = reference_outputs["messages"] score = compare_messages(output_messages, reference_messages) return {"key": "evaluator_score", "score": score} ``` diff --git a/docs/docs/agents/models.md b/docs/docs/agents/models.md index 6b8af56a7..46db9c41d 100644 --- a/docs/docs/agents/models.md +++ b/docs/docs/agents/models.md @@ -7,7 +7,7 @@ LangGraph provides built-in support for [LLMs (language models)](https://python. Use [`init_chat_model`](https://python.langchain.com/docs/how_to/chat_models_universal_init/) to initialize models: -{!snippets/chat_model_tabs.md!} +{% include-markdown "../../snippets/chat_model_tabs.md" %} ### Instantiate a model directly diff --git a/docs/docs/cloud/deployment/self_hosted_data_plane.md b/docs/docs/cloud/deployment/self_hosted_data_plane.md index bcb07028c..f6d4dcf65 100644 --- a/docs/docs/cloud/deployment/self_hosted_data_plane.md +++ b/docs/docs/cloud/deployment/self_hosted_data_plane.md @@ -35,7 +35,6 @@ Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](. 1. Configure your `langgraph-dataplane-values.yaml` file. config: - langgraphPlatformLicenseKey: "" # Your LangGraph Platform license key langsmithApiKey: "" # API Key of your Workspace langsmithWorkspaceId: "" # Workspace ID hostBackendUrl: "https://api.host.langchain.com" # Only override this if on EU diff --git a/docs/docs/cloud/how-tos/add-human-in-the-loop.md b/docs/docs/cloud/how-tos/add-human-in-the-loop.md index 7077d01b4..c16e4db1e 100644 --- a/docs/docs/cloud/how-tos/add-human-in-the-loop.md +++ b/docs/docs/cloud/how-tos/add-human-in-the-loop.md @@ -2,7 +2,7 @@ To review, edit, and approve tool calls in an agent or workflow, use LangGraph's [human-in-the-loop](../../concepts/human_in_the_loop.md) features. -## LangGraph API invoke & resume +## Dynamic interrupts === "Python" @@ -301,6 +301,185 @@ To review, edit, and approve tool calls in an agent or workflow, use LangGraph's }" ``` +## Static interrupts + +Static interrupts (also known as static breakpoints) are triggered either before or after a node executes. + +!!! warning + + Static interrupts are **not** recommended for human-in-the-loop workflows. They are best used for debugging and testing. + +You can set static interrupts by specifying `interrupt_before` and `interrupt_after` at compile time: + +```python +# highlight-next-line +graph = graph_builder.compile( # (1)! + # highlight-next-line + interrupt_before=["node_a"], # (2)! + # highlight-next-line + interrupt_after=["node_b", "node_c"], # (3)! +) +``` + +1. The breakpoints are set during `compile` time. +2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. +3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. + +Alternatively, you can set static interrupts at run time: + +=== "Python" + + ```python + # highlight-next-line + await client.runs.wait( # (1)! + thread_id, + assistant_id, + inputs=inputs, + # highlight-next-line + interrupt_before=["node_a"], # (2)! + # highlight-next-line + interrupt_after=["node_b", "node_c"] # (3)! + ) + ``` + + 1. `client.runs.wait` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation. + 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. + 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. + +=== "JavaScript" + + ```js + // highlight-next-line + await client.runs.wait( // (1)! + threadID, + assistantID, + { + input: input, + // highlight-next-line + interruptBefore: ["node_a"], // (2)! + // highlight-next-line + interruptAfter: ["node_b", "node_c"] // (3)! + } + ) + ``` + + 1. `client.runs.wait` is called with the `interruptBefore` and `interruptAfter` parameters. This is a run-time configuration and can be changed for every invocation. + 2. `interruptBefore` specifies the nodes where execution should pause before the node is executed. + 3. `interruptAfter` specifies the nodes where execution should pause after the node is executed. + +=== "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/wait \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"interrupt_before\": [\"node_a\"], + \"interrupt_after\": [\"node_b\", \"node_c\"], + \"input\": + }" + ``` + +The following example shows how to add static interrupts: + +=== "Python" + + ```python + from langgraph_sdk import get_client + client = get_client(url=) + + # Using the graph deployed with the name "agent" + assistant_id = "agent" + + # create a thread + thread = await client.threads.create() + thread_id = thread["thread_id"] + + # Run the graph until the breakpoint + result = await client.runs.wait( + thread_id, + assistant_id, + input=inputs # (1)! + ) + + # Resume the graph + await client.runs.wait( + thread_id, + assistant_id, + input=None # (2)! + ) + ``` + + 1. The graph is run until the first breakpoint is hit. + 2. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit. + +=== "JavaScript" + + ```js + import { Client } from "@langchain/langgraph-sdk"; + const client = new Client({ apiUrl: }); + + // Using the graph deployed with the name "agent" + const assistantID = "agent"; + + // create a thread + const thread = await client.threads.create(); + const threadID = thread["thread_id"]; + + // Run the graph until the breakpoint + const result = await client.runs.wait( + threadID, + assistantID, + { input: input } // (1)! + ); + + // Resume the graph + await client.runs.wait( + threadID, + assistantID, + { input: null } // (2)! + ); + ``` + + 1. The graph is run until the first breakpoint is hit. + 2. The graph is resumed by passing in `null` for the input. This will run the graph until the next breakpoint is hit. + +=== "cURL" + + Create a thread: + + ```bash + curl --request POST \ + --url /threads \ + --header 'Content-Type: application/json' \ + --data '{}' + ``` + + Run the graph until the breakpoint: + + ```bash + curl --request POST \ + --url /threads//runs/wait \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": + }" + ``` + + Resume the graph: + + ```bash + curl --request POST \ + --url /threads//runs/wait \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\" + }" + ``` + + ## Learn more - [Human-in-the-loop conceptual guide](../../concepts/human_in_the_loop.md): learn more about LangGraph human-in-the-loop features. diff --git a/docs/docs/cloud/how-tos/human_in_the_loop_breakpoint.md b/docs/docs/cloud/how-tos/human_in_the_loop_breakpoint.md deleted file mode 100644 index f52c96954..000000000 --- a/docs/docs/cloud/how-tos/human_in_the_loop_breakpoint.md +++ /dev/null @@ -1,185 +0,0 @@ -# Set breakpoints using Server API - -[Breakpoints](../../concepts/breakpoints.md) pause graph execution at defined points and let you step through each stage. They use LangGraph's [**persistence layer**](../../concepts/persistence.md), which saves the graph state after each step. - -With breakpoints, you can inspect the graph's state and node inputs at any point. Execution pauses indefinitely until you resume, as the checkpointer preserves the state. - -!!! tip - - For conceptual information on breakpoints, see [Breakpoints](../../concepts/breakpoints.md). - -## Set static breakpoints - -Static breakpoints are triggered either before or after a node executes. You can set static breakpoints by specifying `interrupt_before` and `interrupt_after` at compile time or run time. - -=== "Compile time" - - ```python - # highlight-next-line - graph = graph_builder.compile( # (1)! - # highlight-next-line - interrupt_before=["node_a"], # (2)! - # highlight-next-line - interrupt_after=["node_b", "node_c"], # (3)! - ) - ``` - - 1. The breakpoints are set during `compile` time. - 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. - 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. - -=== "Run time" - - === "Python" - - ```python - # highlight-next-line - await client.runs.wait( # (1)! - thread_id, - assistant_id, - inputs=inputs, - # highlight-next-line - interrupt_before=["node_a"], # (2)! - # highlight-next-line - interrupt_after=["node_b", "node_c"] # (3)! - ) - ``` - - 1. `client.runs.wait` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation. - 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. - 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. - - === "JavaScript" - - ```js - // highlight-next-line - await client.runs.wait( // (1)! - threadID, - assistantID, - { - input: input, - // highlight-next-line - interruptBefore: ["node_a"], // (2)! - // highlight-next-line - interruptAfter: ["node_b", "node_c"] // (3)! - } - ) - ``` - - 1. `client.runs.wait` is called with the `interruptBefore` and `interruptAfter` parameters. This is a run-time configuration and can be changed for every invocation. - 2. `interruptBefore` specifies the nodes where execution should pause before the node is executed. - 3. `interruptAfter` specifies the nodes where execution should pause after the node is executed. - - === "cURL" - - ```bash - curl --request POST \ - --url /threads//runs/wait \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"interrupt_before\": [\"node_a\"], - \"interrupt_after\": [\"node_b\", \"node_c\"], - \"input\": - }" - ``` - -## Example - -This example shows how to add **static** breakpoints. See [Use breakpoints](../../how-tos/human_in_the_loop/breakpoints.md) for more options on adding breakpoints. - -=== "Python" - - ```python - from langgraph_sdk import get_client - client = get_client(url=) - - # Using the graph deployed with the name "agent" - assistant_id = "agent" - - # create a thread - thread = await client.threads.create() - thread_id = thread["thread_id"] - - # Run the graph until the breakpoint - result = await client.runs.wait( - thread_id, - assistant_id, - input=inputs # (1)! - ) - - # Resume the graph - await client.runs.wait( - thread_id, - assistant_id, - input=None # (2)! - ) - ``` - - 1. The graph is run until the first breakpoint is hit. - 2. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit. - -=== "JavaScript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - const client = new Client({ apiUrl: }); - - // Using the graph deployed with the name "agent" - const assistantID = "agent"; - - // create a thread - const thread = await client.threads.create(); - const threadID = thread["thread_id"]; - - // Run the graph until the breakpoint - const result = await client.runs.wait( - threadID, - assistantID, - { input: input } // (1)! - ); - - // Resume the graph - await client.runs.wait( - threadID, - assistantID, - { input: null } // (2)! - ); - ``` - - 1. The graph is run until the first breakpoint is hit. - 2. The graph is resumed by passing in `null` for the input. This will run the graph until the next breakpoint is hit. - -=== "cURL" - - Create a thread: - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' \ - --data '{}' - ``` - - Run the graph until the breakpoint: - - ```bash - curl --request POST \ - --url /threads//runs/wait \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": - }" - ``` - - Resume the graph: - - ```bash - curl --request POST \ - --url /threads//runs/wait \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\" - }" - ``` \ No newline at end of file diff --git a/docs/docs/cloud/how-tos/invoke_studio.md b/docs/docs/cloud/how-tos/invoke_studio.md index 0548373e1..d01b8eeb3 100644 --- a/docs/docs/cloud/how-tos/invoke_studio.md +++ b/docs/docs/cloud/how-tos/invoke_studio.md @@ -29,7 +29,7 @@ Click the dropdown next to "Submit" and click the toggle to enable/disable strea To run your graph with breakpoints, click the "Interrupt" button. Select a node and whether to pause before and/or after that node has executed. Click "Continue" in the thread log to resume execution. -For more information on breakpoints see [here](../../concepts/breakpoints.md). +For more information on breakpoints see [here](../../concepts/human_in_the_loop.md). ### Submit run diff --git a/docs/docs/cloud/reference/cli.md b/docs/docs/cloud/reference/cli.md index 2181f59e2..87f405cba 100644 --- a/docs/docs/cloud/reference/cli.md +++ b/docs/docs/cloud/reference/cli.md @@ -409,6 +409,8 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema]( | Option | Default | Description | | ---------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `--wait` | | Wait for services to start before returning. Implies --detach | +| `--base-image TEXT` | `langchain/langgraph-api` | Base image to use for the LangGraph API server. Pin to specific versions using version tags. | +| `--image TEXT` | | Docker image to use for the langgraph-api service. If specified, skips building and uses this image directly. | | `--postgres-uri TEXT` | Local database | Postgres URI to use for the database. | | `--watch` | | Restart on file changes | | `--debugger-base-url TEXT` | `http://127.0.0.1:[PORT]` | URL used by the debugger to access LangGraph API. | @@ -436,6 +438,8 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema]( | Option | Default | Description | | ---------------------------------------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `--wait` | | Wait for services to start before returning. Implies --detach | +| `--base-image TEXT` | `langchain/langgraph-api` | Base image to use for the LangGraph API server. Pin to specific versions using version tags. | +| `--image TEXT` | | Docker image to use for the langgraph-api service. If specified, skips building and uses this image directly. | | `--postgres-uri TEXT` | Local database | Postgres URI to use for the database. | | `--watch` | | Restart on file changes | | `-c, --config FILE` | `langgraph.json` | Path to configuration file declaring dependencies, graphs and environment variables. | diff --git a/docs/docs/cloud/reference/langgraph_server_changelog.md b/docs/docs/cloud/reference/langgraph_server_changelog.md index bd5484e8c..369c21530 100644 --- a/docs/docs/cloud/reference/langgraph_server_changelog.md +++ b/docs/docs/cloud/reference/langgraph_server_changelog.md @@ -4,6 +4,64 @@ --- +## v0.2.86 (2025-07-11) +- Honored tool descriptions in the `/mcp` endpoint to align with expected functionality. + +## v0.2.85 (2025-07-10) +- Added support for the `on_disconnect` field to `runs/wait` and included disconnect logs for better debugging. + +## v0.2.84 (2025-07-09) +- Removed unnecessary status updates to streamline thread handling and updated version to 0.2.84. + +## v0.2.83 (2025-07-09) +- Reduced the default time-to-live for resumable streams to 2 minutes. +- Enhanced data submission logic to send data to both Beacon and LangSmith instance based on license configuration. +- Enabled submission of self-hosted data to a Langsmith instance when the endpoint is configured. + +## v0.2.82 (2025-07-03) +- Addressed a race condition in background runs by implementing a lock using join, ensuring reliable execution across CTEs. + +## v0.2.81 (2025-07-03) +- Optimized run streams by reducing initial wait time to improve responsiveness for older or non-existent runs. + +## v0.2.80 (2025-07-03) +- Corrected parameter passing in the `logger.ainfo()` API call to resolve a TypeError. + +## v0.2.79 (2025-07-02) +- Fixed a JsonDecodeError in checkpointing with remote graph by correcting JSON serialization to handle trailing slashes properly. +- Introduced a configuration flag to disable webhooks globally across all routes. + +## v0.2.78 (2025-07-02) +- Added timeout retries to webhook calls to improve reliability. +- Added HTTP request metrics, including a request count and latency histogram, for enhanced monitoring capabilities. + +## v0.2.77 (2025-07-02) +- Added HTTP metrics to improve performance monitoring. +- Changed the Redis cache delimiter to reduce conflicts with subgraph message names and updated caching behavior. + +## v0.2.76 (2025-07-01) +- Updated Redis cache delimiter to prevent conflicts with subgraph messages. + +## v0.2.74 (2025-06-30) +- Scheduled webhooks in an isolated loop to ensure thread-safe operations and prevent errors with PYTHONASYNCIODEBUG=1. + +## v0.2.73 (2025-06-27) +- Fixed an infinite frame loop issue and removed the dict_parser due to structlog's unexpected behavior. +- Throw a 409 error on deadlock occurrence during run cancellations to handle lock conflicts gracefully. + +## v0.2.72 (2025-06-27) +- Ensured compatibility with future langgraph versions. +- Implemented a 409 response status to handle deadlock issues during cancellation. + +## v0.2.71 (2025-06-26) +- Improved logging for better clarity and detail regarding log types. + +## v0.2.70 (2025-06-26) +- Improved error handling to better distinguish and log TimeoutErrors caused by users from internal run timeouts. + +## v0.2.69 (2025-06-26) +- Added sorting and pagination to the crons API and updated schema definitions for improved accuracy. + ## v0.2.66 (2025-06-26) - Fixed a 404 error when creating multiple runs with the same thread_id using `on_not_exist="create"`. diff --git a/docs/docs/concepts/breakpoints.md b/docs/docs/concepts/breakpoints.md deleted file mode 100644 index ecd580271..000000000 --- a/docs/docs/concepts/breakpoints.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -search: - boost: 2 ---- - -# Breakpoints - -[Breakpoints](../how-tos/human_in_the_loop/breakpoints.md) pause graph execution at defined points and let you step through each stage. They use LangGraph's [**persistence layer**](./persistence.md), which saves the graph state after each step. - -With breakpoints, you can inspect the graph's state and node inputs at any point. Execution pauses **indefinitely** until you resume, as the checkpointer preserves the state. - -
-![image](img/breakpoints.png){: style="max-height:400px"} -
An example graph consisting of 3 sequential steps with a breakpoint before step_3.
- -!!! tip - - For information on how to use breakpoints, see [Set breakpoints](../how-tos/human_in_the_loop/breakpoints.md) and [Set breakpoints using Server API](../cloud/how-tos/human_in_the_loop_breakpoint.md). \ No newline at end of file diff --git a/docs/docs/concepts/human_in_the_loop.md b/docs/docs/concepts/human_in_the_loop.md index b11e5c2ae..eabe5fe85 100644 --- a/docs/docs/concepts/human_in_the_loop.md +++ b/docs/docs/concepts/human_in_the_loop.md @@ -23,9 +23,18 @@ To review, edit, and approve tool calls in an agent or workflow, [use LangGraph' ## Key capabilities -* **Persistent execution state**: LangGraph allows you to pause execution **indefinitely** β€” for minutes, hours, or even daysβ€”until human input is received. This is possible because LangGraph checkpoints the graph state after each step, which allows the system to persist execution context and later resume the workflow, continuing from where it left off. This supports asynchronous human review or input without time constraints. +* **Persistent execution state**: Interrupts use LangGraph's [persistence](../../concepts/persistence.md) layer, which saves the graph state, to indefinitely pause graph execution until you resume. This is possible because LangGraph checkpoints the graph state after each step, which allows the system to persist execution context and later resume the workflow, continuing from where it left off. This supports asynchronous human review or input without time constraints. -* **Flexible integration points**: HIL logic can be introduced at any point in the workflow. This allows targeted human involvement, such as approving API calls, correcting outputs, or guiding conversations. + There are two ways to pause a graph: + + - [Dynamic interrupts](../how-tos/human_in_the_loop/add-human-in-the-loop.md#pause-using-interrupt): Use `interrupt` to pause a graph from inside a specific node, based on the current state of the graph. + - [Static interrupts](../how-tos/human_in_the_loop/add-human-in-the-loop.md#debug-with-interrupts): Use `interrupt_before` and `interrupt_after` to pause the graph at defined points, either before or after a node executes. + +
+ ![image](./img/breakpoints.png){: style="max-height:400px"} +
An example graph consisting of 3 sequential steps with a breakpoint before step_3.
+ +* **Flexible integration points**: Human-in-the-loop logic can be introduced at any point in the workflow. This allows targeted human involvement, such as approving API calls, correcting outputs, or guiding conversations. ## Patterns diff --git a/docs/docs/concepts/img/human_in_the_loop/static-interrupt.png b/docs/docs/concepts/img/human_in_the_loop/static-interrupt.png new file mode 100644 index 000000000..d095dd2d7 Binary files /dev/null and b/docs/docs/concepts/img/human_in_the_loop/static-interrupt.png differ diff --git a/docs/docs/concepts/persistence.md b/docs/docs/concepts/persistence.md index f3d807946..185db6b62 100644 --- a/docs/docs/concepts/persistence.md +++ b/docs/docs/concepts/persistence.md @@ -33,7 +33,7 @@ The state of a thread at a particular point in time is called a checkpoint. Chec - `metadata`: Metadata associated with this checkpoint. - `values`: Values of the state channels at this point in time. - `next` A tuple of the node names to execute next in the graph. -- `tasks`: A tuple of `PregelTask` objects that contain information about next tasks to be executed. If the step was previously attempted, it will include error information. If a graph was interrupted [dynamically](../how-tos/human_in_the_loop/breakpoints.md#dynamic-breakpoints) from within a node, tasks will contain additional data associated with interrupts. +- `tasks`: A tuple of `PregelTask` objects that contain information about next tasks to be executed. If the step was previously attempted, it will include error information. If a graph was interrupted [dynamically](../how-tos/human_in_the_loop/add-human-in-the-loop.md#pause-using-interrupt) from within a node, tasks will contain additional data associated with interrupts. Checkpoints are persisted and can be used to restore the state of a thread at a later time. @@ -525,7 +525,7 @@ When running on LangGraph Platform, encryption is automatically enabled whenever ### Human-in-the-loop -First, checkpointers facilitate [human-in-the-loop workflows](agentic_concepts.md#human-in-the-loop) workflows by allowing humans to inspect, interrupt, and approve graph steps. Checkpointers are needed for these workflows as the human has to be able to view the state of a graph at any point in time, and the graph has to be to resume execution after the human has made any updates to the state. See [these how-to guides](../how-tos/human_in_the_loop/breakpoints.md) for concrete examples. +First, checkpointers facilitate [human-in-the-loop workflows](agentic_concepts.md#human-in-the-loop) workflows by allowing humans to inspect, interrupt, and approve graph steps. Checkpointers are needed for these workflows as the human has to be able to view the state of a graph at any point in time, and the graph has to be to resume execution after the human has made any updates to the state. See [the how-to guides](../how-tos/human_in_the_loop/add-human-in-the-loop.md) for examples. ### Memory diff --git a/docs/docs/guides/index.md b/docs/docs/guides/index.md index 1d57f63ea..7a5098dc5 100644 --- a/docs/docs/guides/index.md +++ b/docs/docs/guides/index.md @@ -19,8 +19,7 @@ These capabilities are available in both LangGraph OSS and the LangGraph Platfor - [Context](../agents/context.md): Pass outside data to a LangGraph graph to provide context for the graph execution. - [Models](../agents/models.md): Integrate various LLMs into your LangGraph application. - [Tools](../concepts/tools.md): Interface directly with external systems. -- [Human-in-the-loop](../concepts/human_in_the_loop.md): Enable human intervention at any point in a workflow. -- [Breakpoints](../concepts/breakpoints.md): Pause the execution of a LangGraph graph at a specific point. +- [Human-in-the-loop](../concepts/human_in_the_loop.md): Pause a graph and wait for human input at any point in a workflow. - [Time travel](../concepts/time-travel.md): Travel back in time to a specific point in the execution of a LangGraph graph. - [Subgraphs](../concepts/subgraphs.md): Build modular graphs. - [Multi-agent](../concepts/multi_agent.md): Break down a complex workflow into multiple agents. @@ -31,11 +30,11 @@ These capabilities are available in both LangGraph OSS and the LangGraph Platfor These capabilities are only available in [LangGraph Platform](../concepts/langgraph_platform.md). -- [Authentication and access control](../concepts/auth.md): Authenticate and authorize users to access a Langraph graph. +- [Authentication and access control](../concepts/auth.md): Authenticate and authorize users to access a LangGraph graph. - [Assistants](../concepts/assistants.md): Build assistants that can be used to interact with a LangGraph graph. - [Double-texting](../concepts/double_texting.md): Handle double-texting (consecutive messages before a first response is returned) in a LangGraph graph. - [Webhooks](../cloud/concepts/webhooks.md): Send webhooks to a LangGraph graph. - [Cron jobs](../cloud/concepts/cron_jobs.md): Schedule jobs to run at a specific time. - [Server customization](../how-tos/http/custom_lifespan.md): Customize the server that runs a LangGraph graph. - [Data management](../cloud/concepts/data_storage_and_privacy.md): Manage data in a LangGraph graph. -- [Deployment](../concepts/deployment_options.md): Deploy a LangGraph graph to a server. \ No newline at end of file +- [Deployment](../concepts/deployment_options.md): Deploy a LangGraph graph to a server. diff --git a/docs/docs/how-tos/assets/graph_api_image_3.png b/docs/docs/how-tos/assets/graph_api_image_3.png index 7cd869d09..61520b53e 100644 Binary files a/docs/docs/how-tos/assets/graph_api_image_3.png and b/docs/docs/how-tos/assets/graph_api_image_3.png differ diff --git a/docs/docs/how-tos/graph-api.md b/docs/docs/how-tos/graph-api.md index 4a71cc77d..b0f692738 100644 --- a/docs/docs/how-tos/graph-api.md +++ b/docs/docs/how-tos/graph-api.md @@ -1149,7 +1149,8 @@ Adding "C" to ['A'] LangGraph supports map-reduce and other advanced branching patterns using the Send API. Here is an example of how to use it: ```python -from langgraph.graph import StateGraph, START, END, Send +from langgraph.graph import StateGraph, START, END +from langgraph.types import Send from typing_extensions import TypedDict class OverallState(TypedDict): @@ -1507,7 +1508,7 @@ Because many LangChain objects implement the [Runnable Protocol](https://python. See example below. To demonstrate async invocations of underlying LLMs, we will include a chat model: -{!snippets/chat_model_tabs.md!} +{% include-markdown "../../snippets/chat_model_tabs.md" %} ```python from langchain.chat_models import init_chat_model diff --git a/docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md b/docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md index b1d9c7aea..b0392618f 100644 --- a/docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md +++ b/docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md @@ -11,11 +11,19 @@ hide: # Enable human intervention -To review, edit, and approve tool calls in an agent or workflow, use LangGraph's [human-in-the-loop](../../concepts/human_in_the_loop.md) features. +To review, edit, and approve tool calls in an agent or workflow, use interrupts to pause a graph and wait for human input. Interrupts use LangGraph's [persistence](../../concepts/persistence.md) layer, which saves the graph state, to indefinitely pause graph execution until you resume. + +!!! info + + For more information about human-in-the-loop workflows, see the [Human-in-the-Loop](../../concepts/human_in_the_loop.md) conceptual guide. ## Pause using `interrupt` -The [`interrupt` function][langgraph.types.interrupt] in LangGraph enables human-in-the-loop workflows by pausing the graph at a specific node, presenting information to a human, and resuming the graph with their input. It's useful for tasks like approvals, edits, or gathering additional context. +[Dynamic interrupts](../../concepts/human_in_the_loop.md#key-capabilities) (also known as dynamic breakpoints) are triggered based on the current state of the graph. You can set dynamic interrupts by calling [`interrupt` function][langgraph.types.interrupt] in the appropriate place. The graph will pause, which allows for human intervention, and then resumes the graph with their input. It's useful for tasks like approvals, edits, or gathering additional context. + +!!! note + + As of v1.0, `interrupt` is the recommended way to pause a graph. `NodeInterrupt` is deprecated and will be removed in v2.0. To use `interrupt` in your graph, you need to: @@ -124,15 +132,10 @@ print(graph.invoke(Command(resume="Edited text"), config=config)) # (7)! !!! warning - Interrupts are both powerful and ergonomic. However, while they may resemble Python's input() function in terms of developer experience, it's important to note that they do not automatically resume execution from the interruption point. Instead, they rerun the entire node where the interrupt was used. For this reason, interrupts are typically best placed at the start of a node or in a dedicated node. - + Interrupts resemble Python's input() function in terms of developer experience, but they do not automatically resume execution from the interruption point. Instead, they rerun the entire node where the interrupt was used. For this reason, interrupts are typically best placed at the start of a node or in a dedicated node. ## Resume using the `Command` primitive -!!! warning - - Resuming from an `interrupt` is different from Python's `input()` function, where execution resumes from the exact point where the `input()` function was called. - When the `interrupt` function is used within a graph, execution pauses at that point and awaits user input. To resume execution, use the [`Command`][langgraph.types.Command] primitive, which can be supplied via the `invoke`, `ainvoke`, `stream`, or `astream` methods. The graph resumes execution from the beginning of the node where `interrupt(...)` was initially called. This time, the `interrupt` function will return the value provided in `Command(resume=value)` rather than pausing again. All code from the beginning of the node to the `interrupt` will be re-executed. @@ -699,6 +702,162 @@ def human_node(state: State): print(final_result) # Should include the valid age ``` +## Debug with interrupts + +To debug and test a graph, use [static interrupts](../../concepts/human_in_the_loop.md#key-capabilities) (also known as static breakpoints) to step through the graph execution one node at a time or to pause the graph execution at specific nodes. Static interrupts are triggered at defined points either before or after a node executes. You can set static interrupts by specifying `interrupt_before` and `interrupt_after` at compile time or run time. + +!!! warning + + Static interrupts are **not** recommended for human-in-the-loop workflows. Use [dynamic interrupts](#pause-using-interrupt) instead. + +=== "Compile time" + + ```python + # highlight-next-line + graph = graph_builder.compile( # (1)! + # highlight-next-line + interrupt_before=["node_a"], # (2)! + # highlight-next-line + interrupt_after=["node_b", "node_c"], # (3)! + checkpointer=checkpointer, # (4)! + ) + + config = { + "configurable": { + "thread_id": "some_thread" + } + } + + # Run the graph until the breakpoint + graph.invoke(inputs, config=thread_config) # (5)! + + # Resume the graph + graph.invoke(None, config=thread_config) # (6)! + ``` + + 1. The breakpoints are set during `compile` time. + 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. + 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. + 4. A checkpointer is required to enable breakpoints. + 5. The graph is run until the first breakpoint is hit. + 6. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit. + +=== "Run time" + + ```python + # highlight-next-line + graph.invoke( # (1)! + inputs, + # highlight-next-line + interrupt_before=["node_a"], # (2)! + # highlight-next-line + interrupt_after=["node_b", "node_c"] # (3)! + config={ + "configurable": {"thread_id": "some_thread"} + }, + ) + + config = { + "configurable": { + "thread_id": "some_thread" + } + } + + # Run the graph until the breakpoint + graph.invoke(inputs, config=config) # (4)! + + # Resume the graph + graph.invoke(None, config=config) # (5)! + ``` + + 1. `graph.invoke` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation. + 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. + 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. + 4. The graph is run until the first breakpoint is hit. + 5. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit. + + !!! note + + You cannot set static breakpoints at runtime for **sub-graphs**. + If you have a sub-graph, you must set the breakpoints at compilation time. + +??? example "Setting static breakpoints" + + ```python + from IPython.display import Image, display + from typing_extensions import TypedDict + + from langgraph.checkpoint.memory import InMemorySaver + from langgraph.graph import StateGraph, START, END + + + class State(TypedDict): + input: str + + + def step_1(state): + print("---Step 1---") + pass + + + def step_2(state): + print("---Step 2---") + pass + + + def step_3(state): + print("---Step 3---") + pass + + + builder = StateGraph(State) + builder.add_node("step_1", step_1) + builder.add_node("step_2", step_2) + builder.add_node("step_3", step_3) + builder.add_edge(START, "step_1") + builder.add_edge("step_1", "step_2") + builder.add_edge("step_2", "step_3") + builder.add_edge("step_3", END) + + # Set up a checkpointer + checkpointer = InMemorySaver() # (1)! + + graph = builder.compile( + checkpointer=checkpointer, # (2)! + interrupt_before=["step_3"] # (3)! + ) + + # View + display(Image(graph.get_graph().draw_mermaid_png())) + + + # Input + initial_input = {"input": "hello world"} + + # Thread + thread = {"configurable": {"thread_id": "1"}} + + # Run the graph until the first interruption + for event in graph.stream(initial_input, thread, stream_mode="values"): + print(event) + + # This will run until the breakpoint + # You can get the state of the graph at this point + print(graph.get_state(config)) + + # You can continue the graph execution by passing in `None` for the input + for event in graph.stream(None, thread, stream_mode="values"): + print(event) + ``` + +### Use static interrupts in LangGraph Studio + +You can use [LangGraph Studio](../../concepts/langgraph_studio.md) to debug your graph. You can set static breakpoints in the UI and then run the graph. You can also use the UI to inspect the graph state at any point in the execution. + +![image](../../concepts/img/human_in_the_loop/static-interrupt.png){: style="max-height:400px"} + +LangGraph Studio is free with [locally deployed applications](../../tutorials/langgraph-platform/local-server.md) using `langgraph dev`. + ## Considerations When using human-in-the-loop, there are some considerations to keep in mind. @@ -940,4 +1099,3 @@ To avoid issues, refrain from dynamically changing the node's structure between Name: N/A. Age: John {'human_node': {'age': 'John', 'name': 'N/A'}} ``` - diff --git a/docs/docs/how-tos/human_in_the_loop/breakpoints.md b/docs/docs/how-tos/human_in_the_loop/breakpoints.md deleted file mode 100644 index 16c8fb552..000000000 --- a/docs/docs/how-tos/human_in_the_loop/breakpoints.md +++ /dev/null @@ -1,342 +0,0 @@ -# Set breakpoints - -There are two places where you can set breakpoints: - -1. **Before** or **after** a node executes by setting breakpoints at **compile time** or **run time**. We call these [**static breakpoints**](#static-breakpoints). -2. **Inside** a node using the `NodeInterrupt` exception. We call these [**dynamic breakpoints**](#dynamic-breakpoints). - -To use breakpoints, you will need to: - -1. [**Specify a checkpointer**](../../concepts/persistence.md#checkpoints) to save the graph state after each step. -2. **Set breakpoints** to specify where execution should pause. -3. **Run the graph** with a [**thread ID**](../../concepts/persistence.md#threads) to pause execution at the breakpoint. -4. **Resume execution** using `invoke`/`ainvoke`/`stream`/`astream` passing a `None` as the argument for the inputs. - -!!! tip - - For a conceptual overview of breakpoints, see [Breakpoints](../../concepts/breakpoints.md). - -## Static breakpoints - -Static breakpoints are triggered either before or after a node executes. You can set static breakpoints by specifying `interrupt_before` and `interrupt_after` at compile time or run time. - -Static breakpoints can be especially useful for debugging if you want to step through the graph execution one -node at a time or if you want to pause the graph execution at specific nodes. - -=== "Compile time" - - ```python - # highlight-next-line - graph = graph_builder.compile( # (1)! - # highlight-next-line - interrupt_before=["node_a"], # (2)! - # highlight-next-line - interrupt_after=["node_b", "node_c"], # (3)! - checkpointer=checkpointer, # (4)! - ) - - config = { - "configurable": { - "thread_id": "some_thread" - } - } - - # Run the graph until the breakpoint - graph.invoke(inputs, config=thread_config) # (5)! - - # Resume the graph - graph.invoke(None, config=thread_config) # (6)! - ``` - - 1. The breakpoints are set during `compile` time. - 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. - 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. - 4. A checkpointer is required to enable breakpoints. - 5. The graph is run until the first breakpoint is hit. - 6. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit. - -=== "Run time" - - ```python - # highlight-next-line - graph.invoke( # (1)! - inputs, - # highlight-next-line - interrupt_before=["node_a"], # (2)! - # highlight-next-line - interrupt_after=["node_b", "node_c"] # (3)! - config={ - "configurable": {"thread_id": "some_thread"} - }, - ) - - config = { - "configurable": { - "thread_id": "some_thread" - } - } - - # Run the graph until the breakpoint - graph.invoke(inputs, config=config) # (4)! - - # Resume the graph - graph.invoke(None, config=config) # (5)! - ``` - - 1. `graph.invoke` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation. - 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed. - 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed. - 4. The graph is run until the first breakpoint is hit. - 5. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit. - - !!! note - - You cannot set static breakpoints at runtime for **sub-graphs**. - If you have a sub-graph, you must set the breakpoints at compilation time. - -??? example "Setting static breakpoints" - - ```python - from IPython.display import Image, display - from typing_extensions import TypedDict - - from langgraph.checkpoint.memory import InMemorySaver - from langgraph.graph import StateGraph, START, END - - - class State(TypedDict): - input: str - - - def step_1(state): - print("---Step 1---") - pass - - - def step_2(state): - print("---Step 2---") - pass - - - def step_3(state): - print("---Step 3---") - pass - - - builder = StateGraph(State) - builder.add_node("step_1", step_1) - builder.add_node("step_2", step_2) - builder.add_node("step_3", step_3) - builder.add_edge(START, "step_1") - builder.add_edge("step_1", "step_2") - builder.add_edge("step_2", "step_3") - builder.add_edge("step_3", END) - - # Set up a checkpointer - checkpointer = InMemorySaver() # (1)! - - graph = builder.compile( - checkpointer=checkpointer, # (2)! - interrupt_before=["step_3"] # (3)! - ) - - # View - display(Image(graph.get_graph().draw_mermaid_png())) - - - # Input - initial_input = {"input": "hello world"} - - # Thread - thread = {"configurable": {"thread_id": "1"}} - - # Run the graph until the first interruption - for event in graph.stream(initial_input, thread, stream_mode="values"): - print(event) - - # This will run until the breakpoint - # You can get the state of the graph at this point - print(graph.get_state(config)) - - # You can continue the graph execution by passing in `None` for the input - for event in graph.stream(None, thread, stream_mode="values"): - print(event) - ``` - -## Dynamic breakpoints - -Use dynamic breakpoints if you need to interrupt the graph from inside a given node based on a condition. - -```python -from langgraph.errors import NodeInterrupt - -def step_2(state: State) -> State: - # highlight-next-line - if len(state["input"]) > 5: - # highlight-next-line - raise NodeInterrupt( # (1)! - f"Received input that is longer than 5 characters: {state['foo']}" - ) - return state -``` - -1. raise NodeInterrupt exception based on a some condition. In this example, we create a dynamic breakpoint if the length of the attribute `input` is longer than 5 characters. - -
Using dynamic breakpoints - -```python -from typing_extensions import TypedDict -from IPython.display import Image, display - -from langgraph.graph import StateGraph, START, END -from langgraph.checkpoint.memory import MemorySaver -from langgraph.errors import NodeInterrupt - - -class State(TypedDict): - input: str - - -def step_1(state: State) -> State: - print("---Step 1---") - return state - - -def step_2(state: State) -> State: - # Let's optionally raise a NodeInterrupt - # if the length of the input is longer than 5 characters - if len(state["input"]) > 5: - raise NodeInterrupt( - f"Received input that is longer than 5 characters: {state['input']}" - ) - print("---Step 2---") - return state - - -def step_3(state: State) -> State: - print("---Step 3---") - return state - - -builder = StateGraph(State) -builder.add_node("step_1", step_1) -builder.add_node("step_2", step_2) -builder.add_node("step_3", step_3) -builder.add_edge(START, "step_1") -builder.add_edge("step_1", "step_2") -builder.add_edge("step_2", "step_3") -builder.add_edge("step_3", END) - -# Set up memory -memory = MemorySaver() - -# Compile the graph with memory -graph = builder.compile(checkpointer=memory) - -# View -display(Image(graph.get_graph().draw_mermaid_png())) -``` - -First, let's run the graph with an input that <= 5 characters long. This should safely ignore the interrupt condition we defined and return the original input at the end of the graph execution. - -```python -initial_input = {"input": "hello"} -thread_config = {"configurable": {"thread_id": "1"}} - -for event in graph.stream(initial_input, thread_config, stream_mode="values"): - print(event) -``` - -If we inspect the graph at this point, we can see that there are no more tasks left to run and that the graph indeed finished execution. - -```python -state = graph.get_state(thread_config) -print(state.next) -print(state.tasks) -``` - -Now, let's run the graph with an input that's longer than 5 characters. This should trigger the dynamic interrupt we defined via raising a `NodeInterrupt` error inside the `step_2` node. - -```python -initial_input = {"input": "hello world"} -thread_config = {"configurable": {"thread_id": "2"}} - -# Run the graph until the first interruption -for event in graph.stream(initial_input, thread_config, stream_mode="values"): - print(event) -``` - -We can see that the graph now stopped while executing `step_2`. If we inspect the graph state at this point, we can see the information on what node is set to execute next (`step_2`), as well as what node raised the interrupt (also `step_2`), and additional information about the interrupt. - -```python -state = graph.get_state(thread_config) -print(state.next) -print(state.tasks) -``` - -If we try to resume the graph from the breakpoint, we will simply interrupt again as our inputs & graph state haven't changed. - -```python -# NOTE: to resume the graph from a dynamic interrupt we use the same syntax as with regular interrupts -- we pass None as the input -for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) -``` - -```python -state = graph.get_state(thread_config) -print(state.next) -print(state.tasks) -``` - -
- -## Use with subgraphs - -To add breakpoints to subgraph either: - -* Define [static breakpoints](#static-breakpoints) by specifying them when **compiling** the subgraph. -* Define [dynamic breakpoints](#dynamic-breakpoints). - -
Add breakpoints to subgraphs - -```python -from typing_extensions import TypedDict - -from langgraph.graph import START, StateGraph -from langgraph.checkpoint.memory import InMemorySaver -from langgraph.types import interrupt - - -class State(TypedDict): - foo: str - - -def subgraph_node_1(state: State): - return {"foo": state["foo"]} - - -subgraph_builder = StateGraph(State) -subgraph_builder.add_node(subgraph_node_1) -subgraph_builder.add_edge(START, "subgraph_node_1") - -subgraph = subgraph_builder.compile(interrupt_before=["subgraph_node_1"]) - -builder = StateGraph(State) -builder.add_node("node_1", subgraph) # directly include subgraph as a node -builder.add_edge(START, "node_1") - -checkpointer = InMemorySaver() -graph = builder.compile(checkpointer=checkpointer) - -config = {"configurable": {"thread_id": "1"}} - -graph.invoke({"foo": ""}, config) - -# Fetch state including subgraph state. -print(graph.get_state(config, subgraphs=True).tasks[0].state) - -# resume the subgraph -graph.invoke(None, config) -``` - -
\ No newline at end of file diff --git a/docs/docs/how-tos/human_in_the_loop/time-travel.md b/docs/docs/how-tos/human_in_the_loop/time-travel.md index 4b1a78182..84ded8410 100644 --- a/docs/docs/how-tos/human_in_the_loop/time-travel.md +++ b/docs/docs/how-tos/human_in_the_loop/time-travel.md @@ -4,7 +4,7 @@ To use [time-travel](../../concepts/time-travel.md) in LangGraph: 1. [Run the graph](#1-run-the-graph) with initial inputs using [`invoke`][langgraph.graph.state.CompiledStateGraph.invoke] or [`stream`][langgraph.graph.state.CompiledStateGraph.stream] methods. 2. [Identify a checkpoint in an existing thread](#2-identify-a-checkpoint): Use the [`get_state_history()`][langgraph.graph.state.CompiledStateGraph.get_state_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`. - Alternatively, set a [breakpoint](../../concepts/breakpoints.md) before the node(s) where you want execution to pause. You can then find the most recent checkpoint recorded up to that breakpoint. + Alternatively, set an [interrupt](../../how-tos/human_in_the_loop/add-human-in-the-loop.md) before the node(s) where you want execution to pause. You can then find the most recent checkpoint recorded up to that interrupt. 3. [Update the graph state (optional)](#3-update-the-state-optional): Use the [`update_state`][langgraph.graph.state.CompiledStateGraph.update_state] method to modify the graph's state at the checkpoint and resume execution from alternative state. 4. [Resume execution from the checkpoint](#4-resume-execution-from-the-checkpoint): Use the `invoke` or `stream` methods with an input of `None` and a configuration containing the appropriate `thread_id` and `checkpoint_id`. diff --git a/docs/docs/how-tos/memory/semantic-search.ipynb b/docs/docs/how-tos/memory/semantic-search.ipynb index 890363ef4..c952ac6ea 100644 --- a/docs/docs/how-tos/memory/semantic-search.ipynb +++ b/docs/docs/how-tos/memory/semantic-search.ipynb @@ -125,7 +125,7 @@ "memories = store.search((\"user_123\", \"memories\"), query=\"I like food?\", limit=5)\n", "\n", "for memory in memories:\n", - " print(f'Memory: {memory.value[\"text\"]} (similarity: {memory.score})')" + " print(f\"Memory: {memory.value['text']} (similarity: {memory.score})\")" ] }, { diff --git a/docs/docs/index.md b/docs/docs/index.md index 60ec1b509..db036367a 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -28,4 +28,4 @@ title: LangGraph } -{!../README.md!} \ No newline at end of file +{% include-markdown "../../README.md" %} \ No newline at end of file diff --git a/docs/docs/snippets/chat_model_tabs.md b/docs/docs/snippets/chat_model_tabs.md new file mode 100644 index 000000000..e984e1821 --- /dev/null +++ b/docs/docs/snippets/chat_model_tabs.md @@ -0,0 +1,87 @@ +=== "OpenAI" + + ```shell + pip install -U "langchain[openai]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["OPENAI_API_KEY"] = "sk-..." + + llm = init_chat_model("openai:gpt-4.1") + ``` + + πŸ‘‰ Read the [OpenAI integration docs](https://python.langchain.com/docs/integrations/chat/openai/) + +=== "Anthropic" + + ```shell + pip install -U "langchain[anthropic]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["ANTHROPIC_API_KEY"] = "sk-..." + + llm = init_chat_model("anthropic:claude-3-5-sonnet-latest") + ``` + + πŸ‘‰ Read the [Anthropic integration docs](https://python.langchain.com/docs/integrations/chat/anthropic/) + +=== "Azure" + + ```shell + pip install -U "langchain[openai]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["AZURE_OPENAI_API_KEY"] = "..." + os.environ["AZURE_OPENAI_ENDPOINT"] = "..." + os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview" + + llm = init_chat_model( + "azure_openai:gpt-4.1", + azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"], + ) + ``` + + πŸ‘‰ Read the [Azure integration docs](https://python.langchain.com/docs/integrations/chat/azure_chat_openai/) + +=== "Google Gemini" + + ```shell + pip install -U "langchain[google-genai]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["GOOGLE_API_KEY"] = "..." + + llm = init_chat_model("google_genai:gemini-2.0-flash") + ``` + + πŸ‘‰ Read the [Google GenAI integration docs](https://python.langchain.com/docs/integrations/chat/google_generative_ai/) + +=== "AWS Bedrock" + + ```shell + pip install -U "langchain[aws]" + ``` + ```python + from langchain.chat_models import init_chat_model + + # Follow the steps here to configure your credentials: + # https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html + + llm = init_chat_model( + "anthropic.claude-3-5-sonnet-20240620-v1:0", + model_provider="bedrock_converse", + ) + ``` + + πŸ‘‰ Read the [AWS Bedrock integration docs](https://python.langchain.com/docs/integrations/chat/bedrock/) diff --git a/docs/docs/tutorials/get-started/1-build-basic-chatbot.md b/docs/docs/tutorials/get-started/1-build-basic-chatbot.md index 3304822c6..b32e42861 100644 --- a/docs/docs/tutorials/get-started/1-build-basic-chatbot.md +++ b/docs/docs/tutorials/get-started/1-build-basic-chatbot.md @@ -63,7 +63,7 @@ Next, add a "`chatbot`" node. **Nodes** represent units of work and are typicall Let's first select a chat model: -{!snippets/chat_model_tabs.md!} +{% include-markdown "../../../snippets/chat_model_tabs.md" %}