mirror of
https://github.com/google/adk-docs.git
synced 2026-09-14 16:16:59 +08:00
e9174a1efe
* adding go getting started to 2.0 docs * updating graphs docs for go; adding in workflow example go snippets * Updating HiTL docs for Go 2.0 * updating Go getting started guide for v2 * Updating Routes docs for Go v2 * Updating data handling docs for Go 2.0 * Updating dynamic workflows docs for Go 2.0 * fix(docs): set ADK Go 2.0 GA date on the 2.0 landing page * fix(docs): standardize ADK Go 2.0 install/import on /v2 @ v2.0.0 * updating announcement banner * routes snippets updates * 2.0 install instructions clean-up * updating collaboration docs for go v2 + new example snippet --------- Co-authored-by: Karol Piotrowicz <kpiotrowicz@google.com>
387 lines
14 KiB
Markdown
387 lines
14 KiB
Markdown
# Data handling for agent workflows
|
|
|
|
<div class="language-support-tag">
|
|
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v2.0.0</span><span class="lst-go">Go v2.0.0</span>
|
|
</div>
|
|
|
|
Structuring and managing data between agents and graph-based nodes is critical
|
|
for building reliable processes with ADK. This guide explains data handling
|
|
within graph-based workflows and collaboration agents, including how information
|
|
is transmitted and received between graph nodes. It covers the essential
|
|
parameters for passing data, content, and state, and explains how to implement
|
|
structured data transfer for both function and agent nodes using data format
|
|
schemas and specific instruction syntax.
|
|
|
|
## Workflow data flow
|
|
|
|
Within a graph-based workflow, nodes pass data to downstream steps through
|
|
events. A step writes its output to a named event field, and the next step
|
|
receives it as its typed input.
|
|
|
|
=== "Python"
|
|
|
|
In Python, data is exchanged between graph nodes using ***Events***. The key
|
|
parameters for node data handling are:
|
|
|
|
- **`output`**: Parameter for passing information between *nodes*.
|
|
- **`message`**: Data intended as a response to a user.
|
|
- **`state`**: Data automatically persisted across nodes via ***Events***
|
|
throughout an ADK session.
|
|
|
|
=== "Go"
|
|
|
|
In ADK Go v2.0.0, the data-passing mechanism depends on which agent style
|
|
you use:
|
|
|
|
**workflow package** (`FunctionNode`, `AgentNode`, `DynamicNode`): nodes
|
|
communicate through `session.Event` fields, mirroring Python closely:
|
|
|
|
- **`Event.Output`**: the node's return value, set automatically by the
|
|
framework when a `FunctionNode` returns a non-`*genai.Content` value.
|
|
The successor node receives this as its typed `input` parameter.
|
|
- **`Event.Routes`**: routing keys set explicitly by an emitting node to
|
|
select which conditional edge to follow — the Go equivalent of
|
|
Python's `Event(route=...)`.
|
|
- **`Event.NodeInfo`**: scheduler metadata (`path`, `MessageAsOutput`,
|
|
`OutputFor`). Set by the workflow engine; nodes do not set this
|
|
directly.
|
|
|
|
**Prebuilt workflow agents** (`sequentialagent`, `parallelagent`,
|
|
`loopagent`): these agents communicate through session state:
|
|
|
|
- **`OutputKey`** on `llmagent.Config`: the framework writes the agent's
|
|
final text response to `state[OutputKey]` after each turn.
|
|
- **`ctx.Session().State().Set` / `.Get`**: write or read arbitrary
|
|
values from state inside custom code.
|
|
- **`{key}` in `Instruction`**: the framework substitutes `state["key"]`
|
|
into the prompt before calling the model.
|
|
|
|
State keys may carry a prefix that controls their lifetime and scope:
|
|
|
|
| Prefix constant | Prefix string | Scope |
|
|
|---|---|---|
|
|
| `session.KeyPrefixApp` | `"app:"` | Shared across all users and sessions for the app |
|
|
| `session.KeyPrefixUser` | `"user:"` | Tied to the user, shared across their sessions |
|
|
| `session.KeyPrefixTemp` | `"temp:"` | Discarded after the current invocation ends |
|
|
| *(none)* | — | Persists for the lifetime of the session |
|
|
|
|
### Node output
|
|
|
|
Each step in a workflow produces output for its successor.
|
|
|
|
=== "Python"
|
|
|
|
Use the ***return*** or ***yield*** syntax to hand off data to the next node:
|
|
|
|
```python
|
|
from google.adk import Event
|
|
|
|
def my_function_node(node_input: str):
|
|
output_value = node_input.upper()
|
|
return Event(output=output_value) # "THE RESULT"
|
|
```
|
|
|
|
Use the ***return*** syntax when outputting ***Event*** data that does not
|
|
require additional processing. When emitting data that requires additional
|
|
processing, or if you are generating more than one data item, you can use
|
|
more than one ***yield*** command. Each ***yield*** call adds to a list of
|
|
data objects on the Event which is passed to the next node of a graph. A
|
|
***return*** or ***yield*** command without a parameter passes a `None` value
|
|
to the next node.
|
|
|
|
=== "Go"
|
|
|
|
**workflow package**: a `FunctionNode` simply returns a typed Go value.
|
|
The framework automatically wraps the return value in a `session.Event`
|
|
and sets `Event.Output`. The successor node receives this value as its
|
|
typed `input` parameter — no manual event construction needed:
|
|
|
|
```go
|
|
--8<-- "examples/go/snippets/graphs/data-handling/main.go:event-output"
|
|
```
|
|
|
|
**Prebuilt workflow agents**: use `OutputKey` on `llmagent.Config` to
|
|
save an agent's text response to session state, then reference it with
|
|
`{key}` in downstream agents' `Instruction` templates:
|
|
|
|
```go
|
|
--8<-- "examples/go/snippets/graphs/data-handling/main.go:output-key"
|
|
```
|
|
|
|
### Node output: passing structured data
|
|
|
|
=== "Python"
|
|
|
|
You can pass longer, structured data in a serializable format:
|
|
|
|
```python
|
|
def my_function_node_3():
|
|
yield Event(
|
|
output={
|
|
"city_name": "Paris",
|
|
"city_time": "10:10 AM",
|
|
},
|
|
)
|
|
```
|
|
|
|
!!! warning "Caution: Event.output limitation"
|
|
|
|
Nodes are only allowed to emit a single ***Event.output*** data payload
|
|
per execution. This limitation means that while you can use more than
|
|
one ***yield*** in a node, having two or more ***yield*** commands with
|
|
an ***Event.output*** results in a runtime error.
|
|
|
|
=== "Go"
|
|
|
|
**workflow package**: a `FunctionNode` can return any JSON-serializable
|
|
Go struct. The framework serializes it into `Event.Output` and
|
|
deserializes it back into the successor node's typed `input` parameter.
|
|
There is no single-payload restriction — each node has exactly one typed
|
|
return value:
|
|
|
|
```go
|
|
--8<-- "examples/go/snippets/graphs/data-handling/main.go:structured-output"
|
|
```
|
|
|
|
**Prebuilt workflow agents**: use multiple `OutputKey` values, one per
|
|
agent, to store individual fields in session state. Downstream agents
|
|
read each field independently via `{key}` in their `Instruction`.
|
|
|
|
### Routing output
|
|
|
|
=== "Python"
|
|
|
|
Use the `route` parameter of an ***Event*** to drive conditional edge
|
|
dispatch:
|
|
|
|
```python
|
|
def router(node_input: str):
|
|
return Event(route="BUG")
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
**workflow package**: an emitting `FunctionNode` constructs a
|
|
`session.Event` directly, sets `Event.Routes` to the desired route keys,
|
|
and sets `Event.Output` to forward the payload to the successor. The
|
|
workflow engine reads `Event.Routes` at dispatch time to select the
|
|
matching edge:
|
|
|
|
```go
|
|
--8<-- "examples/go/snippets/graphs/data-handling/main.go:routing-output"
|
|
```
|
|
|
|
### User-facing messages
|
|
|
|
=== "Python"
|
|
|
|
Use the ***message*** parameter of an ***Event*** to send a response to a
|
|
user rather than pass data to the next node:
|
|
|
|
```python
|
|
async def user_message(node_input: str):
|
|
"""Tell user research process is starting."""
|
|
yield Event(message="Beginning research process...")
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
**workflow package**: to emit a user-visible message without advancing
|
|
the node's typed output, set `Event.Content` on an intermediate event
|
|
emitted via the `emit` callback in an `EmittingFunctionNode`. The
|
|
terminal return value (or `nil`) controls `Event.Output`.
|
|
|
|
**Prebuilt workflow agents**: any `llmagent` step automatically emits its
|
|
model response as a user-facing event. For non-LLM steps, write a custom
|
|
`Run` function on an `agent.Agent` that yields events whose
|
|
`LLMResponse.Content` contains the text.
|
|
|
|
### Session state and state scopes
|
|
|
|
Session state persists data across turns within a session. It is the primary
|
|
data-sharing mechanism for the prebuilt workflow agents, and is also available
|
|
inside tools and callbacks regardless of which agent style you use.
|
|
|
|
=== "Python"
|
|
|
|
Use the ***state*** parameter of an ***Event*** to maintain values across
|
|
nodes. Nodes can modify state values, and the modified state values are
|
|
available to downstream nodes:
|
|
|
|
```python
|
|
async def init_state_node(attempts: int = 0):
|
|
yield Event(
|
|
state={
|
|
"attempts": attempts,
|
|
},
|
|
)
|
|
|
|
async def task_attempt_node(node_input: Content, attempts: int):
|
|
yield Event(
|
|
state={
|
|
"attempts": attempts + 1,
|
|
},
|
|
)
|
|
|
|
async def read_state_node(ctx: Context):
|
|
print(f"attempts state: {ctx.state}") # attempts state: attempts: 1
|
|
|
|
root_agent = Workflow(
|
|
name="root_agent",
|
|
edges=[("START", init_state_node, task_attempt_node, read_state_node)],
|
|
)
|
|
```
|
|
|
|
!!! warning "Caution: `state` property data limitations"
|
|
|
|
The state parameter *should not be used to persist large amounts of
|
|
data* between nodes. Use artifacts or other data persistence mechanisms,
|
|
such as database Tools, to persist large data resources during the life
|
|
cycle of a Workflow.
|
|
|
|
=== "Go"
|
|
|
|
State is written with `ctx.Session().State().Set(key, value)` and read
|
|
with `.Get(key)`. The `session` package defines prefix constants that map
|
|
to the same lifetime scopes as Python's state parameter. This pattern
|
|
applies to prebuilt workflow agents and to tools and callbacks in any
|
|
agent style:
|
|
|
|
```go
|
|
--8<-- "examples/go/snippets/graphs/data-handling/main.go:state-scopes"
|
|
```
|
|
|
|
!!! warning "Caution: state data limitations"
|
|
|
|
Session state is a lightweight key-value store. Do not use it to persist
|
|
large payloads such as file contents or binary data. Use ADK artifacts
|
|
or external storage tools instead.
|
|
|
|
!!! tip "workflow package: prefer Event.Output over state"
|
|
|
|
For the `workflow` package (`FunctionNode`, `AgentNode`, `DynamicNode`),
|
|
pass data between nodes by returning typed values — the framework sets
|
|
`Event.Output` automatically. Only use `State().Set` when you need to
|
|
share values with tools, callbacks, or agent `Instruction` templates.
|
|
|
|
## Constrain node data with schemas
|
|
|
|
You can set input and output data schemas to constrain the data formats
|
|
accepted and produced by any agent node.
|
|
|
|
=== "Python"
|
|
|
|
Use `input_schema` and `output_schema` with a class that extends
|
|
***BaseModel*** to constrain any agent's input and output:
|
|
|
|
```python
|
|
from google.adk import Agent
|
|
from pydantic import BaseModel
|
|
|
|
class FlightSearchInput(BaseModel):
|
|
origin: str # Airport code "SFO"
|
|
destination: str # Airport code "CDG"
|
|
departure_date: date # date(2026, 3, 15)
|
|
passengers: int = 1 # Number of passengers
|
|
|
|
class FlightSearchOutput(BaseModel):
|
|
flights: list[Flight]
|
|
cheapest_price: float
|
|
|
|
flight_searcher = Agent(
|
|
name="flight_searcher",
|
|
instruction="Search for available flights.",
|
|
input_schema=FlightSearchInput,
|
|
output_schema=FlightSearchOutput,
|
|
tools=[search_flights_api],
|
|
mode="single_turn",
|
|
...
|
|
)
|
|
|
|
assistant = Agent(
|
|
name="assistant",
|
|
instruction="You help users plan trips.",
|
|
sub_agents=[flight_searcher],
|
|
...
|
|
)
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
**workflow package**: use `workflow.NewAgentNodeTyped[Input, Output]` to
|
|
attach schemas to an agent node. The generic type parameters are reflected
|
|
into `*jsonschema.Schema` automatically — no hand-built schema construction
|
|
needed. The node's `Event.Output` carries the structured result to the
|
|
successor — no `OutputKey` or state write is needed:
|
|
|
|
```go
|
|
--8<-- "examples/go/snippets/graphs/data-handling/main.go:input-output-schema"
|
|
```
|
|
|
|
**Prebuilt workflow agents**: set `InputSchema` and `OutputSchema` on
|
|
`llmagent.Config`. `OutputSchema` forces the model to reply with a JSON
|
|
object matching the schema (the agent cannot use tools when `OutputSchema`
|
|
is set). Use `OutputKey` to save the JSON string to state for downstream
|
|
agents to reference via `{key}` in their `Instruction`.
|
|
|
|
## Access structured data in agents
|
|
|
|
=== "Python"
|
|
|
|
Use the curly-brace `{ }` syntax to select properties from the input
|
|
schema, or `< >` to select a property and also qualify it by the name
|
|
of the source node:
|
|
|
|
```python
|
|
class CityTime(BaseModel):
|
|
time_info: str # time information
|
|
city: str # city name
|
|
|
|
def lookup_time_function(city: str):
|
|
"""Simulate returning the current time in the specified city."""
|
|
return Event(output=CityTime(time_info='10:10 AM', city=city))
|
|
|
|
city_report_agent = Agent(
|
|
name="city_report_agent",
|
|
model="gemini-flash-latest",
|
|
input_schema=CityTime,
|
|
|
|
# data selection based on class and parameter
|
|
# instruction="""
|
|
# Return a sentence in the following format:
|
|
# It is {CityTime.time_info} in {CityTime.city} right now.
|
|
# """,
|
|
|
|
# more restrictive data selection based on source node name
|
|
instruction="""
|
|
Return a sentence in the following format:
|
|
It is <CityTime.time_info from lookup_time_function> in
|
|
<CityTime.city from lookup_time_function> right now.
|
|
""",
|
|
)
|
|
|
|
root_agent = Workflow(
|
|
name="root_agent",
|
|
edges=[
|
|
(START, city_generator_agent, lookup_time_function, city_report_agent)
|
|
],
|
|
)
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
In ADK Go v2.0.0, a `FunctionNode` returns a typed struct and the
|
|
framework serializes it into `Event.Output`. The successor `AgentNode`
|
|
receives the struct as its user content — the fields are available to the
|
|
agent's `Instruction` without any `{key}` template syntax. This is the
|
|
direct equivalent of Python's `input_schema=CityTime` with
|
|
`{CityTime.time_info}` template placeholders: the struct fields are
|
|
delivered as typed input rather than looked up by name from state.
|
|
|
|
```go
|
|
--8<-- "examples/go/snippets/graphs/data-handling/main.go:structured-output"
|
|
```
|
|
|
|
For a complete example of this workflow, see
|
|
[Graph-based agent workflows](/graphs/#get-started).
|