Skip to main content

Build Your First Agent from Scratch

Welcome to OrbitAI! This guide will walk you through building a complete multi-agent system using a practical recipe preparation workflow. You’ll create specialized AI agents that work together to plan meals, find recipes, and generate shopping lists.

Meal Planner

Analyzes dietary preferences and creates personalized meal plans

Recipe Researcher

Finds and analyzes recipes for planned meals

Shopping List

Generates organized shopping lists from recipes

Installation & Setup

1

Create a New Swift Package

Initialize a new Swift executable package for your recipe prep system:
mkdir RecipePrepOrbit
cd RecipePrepOrbit
swift package init --type executable
2

Add OrbitAI Dependency

Edit your Package.swift file to include OrbitAI:
Package.swift
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "RecipePrepOrbit",
    platforms: [
        .macOS(.v13),
        .iOS(.v16)
    ],
    dependencies: [
        .package(url: "https://github.com/tryorbitai/orbit-ai.git", from: "1.0.0")
    ],
    targets: [
        .executableTarget(
            name: "RecipePrepOrbit",
            dependencies: [
                .product(name: "OrbitAI", package: "orbit-ai")
            ]
        )
    ]
)
3

Configure Environment Variables

Create a .env file in your project root with your API credentials:
.env
# Required: At least one LLM provider
OPENAI_API_KEY=your-openai-api-key-here
Never commit your .env file to version control. Add it to .gitignore!

Understanding Core Concepts

Agents are autonomous AI entities with specific roles and capabilities:
  • Role: What the agent represents (e.g., “Meal Planner”).
  • Purpose: The agent’s primary goal.
  • Context: Background information that shapes behavior.
  • Tools: Available capabilities (web search, read files, etc.)
Agents can work independently or collaborate with other agents in coordinated workflows.
Tasks define specific work to be completed:
  • Description: What needs to be done.
  • Expected Output: Format and content requirements.
  • Agent Assignment: Which agent handles the task.
  • Dependencies: Tasks that must complete first.
Tasks can reference outputs from previous tasks to create complex workflows.
Orbits orchestrate agents and tasks into workflows:
  • Process Type: Sequential (one after another) or Hierarchical (manager delegates).
  • Execution Flow: How tasks are coordinated.
  • Resource Management: Memory, knowledge bases, tool access.
Orbits manage the entire execution lifecycle and provide detailed metrics.

Step-by-Step Implementation

Step 1: Initialize OrbitAI

Create your main entry point in Sources/RecipePrepOrbit/main.swift:
main.swift
import Foundation
import OrbitAI

@main
struct RecipePrepApp {
    static func main() async throws {
        // Initialize OrbitAI framework
        OrbitAI.configure()
        
        // Set up LLM manager with OpenAI provider
        let llmManager = LLMManager(
            enableMetrics: true,
            enableCaching: true,
            defaultTimeout: 30,
            cacheTTL: 120,
            cacheCapacity: 256
        )
        
        // Configure OpenAI provider from environment
        let openAIProvider = try OpenAIProvider.fromEnvironment(model: .gpt4o)
        try await llmManager.addProvider(openAIProvider)
        
        print("🚀 OrbitAI Recipe Prep System Starting...")
        
        // Create and run the recipe prep workflow
        let workflow = RecipePrepWorkflow()
        try await workflow.execute()
    }
}
The LLM manager handles all communication with AI providers, including caching, metrics, and error handling.

Step 2: Create Specialized Agents

Define three specialized agents for your workflow:
  • Meal Planner Agent
  • Recipe Research Agent
  • Shopping List Agent
private func createMealPlannerAgent() -> Agent {
    return Agent(
        role: "Meal Planning Specialist",
        purpose: "Create personalized meal plans based on dietary preferences and constraints",
        context: """
        You are an expert nutritionist and meal planning specialist with extensive knowledge of:
        - Dietary requirements and restrictions (vegetarian, vegan, gluten-free, keto, etc.)
        - Nutritional balance and meal composition
        - Seasonal ingredient availability
        - Budget-conscious meal planning
        - Family-friendly meal options

        Your goal is to create practical, healthy, and delicious meal plans that fit the user's
        lifestyle, preferences, and constraints.
        """,
        verbose: true,
        temperature: 0.7
    )
}
Temperature Settings: Use lower values (0.1-0.3) for structured tasks like list organization, and higher values (0.7-0.9) for creative tasks like meal planning.

Step 3: Define Workflow Tasks

Create tasks with proper dependencies:
private func createWorkflowTasks(
    mealPlannerAgent: Agent,
    recipeResearchAgent: Agent,
    shoppingListAgent: Agent
) -> (ORTask, ORTask, ORTask) {
    
    // Task 1: Meal Planning
    let planningTask = ORTask(
        description: """
        Create a 7-day meal plan for a family of 4 with the following requirements:
        - 2 adults, 2 children (ages 8 and 12)
        - Budget: $150 per week
        - Dietary preferences: Reduce processed foods, include more vegetables
        - Allergies: One child has a mild nut allergy
        - Cooking time: Maximum 45 minutes per meal on weekdays, unlimited on weekends
        - Must include: 7 breakfasts, 7 lunches, 7 dinners
        
        Consider seasonal ingredients (current season), nutritional balance, 
        and variety in cuisines and flavors.
        """,
        expectedOutput: """
        A detailed 7-day meal plan formatted as follows:
        - Day-by-day breakdown (Monday through Sunday)
        - Each day should include breakfast, lunch, and dinner
        - Estimated prep time for each meal
        - Nutritional highlights
        - Special notes for dietary considerations
        - Total estimated weekly cost
        """,
        agent: await mealPlannerAgent.id,
        outputFormat: .markdown,
        maxExecutionTime: 120,
        guardrails: [.noHarmfulContent]
    )
    
    // Task 2: Recipe Research (depends on meal planning)
    let researchTask = ORTask(
        description: """
        Based on the meal plan from the previous task, research and provide detailed recipes 
        for each meal.
        
        Previous meal plan: {task_0_output}
        
        Research priority should be given to meals that are:
        - Family-friendly and kid-approved
        - Use common, easily-found ingredients
        - Have good nutritional balance
        - Fit within the time constraints specified
        """,
        expectedOutput: """
        A comprehensive recipe collection with step-by-step instructions, 
        ingredient lists, and cooking tips for each meal.
        """,
        agent: await recipeResearchAgent.id,
        context: [planningTask.id],  // Depends on meal planning task
        outputFormat: .markdown,
        maxExecutionTime: 180,
        guardrails: [.noHarmfulContent]
    )
    
    // Task 3: Shopping List Generation (depends on recipe research)
    let shoppingTask = ORTask(
        description: """
        Create an organized shopping list based on all the recipes from the previous task.
        
        Recipe collection: {task_1_output}
        
        Requirements:
        1. Consolidate duplicate ingredients across all recipes
        2. Calculate total quantities needed for the week
        3. Organize by grocery store sections
        4. Include estimated prices and total budget
        """,
        expectedOutput: """
        A comprehensive shopping list organized by store sections with quantities, 
        estimated prices, and shopping tips.
        """,
        agent: await shoppingListAgent.id,
        context: [researchTask.id],  // Depends on recipe research task
        outputFormat: .markdown,
        maxExecutionTime: 90,
        guardrails: [.noHarmfulContent]
    )
    
    return (planningTask, researchTask, shoppingTask)
}
Tasks can reference previous task outputs using {task_N_output} syntax in their descriptions. This enables powerful chaining of agent workflows.

Step 4: Create and Execute the Orbit

Bring everything together by creating the orbit:
func execute() async throws {
    print("👨‍🍳 Building Recipe Preparation Orbit...")
    
    // Create specialized agents
    let mealPlannerAgent = createMealPlannerAgent()
    let recipeResearchAgent = createRecipeResearchAgent()
    let shoppingListAgent = createShoppingListAgent()
    
    // Define the workflow tasks
    let (planningTask, researchTask, shoppingTask) = createWorkflowTasks(
        mealPlannerAgent: mealPlannerAgent,
        recipeResearchAgent: recipeResearchAgent,
        shoppingListAgent: shoppingListAgent
    )
    
    // Create the orbit
    let orbit = try await Orbit.create(
        name: "Recipe Prep Orbit",
        description: "Multi-agent system for meal planning and preparation",
        agents: [mealPlannerAgent, recipeResearchAgent, shoppingListAgent],
        tasks: [planningTask, researchTask, shoppingTask],
        process: .sequential,
        verbose: true,
        memory: true,
        usageMetrics: true
    )
    
    print("🎯 Executing Recipe Prep Workflow...")
    
    // Execute the orbit and get results
    let result = try await orbit.start()
    
    // Display results
    await displayResults(result)
}

Step 5: Build and Run

Execute your first agent workflow:
# Build the project
swift build

# Run your recipe prep workflow
swift run

Expected Output

When you run the application, you’ll see:
🚀 OrbitAI Recipe Prep System Starting...
👨‍🍳 Building Recipe Preparation Orbit...
🎯 Executing Recipe Prep Workflow...

[Agent: Meal Planning Specialist] Starting task: Create a 7-day meal plan...
[Agent: Meal Planning Specialist] Task completed successfully

[Agent: Recipe Research Specialist] Starting task: Research detailed recipes...
[Agent: Recipe Research Specialist] Using context from previous task...
[Agent: Recipe Research Specialist] Task completed successfully

[Agent: Shopping List Organizer] Starting task: Generate organized shopping list...
[Agent: Shopping List Organizer] Using context from recipe collection...
[Agent: Shopping List Organizer] Task completed successfully

🎉 Recipe Prep Workflow Complete!
=====================================
📊 Execution Summary:
   • Total tokens used: 4,521
   • Completion tokens: 3,089
   • Prompt tokens: 1,432

✅ Results saved to local files!

Advanced Features

Enhance your agents with persistent memory and knowledge sources:
let orbit = try await Orbit.create(
    name: "Recipe Prep Orbit",
    agents: agents,
    tasks: tasks,
    process: .sequential,
    verbose: true,
    memory: true,                    // Enable short-term memory
    longTermMemory: true,            // Enable long-term memory
    entityMemory: true,              // Track named entities
    knowledgeSources: [              // Add knowledge sources
        "./nutrition-guidelines.pdf",
        "./family-preferences.txt"
    ]
)
Memory enables agents to learn from past interactions and maintain context across sessions.
Create custom tools for specialized functionality:
final class RecipeDBTool: BaseTool {
    override var name: String { "recipe_database" }
    override var description: String { "Search and retrieve recipes from database" }
    
    override var parametersSchema: JSONSchema {
        JSONSchema(
            type: .object,
            properties: [
                "query": JSONSchema(type: .string, description: "Recipe search query"),
                "max_cook_time": JSONSchema(type: .integer, description: "Max cooking time in minutes")
            ],
            required: ["query"]
        )
    }
    
    override func execute(with parameters: Metadata) async throws -> ToolResult {
        guard let query = parameters["query"]?.stringValue else {
            throw OrbitAIError.invalidToolParameters("Missing query parameter")
        }
        
        let recipes = searchRecipeDatabase(query: query)
        
        var resultData = Metadata()
        resultData["recipes"] = .array(recipes.map { .string($0) })
        
        return ToolResult(success: true, data: resultData)
    }
}

// Register the custom tool
let toolsHandler = ToolsHandler.shared
await toolsHandler.registerTool(RecipeDBTool())
Custom tools extend agent capabilities with domain-specific functionality.
Use structured output for JSON data:
struct ShoppingList: Codable, Sendable {
    struct Item: Codable, Sendable {
        let name: String
        let quantity: String
        let estimatedPrice: Double
        let section: String
    }
    
    let totalEstimatedCost: Double
    let items: [Item]
}

// Create task with structured output
let structuredTask = ORTask.withStructuredOutput(
    description: "Generate shopping list...",
    expectedType: ShoppingList.self,
    agent: await shoppingListAgent.id
)
Structured output ensures consistent, parseable results from your agents.
Track detailed metrics and performance:
// Access orbit metrics after execution
let metrics = await orbit.getUsageMetrics()
print("🔍 Detailed Metrics:")
print("   • Execution time: \(metrics.executionTime) seconds")
print("   • Successful requests: \(metrics.successfulRequests)")
print("   • Average response time: \(metrics.averageResponseTime)")

// Agent-specific metrics
for agent in await orbit.getAgents() {
    let agentMetrics = await agent.totalUsageMetrics
    print("   • \(agent.role): \(agentMetrics.totalTokens) tokens")
}
Metrics help you optimize performance and track resource usage.

Best Practices

Agent Design

  • Single Responsibility: One clear purpose per agent.
  • Clear Context: Detailed background information.
  • Appropriate Tools: Only assign needed tools.
  • Temperature: Lower for structured, higher for creative.

Task Definition

  • Be Specific: Explicit descriptions.
  • Define Output: Clear format and structure.
  • Set Constraints: Realistic time limits.
  • Use Dependencies: Chain task outputs.

Error Handling

  • Try-Catch Blocks: Handle specific errors.
  • Retry Logic: Implement for transient failures.
  • Graceful Degradation: Fallback strategies.
  • Verbose Logging: Debug mode for troubleshooting.

Resource Management

  • Rate Limiting: Prevent API throttling.
  • Timeouts: Set appropriate limits.
  • Caching: Reduce redundant API calls.
  • Metrics: Track usage and costs.

Troubleshooting

Problem: Invalid API key or authentication failed.Solution: Check your environment variables:
echo $OPENAI_API_KEY  # Should display your API key
Ensure the .env file is in the correct directory and properly formatted.
Problem: Task execution exceeded maximum time limit.Solution: Increase the timeout or simplify the task:
let task = ORTask(
    description: "...",
    expectedOutput: "...",
    maxExecutionTime: 180  // Increase from default
)
Problem: Unable to process large outputs.Solution: Use streaming or chunked processing:
let llmManager = LLMManager(
    enableStreaming: true,
    chunkSize: 1024
)
Problem: Tool execution failed.Solution: Check tool availability:
let handler = ToolsHandler.shared
let isAvailable = await handler.isToolAvailable(named: "webSearch")
if !isAvailable {
    print("Tool not available, using alternative approach")
}

Next Steps

Congratulations on building your first OrbitAI agent system! Here’s what to explore next:
Need help? Join our GitHub Discussions or check out the Issue Tracker for support.