Node as tool
Workflows and individual execution nodes can be exposed directly as agent tools. The framework automatically manages schema generation, argument validation, isolated runtime branch scoping, and resumption for human-in-the-loop interactions.
Introduction
In multi-agent architectures, agents frequently need to delegate work to deterministic workflows, data processing pipelines, or specialized calculation steps. Exposing these multi-step routines as tools allows the parent agent model to call them dynamically as functions.
Passing a node or workflow directly into an agent's tools list bridges workflow execution units with the tool subsystem. When an agent invokes a node-based tool, the runner executes the underlying node or workflow within an isolated sub-branch. The sub-branch prevents intermediate progress messages and internal state changes from cluttering the parent agent context while still permitting human-in-the-loop pauses to surface to the caller.
An LlmAgent automatically wraps any Workflow or BaseNode instance passed in its tools list.
Get started
The following example builds a customer verification workflow and exposes it to a parent customer service agent.
fromgoogle.adkimportAgentfromgoogle.adkimportWorkflowfrompydanticimportBaseModel, FieldclassCustomerLookupArgs(BaseModel): user_id: str=Field(description="The unique identifier of the customer.") deffetch_tier(node_input: CustomerLookupArgs, ctx) ->dict[str, str]: return {"user_id": node_input.user_id, "tier": "Gold Member"} verification_workflow=Workflow( name="lookup_customer_tier", description="Look up membership status and account tier for a customer.", input_schema=CustomerLookupArgs, edges=[("START", fetch_tier)], ) root_agent=Agent( name="support_agent", instruction="Answer customer questions using the available lookup tools.", tools=[verification_workflow], )How it works
When an agent model generates a tool call targeting a node or workflow, the runner passes execution to the tool alongside the tool context.
The tool adapter reads the input schema of the wrapped node to generate a function declaration for the model. Upon receiving arguments from the model, the framework validates the input dictionary against the node input schema before invoking the node runtime.
During execution, the tool constructs an isolated sub-branch path formatted as {tool_name}@{function_call_id} appended to the parent branch. All intermediate events, state deltas, and progress logs generated by the node or inner workflow belong to this sub-branch. The parent agent filters out sub-branch events when constructing subsequent model prompts, preserving only the final output returned by the tool.
If a node within the tool pauses for human approval or input, the tool propagates the interruption upward. When the user resumes the invocation with a response event, the runner rehydrates the execution tree and routes the resume response directly to the paused node inside the tool branch.
Configuration options
When an agent exposes a node or workflow as a tool, the resulting tool configuration is derived from the node's properties:
PropertySourceDescriptionTool namenode.nameThe function call identifier presented to the model.Descriptionnode.description or docstringThe prompt context describing the tool's purpose to the model.Parametersnode.input_schema or signatureThe JSON Schema for model function calling arguments.The wrapped node accepts any instance derived from BaseNode, including Workflow graphs and functions decorated with @node. Wrapping an agent directly as a tool is rejected because agents operate with conversational session semantics and belong in sub_agents.
For workflows, the input schema is specified using input_schema on the Workflow. For standalone @node functions, parameters and their docstring descriptions are inferred directly from the function signature.
Advanced applications
Function node as a tool
Passing a function decorated with @node directly to an agent tools argument automatically wraps it as a tool. Tool parameter names and types are inferred directly from the function signature and docstrings.
fromgoogle.adkimportAgentfromgoogle.adk.workflowimportnode@nodedefcheck_order(order_id: str) ->dict[str, str]: """Checks shipping status for an existing order identifier. Args: order_id: The identifier of the order to check. """return {"status": "shipped"} agent=Agent( name="order_assistant", instruction="Help users check their order status.", tools=[check_order], )Human-in-the-loop interruption and resumption
Nodes used as tools can yield interactive control-flow events such as RequestInput. Because pausing and resuming across user turns requires the agent runner to save and restore session state, the agent should be wrapped in an App configured with ResumabilityConfig(is_resumable=True).
fromtypingimportGeneratorfromgoogle.adkimportAgentfromgoogle.adkimportContextfromgoogle.adk.appsimportAppfromgoogle.adk.appsimportResumabilityConfigfromgoogle.adk.eventsimportRequestInputfromgoogle.adk.workflowimportnode@node(rerun_on_resume=True)defprocess_refund( amount: float, ctx: Context ) ->Generator[str, None, None]: """Processes customer refund requests with manager approval. Args: amount: The refund amount in dollars. """resume_input=ctx.resume_inputs.get("manager_approval") ifnotresume_input: yieldRequestInput( interrupt_id="manager_approval", message=f"Authorize refund of ${amount}?", ) returndecision=str(resume_input).strip().lower() ifdecisionin ("approved", "yes"): yield"Refund processed successfully."else: yield"Refund request rejected."service_agent=Agent( name="finance_agent", instruction="Process customer refund requests using the refund tool.", tools=[process_refund], ) app=App( name="finance_app", root_agent=service_agent, resumability_config=ResumabilityConfig(is_resumable=True), )Limitations
Exposing nodes as tools is intended for task-oriented, bounded workflows and deterministic nodes. The framework prohibits wrapping conversational BaseAgent instances as tools because conversational agents require separate turn-taking, multi-message histories, and sub-agent handoffs. To delegate to another agent, configure sub_agents instead.
Any workflow used as a tool must define a Pydantic BaseModel as its input_schema so the runner can generate valid parameter declarations for model function calling. In contrast, standalone @node functions declare their parameter names and type hints directly on the function signature.
Related samples
- Demonstrates an agent invoking both a workflow and an interactive human-in-the-loop node as tools.