This commit is contained in:
Eugene Yurtsev
2024-12-11 11:40:09 -05:00
parent 6907d1b775
commit d9c0a5d827
+17 -18
View File
@@ -38,7 +38,7 @@ graph = graph_builder.compile(
checkpointer=checkpointer # Required for `interrupt` to work
)
# Run the graph and hit the breakpoint
# Run the graph until the interrupt
thread_config = {"configurable": {"thread_id": "some_id"}}
graph.invoke(some_input, config=thread_config)
@@ -52,7 +52,7 @@ To use `interrupt` in your graph, you need to:
1. [**Specify a checkpointer**](persistence.md#checkpoints) to save the graph state after each step.
2. **Call `interrupt()`** in the appropriate place. See the [Design Patterns](#design-patterns) section for examples.
3. **Run the graph** with a [**thread ID**](./persistence.md#threads) to pause execution at the breakpoint.
3. **Run the graph** with a [**thread ID**](./persistence.md#threads) until the `interrupt` is hit.
4. **Resume execution** using `invoke`/`ainvoke`/`stream`/`astream` (see [**The `Command` primitive**](#the-command-primitive)).
## Design Patterns
@@ -99,7 +99,7 @@ def human_approval(state: State) -> Command[Literal["some_node", "another_node"]
graph_builder.add_node("human_approval", human_approval)
graph = graph_builder.compile(checkpointer=checkpointer)
# After running the graph and hitting the breakpoint, the graph will pause.
# After running the graph and hitting the interrupt, the graph will pause.
# Resume it with either an approval or rejection.
thread_config = {"configurable": {"thread_id": "some_id"}}
graph.invoke(Command(resume=True), config=thread_config)
@@ -141,7 +141,7 @@ graph = graph_builder.compile(checkpointer=checkpointer)
...
# After running the graph and hitting the breakpoint, the graph will pause.
# After running the graph and hitting the interrupt, the graph will pause.
# Resume it with the edited text.
thread_config = {"configurable": {"thread_id": "some_id"}}
graph.invoke(
@@ -236,7 +236,7 @@ it may be part of a larger graph consisting of multiple nodes and include a cond
graph_builder.add_edge("human_input", "agent")
graph = graph_builder.compile(checkpointer=checkpointer)
# After running the graph and hitting the breakpoint, the graph will pause.
# After running the graph and hitting the interrupt, the graph will pause.
# Resume it with the human's input.
graph.invoke(
Command(resume="hello!"),
@@ -306,13 +306,13 @@ def human_node(state: State):
## The `Command` primitive
When using the `interrupt` function, the graph will pause at the breakpoint and wait for user input.
When using the `interrupt` function, the graph will pause at the interrupt and wait for user input.
Graph execution can be resumed using the [Command](../reference/types.md#langgraph.types.Command) primitive which can be passed through the `invoke`, `ainvoke`, `stream` or `astream` methods.
The `Command` primitive provides several options to control and modify the graph's state during resumption:
1. **Pass a value to the `interrupt`**: Provide data, such as a user's response, to the graph using `Command(resume=value)`. Execution resumes from the beginning of the node where the `interrupt` was used, however, this time the `interrupt(...)` call will return the value passed in the `Command(resume=value)` instead of pausing the graph. The `resume` value is only used when using `interrupt` as a breakpoint.
1. **Pass a value to the `interrupt`**: Provide data, such as a user's response, to the graph using `Command(resume=value)`. Execution resumes from the beginning of the node where the `interrupt` was used, however, this time the `interrupt(...)` call will return the value passed in the `Command(resume=value)` instead of pausing the graph.
```python
# Resume graph execution with the user's input.
@@ -331,12 +331,12 @@ By leveraging `Command`, you can resume graph execution, handle user inputs, and
## Using with `invoke` and `ainvoke`
When you use `stream` or `astream` to run the graph, you will receive an `Interrupt` event that let you know that a breakpoint has been hit.
When you use `stream` or `astream` to run the graph, you will receive an `Interrupt` event that let you know the `interrupt` was triggered.
`invoke` and `ainvoke` do not return the interrupt information. To access this information, you must use the [get_state](../reference/graphs.md#langgraph.graph.graph.CompiledGraph.get_state) method to retrieve the graph state after calling `invoke` or `ainvoke`.
```python
# Run the graph up to the breakpoint
# Run the graph up to the interrupt
result = graph.invoke(inputs, thread_config)
# Get the graph state to get interrupt information.
state = graph.get_state(thread_config)
@@ -362,20 +362,20 @@ graph.invoke(Command(resume={"age": "25"}), thread_config)
) # Pending tasks. interrupts
```
## How does resuming from a breakpoint work?
## How does resuming from an interrupt work?
!!! 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.
A critical aspect of using breakpoints is understanding how resuming from a breakpoint works. When you resume execution after a breakpoint, the graph execution starts from the **beginning** of the **graph node** where the last breakpoint was triggered.
A critical aspect of using `interrupt` is understanding how resuming works. When you resume execution after an `interrupt`, graph execution starts from the **beginning** of the **graph node** where the last `interrupt` was triggered.
**All** code from the beginning of the node to the **breakpoint** will be re-executed.
**All** code from the beginning of the node to the `interrupt` will be re-executed.
```python
counter = 0
def node(state: State):
# All the code from the beginning of the node to the breakpoint will be re-executed
# All the code from the beginning of the node to the interrupt will be re-executed
# when the graph resumes.
global counter
counter += 1
@@ -393,15 +393,15 @@ Upon **resuming** the graph, the counter will be incremented a second time, resu
The value of counter is: 2
```
## Gotchyas
## Common Pitfalls
!!! warning
Resuming from a breakpoint is **different** from traditional breakpoints or Python's `input()` function, where execution resumes from the exact point where the breakpoint was triggered or where the `input()` function was called.
Resuming from a interrupt is **different** from using Python's `input()` function, where execution resumes from the exact point where `input()` was called.
A critical aspect of using `interrupt` is understanding how resuming works. When you resume execution, the graph execution starts from the **beginning** of the **graph node** where the last breakpoint was triggered.
A critical aspect of using `interrupt` is understanding how resuming works. When you resume execution, the graph execution starts from the **beginning** of the **graph node** where the `interrupt` was triggered.
**All** code from the beginning of the node to the **breakpoint** will be re-executed.
**All** code from the beginning of the node to the `interrupt` will be re-executed.
### Side-effects
@@ -545,6 +545,5 @@ To avoid issues, refrain from dynamically changing the node's structure between
## Additional Resources 📚
- [**Conceptual Guide: Persistence**](persistence.md#replay): Read the persistence guide for more context on replaying.
- [**Conceptual Guide: Breakpoints**](breakpoints.md): Read the breakpoints guide for more context on breakpoints.
- [**How to Guides: Human-in-the-loop**](../how-tos/index.md#human-in-the-loop): Learn how to implement human-in-the-loop workflows in LangGraph.
- [**How to implement multi-turn conversations**](../how-tos/multi-agent-multi-turn-convo.ipynb): Learn how to implement multi-turn conversations in LangGraph.