Ga naar hoofdinhoud

Agent-swarm-tutorial: AI-agents coördineren met CrewAI

Bouw een CrewAI agent-swarm met Gemini 3.5 Flash, Olostep live websearch en hiërarchische taakdelegatie voor een multi-agent onderzoeks- en schrijfworkflow.
Bijgewerkt 9 jun 2026  · 11 min lezen

Vraag je één enkel model om in één keer een onderwerp te onderzoeken, een artikel te schrijven, het te reviewen en de laatste versie te polijsten, dan krijg je meestal iets dat op alle vier de punten middelmatig is. Het model heeft op geen enkel moment een duidelijke rol, dus het probeert alles tegelijk te doen en doet zelden iets echt goed. Dat werk opsplitsen over gespecialiseerde agents levert vaak een beter resultaat op, omdat elke agent zich kan concentreren op zijn eigen deel.

In deze gids bouwen we een agent-swarm die precies dat doet. We gebruiken CrewAI om de agents te coördineren en Gemini 3.5 Flash voor hun redeneren en schrijven. De swarm heeft vier leden: een Researcher om actuele informatie te verzamelen, een Writer voor de eerste versie, een Reviewer om duidelijkheid en juistheid te verbeteren, en een Manager om de workflow te coördineren. 

We geven de Researcher ook live webtoegang via Olostep, zodat die verse bronnen kan binnenhalen in plaats van alleen te vertrouwen op de interne kennis van het model. Aan het eind heb je een werkende hiërarchische swarm die een onderwerp aanneemt en een publicatieklaar artikel oplevert — en een helder beeld van wanneer deze aanpak de kosten waard is en wanneer niet.

Wat is een agent-swarm?

Een agent-swarm is een groep AI-agents die samenwerken om een taak te voltooien. In plaats van één model te vragen om alles zelf te onderzoeken, te schrijven, te reviewen en af te ronden, verdeelt een agent-swarm het werk over meerdere gespecialiseerde agents. Elke agent heeft een duidelijke rol, en het systeem coördineert ze om een sterker eindresultaat te produceren.

Het voordeel is specialisatie. Een onderzoeksgerichte agent kan zich toeleggen op het vinden en verifiëren van bronnen, een schrijvende agent kan focussen op structuur en helderheid, en een reviewer kan de versie toetsen aan het oorspronkelijke onderzoek zonder afgeleid te worden door de tekst die hij net heeft geproduceerd. 

Een coördinerende agent verbindt de stappen en beslist wat er daarna gebeurt. In de swarm die we bouwen, komen die rollen rechtstreeks overeen met de Researcher, Writer, Reviewer en Manager.

Architectuur van onze CrewAI agent-swarm

Dit is niet gratis. Meer agents betekent meer model-calls, meer tijd en meer punten waar de workflow kan stuklopen; een afweging waar we aan het einde op terugkomen, zodra je hebt gezien wat het in de praktijk kost.

Wat is CrewAI?

CrewAI is een open-source framework voor het bouwen van multi-agent-systemen. Het biedt een duidelijke manier om agents te definiëren, ze taken toe te wijzen en de coördinatievorm te kiezen, zodat je je kunt richten op de rollen en de workflow in plaats van op de onderlinge koppeling.

Drie concepten doen het meeste werk. 

  • Agents zijn de individuele werkers, elk gedefinieerd door een rol, een doel en een achtergrondverhaal dat hun gedrag stuurt. 
  • Taken beschrijven het werk dat moet worden gedaan en de output die elke taak moet opleveren. 
  • Een crew brengt agents en taken samen en voert ze uit onder een gekozen proces

Dit proces kan sequentieel zijn, waarbij taken in vaste volgorde lopen, of hiërarchisch, waarbij een manager-agent werk delegeert en de output valideert. We gebruiken hier het hiërarchische proces, met de Manager voor de delegatie.

CrewAI regelt ook modeltoegang via LiteLLM, een open-sourcebibliotheek die één uniforme interface biedt voor veel providers. Daarmee kunnen we één Gemini 3.5 Flash-model definiëren en herbruiken voor alle vier de agents, die we hieronder instellen.

Een agent-swarm bouwen met CrewAI en Gemini 3.5 Flash

Laten we beginnen met de setup.

1. Vereisten

Zorg ervoor dat je het volgende hebt voordat je begint:

  • Python 3.11 of later geïnstalleerd
  • Jupyter Notebook of JupyterLab geïnstalleerd
  • Basiskennis van Python en notebooks
  • Een Google AI Studio-account
  • Facturatie ingeschakeld, of tegoeden toegevoegd aan je Google-account voor Gemini-gebruik
  • Een gratis Olostep-account

2. Installeer dependencies

Start Jupyter Notebook of JupyterLab en open een notebook met de nieuwste Python-kernel die in je omgeving beschikbaar is. Voer vervolgens de volgende cel uit om de vereiste pakketten te installeren.

%pip install --quiet -U \
    crewai \
    crewai-tools \
    google-genai \
    litellm \
    olostep \
    nest-asyncio

Voer na de installatie de volgende cel uit om de geïnstalleerde pakketversies te controleren. Dit helpt te bevestigen dat alles correct is geïnstalleerd.

import importlib.metadata as md

for pkg in [
    "crewai",
    "crewai-tools",
    "google-genai",
    "litellm",
    "olostep",
    "nest-asyncio",
]:
    print(f"{pkg:>16}  {md.version(pkg)}")

Je zou output moeten zien die hierop lijkt:

         crewai  1.14.6
    crewai-tools  1.14.6
      google-genai  2.8.0
          litellm  1.87.1
          olostep  1.1.0
    nest-asyncio  1.6.0

3. Stel omgevingsvariabelen in

Je hebt twee API-sleutels nodig voor dit project. 

Maak eerst een Gemini API-sleutel aan in Google AI Studio. Open Google AI Studio, ga naar de sectie API key en maak een nieuwe sleutel voor je project. Gemini biedt een gratis laag, maar met beperkt gebruik en rate-limits. Om Gemini betrouwbaarder te testen en draaien, koppel je je Google-facturatieaccount of voeg je tegoeden toe aan je Google-account zodat gebruik kan worden gefactureerd wanneer je de limieten van de gratis laag overschrijdt.

Maak vervolgens een Olostep API-sleutel aan. Meld je aan bij Olostep, open het Olostep-dashboard en genereer een API-sleutel via de API keys-pagina. We gebruiken deze sleutel om de Researcher-agent live webtoegang te geven voor zoeken en het scrapen van pagina's.

Sla beide sleutels, zodra ze klaar zijn, op als omgevingsvariabelen. Gemini voedt de CrewAI-agents, terwijl Olostep de Researcher-agent toestaat om actuele informatie van het web te verzamelen.

Nadat je beide sleutels hebt gemaakt, sla je ze op als omgevingsvariabelen voordat je het notebook draait.

PowerShell:

$env:GEMINI_API_KEY="your-gemini-key"
$env:OLOSTEP_API_KEY="your-olostep-key"

macOS/Linux:

export GEMINI_API_KEY="your-gemini-key"
export OLOSTEP_API_KEY="your-olostep-key"

Voer nu de volgende cel uit om te controleren of de Gemini API-sleutel correct is geladen.

import os

api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")

if not api_key:
    raise RuntimeError(
        "Set GEMINI_API_KEY or GOOGLE_API_KEY in your environment, "
        "then restart the notebook kernel."
    )
print(f"Gemini API key loaded")

Je zou dit moeten zien: 

Gemini API key loaded

4. Configureer Gemini 3.5 Flash via LiteLLM

In dit project gebruiken we Gemini 3.5 Flash als gedeelde LLM voor alle CrewAI-agents. Gemini 3.5 Flash is ontworpen voor snelle, agentische en codegerichte workloads. Het is nuttig voor dit project omdat onze agents over meerdere stappen moeten redeneren, instructies volgen, met tools werken en gestructureerde outputs produceren.

Gemini 3.5 Flash ondersteunt ook een groot contextvenster, lange outputs, thinking en toolgebruik, waardoor het een sterke keuze is voor agent-workflows. Omdat een agent-swarm het model meerdere keren kan aanroepen via de Researcher-, Writer-, Reviewer- en Manager-agents, helpt een Flash-model de workflow responsief te houden met toch sterke redeneer- en schrijfkwaliteit.

Als je het model wilt vergelijken met andere state-of-the-art LLM's, raad ik onze gidsen aan over Gemini 3.5 Flash vs GPT-5.5 en Gemini 3.5 Flash vs Claude Opus 4.8.

We benaderen Gemini via LiteLLM. LiteLLM is een open-sourcebibliotheek die één uniforme interface biedt voor het aanroepen van veel LLM-providers, waaronder Gemini, OpenAI, Anthropic, Bedrock, Vertex AI en andere. In deze setup gebruikt CrewAI LiteLLM onder de motorkap, zodat we de Gemini-modelnaam kunnen doorgeven in een eenvoudig provider/model-formaat.

We maken nu een gedeelde CrewAI LLM en hergebruiken die voor alle agents. Dit houdt de setup eenvoudig, omdat de Researcher, Writer, Reviewer en Manager allemaal hetzelfde Gemini-model gebruiken.

from crewai import LLM

GEMINI_MODEL = "gemini/gemini-3.5-flash"

gemini_llm = LLM(
    model=GEMINI_MODEL,
    api_key=os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY"),
    temperature=1.0,
)

print(f"LLM ready: {gemini_llm.model}")
print("Provider API: Google Gemini (via LiteLLM)")

Je zou output moeten zien die hierop lijkt:

LLM ready: gemini-3.5-flash
Provider API: Google Gemini (via LiteLLM)

Dit bevestigt dat CrewAI nu toegang heeft tot Gemini via LiteLLM. In de volgende stappen geven we dit gedeelde gemini_llm-object door aan elke agent.

5. Voeg live webtoegang toe

De Researcher-agent heeft toegang nodig tot actuele informatie. Hiervoor maken we een aangepaste Olostep-zoektool en geven die later aan de Researcher-agent.

Deze tool kan in twee modi werken. Hij kan alleen zoekresultaat-samenvattingen teruggeven, wat sneller is, of de resultatenpagina's scrapen en paginacontent in markdown teruggeven. We voegen ook een klein zoekbudget toe zodat de agent de webtool niet te vaak blijft aanroepen.

from pydantic import Field, PrivateAttr
from crewai.tools import BaseTool

try:
    from olostep import Olostep, Olostep_BaseError
except ImportError:
    raise ImportError(
        "The 'olostep' package is not installed. Run %pip install -U olostep."
    )

Laad eerst de Olostep API-sleutel uit de omgeving.

olostep_api_key = os.getenv("OLOSTEP_API_KEY")

if not olostep_api_key or olostep_api_key == "your-olostep-api-key-here":
    print(
        "The Olostep tool will fail at call time unless OLOSTEP_API_KEY "
        "is set in the environment."
    )
else:
    print("Olostep API key loaded.")

_olostep_client = Olostep(api_key=olostep_api_key) if olostep_api_key else None

Maak nu de aangepaste CrewAI-tool.

class OlostepSearchTool(BaseTool):
    """Search the web with a strict research-call budget."""

    name: str = "olostep_web_search"
    description: str = (
        "Search the live web. Set scrape=false for fast discovery and "
        "scrape=true for full-page evidence. You have at most 3 discovery "
        "searches without scraping and 6 external search calls total. After "
        "3 discovery searches, use scrape=true on the strongest query or "
        "domain. Each call returns at most 3 results. Inputs: query, scrape, "
        "limit, and optional include_domains."
    )

    default_limit: int = Field(default=3, ge=1, le=3)
    max_chars_per_page: int = Field(default=4000, ge=500, le=12000)

    _total_calls: int = PrivateAttr(default=0)
    _discovery_calls: int = PrivateAttr(default=0)
    _call_history: list[dict] = PrivateAttr(default_factory=list)

    def _run(
        self,
        query: str,
        scrape: bool = False,
        limit: int | None = None,
        include_domains: list[str] | None = None,
    ) -> str:
        if _olostep_client is None:
            return (
                "OLOSTEP_API_KEY is not set. Set it in the environment "
                "and restart the kernel."
            )

        if self._total_calls >= 6:
            return (
                "Research search budget exhausted: 6 external calls have "
                "already been used. Stop searching and complete the task "
                "with the collected sources."
            )

        if not scrape and self._discovery_calls >= 3:
            return (
                "Discovery-search limit reached. Do not run another "
                "scrape=False search. Use scrape=True on the strongest query "
                "or selected domains, or finish with the sources already found."
            )

        clean_query = query.strip()
        if not clean_query:
            return "Search query cannot be empty."

        result_limit = max(1, min(limit or self.default_limit, 3))
        kwargs = {"query": clean_query, "limit": result_limit}

        if scrape:
            kwargs["scrape_options"] = {
                "formats": ["markdown"],
                "timeout": 25,
            }

        if include_domains:
            kwargs["include_domains"] = include_domains

        self._total_calls += 1
        if not scrape:
            self._discovery_calls += 1

        call_record = {
            "number": self._total_calls,
            "query": clean_query,
            "scrape": scrape,
            "limit": result_limit,
            "domains": include_domains or [],
            "status": "started",
            "results": 0,
        }
        self._call_history.append(call_record)

        try:
            search = _olostep_client.searches.create(**kwargs)
        except Olostep_BaseError as error:
            call_record["status"] = "error"
            call_record["error"] = f"{type(error).__name__}: {error}"
            return (
                f"Olostep search error: {type(error).__name__}: {error}\n"
                f"Budget used: {self._total_calls}/6 total calls; "
                f"{self._discovery_calls}/3 discovery calls."
            )

        if not search.links:
            call_record["status"] = "no_results"
            return (
                f"No results found for query: {clean_query!r}\n"
                f"Budget used: {self._total_calls}/6 total calls; "
                f"{self._discovery_calls}/3 discovery calls."
            )

        call_record["status"] = "success"
        call_record["results"] = len(search.links)

        chunks = [
            f"## Web results for: {clean_query!r}",
            f"Page scraping: {'enabled' if scrape else 'disabled'}",
            (
                f"Budget used: {self._total_calls}/6 total calls; "
                f"{self._discovery_calls}/3 discovery calls."
            ),
        ]

        for index, link in enumerate(search.links, 1):
            url = link.get("url", "")
            title = link.get("title") or url or "Untitled result"
            description = link.get("description") or "No description provided."

            chunks.append(
                f"### {index}. {title}\n"
                f"URL: {url}\n"
                f"Summary: {description}"
            )

            markdown = link.get("markdown_content")
            if scrape and markdown:
                body = markdown.strip()
                if len(body) > self.max_chars_per_page:
                    body = body[: self.max_chars_per_page] + "\n...[truncated]"
                chunks.append(f"Page content:\n{body}")

        return "\n\n".join(chunks)

Maak tot slot een instantie van de tool.

olostep_search_tool = OlostepSearchTool()
print(f"Tool ready: {olostep_search_tool.name}")

Je zou output moeten zien die hierop lijkt:

Olostep API key loaded.
Tool ready: olostep_web_search

Dit bevestigt dat de Olostep-webzoektool klaar is. Later koppelen we deze tool aan de Researcher-agent, zodat die actuele informatie van het web kan verzamelen.

6. Maak de agents

We maken nu de agents voor onze swarm. We definiëren drie werkende agents en één manager-agent. De werkende agents doen het hoofdbestanddeel, terwijl de manager de workflow coördineert.

De Researcher-agent gebruikt de Olostep-tool om actuele informatie te vinden. De Writer-agent zet het onderzoek om in een concept. De Reviewer-agent verbetert het concept. De Manager-agent beslist hoe het werk in de hiërarchische crew wordt gedelegeerd.

Maak de werkende agents

We beginnen met de drie werkende agents.

from crewai import Agent

researcher = Agent(
    role="Senior Research Analyst",
    goal=(
        "Find accurate, current, and well-sourced information about {topic}. "
        "Produce concrete, verifiable points for the writer."
    ),
    backstory=(
        "You are a meticulous research analyst. You decide whether each web "
        "search needs page scraping. Use scrape=False when titles, URLs, and "
        "summaries are enough. Use scrape=True when you need full-page evidence "
        "to verify a claim or understand a source in detail. Cite source URLs."
    ),
    llm=gemini_llm,
    tools=[olostep_search_tool],
    verbose=True,
    allow_delegation=False,
)

Maak vervolgens de Writer-agent.

writer = Agent(
    role="Blog Post Writer",
    goal=(
        "Turn the research into a complete, publication-ready educational "
        "article on {topic}. Include a strong title, an unlabeled italic "
        "summary, TL;DR, detailed body sections, conclusion, and FAQs. Add a "
        "table only when it makes a comparison or decision easier to understand."
    ),
    backstory=(
        "You are a seasoned technology educator and writer. You create "
        "practical, approachable articles similar in structure to high-quality "
        "DataCamp content, without copying its wording or branding. You use "
        "clear headings, short paragraphs, concrete examples, and sourced facts."
    ),
    llm=gemini_llm,
    verbose=True,
    allow_delegation=False,
)

Maak nu de Reviewer-agent.

reviewer = Agent(
    role="Senior Editor",
    goal=(
        "Review the draft for factual accuracy, clarity, structure, and "
        "completeness. Ensure it follows the required article order and return "
        "a polished, publication-ready version."
    ),
    backstory=(
        "You are a detail-oriented senior editor for an educational technology "
        "publication. You verify claims, improve flow, remove repetition, and "
        "ensure the title is followed by an unlabeled italic summary and TL;DR. "
        "You keep a table only when it adds real value, remove any Key Takeaways "
        "section, and ensure Conclusion appears immediately before FAQs."
    ),
    llm=gemini_llm,
    verbose=True,
    allow_delegation=False,
)

Maak de manager-agent

Maak tot slot de Manager-agent.

manager = Agent(
    role="Content Coordinator",
    goal=(
        "Coordinate research, writing, and review for {topic}. Delegate each "
        "task to the correct specialist and ensure the reviewed article is the "
        "final result."
    ),
    backstory=(
        "You are an experienced editorial lead. You keep the workflow simple: "
        "research first, writing second, and editorial review last."
    ),
    llm=gemini_llm,
    verbose=True,
    allow_delegation=True,
)

De manager wordt apart geconfigureerd wanneer we de hiërarchische crew bouwen. Daarom is die nog niet toegevoegd aan de lijst met werkende agents.

7. Definieer taken

We definiëren nu de taken voor de agent-swarm. Deze taken worden niet direct aan de werkende agents toegewezen. In plaats daarvan beslist de Manager-agent welke werker elke taak moet uitvoeren.

In deze workflow is de eerste taak onderzoek, de tweede schrijven en de derde review. Elke taak bevat ook een verwachte output, zodat de agents precies weten wat ze moeten opleveren.

from crewai import Task

research_task = Task(
    description=(
        "Delegate to the Senior Research Analyst. Research '{topic}' using at "
        "most 6 web-tool calls. Use no more than 3 calls with scrape=False, "
        "then use scrape=True only when detailed evidence is needed. Collect "
        "5-7 useful findings, source URLs, and common reader questions."
    ),
    expected_output=(
        "Clear markdown research notes with 5-7 sourced findings and 3-5 "
        "potential FAQ questions."
    ),
)

Maak vervolgens de schrijftaak. Deze taak gebruikt de onderzoekstaak als context, zodat de Writer het artikel kan opbouwen op basis van het verzamelde onderzoek.

write_task = Task(
    description=(
        "Delegate to the Blog Post Writer. Write one complete educational "
        "markdown article on '{topic}', approximately 1,000-1,500 words. Start "
        "with one H1 title and an unlabeled italic summary. Then include TL;DR, "
        "an introduction, useful body sections, an optional table only when it "
        "improves understanding, a Conclusion, and FAQs. Use source links."
    ),
    expected_output=(
        "One continuous publication-ready markdown article with title, italic "
        "summary, TL;DR, body, Conclusion, and 3-5 FAQs."
    ),
    context=[research_task],
)

Maak nu de reviewtaak. Deze taak gebruikt zowel de onderzoeks- als de schrijftaak als context, zodat de Reviewer het artikel kan toetsen aan het oorspronkelijke onderzoek.

review_task = Task(
    description=(
        "Delegate to the Senior Editor. Review the article for accuracy, "
        "clarity, structure, and source support. Return only the corrected full "
        "article. Keep the same continuous article format and ensure FAQs are "
        "the final section."
    ),
    expected_output=(
        "Only the final reviewed markdown article, beginning with its H1 title "
        "and ending with the final FAQ answer."
    ),
    context=[research_task, write_task],
)

Voeg tot slot alle drie de taken toe aan een lijst.

tasks = [research_task, write_task, review_task]

print(f"Defined {len(tasks)} manager-delegated tasks.")

Je zou dit moeten zien:

Defined 3 manager-delegated tasks.

8. Bouw de workflow

We koppelen nu de agents en taken tot één CrewAI-workflow. We gebruiken een hiërarchisch proces waarin de Manager-agent de werkende agents coördineert.

In deze setup worden de Researcher, Writer en Reviewer toegevoegd als werkers. De Manager wordt apart doorgegeven via manager_agent, omdat die verantwoordelijk is voor delegatie en coördinatie.

from crewai import Crew, Process

crew = Crew(
    agents=[researcher, writer, reviewer],
    tasks=tasks,
    manager_agent=manager,
    process=Process.hierarchical,
    verbose=True,
    memory=False,
)

Print nu de crewdetails om te bevestigen dat de workflow correct is samengesteld.

print("Hierarchical crew assembled.")
print(f"  Workers : {[a.role for a in crew.agents]}")
print(f"  Manager : {crew.manager_agent.role}")
print(f"  Tasks   : {len(crew.tasks)}")
print(f"  Process : {crew.process}")

Je zou output moeten zien die hierop lijkt:

Hierarchical crew assembled.
  Workers : ['Senior Research Analyst', 'Blog Post Writer', 'Senior Editor']
  Manager : Content Coordinator
  Tasks   : 3
  Process : Process.hierarchical

Dit bevestigt dat de hiërarchische agent-swarm klaar is. In de volgende stap draaien we de crew op een onderwerp en genereren we de uiteindelijke response.

9. Draai de agent-swarm

Nu kunnen we de agent-swarm draaien. We geven een onderwerp mee en starten de workflow met kickoff_async().

Jupyter draait al een eventloop op de achtergrond. Daarom passen we eerst nest_asyncio toe, zodat de asynchrone CrewAI-workflow binnen het notebook kan draaien.

try:
    import nest_asyncio

    nest_asyncio.apply()

    print("nest_asyncio applied: CrewAI can now run inside this kernel.")

except ModuleNotFoundError:
    print("nest_asyncio not installed. Run: pip install nest-asyncio")

Je zou dit moeten zien:

nest_asyncio applied: CrewAI can now run inside this kernel.

Definieer vervolgens een onderwerp en maak een helperfunctie om de crew te draaien.

from datetime import datetime

topic = "Learning Adaptive Thresholds for LLM Tool Use: When to Rely on Memory and When to Call a Tool"

async def run_crew(topic: str):
    """Run the CrewAI crew asynchronously."""
    print(f"Starting crew at {datetime.now().isoformat(timespec='seconds')}")
    print(f"Topic: {topic!r}\n")

    result = await crew.kickoff_async(inputs={"topic": topic})

    print(f"\nFinished at {datetime.now().isoformat(timespec='seconds')}")
    print(f"Result type: {type(result).__name__}")
    return result

result = await run_crew(topic)

Wanneer de workflow start, geeft CrewAI de taak eerst aan de Manager-agent. De Manager delegeert vervolgens het onderzoek aan de Senior Research Analyst. De Researcher gebruikt de olostep_web_search-tool om het web te doorzoeken naar informatie over adaptieve drempels, LLM-toolgebruik, geheugen en beslissingen om tools aan te roepen.

Crew AI Agent Swarm Logs

In de log gebruikt de Researcher zowel zoekaanvragen zonder scraping als met scraping. Het zoekbudget wordt volledig benut: 6 van de 6 webcalls en 3 van de 3 discovery-calls. Eén extra zoekaanvraag zonder scraping wordt geblokkeerd omdat de discovery-limiet al is bereikt. Dit laat zien dat de budgetregels in onze aangepaste Olostep-tool correct werken.

Crew AI Agent Swarm Logs bij het uitvoeren van de agent en vervolgens de webtool.

Na de onderzoeksfase gaat de Manager door met het delegeren van de schrijf- en reviewstappen. De agents produceren onderzoeksnotities, maken het artikel en polijsten vervolgens de uiteindelijke response. De run voltooit succesvol en levert een CrewOutput-object op.

Je zou output moeten zien die hierop lijkt:

Starting crew at 2026-06-05T13:54:07
Topic: 'Learning Adaptive Thresholds for LLM Tool Use: When to Rely on Memory and When to Call a Tool'

Crew Execution Started
Task Started
Agent: Content Coordinator
Agent: Senior Research Analyst
Tool: olostep_web_search
Budget used: 6/6 total calls; 3/3 discovery calls

Finished at 2026-06-05T13:59:29
Result type: CrewOutput

Dit betekent dat de volledige swarm succesvol is gedraaid. De Manager coördineerde de workflow, de Researcher verzamelde actuele informatie, de Writer maakte het concept en de Reviewer verbeterde de uiteindelijke output.

10. Bekijk het resultaat

Nadat de swarm klaar is, kunnen we het uiteindelijke artikel tonen dat door de crew is gegenereerd. De waarde result.raw bevat de finale response van de workflow.

from IPython.display import Markdown, display

raw = result.raw

if "Blog Post" in raw:
    raw = raw.split("Blog Post", 1)[1].strip()

display(Markdown(raw))

Dit rendert de uiteindelijke output als opgemaakte markdown in het notebook. 

In de meeste gevallen is de gegenereerde blog al goed gestructureerd, met meerdere koppen, duidelijke secties, diagrammen of visuele uitleg waar passend, en een sterke conclusie. 

De combinatie van onderzoek, schrijven en redactionele review helpt om content te produceren die publicatieklaar is. Na het doornemen van de output zou ik persoonlijk groen licht geven voor publicatie.

Gegenereerde ~1500-woordenblog met de Crew AI Agent Swarm

Vervolgens kunnen we een execution trace printen. Dit helpt te begrijpen hoe de swarm heeft gewerkt, welke agents meededen, hoeveel webcalls er zijn gebruikt en hoe elke taak is verwerkt.

from collections import Counter

def role_name(value):
    """Return a readable role/name for CrewAI agent values."""
    if value is None:
        return "Not reported"
    if isinstance(value, str):
        return value
    return getattr(value, "role", None) or getattr(value, "name", None) or str(value)

print("=" * 70)
print("SWARM EXECUTION TRACE")
print("=" * 70)

# Hierarchical crew structure
print("\nCOORDINATION")
print(f"Process : {crew.process}")
print(f"Manager : {role_name(crew.manager_agent)}")
print(f"Workers : {', '.join(role_name(agent) for agent in crew.agents)}")
print(
    "Flow    : Manager receives each task, delegates specialist work, "
    "validates the response, and passes approved context to the next task."
)

Now print the web-tool usage recorded by the custom Olostep tool.
history = list(getattr(olostep_search_tool, "_call_history", []))
discovery_calls = sum(not item["scrape"] for item in history)
scrape_calls = sum(item["scrape"] for item in history)
successful_calls = sum(item["status"] == "success" for item in history)

print("\nWEB TOOL USAGE")
print(f"Total external calls : {len(history)}/6")
print(f"Without scraping     : {discovery_calls}/3")
print(f"With scraping        : {scrape_calls}")
print(f"Successful calls     : {successful_calls}")

if history:
    for item in history:
        mode = "scrape" if item["scrape"] else "search only"
        domains = ", ".join(item["domains"]) if item["domains"] else "all domains"
        print(
            f"  {item['number']}. {mode}; status={item['status']}; "
            f"results={item['results']}; scope={domains}"
        )
        print(f"     Query: {item['query']}")
else:
    print("  No Olostep calls were recorded.")

Finally, print the task-by-task trace.
print("\nTASK-BY-TASK TRACE")
agent_activity = Counter()

for index, task_out in enumerate(result.tasks_output, start=1):
    task = crew.tasks[index - 1] if index <= len(crew.tasks) else None
    reported_agent = role_name(getattr(task_out, "agent", None))
    processed_by = sorted(getattr(task, "processed_by_agents", set()) or [])
    participants = processed_by or [reported_agent]

    for participant in participants:
        agent_activity[role_name(participant)] += 1

    delegations = getattr(task, "delegations", 0) if task else 0
    used_tools = getattr(task, "used_tools", 0) if task else 0
    tool_errors = getattr(task, "tools_errors", 0) if task else 0
    start_time = getattr(task, "start_time", None) if task else None
    end_time = getattr(task, "end_time", None) if task else None
    duration = end_time - start_time if start_time and end_time else None

    print(f"\n--- Task {index} ---")
    print(f"Reported owner : {reported_agent}")
    print(f"Processed by   : {', '.join(map(role_name, participants))}")
    print(f"Delegations    : {delegations}")
    print(f"Tool uses      : {used_tools}")
    print(f"Tool errors    : {tool_errors}")
    if duration is not None:
        print(f"Duration       : {duration}")

    preview = getattr(task_out, "raw", "").strip().replace("\n", " ")
    print(f"Output preview : {preview[:300]}{'...' if len(preview) > 300 else ''}")

print("\nAGENT ACTIVITY")
for agent, count in agent_activity.most_common():
    print(f"{agent}: participated in {count} task(s)")

if not agent_activity:
    print("CrewAI did not expose per-agent processing metadata for this run.")

Je zou output moeten zien die hierop lijkt:

Crew AI Agent Swarm Executions Trace

Deze trace laat zien dat de hiërarchische swarm werkte zoals verwacht. De Manager coördineerde alle drie de taken, de Researcher verzorgde de onderzoeksstap, de Writer maakte het artikelconcept en de Reviewer verbeterde de uiteindelijke response.

Maar dit toont ook een belangrijke beperking: multi-agent-workflows kunnen duur worden. 

In deze run gebruikte de workflow 6 externe webcalls en meerdere LLM-calls over de Manager, Researcher, Writer en Reviewer. Eén run kan tot ongeveer $0,28 kosten, en het maken van deze gids kostte tijdens het testen ongeveer $2,78. Dat is veel voor een eenvoudig tutorialproject.

Bijna 8 runs voor Crew AI Agent Swarm Gemini 3.5 Flash-kosten

Tot slot

Agent-swarms en multi-agent-workflows zien er op papier geweldig uit. Het idee dat een Researcher, Writer, Reviewer en Manager samenwerken voelt krachtig, en in deze gids was de uiteindelijke output inderdaad goed genoeg om met kleine aanpassingen te publiceren.

Maar in de praktijk kan deze setup meer kosten, meer tijd nemen en meer faalpunten creëren. In mijn geval kost één run ongeveer $0,28 en het maken van deze gids ongeveer $2,78. Dat is veel voor een eenvoudig tutorialproject.

Voor echte toepassingen zou ik niet altijd een volledige multi-agent-swarm gebruiken. Ik geef de voorkeur aan een meer programmatische setup waarin simpele taken door code of regels worden afgehandeld, en alleen complexe taken aan agents worden overgedragen. We kunnen de kosten ook verlagen door tool-calls te beperken, minder agents te gebruiken, prompts te verkorten en een lineaire workflow te gebruiken in plaats van een hiërarchische.

Natuurlijk, als we te veel optimaliseren, is het misschien geen echte agent-swarm meer. Het lijkt dan meer op een regelgebaseerde AI-workflow. Daarom is balans het doel: gebruik agent-swarms wanneer ze echte waarde toevoegen, maar houd het simpel wanneer dat niet zo is.


Abid Ali Awan's photo
Author
Abid Ali Awan
LinkedIn
Twitter

Als gecertificeerd data scientist haal ik met passie het maximale uit de nieuwste technologie om innovatieve machinelearning-toepassingen te bouwen. Met een sterke achtergrond in spraakherkenning, data-analyse en -rapportage, MLOps, conversationele AI en NLP heb ik mijn vaardigheden aangescherpt in het ontwikkelen van intelligente systemen die echt impact maken. Naast mijn technische expertise ben ik ook een sterke communicator met een talent om complexe concepten terug te brengen tot heldere, beknopte taal. Daardoor ben ik uitgegroeid tot een veelgelezen blogger over data science, waar ik mijn inzichten en ervaringen deel met een groeiende community van data-professionals. Op dit moment richt ik me op contentcreatie en redactie, waarbij ik met large language models werk aan krachtige en aansprekende content die zowel bedrijven als individuen helpt het beste uit hun data te halen.

Onderwerpen

Leer Agentic AI met DataCamp!

Leerpad

Basisprincipes van AI-agenten

6 Hr
Ontdek hoe AI-agenten je manier van werken kunnen veranderen en waarde kunnen toevoegen aan je organisatie!
Bekijk detailsRight Arrow
Begin met de cursus
Meer zienRight Arrow