ec2b666284
Continuous Integration / Pre-commit Linter (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.10) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.11) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.12) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.10) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.11) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.12) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.14) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Waiting to run
Copybara PR Handler / close-imported-pr (push) Waiting to run
134 lines
6.0 KiB
Markdown
134 lines
6.0 KiB
Markdown
# Workflow Graphs
|
|
|
|
In ADK 2.0, workflows are represented as directed graphs where execution flows from node to node along defined edges. This guide explains the core concepts of **nodes**, **edges**, and **graphs**, how to define them, and the validation rules enforced by the framework.
|
|
|
|
## Introduction
|
|
|
|
A workflow graph defines the execution plan for your multi-step agent interactions. It specifies:
|
|
- What tasks to run (Nodes).
|
|
- The order of execution (Edges).
|
|
- How data flows and how branches fork or merge.
|
|
|
|
The graph structure is compiled and validated when you instantiate the `Workflow` class.
|
|
|
|
## Core Concepts
|
|
|
|
### Nodes (`NodeLike`)
|
|
|
|
A node represents a single unit of execution in the workflow. In ADK, you can use several types of objects as nodes (collectively referred to as `NodeLike`):
|
|
|
|
1. **Python Functions**: Sync or async functions (and generators) decorated with `@node`. They are automatically wrapped in a `FunctionNode`.
|
|
2. **Agents**: `LlmAgent` instances (typically in `single_turn` mode). They are automatically wrapped in an internal `_LlmAgentWrapper`.
|
|
3. **Tools**: `BaseTool` instances. They are wrapped in a `ToolNode`.
|
|
4. **Workflows**: A `Workflow` is itself a `BaseNode` and can be nested as a child node in another workflow.
|
|
5. **`START`**: A special sentinel node that marks the entry point of the workflow. Every graph must have exactly one edge starting from `START`.
|
|
|
|
### Edges (`Edge`)
|
|
|
|
An edge defines a transition from a source node (`from_node`) to a destination node (`to_node`).
|
|
|
|
#### Unconditional Edges
|
|
By default, edges are unconditional. When the source node completes, execution immediately transitions to the destination node.
|
|
|
|
#### Conditional Edges (Routing)
|
|
An edge can be associated with one or more **routes** (a string, integer, or boolean). The edge is only followed if the source node explicitly emits a matching route.
|
|
|
|
To emit a route, the source node must yield an `Event(route="my_route")` (or return/yield an object that maps to that route).
|
|
|
|
#### Default Route
|
|
You can define a fallback edge using `DEFAULT_ROUTE` (imported as `from google.adk.workflow import DEFAULT_ROUTE` or using `"__DEFAULT__"`). This edge is followed if the source node emits a route, but no specific conditional edge matches it.
|
|
|
|
---
|
|
|
|
## Defining the Graph (Syntax)
|
|
|
|
You define the graph structure by passing a list of `edges` to the `Workflow` constructor. ADK supports two syntax styles:
|
|
|
|
### 1. Chain Tuples (Recommended)
|
|
|
|
Chain tuples provide a concise way to define sequential, parallel, and conditional transitions using Python tuples.
|
|
|
|
* **Sequential Chain**:
|
|
```python
|
|
edges=[
|
|
(START, step_a, step_b, step_c),
|
|
]
|
|
```
|
|
This defines: `START -> step_a -> step_b -> step_c`.
|
|
|
|
* **Parallel Fan-Out**: Use a tuple of nodes to split execution into parallel branches.
|
|
```python
|
|
edges=[
|
|
(START, step_a, (step_b, step_c)),
|
|
]
|
|
```
|
|
This defines: `START -> step_a`, and then `step_a -> step_b` AND `step_a -> step_c` in parallel.
|
|
|
|
* **Conditional Routing**: Use a dictionary (Routing Map) to define conditional branches.
|
|
```python
|
|
from google.adk.workflow import DEFAULT_ROUTE
|
|
|
|
edges=[
|
|
(START, step_a, {
|
|
"success": step_b,
|
|
"failure": step_c,
|
|
DEFAULT_ROUTE: fallback_step,
|
|
}),
|
|
]
|
|
```
|
|
If `step_a` yields `Event(route="success")`, it goes to `step_b`. If it yields `"failure"`, it goes to `step_c`. Any other route goes to `fallback_step`.
|
|
|
|
### 2. Explicit Edge Objects
|
|
|
|
For complex graphs or when you prefer explicit declarations, you can use `Edge` objects:
|
|
|
|
```python
|
|
from google.adk.workflow import Edge, START
|
|
|
|
edges=[
|
|
Edge(from_node=START, to_node=step_a),
|
|
Edge(from_node=step_a, to_node=step_b, route="success"),
|
|
Edge(from_node=step_a, to_node=step_c, route="failure"),
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## Graph Validation
|
|
|
|
When a `Workflow` is initialized, it builds an internal `Graph` representation and runs `validate_graph()` to catch structural errors early. The following rules are strictly enforced:
|
|
|
|
### 1. Unique Node Names
|
|
All distinct node objects in the graph must have unique names.
|
|
* *Error*: If you have two different function nodes named `process_data`, validation will fail.
|
|
* *Solution*: Ensure unique names, or reuse the exact same object instance if you want to route back to the same node.
|
|
|
|
### 2. Single START Entry Point
|
|
The graph must contain the `START` node, and `START` must not have any incoming edges.
|
|
* *Error*: A graph without `START` or with an edge pointing back to `START` will fail validation.
|
|
|
|
### 3. Connectivity (Reachability)
|
|
All nodes in the graph must be reachable from the `START` node.
|
|
* *Error*: If you define a node but do not connect it to the rest of the graph, validation will fail.
|
|
|
|
### 4. No Duplicate Edges
|
|
You cannot define duplicate edges between the same two nodes.
|
|
* *Error*: `Edge(from_node=A, to_node=B)` and `Edge(from_node=A, to_node=B)` in the same list will fail.
|
|
|
|
### 5. Default Route Constraints
|
|
- A node can have at most one outgoing `DEFAULT_ROUTE` edge.
|
|
- `DEFAULT_ROUTE` cannot be combined with other routes in a list (e.g., `route=["success", DEFAULT_ROUTE]` is invalid).
|
|
|
|
### 6. No Unconditional Cycles
|
|
The graph must not contain cycles consisting entirely of unconditional edges (edges with no route).
|
|
* *Allowed*: Conditional loops are allowed (e.g., `A -> B -> A` where `B -> A` is conditional on a route).
|
|
* *Forbidden*: Unconditional loops (`A -> B -> A` with no routes) are rejected to prevent infinite execution loops.
|
|
|
|
### 7. Static Schema Matching
|
|
If a node defines an `output_schema` and its successor defines an `input_schema`, they must match exactly.
|
|
* *Error*: Schema mismatch on transition edges will fail validation.
|
|
|
|
### 8. Chat Agent Wiring
|
|
`LlmAgent` instances configured with `mode='chat'` are only allowed to follow the `START` node.
|
|
* *Reason*: Chat-mode agents manage their own conversational history and cannot consume direct inputs from preceding nodes in a workflow chain. For sequential steps, use `mode='single_turn'`.
|