#4612 App to Create and Run AI Agent Teams Based on User-Specified Goal

#4612 App to Create and Run AI Agent Teams Based on User-Specified Goal

#4612 Provide the requirements for developing a Python app, using Ollama-supported LLMs, to create and execute agent teams dynamically created based on the user's goal.

To build a Python application that dynamically designs and executes custom teams of AI agents using local Ollama LLMs, your system needs to function in two stages: a Manager Stage (which takes a user goal, analyzes it, and structures the team) and an Execution Stage (where the dynamic team collaborates to solve the problem).

Using a dedicated multi-agent framework like CrewAI alongside Ollama's OpenAI-compatible API is the most efficient architectural choice. Below are the functional, architectural, and systemic requirements needed to build this application.

1. System Architecture Requirements

Your app needs a structured, multi-layered architecture to safely handle dynamic runtime configuration.

  • Dynamic Orchestrator Module: A Python script that acts as the "metacognitive layer." It passes the user prompt to an LLM to generate a structured JSON object containing the blueprints for the team (roles, backstories, specific goals, and assigned tasks).

  • Local LLM Host (Ollama): A running instance of Ollama serving models locally.

  • Agent Runtime Framework: A library (like crewai) to instantiate the objects dynamically generated by the Orchestrator.

2. Infrastructure & Software Dependencies

Before writing code, the system must satisfy these environment baselines:

  • Python Environment: Python $\ge$ 3.10 and < 3.14.

  • Ollama Installation: The Ollama daemon must be installed and running locally (ollama serve).

  • Target LLMs: You need at least one high-capability model for the Orchestration phase (e.g., llama3.1:8b or mistral) and a lighter model if you choose to offload simpler agent tasks (e.g., phi3).

  • Key Libraries:

    • crewai (for multi-agent structural definitions)

    • pydantic (for enforcing strict JSON schemas during dynamic agent generation)

    • langchain-community or built-in CrewAI LLM configurations for routing to Ollama.

3. The Core Code Blueprint (Functional Requirements)

The Python backend must implement a distinct two-step pipeline. Below is the programmatic requirement for handling this workflow:

Step A: The Dynamic Team Architect

This function acts as the supervisor, using Pydantic to guarantee the LLM returns an exact data schema for the new agents.

from pydantic import BaseModel, Field
from typing import List
from crewai import LLM

# 1. Connect to Ollama
ollama_llm = LLM(
    model="ollama/llama3.1:8b",
    base_url="http://localhost:11434"
)

# 2. Define schema for dynamic team generation
class AgentBlueprint(BaseModel):
    role: str = Field(description="The specific role of the agent.")
    goal: str = Field(description="What the agent aims to achieve.")
    backstory: str = Field(description="The persona and professional experience.")

class TaskBlueprint(BaseModel):
    description: str = Field(description="Detailed instructions of what the agent must do.")
    expected_output: str = Field(description="Clear explanation of what the final asset looks like.")
    assigned_agent_role: str = Field(description="The role of the agent who should execute this.")

class TeamBlueprint(BaseModel):
    agents: List[AgentBlueprint]
    tasks: List[TaskBlueprint]

Step B: The Dynamic Assembly & Execution Loop

Your application must ingest the Pydantic data structure, map the tasks to the newly minted agents, and kick off the workflow.

from crewai import Agent, Task, Crew, Process

def run_dynamic_team(user_goal: str):
    # 1. Ask the Orchestrator LLM to output Structured Data matching TeamBlueprint
    # (Using your preferred structured output method or system prompt)
    team_structure = orchestrator_llm.generate_structure(
        prompt=f"Create an optimal team blueprint to achieve: {user_goal}",
        response_model=TeamBlueprint
    )
    
    # 2. Dynamically instantiate Agents
    created_agents = {}
    for a in team_structure.agents:
        created_agents[a.role] = Agent(
            role=a.role,
            goal=a.goal,
            backstory=a.backstory,
            llm=ollama_llm,
            verbose=True
        )
        
    # 3. Dynamically instantiate Tasks and link them to the specific Agent
    created_tasks = []
    for t in team_structure.tasks:
        created_tasks.append(
            Task(
                description=t.description,
                expected_output=t.expected_output,
                agent=created_agents[t.assigned_agent_role]
            )
        )
        
    # 4. Assemble and execute the Crew
    crew = Crew(
        agents=list(created_agents.values()),
        tasks=created_tasks,
        process=Process.sequential # Or hierarchical if you add a manager agent
    )
    
    return crew.kickoff()

4. Guardrails and Context Management

Running multi-agent systems purely on local hardware introduces specific boundaries you must account for:

  • Context Window Constraints: Local open-source models usually default to a 4k or 8k context window unless explicitly configured otherwise. When multiple agents chat and pass task history back and forth, the window fills up fast. You must use frameworks that offer automated history pruning or set respect_context_window=True.

  • Structured Output Enforcement: If the Orchestrator outputs raw text instead of valid JSON when defining the team, your Python script will throw a parsing exception. Enforce JSON output modes or use Pydantic validation layers explicitly.

  • System Compute Scaling: Unlike cloud APIs, running 3 or 4 local agents simultaneously means your CPU/GPU will face sequential or concurrent spikes. A queue system or max_iter limit (e.g., maximum 5 loops per task) is required to stop agents from getting stuck in infinite reasoning loops that exhaust local hardware.

Would you like to explore how to integrate specific local tools—like web scrapers or file editors—into these dynamically generated agent profiles?


Add the requirement for using tools

To enable the dynamic agent team to interact with the real world (e.g., search the web, read files, scrape sites, or execute code), the system needs a Tool Registry Mapping Layer.

Because local LLMs cannot spontaneously import Python functions, the Orchestrator must be restricted to a predetermined "menu" of available tools, and the backend must map those text selections to live tool instances.

1. Updated System Architecture: Tool Binding

Your dynamic pipeline now requires three components for tool handling:

  • A Pre-defined Tool Registry: A Python dictionary mapping string identifiers (e.g., "web_search") to actual executable tool objects.

  • Tool Inclusion in the Schema: The Pydantic model must be updated so the Orchestrator LLM can choose which tools to grant to each agent.

  • Local Tool-Calling LLM Support: The target local LLM must support Native Function Calling (like llama3.1, mistral, or qwen2.5).

2. Technical Code Blueprint (With Tools)

Below is the implementation required to expose tools to your Orchestrator and dynamically bind them to the created agents at runtime.

Step A: The Tool Registry & Updated Pydantic Schema

First, instantiate your actual tool objects and update the Pydantic blueprints to allow the Orchestrator to assign tools from an explicit whitelist.

from pydantic import BaseModel, Field
from typing import List, Literal
from crewai import LLM
from crewai_tools import SerperDevTool, ScrapeWebsiteTool, FileWriterTool

# 1. Instantiate concrete tools available on the host machine
AVAILABLE_TOOLS = {
    "web_search": SerperDevTool(),
    "web_scracing": ScrapeWebsiteTool(),
    "file_writer": FileWriterTool()
}

# 2. Extract the literal keys for the Pydantic schema
# This restricts the LLM to ONLY picking tools that actually exist in your code
ToolNames = Literal["web_search", "web_scracing", "file_writer"]

class AgentBlueprint(BaseModel):
    role: str = Field(description="The specific role of the agent.")
    goal: str = Field(description="What the agent aims to achieve.")
    backstory: str = Field(description="The persona and professional experience.")
    # The Orchestrator can choose 0, 1, or multiple tools for this agent
    assigned_tools: List[ToolNames] = Field(
        default=[], 
        description="The tools this agent requires to fulfill its specific goal."
    )

class TaskBlueprint(BaseModel):
    description: str = Field(description="Detailed instructions of what the agent must do.")
    expected_output: str = Field(description="Clear explanation of the final asset.")
    assigned_agent_role: str = Field(description="The role of the agent who should execute this.")

class TeamBlueprint(BaseModel):
    agents: List[AgentBlueprint]
    tasks: List[TaskBlueprint]

Step B: The Dynamic Tool Injection Loop

During the runtime construction loop, the system must cross-reference the text list generated by the Orchestrator against the AVAILABLE_TOOLS registry map.

from crewai import Agent, Task, Crew

def run_dynamic_team_with_tools(user_goal: str):
    # Inject the available tools list into the system prompt so the LLM knows its options
    tool_options_string = ", ".join(AVAILABLE_TOOLS.keys())
    
    # 1. Ask Orchestrator to generate the structure
    team_structure = orchestrator_llm.generate_structure(
        prompt=f"Create a team blueprint for: {user_goal}. Available tools to assign: [{tool_options_string}]",
        response_model=TeamBlueprint
    )
    
    # 2. Dynamically instantiate Agents and map their tools
    created_agents = {}
    for a in team_structure.agents:
        
        # Look up the real tool objects using the string keys provided by the LLM
        real_tools = [AVAILABLE_TOOLS[tool_name] for tool_name in a.assigned_tools if tool_name in AVAILABLE_TOOLS]
        
        created_agents[a.role] = Agent(
            role=a.role,
            goal=a.goal,
            backstory=a.backstory,
            tools=real_tools, # Injecting the concrete tools here
            llm=ollama_llm,
            verbose=True
        )
        
    # 3. Instantiate Tasks
    created_tasks = []
    for t in team_structure.tasks:
        created_tasks.append(
            Task(
                description=t.description,
                expected_output=t.expected_output,
                agent=created_agents[t.assigned_agent_role]
            )
        )
        
    # 4. Assemble and execute
    crew = Crew(
        agents=list(created_agents.values()),
        tasks=created_tasks
    )
    
    return crew.kickoff()

3. Tool-Specific Local Guardrails

Giving local LLMs tools requires strict structural boundaries to prevent them from crashing or locking up your system:

  • Function-Calling Model Requirements: Ensure you pass a function_calling_llm parameter to the Crew or Agent if your main reasoning model struggles with tool syntax. Ollama models like llama3.1:8b handle basic tools well, but smaller models (like phi3) will often fail to format tool arguments correctly and trigger infinite loops.

  • Maximum Tool Iterations (max_iter): A local agent might get stuck trying to use a tool repeatedly if it receives an unexpected error (e.g., a website blocking a scraper). You must set max_iter=5 or max_rpm on the Agent or Crew configuration to force the agent to give up and move on if a tool stalls.

  • Argument Validation Guardrails: Local models occasionally hallucinate arguments for tools (e.g., passing a poorly formatted dictionary instead of a single string to a search tool). Custom tools should always wrap their internal logic in try/except blocks that return a clean string error back to the agent (e.g., "Error: Invalid URL format. Please try again with a valid string URL.") rather than letting the Python application crash.



Generate a set of application requirements that can be input to an AI-Assisted code generator

This structured Product Requirement Document (PRD) is optimized to be pasted directly into an AI-Assisted code generator (such as Cursor, Windsurf, or GitHub Copilot) to build your dynamic Python multi-agent system.

System Prompt & Specification: Dynamic Local Multi-Agent Blueprint System

Project Overview

Build a Python 3.11+ backend application that dynamically generates, configures, and executes custom teams of AI agents using local Ollama LLMs via the CrewAI framework. The application must accept a natural language goal from a user, pass it to an Orchestrator model to design the team, map whitelisted tools, and execute the workflow sequentially.

Technical Stack & Constraints

  • Language: Python $\ge$ 3.10 and < 3.14

  • Agent Framework: crewai (Latest version)

  • LLM Engine: Local Ollama API running on http://localhost:11434

  • Target Models:

    • Orchestration/Structuring: ollama/llama3.1:8b (or high-capability alternative)

    • Agent Reasoning: ollama/llama3.1:8b (Must support native function calling)

  • Data Validation: pydantic v2 for structured output schema enforcement.

Detailed Functional Requirements

1. The Whitelisted Tool Registry

Create a centralized dictionary mapping string identifiers to concrete CrewAI tool instances.

# Permitted Tools Matrix
"web_search"    -> SerperDevTool()
"web_scraping"  -> ScrapeWebsiteTool()
"file_writer"   -> FileWriterTool()

2. Strict Pydantic Schema Specification

Define schemas that enforce structured JSON responses from the Orchestrator LLM:

  • AgentBlueprint:

    • role (string, unique identifier)

    • goal (string)

    • backstory (string)

    • assigned_tools (List of Literal strings: "web_search", "web_scraping", "file_writer")

  • TaskBlueprint:

    • description (string)

    • expected_output (string)

    • assigned_agent_role (string, must match an agent's role)

  • TeamBlueprint:

    • agents (List of AgentBlueprint)

    • tasks (List of TaskBlueprint)

3. Execution Pipeline Logic

Implement a main entry function run_dynamic_team(user_goal: str) -> str that executes these phases sequentially:

Phase 1: Team Architecture Generation

  • Pass the user_goal along with a whitelisted string array of available tools to the Orchestrator LLM.

  • Enforce structured extraction matching the TeamBlueprint schema. Throw a parsing exception if the output fails Pydantic validation.

Phase 2: Dynamic Crew Assembly

  • Iterate through the generated agents list.

  • Map the text strings in assigned_tools to the concrete tool objects inside the Tool Registry.

  • Instantiate crewai.Agent objects injecting the local ollama_llm.

  • Iterate through the tasks list, instantiating crewai.Task objects linked to their corresponding generated Agent object.

Phase 3: Assembly & Kickoff

  • Instantiate a crewai.Crew passing the generated agents and tasks.

  • Set the process parameter to Process.sequential.

  • Execute .kickoff() and return the final string result.

Non-Functional Guardrails & Error Handling

  • Infinite Loop Mitigation: Force max_iter=5 on all dynamically generated Agents to prevent local hardware exhaustion if an agent gets stuck in a reasoning loop.

  • Context Window Protection: Explicitly handle context limitations by appending a safety flag to the LLM configurations to prevent runtime token overflow crashes during multi-turn agent execution.

  • Graceful Tool Failure: Custom tools or mapped tools must execute within a try/except block. If a tool fails (e.g., HTTP 403 error during web scraping), it must return the error string back to the agent as text context rather than crashing the core Python process.

  • Missing Agent Reference Catching: Include a pre-flight validation check before launching the Crew: if a Task specifies an assigned_agent_role that does not exist in the generated Agents list, raise a standard ValueError explicitly detailing the missing dependency.

Output Verification Target

The final script must run cleanly from the command line:

python main.py --goal "Research the top 3 machine learning trends in 2026, compile a summary file, and save it locally."

It should log the dynamic creation of the agents, the tools assigned to them, and output the final file without throwing schema alignment or connection timeout exceptions.


From <>  Google Gemini (3.5 Flash)

Comments

Popular posts from this blog

#4297 ISS Astronaut Unable to Speak

#4054 AI Agents in AI Studio