watsonx Orchestrate (wxO) Solution Generator
Table of Contents
- Overview
- Navigating the ADK
- Core Concepts
- Example Categories
- Standard Project Structure
- Implementation Patterns
- Quick Start Guide
Overview
This guide helps you generate watsonx Orchestrate native solutions from Standard Operating Procedures (SOPs) or simple prompts. It uses the IBM watsonx Orchestrate Agent Development Kit (ADK) as the foundation for implementing agents, flows, tools, and knowledge bases.
Purpose
Generate complete watsonx Orchestrate implementations from:
- SOPs: Standard Operating Procedures (recommended - use
sop-builderskill to generate SOPs from BPMN diagrams, n8n JSON, Langflow JSON, or other workflow models first) - Simple Prompts: Direct descriptions of business requirements or workflows
Workflow
Start with Business Requirements:
- If you have BPMN diagrams, n8n JSON, Langflow JSON, or other workflow models → Use
sop-builderskill to generate an SOP first - If you have a simple business requirement → Provide it directly as a prompt
- If you have BPMN diagrams, n8n JSON, Langflow JSON, or other workflow models → Use
Generate wxO Solution: This skill (
wxo-builder) transforms the SOP or prompt into a complete watsonx Orchestrate implementation with:- Agent configurations (YAML)
- Python tools and flows
- Knowledge base integrations
- Import scripts and documentation
ADK Repository: https://github.com/IBM/ibm-watsonx-orchestrate-adk
The ADK provides:
- Python SDK for programmatic agent development
- CLI tool (
orchestratecommand) for managing agents, tools, and environments - Developer Edition - a local, self-contained instance of watsonx Orchestrate
- Production Integration - ability to deploy to production watsonx Orchestrate instances
Navigating the ADK
GitHub Repository
All examples and source code are available in the official GitHub repository:
Repository: https://github.com/IBM/watsonx-orchestrate-adk
Key Directories in Repository
watsonx-orchestrate-adk/
├── examples/ # Example implementations (START HERE)
│ ├── agent_builder/ # Agent examples
│ ├── flow_builder/ # Flow examples
│ ├── channel-integrations/ # Channel integration examples
│ └── plugins/ # Plugin examples
├── src/ibm_watsonx_orchestrate/ # SDK source (for reference)
│ ├── agent_builder/ # Agent creation APIs
│ ├── flow_builder/ # Flow/workflow APIs
│ └── cli/ # CLI commands
└── packages/ # Additional packages
How to Use This Guide
- Browse GitHub Examples - Visit the examples directory to find examples similar to your use case
- Study Standard Structure - Understand the consistent project layout
- Follow Implementation Patterns - Use proven patterns for common scenarios
- Use Quick Start Guide - Create new projects based on examples
Core Concepts
1. Agents
AI assistants that can use tools and interact with users. Defined using YAML configuration:
spec_version: v1
kind: native
name: my_agent
description: Agent description
instructions: Detailed instructions for the agent
llm: groq/openai/gpt-oss-120b
style: react_core
tools:
- tool_name_1
- tool_name_2
2. Tools
Functions that agents can invoke. Three main types:
- Python Tools: Python functions decorated with
@tool - Flow Tools: Workflows built with the flow builder
- OpenAPI Tools: REST APIs defined by OpenAPI specs
3. Flows
Workflows that orchestrate multiple steps, tools, and logic:
from ibm_watsonx_orchestrate.flow_builder.flows import Flow, flow, START, END
@flow(
name="my_flow",
display_name="My Flow",
description="Flow description",
input_schema=MyInputSchema
)
def build_my_flow(aflow: Flow) -> Flow:
# Define flow nodes and sequence
node1 = aflow.tool(my_tool_function)
node2 = aflow.prompt(
name="process_data",
system_prompt=["Process the data"],
user_prompt=["Process this: {input}"],
llm="watsonx/openai/gpt-oss-120b",
input_schema=MyInputSchema,
output_schema=MyOutputSchema
)
aflow.sequence(START, node1, node2, END)
return aflow
CRITICAL - Flow Function Signature:
- Flow functions MUST follow this exact signature:
def build_<flow_name>(aflow: Flow) -> Flow: - The parameter MUST be named
aflowwith typeFlow - The function MUST return
Flow - The function name MUST start with
build_ - Do NOT invent alternative signatures or parameter names
4. Connections
Authenticated connections to external services (ServiceNow, Salesforce, etc.)
5. Knowledge Bases
Document repositories that agents can search through for information
LLM Usage Guidelines
When to Use Built-in Prompt Nodes vs. Agents
For Direct LLM Generation Tasks: When your specification calls for using an LLM directly to generate content, analyze text, or perform transformations, use the built-in Prompt node in Flow rather than creating custom tools or external LLM calls.
Default LLM Model: groq/openai/gpt-oss-120b
Example - Using Prompt Node in Flow:
from ibm_watsonx_orchestrate.flow_builder.flows import Flow, flow, START, END
@flow(
name="content_generator",
display_name="Content Generator",
description="Generate content using LLM"
)
def build_content_generator(aflow: Flow) -> Flow:
# Use built-in Prompt node for LLM generation
generate_node = aflow.prompt(
name="generate_content",
system_prompt=["You are a helpful content generator."],
user_prompt=["Generate content based on: {input}"],
llm="groq/openai/gpt-oss-120b", # Default LLM model
input_schema=InputSchema,
output_schema=OutputSchema
)
aflow.sequence(START, generate_node, END)
return aflow
For Knowledge-Based Tasks: When your specification requires accessing knowledge bases, retrieving information from documents, or performing RAG (Retrieval-Augmented Generation), rely on the agent's built-in knowledge base capabilities rather than implementing custom retrieval logic.
Example - Agent with Knowledge Base:
spec_version: v1
kind: native
name: knowledge_assistant
description: Assistant with access to knowledge base
instructions: |
You are a helpful assistant with access to a knowledge base.
Use the knowledge base to answer questions accurately.
llm: groq/openai/gpt-oss-120b
knowledge_bases:
- my_knowledge_base
tools:
- my_flow_tool
Key Principles:
- LLM Generation → Use
aflow.prompt()node in flows withgroq/openai/gpt-oss-120b - Knowledge Retrieval → Use agent's
knowledge_basesconfiguration - Custom Logic → Use Python tools only for business logic, API calls, or data transformations
- Don't Reinvent → Leverage built-in capabilities instead of custom implementations
Knowledge Base Providers
watsonx Orchestrate supports multiple knowledge base providers for RAG (Retrieval Augmented Generation) implementations. Choose the appropriate provider based on your existing infrastructure or requirements.
Supported Knowledge Base Providers
1. Built-in Milvus (Managed)
Use When: You don't have an existing vector database and want a fully managed solution.
Configuration:
spec_version: v1
kind: knowledge_base
name: my_knowledge_base
description: Knowledge base with uploaded documents
documents:
- path: document1.pdf
- path: document2.pdf
vector_index:
embeddings_model_name: ibm/slate-125m-english-rtrvr-v2
Features:
- Automatic document ingestion and indexing
- No external infrastructure required
- Supports PDF, DOCX, PPTX, XLSX, CSV, HTML, TXT
- Built-in embedding generation
Authentication: None required (managed service)
2. AstraDB (DataStax)
Use When: You have an existing AstraDB instance or need Cassandra-based vector storage.
Configuration:
spec_version: v1
kind: knowledge_base
name: my_astradb_kb
description: Knowledge base connected to AstraDB
app_id: my_astradb_connection
prioritize_built_in_index: false
conversational_search_tool:
index_config:
- astradb:
api_endpoint: 'https://xxx-us-east-2.apps.astra.datastax.com'
data_type: collection # or 'table'
collection: my_collection
embedding_model_id: nvidia/nv-embedqa-e5-v5
embedding_mode: server # or 'client'
port: '443'
search_mode: vector # 'vector', 'lexical', or 'hybrid'
limit: 5
field_mapping:
title: title_field
body: content_field
url: url_field
Features:
- Server-side or client-side embeddings
- Multiple search modes (vector, lexical, hybrid)
- Collection or table-based storage
- Scalable cloud-native solution
Authentication: API Key (Application Token)
orchestrate connections configure -a my_astradb_connection --kind api_key
orchestrate connections set-credentials -a my_astradb_connection --api-key <TOKEN>
3. Milvus (External)
Use When: You have an existing Milvus instance or need self-hosted vector storage.
Configuration:
spec_version: v1
kind: knowledge_base
name: my_milvus_kb
description: Knowledge base connected to external Milvus
app_id: my_milvus_connection
prioritize_built_in_index: false
conversational_search_tool:
index_config:
- milvus:
endpoint: 'https://my-milvus-instance.com'
collection_name: my_collection
embedding_provider: nvidia
embedding_model: nvidia/nv-embedqa-e5-v5
embedding_dimension: 1024
field_mapping:
title: title
body: content
url: source_url
Features:
- Self-hosted or cloud-hosted options
- High-performance vector search
- Flexible schema design
- Open-source foundation
Authentication: Basic Auth
orchestrate connections configure -a my_milvus_connection --kind basic
orchestrate connections set-credentials -a my_milvus_connection -u <USERNAME> -p <PASSWORD>
4. Elasticsearch
Use When: You have an existing Elasticsearch cluster or need full-text + vector search.
Configuration:
spec_version: v1
kind: knowledge_base
name: my_elasticsearch_kb
description: Knowledge base connected to Elasticsearch
app_id: my_elasticsearch_connection
prioritize_built_in_index: false
conversational_search_tool:
index_config:
- elasticsearch:
endpoint: 'https://my-elasticsearch-cluster.com'
index_name: my_index
embedding_field: vector_embedding
field_mapping:
title: title
body: content
url: url
Features:
- Combined full-text and vector search
- Mature ecosystem and tooling
- Advanced query capabilities
- Hybrid search support
Authentication: API Key or Basic Auth
# API Key
orchestrate connections configure -a my_elasticsearch_connection --kind api_key
orchestrate connections set-credentials -a my_elasticsearch_connection --api-key <KEY>
# Basic Auth
orchestrate connections configure -a my_elasticsearch_connection --kind basic
orchestrate connections set-credentials -a my_elasticsearch_connection -u <USER> -p <PASS>
When to Use Custom Python Tools Instead
If your vector database or search system is NOT one of the supported providers above, create a custom Python tool instead of using a knowledge base.
Unsupported Systems Requiring Custom Tools:
- Pinecone
- Weaviate
- Qdrant
- Chroma
- Custom REST APIs
- Legacy search systems
- Proprietary databases
Custom Tool Pattern for RAG:
from ibm_watsonx_orchestrate.agent_builder.tools import tool
from pydantic import BaseModel, Field
from typing import List, Dict, Any
import requests
class SearchQuery(BaseModel):
"""Input for searching the knowledge base."""
query: str = Field(..., description="The search query")
top_k: int = Field(default=5, description="Number of results to return")
class SearchResult(BaseModel):
"""Search result from the knowledge base."""
results: List[Dict[str, Any]] = Field(..., description="List of search results")
@tool(
name="search_custom_vector_db",
description="Search a custom vector database for relevant information"
)
def search_custom_vector_db(query: SearchQuery) -> SearchResult:
"""
Search a custom vector database and return relevant results.
Args:
query: SearchQuery containing the search query and parameters
Returns:
SearchResult containing the list of relevant documents
"""
# Example: Call your custom vector database API
response = requests.post(
"https://my-custom-db.com/search",
json={
"query": query.query,
"limit": query.top_k
},
headers={"Authorization": f"Bearer {get_api_key()}"}
)
results = response.json()
# Format results for the agent
formatted_results = []
for result in results.get("matches", []):
formatted_results.append({
"title": result.get("metadata", {}).get("title", ""),
"content": result.get("text", ""),
"score": result.get("score", 0.0),
"source": result.get("metadata", {}).get("source", "")
})
return SearchResult(results=formatted_results)
Agent Configuration with Custom Tool:
spec_version: v1
kind: native
name: my_agent_with_custom_search
description: Agent using custom search tool
instructions: |
You are a helpful assistant. When users ask questions, use the
search_custom_vector_db tool to find relevant information, then
provide a clear answer with citations.
llm: groq/openai/gpt-oss-120b
style: react_core
tools:
- search_custom_vector_db
Provider Selection Decision Tree
Do you have an existing vector database?
├─ No → Use Built-in Milvus (managed)
└─ Yes → What type?
├─ AstraDB → Use AstraDB provider
├─ Milvus → Use Milvus provider
├─ Elasticsearch → Use Elasticsearch provider
└─ Other (Pinecone, Weaviate, etc.) → Create Custom Python Tool
Authentication Support Matrix
| Provider | Basic Auth | API Key | Bearer Token | OAuth |
|---|---|---|---|---|
| Built-in Milvus | N/A | N/A | N/A | N/A |
| AstraDB | ❌ | ✅ | ❌ | ❌ |
| Milvus (External) | ✅ | ❌ | ❌ | ❌ |
| Elasticsearch | ✅ | ✅ | ❌ | ❌ |
| Custom Tool | Depends on implementation |
Best Practices
- Use Built-in Providers When Possible: They offer better integration and automatic RAG orchestration
- Field Mapping: Always configure field_mapping to match your data schema
- Embedding Models: Choose embedding models compatible with your provider
- Connection Management: Use connections for secure credential storage
- Testing: Test knowledge base connectivity before deploying agents
- Custom Tools: Only create custom tools when no built-in provider exists
Example Categories
1. Agent Builder Examples
Browse: examples/agent_builder/
Customer Care
- Location: customer_care/
- Purpose: Healthcare customer service agent
- Features: ServiceNow integration, benefits queries, doctor search
- Key Components:
- Agent YAML configuration
- Python tools for API integration
- Connection setup for ServiceNow
Voice-Enabled Agents
- voice_enabled_azure/ - Azure voice integration
- voice_enabled_deepgram/ - Deepgram voice integration
- voice_enabled_elevenlabs/ - ElevenLabs voice integration
- voice_enabled_watson/ - Watson voice integration
2. Flow Builder Examples
Browse: examples/flow_builder/
Simple Flows
- Purpose: Basic flow demonstrating message generation
- Pattern: Simple tool invocation
- Use Case: Learning flow basics
- Purpose: Fetch and display pet facts
- Pattern: External API integration
- Use Case: Simple data retrieval
Document Processing Flows
- Purpose: Extract structured data from documents
- Pattern: Watson Document Understanding integration
- Key Features:
- KVP (Key-Value Pair) schema definition
- Document processing node (
docproc) - Support for PDFs and images
- Purpose: Classify documents by type
- Pattern: Document analysis and categorization
- Purpose: General document data extraction
- Pattern: Flexible extraction framework
Workflow Patterns
- Purpose: Interactive user input collection
- Pattern: User activity nodes
- Use Case: Gathering structured user input
- Purpose: Process multiple emails
- Pattern: Loop/iteration over collections
- Use Case: Batch processing
- Purpose: Tuition reimbursement workflow
- Pattern: Multi-step approval process
- Use Case: Business process automation
Conditional Logic
- Purpose: Conditional flow execution
- Pattern: If-else branching
- Use Case: Decision-based workflows
Advanced Patterns
- Purpose: Multiple agents working together
- Pattern: Agent collaboration
- Use Case: Complex multi-agent scenarios
- Purpose: Agent swarm for task distribution
- Pattern: Dynamic agent selection
- Use Case: Intelligent task routing
- Purpose: Scheduled agent execution
- Pattern: Time-based triggers
- Use Case: Automated periodic tasks
Standard Project Structure
Every example follows a consistent structure:
example_name/
├── __init__.py # Python package initialization
├── README.md # Documentation and usage instructions
├── main_flow.py # Programmatic testing script to test Flow. Not needed if no flow is created.
├── import-all.sh # Import script for CLI
├── .env (optional) # Environment variables
├── tools/ # Tool implementations
│ ├── __init__.py
│ ├── tool_name.py # Python tool definitions
│ └── flow_name.py # Flow definitions
├── agents/ # Agent configurations
│ └── agent_name.yaml # Agent YAML files
└── generated/ # Generated artifacts
└── flow_spec.json # Compiled flow specifications
Key Files Explained
1. tools/[tool_name].py
Python tools decorated with @tool:
from ibm_watsonx_orchestrate.agent_builder.tools import tool, ToolPermission
@tool(permission=ToolPermission.READ_ONLY)
def my_tool(param: str) -> dict:
"""Tool description"""
# Implementation
return {"result": "value"}
2. tools/[flow_name].py
Flow definitions using @flow decorator:
from ibm_watsonx_orchestrate.flow_builder.flows import Flow, flow, START, END
@flow(
name="my_flow",
display_name="My Flow",
description="Flow description",
input_schema=InputSchema
)
def build_my_flow(aflow: Flow) -> Flow:
# Build flow
return aflow
IMPORTANT - Flow Function Signature:
- ALWAYS use:
def build_<flow_name>(aflow: Flow) -> Flow: - Parameter MUST be
aflow: Flow - Return type MUST be
Flow - Function name MUST start with
build_
CRITICAL CONSTRAINTS - MUST FOLLOW
⚠️ Decorator Requirements
ALL functions MUST use decorators:
# Tools - ALWAYS @tool
from ibm_watsonx_orchestrate.agent_builder.tools import tool, ToolPermission
@tool(permission=ToolPermission.READ_ONLY) # or READ_WRITE
def my_tool(param: str) -> dict:
"""Tool description"""
return {"result": "value"}
# Flows - ALWAYS @flow with signature: def build_<name>(aflow: Flow) -> Flow
from ibm_watsonx_orchestrate.flow_builder.flows import Flow, flow, START, END
@flow(name="my_flow", display_name="My Flow", input_schema=Schema)
def build_my_flow(aflow: Flow) -> Flow:
node = aflow.tool(my_tool)
aflow.edge(START, node)
aflow.edge(node, END)
return aflow
Rules:
- ❌ NEVER regular functions without decorators
- ✅ Flow signature:
def build_<name>(aflow: Flow) -> Flow: - ✅ One flow per file:
tools/[flow_name]_flow.py - ✅ Tools can be grouped:
tools/[category]_tools.py - ✅ Credentials as regular parameters (no ExpectCredentials)
Validation Checklist:
- All functions have
@toolor@flow - Flows:
def build_<name>(aflow: Flow) -> Flow: - One flow per file
- Proper ToolPermission values
⚠️ Python Tool Self-Containment Requirement
CRITICAL: Each Python tool implementation file MUST be self-contained.
All function definitions, type definitions, and class definitions used within a Python tool file must be defined within that same file. Cross-file references between local Python files are NOT allowed.
Allowed References:
- ✅ Standard Python library imports (e.g.,
import json,from typing import Optional) - ✅ Common third-party packages (e.g.,
import requests,from pydantic import BaseModel) - ✅
ibm_watsonx_orchestratepackage imports (e.g.,from ibm_watsonx_orchestrate.agent_builder.tools import tool)
NOT Allowed:
- ❌ Importing functions/types from other local Python files in the same project
- ❌ Relative imports from sibling modules (e.g.,
from .utils import helper_function) - ❌ Importing custom types from other local files (e.g.,
from tools.shared_types import MyModel)
Example - ❌ INCORRECT:
# tools/my_tool.py
from tools.shared_utils import format_response # ❌ NOT ALLOWED
from .types import CustomModel # ❌ NOT ALLOWED
@tool(permission=ToolPermission.READ_ONLY)
def my_tool(input: str) -> CustomModel:
return format_response(input)
Example - ✅ CORRECT:
# tools/my_tool.py
from pydantic import BaseModel, Field
from ibm_watsonx_orchestrate.agent_builder.tools import tool, ToolPermission
class CustomModel(BaseModel): # ✅ Defined in same file
result: str = Field(description="Result")
def format_response(input: str) -> str: # ✅ Helper defined in same file
return f"Formatted: {input}"
@tool(permission=ToolPermission.READ_ONLY)
def my_tool(input: str) -> CustomModel:
"""Process input and return formatted result."""
formatted = format_response(input)
return CustomModel(result=formatted)
Rationale:
- Ensures tools are portable and can be deployed independently
- Prevents dependency issues during tool import and execution
- Simplifies tool maintenance and debugging
- Aligns with watsonx Orchestrate's tool isolation model
3. agents/[agent_name].yaml
Agent configuration:
CRITICAL - Required Agent YAML Fields: All agent YAML files MUST include these required fields:
spec_version: v1 # REQUIRED - Always use v1
kind: native # REQUIRED - Use 'native' for standard agents
name: agent_name # REQUIRED - Unique agent identifier
description: Agent description # REQUIRED - Clear description of agent purpose
instructions: Detailed instructions # REQUIRED - Instructions for the LLM
llm: groq/openai/gpt-oss-120b # REQUIRED - LLM model to use
style: react_core # REQUIRED - Agent style (react_core, default, react, etc.)
collaborators: [] # OPTIONAL - List of collaborator agents
tools: # REQUIRED - List of tools/flows
- tool_or_flow_name
knowledge_base: [] # OPTIONAL - List of knowledge bases
starter_prompts: # RECOMMENDED - Suggested prompts for users
is_default_prompts: false
prompts:
- id: default0
title: Short action title
prompt: Example prompt text that users can click
state: active
- id: default1
title: Another action
prompt: Another example prompt
state: active
welcome_content: # RECOMMENDED - Welcome message for users
welcome_message: Welcome to [Agent Name]
description: Brief description of what the agent can help with
is_default_message: false
RECOMMENDED - Starter Prompts and Welcome Content:
Always include starter_prompts and welcome_content to improve user experience:
starter_prompts: Provide 2-4 suggested prompts that guide users on what the agent can do
- Use clear, action-oriented titles (e.g., "Report a concern", "Create support ticket")
- Write prompts that demonstrate the agent's capabilities
- Set
is_default_prompts: falseto use custom prompts - Each prompt needs a unique
id(e.g., default0, default1, etc.) - Set
state: activefor all prompts
welcome_content: Create a welcoming first impression
welcome_message: A friendly greeting that includes the agent's name/purposedescription: A brief explanation of what the agent can help with- Set
is_default_message: falseto use custom content - Set
is_user_barge_in_disabled: trueto disable user barge-in during the welcome message
Example from St. Mary's Hospital Agent:
starter_prompts:
is_default_prompts: false
prompts:
- id: default0
title: Report a concern
prompt: I need to report a concern about my care
state: active
- id: default1
title: Create support ticket
prompt: I want to create a support ticket
state: active
- id: default2
title: Follow up on issue
prompt: I need to follow up on a previous issue
state: active
welcome_content:
welcome_message: Welcome to St. Mary's Group of Hospitals Support
description: I'm here to help you report concerns and create support tickets. How can I assist you today?
is_default_message: false
DO NOT:
- ❌ Omit
spec_version: v1(will cause import errors) - ❌ Omit
kind: native - ❌ Omit required fields like
llm,style, ortools - ❌ Skip
starter_promptsandwelcome_content(reduces user experience quality)
4. main_flow.py
Programmatic testing:
import asyncio
from pathlib import Path
from examples.example_name.tools.flow_name import build_flow
async def main():
flow_def = await build_flow().compile_deploy()
generated_folder = f"{Path(__file__).resolve().parent}/generated"
flow_def.dump_spec(f"{generated_folder}/flow.json")
await flow_def.invoke({"input": "value"}, debug=True)
if __name__ == "__main__":
asyncio.run(main())
5. import-all.sh
CLI import script:
CRITICAL - Import CLI Syntax:
You MUST use the orchestrate CLI commands to import flows and agents. Do NOT use Python scripts or custom import methods.
#!/usr/bin/env bash
# orchestrate env activate local # only used if user asked to activate local env
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Import Python tools
for tool in tool1.py tool2.py; do
orchestrate tools import -k python -f ${SCRIPT_DIR}/tools/${tool}
done
# Import Flow tools
for flow in flow1.py; do
orchestrate tools import -k flow -f ${SCRIPT_DIR}/tools/${flow}
done
# Import agents
for agent in agent1.yaml; do
orchestrate agents import -f ${SCRIPT_DIR}/agents/${agent}
done
IMPORTANT - CLI Command Reference:
- Import Python Tools:
orchestrate tools import -k python -f <path_to_tool.py> - Import Flow Tools:
orchestrate tools import -k flow -f <path_to_flow.py> - Import Agents:
orchestrate agents import -f <path_to_agent.yaml>
DO NOT:
- ❌ Use custom Python import scripts (e.g.,
python3 main_flow.py) - ❌ Use API client methods directly in import scripts
- ❌ Invent alternative import methods
ALWAYS:
- ✅ Use the
orchestrateCLI commands shown above - ✅ Use the
-kflag to specify tool kind (python or flow) - ✅ Use the
-fflag to specify the file path - ✅ Use
${SCRIPT_DIR}for relative paths in the script
Implementation Patterns
Pattern 1: Simple Tool Flow
Use Case: Basic data retrieval or processing
Structure:
example/
├── tools/
│ ├── my_tool.py # Python tool
│ └── my_flow.py # Flow that uses the tool
├── agents/
│ └── my_agent.yaml # Agent configuration
└── main.py # Testing script
Example: get_pet_facts_if_else/
Pattern 2: Document Processing Flow
Use Case: Extract structured data from documents
Structure:
example/
├── tools/
│ ├── get_kvp_schemas.py # Define extraction schema
│ └── processing_flow.py # Document processing flow
├── agents/
│ └── doc_agent.yaml # Agent configuration
└── main.py # Testing script
Key Components:
- KVP Schema Tool: Defines what fields to extract
- Document Processing Node: Uses Watson Document Understanding
- Flow: Orchestrates schema retrieval and document processing
IMPORTANT - Document Upload Handling:
When a flow expects a document as input (e.g., DocProcInput), the agent should invoke the flow tool directly without asking the user to upload the document first. The flow itself will handle the document upload prompt.
✅ Correct Agent Instructions:
instructions: | When the user wants to process a document, immediately invoke the document_processing_flow tool. The flow will prompt the user to upload the document.❌ Incorrect Agent Instructions:
instructions: | Ask the user to upload a document first, then pass it to the document_processing_flow tool. # This will NOT work - the agent cannot pass uploaded documents to flows
Why: Agents cannot directly pass user-uploaded documents to flow tools. The flow's document input nodes (like docproc) handle the upload interaction directly with the user. The agent should simply invoke the flow tool and let the flow manage the document upload process.
Example: extract_airline_invoice/, document_processing/, expense_report_agent/, invoice_agent_6/
Pattern 3: User Activity Flow
Use Case: Interactive multi-step workflows
Structure:
example/
├── tools/
│ └── activity_flow.py # Flow with user activity nodes
├── agents/
│ └── activity_agent.yaml # Agent configuration
└── main.py # Testing script
Key Features:
- User activity nodes for input collection
- Form handling
- Multi-turn conversations
Example: user_activity/, book_a_flight/
Pattern 4: Multi-Agent Collaboration
Use Case: Complex tasks requiring multiple specialized agents
Structure:
example/
├── tools/
│ ├── agent1_tools.py # Tools for agent 1
│ ├── agent2_tools.py # Tools for agent 2
│ └── orchestration_flow.py # Coordination flow
├── agents/
│ ├── agent1.yaml # Specialized agent 1
│ ├── agent2.yaml # Specialized agent 2
│ └── coordinator.yaml # Coordinator agent
└── main.py # Testing script
Example: collaborator_agents/, triage_workflow_agent_swarm/
Quick Start Guide
Creating a New Example
Step 1: Create Directory Structure
Note: You can reference existing examples from the GitHub repository for structure and patterns.
mkdir -p my_example/{tools,agents,generated}
touch my_example/{__init__.py,main_flow.py,README.md,import-all.sh}
touch my_example/tools/__init__.py
Step 2: Create Python Tool (if needed)
# tools/my_tool.py
from ibm_watsonx_orchestrate.agent_builder.tools import tool, ToolPermission
@tool(permission=ToolPermission.READ_ONLY)
def my_tool(input_param: str) -> dict:
"""Tool description"""
return {"result": f"Processed: {input_param}"}
Step 3: Create Flow
# tools/my_flow.py
from pydantic import BaseModel
from ibm_watsonx_orchestrate.flow_builder.flows import Flow, flow, START, END
from .my_tool import my_tool
class MyFlowInput(BaseModel):
input_param: str
@flow(
name="my_flow",
display_name="My Flow",
description="Flow description",
input_schema=MyFlowInput
)
def build_my_flow(aflow: Flow) -> Flow:
"""
CRITICAL: Flow function signature MUST be:
def build_<flow_name>(aflow: Flow) -> Flow:
"""
tool_node = aflow.tool(my_tool)
aflow.sequence(START, tool_node, END)
return aflow
Step 4: Create Agent Configuration
# agents/my_agent.yaml
spec_version: v1
kind: native
name: my_agent
description: My agent description
instructions: Invoke my_flow tool and output the result
llm: groq/openai/gpt-oss-120b
style: react_core
tools:
- my_flow
Step 5: Create Main Script (only needed if there are flows in the projects)
Tip: See flow examples for complete working implementations.
# main_flow.py
import asyncio
from pathlib import Path
from my_example.tools.my_flow import build_my_flow
async def main():
flow_def = await build_my_flow().compile_deploy()
generated_folder = f"{Path(__file__).resolve().parent}/generated"
flow_def.dump_spec(f"{generated_folder}/my_flow.json")
await flow_def.invoke({"input_param": "test"}, debug=True)
if __name__ == "__main__":
asyncio.run(main())
Step 6: Create Import Script
CRITICAL: Always use the orchestrate CLI commands to import flows and agents.
# import-all.sh
#!/usr/bin/env bash
# orchestrate env activate local
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Import Python tools (if any)
for tool in my_tool.py; do
orchestrate tools import -k python -f ${SCRIPT_DIR}/tools/${tool}
done
# Import Flow tools - MUST use: orchestrate tools import -k flow
for flow in my_flow.py; do
orchestrate tools import -k flow -f ${SCRIPT_DIR}/tools/${flow}
done
# Import agents - MUST use: orchestrate agents import
for agent in my_agent.yaml; do
orchestrate agents import -f ${SCRIPT_DIR}/agents/${agent}
done
Required CLI Commands:
- Python tools:
orchestrate tools import -k python -f <file> - Flow tools:
orchestrate tools import -k flow -f <file> - Agents:
orchestrate agents import -f <file>
Step 7: Make Import Script Executable
chmod +x my_example/import-all.sh
Step 8: Create README with Diagrams
Examples: Browse GitHub examples to see complete README files with diagrams.
# My Example
## Overview
Brief description of what this example demonstrates.
## Architecture Diagram
```mermaid
graph TB
User[User] -->|Interacts| Agent[My Agent]
Agent -->|Invokes| Flow[My Flow Tool]
Flow -->|Executes| Tool[My Tool]
Tool -->|Returns| Result[Result]
Result -->|Formatted by| Agent
Agent -->|Presents| User
style Agent fill:#4A90E2,stroke:#2E5C8A,color:#fff
style Flow fill:#50C878,stroke:#2E7D4E,color:#fff
style Tool fill:#F39C12,stroke:#C87F0A,color:#fff
Workflow Diagram
flowchart TD
Start([START]) --> Input[Input Data]
Input --> Process[Processing Node]
Process --> Output[Output Result]
Output --> End([END])
style Start fill:#2ECC71,stroke:#27AE60,color:#fff
style End fill:#E74C3C,stroke:#C0392B,color:#fff
style Process fill:#F39C12,stroke:#D68910,color:#fff
Usage
Via Chat UI
- Run
./import-all.sh - Launch chat:
orchestrate chat start - Select
my_agent - Interact with the agent
Programmatically
- Set PYTHONPATH:
export PYTHONPATH=<ADK>/src:<ADK> - Run:
python3 main.py
Features
- Feature 1
- Feature 2
Output
Description of expected output
### Testing Your Example
#### Option 1: Via Chat UI
```bash
cd examples/category/my_example
./import-all.sh
orchestrate chat start
# Select your agent and interact
Option 2: Programmatically
export PYTHONPATH=/path/to/adk/src:/path/to/adk
cd examples/category/my_example
python3 main.py
Best Practices
1. Naming Conventions
- Use snake_case for Python files and functions
- Use descriptive names that indicate purpose
- Agent names should match their YAML file names
2. Documentation
- Always include a README.md with:
- Purpose and overview
- Architecture Diagram: Mermaid diagram showing agent, flow, and tool relationships
- Workflow Diagram(s): One Mermaid diagram per agentic workflow showing the flow execution path
- Usage instructions (both CLI and programmatic)
- Expected inputs/outputs
- Prerequisites or dependencies
Creating Effective Diagrams
Architecture Diagram Guidelines:
- Show the high-level system components (User → Agent → Flow → Tools/Services)
- Include external services or APIs being used
- Use consistent color coding (e.g., agents in blue, flows in green, tools in orange)
- Keep it simple and focused on the main interaction flow
Workflow Diagram Guidelines:
- Create one diagram per agentic workflow (flow tool)
- Show the complete flow from START to END
- Include all nodes: tool nodes, LLM nodes, decision points, user activity nodes
- Label branches clearly for c
…(truncated)