Dacă ai lucrat vreodată la un proiect mai ambițios cu o singură instanță LLM, știi exact momentul ăla în care totul se blochează. Agentul tău e bun la cercetare, dar nu prea știe să scrie rapoarte. Sau scrie excelent, dar habar n-are să valideze datele. Îi dai prea multe instrumente și începe să halucineze. Îi dai prea puțin context și ratează complet obiectivul.
Frustrează, nu?
Soluția nu e un agent mai mare sau mai „inteligent" — ci mai mulți agenți mai mici, fiecare cu un rol clar definit. Exact ca într-o echipă reală de oameni unde fiecare își cunoaște treaba.
Și aici intră în scenă CrewAI — un framework Python construit de la zero, independent de LangChain, care transformă orchestrarea agenților AI multipli dintr-un coșmar arhitectural într-o experiență aproape intuitivă. Cu peste 57.000 de stele pe GitHub și 12 milioane de execuții zilnice în producție, CrewAI a devenit rapid unul dintre cele mai adoptate framework-uri multi-agent din 2026.
În ghidul ăsta, o să construim pas cu pas un sistem multi-agent funcțional — de la instalare până la deployment cu Flows. Codul e testat, explicațiile sunt practice, și la final o să ai o bază solidă pentru propriile tale proiecte. Deci, hai să începem.
Ce este CrewAI și de ce ai nevoie de el?
CrewAI este un framework Python care îți permite să creezi echipe de agenți AI autonomi — fiecare cu un rol, un obiectiv și o poveste de fundal (backstory). Agenții ăștia colaborează pentru a rezolva sarcini complexe pe care un singur agent pur și simplu nu le-ar putea gestiona eficient.
Gândește-te la o redacție de presă: ai un cercetător care găsește informații, un editor care verifică acuratețea și un redactor care scrie articolul final. Fiecare e specialist pe domeniul lui. Nimeni nu face totul singur.
Exact așa funcționează un Crew în CrewAI.
De ce nu un singur agent cu mai multe instrumente?
E o întrebare legitimă. Sincer, am încercat și eu varianta asta și pot să-ți spun că, atunci când încarci un singur agent cu zeci de instrumente și responsabilități, apar trei probleme majore:
- Pierderea contextului — agentul uită instrucțiuni pe măsură ce conversația crește
- Halucinări — cu prea multe opțiuni, alege instrumente greșite sau inventează date (am pățit-o cu un agent de analiză care a „citat" studii inexistente)
- Lipsa specializării — un prompt generic nu va produce niciodată calitatea unui prompt specializat pe un rol anume
CrewAI rezolvă toate astea prin decompoziția sarcinilor — fiecare agent primește exact ce are nevoie, nimic mai mult. E practic principiul responsabilității unice (Single Responsibility Principle) aplicat agenților AI.
Arhitectura CrewAI: Cele patru componente esențiale
Întreg framework-ul se bazează pe patru concepte fundamentale. Fiecare mapează direct pe un echivalent din lumea reală, ceea ce face totul mai ușor de înțeles.
1. Agenți (Agents)
Un agent este o unitate autonomă cu un rol, un obiectiv și o poveste de fundal. Rolul definește ce face agentul. Obiectivul indică ce trebuie să realizeze. Iar povestea de fundal — partea mea preferată, sincer — îi dă contextul necesar pentru a lua decizii inteligente.
from crewai import Agent
cercetator = Agent(
role="Cercetător Senior",
goal="Găsește informații precise și actualizate despre subiectul primit",
backstory="""Ești un cercetător experimentat cu 15 ani de experiență
în analiza datelor și verificarea surselor. Nu accepți niciodată
informații neverificate și cauți întotdeauna surse multiple.""",
verbose=True,
allow_delegation=False
)
Observă parametrul allow_delegation — când e setat pe True, agentul poate delega sarcini către alți agenți din crew. E util pentru agenți cu rol de coordonare, dar fii atent: poate genera bucle infinite dacă nu ești precaut cu configurarea.
2. Sarcini (Tasks)
O sarcină definește ce trebuie făcut, de cine și ce output se așteaptă. Un sfat important: descrierea sarcinii trebuie să fie cât mai specifică. Agenții lucrează mult mai bine cu instrucțiuni clare decât cu cerințe vagi (la fel ca oamenii, de altfel).
from crewai import Task
sarcina_cercetare = Task(
description="""Cercetează cele mai recente tendințe în domeniul
{topic} pentru anul 2026. Concentrează-te pe:
1. Tehnologii noi apărute în ultimele 6 luni
2. Studii de caz reale din producție
3. Provocări și limitări actuale
Folosește surse verificabile și include referințe.""",
expected_output="""Un raport structurat cu:
- Rezumat executiv (3-5 propoziții)
- Lista tehnologiilor identificate cu descrieri
- Cel puțin 2 studii de caz
- Secțiune de provocări și limitări""",
agent=cercetator
)
3. Instrumente (Tools)
Instrumentele sunt funcții Python pe care agenții le pot apela pentru a interacționa cu lumea exterioară — căutări web, acces la baze de date, apeluri API, procesare de fișiere. CrewAI vine cu instrumente predefinite, dar sincer, puterea reală vine din cele personalizate:
from crewai.tools import tool
@tool("Căutare în baza de date")
def cauta_in_db(query: str) -> str:
"""Caută informații în baza de date internă a companiei.
Primește un query de căutare și returnează rezultatele relevante."""
# Implementarea reală a căutării
import sqlite3
conn = sqlite3.connect("knowledge_base.db")
cursor = conn.cursor()
cursor.execute(
"SELECT content FROM documents WHERE content LIKE ?",
(f"%{query}%",)
)
results = cursor.fetchall()
conn.close()
return "\n".join([r[0] for r in results]) if results else "Niciun rezultat găsit."
Documentația instrumentului (docstring-ul) este critică aici — CrewAI o folosește pentru a decide când și cum să apeleze instrumentul. Un docstring vag duce la utilizări complet greșite. Am învățat asta pe propria piele.
4. Crew (Echipa)
Crew-ul este orchestratorul care pune totul cap la cap — agenții, sarcinile și procesul de execuție:
from crewai import Crew, Process
echipa = Crew(
agents=[cercetator, redactor, editor],
tasks=[sarcina_cercetare, sarcina_scriere, sarcina_editare],
process=Process.sequential,
verbose=True,
memory=True
)
Parametrul process controlează ordinea de execuție. Process.sequential execută sarcinile una după alta, în ordinea definită. Process.hierarchical adaugă automat un manager care coordonează, delegă și validează — util pentru proiecte mai complexe, dar consumă mai mulți tokeni.
Instalare și configurare pas cu pas
Cerințe de sistem
CrewAI necesită Python 3.10 sau mai nou (până la 3.13). Dacă nu ai deja versiunea corectă, recomand pyenv pentru gestiunea versiunilor Python — îți va simplifica viața enorm.
# Verifică versiunea Python
python --version
# Instalează CrewAI
pip install crewai
# Sau cu toate dependențele opționale (incluzând instrumente predefinite)
pip install crewai[tools]
Configurarea cheilor API
CrewAI folosește modele LLM prin API. Implicit, se conectează la OpenAI, dar poți configura orice provider compatibil. Creează un fișier .env în directorul proiectului:
# .env
OPENAI_API_KEY=sk-your-key-here
# Sau pentru alte modele:
# ANTHROPIC_API_KEY=your-anthropic-key
# OPENAI_MODEL_NAME=gpt-4o-mini
Crearea unui proiect nou cu CLI
CrewAI vine cu un CLI care generează structura de proiect automat:
crewai create crew proiectul_meu
Comanda asta creează o structură standardizată cu fișiere YAML pentru configurarea agenților și sarcinilor. Practic, separă configurația de codul Python — o practică excelentă pentru proiecte de producție.
Proiect practic: Sistem multi-agent pentru analiză de conținut
Bun, destulă teorie. Hai să construim ceva concret — un sistem cu trei agenți care analizează un subiect, scrie un raport și verifică calitatea. E un pattern clasic pe care îl poți adapta pentru practic orice domeniu.
Definirea agenților
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool
from dotenv import load_dotenv
load_dotenv()
# Instrumentul de căutare web
search_tool = SerperDevTool()
# Agent 1: Cercetătorul
cercetator = Agent(
role="Analist de Cercetare",
goal="Efectuează cercetări aprofundate și colectează date verificabile",
backstory="""Ești un analist de cercetare meticulos cu experiență
în analiza tendințelor tehnologice. Verifici fiecare informație
din cel puțin două surse independente înainte de a o include
în rapoarte.""",
tools=[search_tool],
verbose=True,
allow_delegation=False
)
# Agent 2: Redactorul
redactor = Agent(
role="Redactor Tehnic",
goal="Transformă datele brute în conținut clar, structurat și captivant",
backstory="""Ești un redactor tehnic cu talent pentru a explica
concepte complexe în termeni accesibili. Scrii întotdeauna cu
exemple practice și structuri clare.""",
verbose=True,
allow_delegation=False
)
# Agent 3: Editorul / QA
editor = Agent(
role="Editor și Control Calitate",
goal="Verifică acuratețea, coerența și calitatea conținutului final",
backstory="""Ești un editor exigent care nu lasă nicio greșeală
să treacă. Verifici faptele, corectezi inconsistențele și te
asiguri că tonul este profesional și consistent.""",
verbose=True,
allow_delegation=True
)
Definirea sarcinilor
sarcina_cercetare = Task(
description="""Cercetează subiectul: {topic}
Cerințe:
- Identifică cele mai recente dezvoltări (2026)
- Găsește cel puțin 3 surse credibile
- Notează statistici și date concrete
- Identifică tendințele principale și predicțiile experților""",
expected_output="""Raport de cercetare cu:
1. Rezumat executiv
2. Dezvoltări cheie cu surse
3. Statistici relevante
4. Tendințe și predicții""",
agent=cercetator
)
sarcina_scriere = Task(
description="""Pe baza cercetării primite, scrie un articol complet
despre {topic}.
Cerințe:
- Introducere captivantă care explică relevanța subiectului
- Secțiuni clare cu subtitluri descriptive
- Exemple practice și studii de caz
- Concluzie cu recomandări acționabile
- Ton profesional dar accesibil
- Minimum 1500 cuvinte""",
expected_output="Articol complet, formatat și gata de publicare",
agent=redactor,
context=[sarcina_cercetare]
)
sarcina_editare = Task(
description="""Revizuiește articolul primit și verifică:
1. Acuratețea faptelor și datelor menționate
2. Coerența structurii și fluxul logic
3. Calitatea limbajului și gramatica
4. Completitudinea — lipsesc informații esențiale?
5. Tonul — este consistent și profesional?
Corectează orice problemă identificată și returnează
versiunea finală.""",
expected_output="Articol revizuit și aprobat pentru publicare",
agent=editor,
context=[sarcina_scriere]
)
Observă parametrul context — ăsta e esențial. Specifică de ce sarcini anterioare depinde sarcina curentă. Redactorul primește automat output-ul cercetătorului, iar editorul primește output-ul redactorului. Fără mecanismul ăsta, fiecare agent ar lucra complet izolat, ceea ce ar cam înfrânge scopul întregului sistem.
Asamblarea și rularea Crew-ului
# Crearea echipei
echipa_content = Crew(
agents=[cercetator, redactor, editor],
tasks=[sarcina_cercetare, sarcina_scriere, sarcina_editare],
process=Process.sequential,
verbose=True,
memory=True
)
# Rularea cu un subiect specific
rezultat = echipa_content.kickoff(
inputs={"topic": "Agenți AI autonomi în producție"}
)
print(rezultat.raw)
Când rulezi kickoff(), CrewAI execută sarcinile secvențial: cercetătorul caută informații, redactorul scrie pe baza lor, editorul revizuiește totul. Fiecare agent „gândește cu voce tare" datorită verbose=True, așa că poți urmări exact ce decide și de ce. E fascinant de urmărit, chiar și după zeci de rulări.
Instrumente personalizate: Extinderea capabilităților agenților
Instrumentele predefinite sunt utile pentru prototipare rapidă, dar puterea reală vine din instrumentele personalizate. Iată cum creezi instrumente care se conectează la API-uri externe sau baze de date proprii:
from crewai.tools import tool
import requests
@tool("Analizator de Sentiment")
def analizeaza_sentiment(text: str) -> str:
"""Analizează sentimentul unui text și returnează scorul
de sentiment (pozitiv, negativ, neutru) cu un nivel de
încredere procentual."""
# Exemplu cu un API extern
response = requests.post(
"https://api.example.com/sentiment",
json={"text": text}
)
if response.status_code == 200:
data = response.json()
return f"Sentiment: {data['label']} (încredere: {data['score']*100:.1f}%)"
return "Eroare la analiza sentimentului"
@tool("Calculator de Metrici")
def calculeaza_metrici(date: str) -> str:
"""Calculează metrici statistice de bază (medie, mediană,
deviație standard) pentru un set de date numerice separate
prin virgulă."""
import statistics
try:
numere = [float(x.strip()) for x in date.split(",")]
return f"""Metrici calculate:
- Medie: {statistics.mean(numere):.2f}
- Mediană: {statistics.median(numere):.2f}
- Deviație standard: {statistics.stdev(numere):.2f}
- Min: {min(numere):.2f}
- Max: {max(numere):.2f}"""
except ValueError:
return "Eroare: Datele trebuie să fie numere separate prin virgulă"
# Atribuirea instrumentelor unui agent
analist = Agent(
role="Analist de Date",
goal="Analizează datele și extrage insight-uri acționabile",
backstory="Ești un analist de date cu experiență în statistică aplicată.",
tools=[analizeaza_sentiment, calculeaza_metrici],
verbose=True
)
Câteva reguli de bază pentru instrumente care chiar funcționează bine: docstring-ul trebuie să descrie clar ce face instrumentul și ce parametri acceptă. Parametrii cu nume descriptive ajută agentul să decidă ce valori să transmită. Și — nu pot sublinia asta destul — întotdeauna gestionează erorile. Un instrument care aruncă excepții necaptate poate bloca întregul crew fără niciun mesaj util de eroare.
CrewAI Flows: Orchestrare de nivel enterprise
Crews sunt excelente pentru colaborare între agenți, dar ce faci când ai nevoie de control secvențial precis? Când vrei să spui: „Rulează pasul A, verifică rezultatul, apoi alege între pasul B sau C." Aici intervin Flows.
Cea mai simplă analogie: un Crew este o echipă, un Flow este planul de proiect care coordonează mai multe echipe. Diferența e subtilă dar importantă.
Structura unui Flow
from crewai.flow.flow import Flow, listen, start, router
class PipelineAnaliza(Flow):
"""Flow pentru procesarea și analiza datelor cu ramificări condiționale."""
@start()
def colecteaza_date(self):
"""Primul pas — colectarea datelor brute."""
print("Colectez date din surse externe...")
# Simulare colectare date
self.state["date_brute"] = {
"articole": 150,
"sentiment_mediu": 0.72,
"surse": ["Reuters", "Bloomberg", "TechCrunch"]
}
return self.state["date_brute"]
@listen(colecteaza_date)
def valideaza_date(self, date_primite):
"""Validează calitatea datelor colectate."""
numar_articole = date_primite["articole"]
if numar_articole < 10:
self.state["calitate"] = "insuficientă"
elif numar_articole < 50:
self.state["calitate"] = "medie"
else:
self.state["calitate"] = "bună"
return self.state["calitate"]
@router(valideaza_date)
def decide_strategie(self, calitate):
"""Routează către strategia potrivită în funcție de calitate."""
if calitate == "bună":
return "analiza_completa"
elif calitate == "medie":
return "analiza_partiala"
else:
return "recolectare"
@listen("analiza_completa")
def ruleaza_analiza_completa(self):
"""Execută analiza completă cu crew-ul de analiză."""
print("Rulez analiza completă cu toate datele...")
# Aici poți integra un Crew complet
return "Raport complet generat"
@listen("analiza_partiala")
def ruleaza_analiza_partiala(self):
"""Execută o analiză simplificată."""
print("Rulez analiza parțială...")
return "Raport parțial generat"
@listen("recolectare")
def recolecteaza(self):
"""Încearcă să colecteze mai multe date."""
print("Insuficiente date — recolectez din surse adiționale...")
return "Recolectare inițiată"
# Rularea Flow-ului
pipeline = PipelineAnaliza()
rezultat = pipeline.kickoff()
Decoratorii cheie în Flows
Flows folosesc patru decoratori principali. Fiecare controlează un aspect diferit al fluxului de execuție:
@start()— marchează metoda care pornește flow-ul. Fiecare flow are cel puțin un punct de start@listen()— declanșează metoda când o altă metodă specifică se finalizează. E practic o legătură event-driven între pași@router()— similar cu@listen, dar returnează un string care determină care ramură se execută mai departe (genial pentru workflow-uri condiționale)@persist()— salvează starea flow-ului pentru a permite reluarea în caz de eșec
Integrarea Crews în Flows
Aici devine cu adevărat interesant. Puterea reală apare când combini Crews cu Flows — Flows oferă controlul logic, Crews oferă inteligența agenților:
from crewai.flow.flow import Flow, listen, start
class WorkflowProduction(Flow):
@start()
def primeste_cerere(self):
"""Primește și validează cererea clientului."""
return {"cerere": "Analiză competitivă pentru piața SaaS"}
@listen(primeste_cerere)
def ruleaza_cercetare(self, cerere):
"""Delegă cercetarea unui Crew specializat."""
crew_cercetare = Crew(
agents=[cercetator],
tasks=[sarcina_cercetare],
process=Process.sequential
)
rezultat = crew_cercetare.kickoff(
inputs={"topic": cerere["cerere"]}
)
return rezultat.raw
@listen(ruleaza_cercetare)
def ruleaza_redactare(self, date_cercetare):
"""Delegă redactarea unui alt Crew."""
crew_redactare = Crew(
agents=[redactor, editor],
tasks=[sarcina_scriere, sarcina_editare],
process=Process.sequential
)
rezultat = crew_redactare.kickoff(
inputs={"topic": date_cercetare}
)
return rezultat.raw
Separarea asta între orchestrare (Flow) și execuție (Crews) e exact ce ai nevoie pentru sisteme de producție serioase. Flow-ul controlează când și în ce ordine se întâmplă lucrurile. Crews controlează cum se execută fiecare pas. Simplu, elegant, și surprinzător de ușor de depanat.
Memoria agenților: Cum învață și rețin informații
Un aspect pe care mulți îl trec cu vederea: CrewAI include un sistem de memorie destul de sofisticat, cu patru tipuri distincte:
- Memorie pe termen scurt — contextul conversației curente, partajat între agenții din același crew
- Memorie pe termen lung — persistă între execuții, ceea ce înseamnă că agenții chiar „învață" din interacțiunile anterioare și își îmbunătățesc performanța în timp
- Memorie de entitate — reține informații despre entități specifice (persoane, companii, produse) pe care agenții le întâlnesc în procesare
- Memorie contextuală — combină celelalte trei tipuri pentru a oferi un context complet la fiecare decizie
Activarea se face simplu, prin parametrul memory=True la crearea Crew-ului. Pentru proiecte de producție, poți configura backend-uri externe de stocare în loc de stocarea locală implicită — ceea ce recomand din start dacă lucrezi cu volume mari de date.
CrewAI vs. LangGraph: Când alegi fiecare?
Dacă ai citit și despre LangGraph, probabil te întrebi: când aleg CrewAI și când LangGraph? E o întrebare pe care o aud des. Răspunsul depinde în mare parte de nivelul de control de care ai nevoie:
- Alege CrewAI când ai nevoie de prototipare rapidă, când problema se descompune natural în roluri și sarcini, sau când echipa ta nu are experiență avansată cu grafuri de stări. CrewAI reduce timpul de la idee la produs funcțional cu circa 40% față de LangGraph
- Alege LangGraph când ai nevoie de control granular asupra fiecărei tranziții de stare, când construiești pipeline-uri RAG complexe cu bucle de auto-corecție, sau când performanța la nivel de latență este critică. Benchmark-urile arată o latență cu 30-40% mai mică la workflow-uri complexe
- Combină-le — da, poți folosi LangGraph pentru controlul de flux exterior și CrewAI pentru execuția sarcinilor la nivel de echipă. Arhitectura asta hibridă e legitimă și deja folosită în producție de câteva companii
Sincer, pentru majoritatea proiectelor, CrewAI e punctul de plecare mai bun. Poți migra ulterior dacă descoperi că ai nevoie de mai mult control.
Bune practici pentru producție
Din experiența comunității CrewAI și din pattern-urile validate în producție, iată câteva recomandări pe care le consider esențiale:
Proiectarea agenților
- Un rol, un agent — nu combina responsabilități multiple într-un singur agent. Un agent care face și cercetare și scriere și validare va face toate trei mediocru. Sună familiar? E aceeași regulă din ingineria software clasică
- Backstory-uri specifice — „Ești un analist de date" e prea vag. „Ești un analist de date cu 10 ani de experiență în piețele financiare, specializat pe analiza sentimentului din social media" — asta da, produce rezultate vizibil mai bune
- Limitează instrumentele — maximum 3-5 instrumente per agent. Mai multe instrumente înseamnă mai multe șanse de confuzie și alegeri greșite
Gestionarea erorilor
- Implementează
max_retry_limitla nivel de task pentru a preveni buclele infinite - Folosește
human_input=Truepe sarcini critice — permite intervenția umană când agentul e incert - Monitorizează costurile API — un crew verbose poate genera mii de apeluri API pe sesiune (am văzut facturi surprinzător de mari la proiecte prost configurate)
Testare și iterare
- Testează fiecare agent izolat înainte de a-l pune în crew — e mult mai ușor să depanezi un agent singular decât un crew întreg
- Folosește
verbose=Trueîn dezvoltare pentru a înțelege raționamentul agenților - Începe cu
Process.sequentialși treci laProcess.hierarchicaldoar când chiar ai nevoie de delegare dinamică
Întrebări frecvente
Ce modele LLM sunt compatibile cu CrewAI?
CrewAI funcționează cu orice model accesibil prin API compatibil OpenAI — inclusiv GPT-4o, GPT-4o-mini, Claude (prin proxy), Llama prin Ollama, Mistral și altele. Configurarea se face prin variabile de mediu sau direct la crearea agentului folosind parametrul llm. Pentru utilizare locală fără costuri API, Ollama cu modele open-source precum Llama 3 sau Mistral e o opțiune foarte viabilă.
CrewAI este gratuit?
Framework-ul în sine este complet open-source și gratuit. Costurile vin exclusiv din apelurile API către modelele LLM. Ca referință, un crew cu trei agenți care procesează o sarcină medie poate genera între 10.000 și 50.000 de tokeni — echivalentul a câțiva cenți cu GPT-4o-mini sau câțiva dolari cu GPT-4o. CrewAI oferă și o platformă enterprise plătită cu funcționalități adiționale de monitorizare și deployment.
Pot folosi CrewAI fără conexiune la internet?
Da, dacă folosești un model LLM local prin Ollama sau un server compatibil. Agenții vor funcționa complet offline, dar evident nu vor avea acces la instrumente care necesită internet. E o configurare populară pentru scenarii unde datele sunt sensibile sau accesul la internet e restricționat.
Cum gestionez agenți care intră în bucle infinite?
O problemă clasică. Buclele infinite apar de obicei când agenții cu allow_delegation=True își delegă sarcini reciproc. Soluțiile: setează allow_delegation=False pe majoritatea agenților, folosește max_iter pentru a limita iterațiile per agent, și configurează max_retry_limit pe sarcini. Și evită configurări circulare unde agentul A poate delega la B care poate delega înapoi la A — pare evident, dar se întâmplă mai des decât ai crede.
Care e diferența dintre Process.sequential și Process.hierarchical?
În modul sequential, sarcinile se execută în ordinea definită — output-ul fiecăreia devine input pentru următoarea. Simplu și previzibil. În modul hierarchical, CrewAI creează automat un agent-manager care decide ordinea execuției, poate delega sarcini și validează rezultatele. Modul ierarhic e potrivit pentru proiecte complexe cu dependențe dinamice, dar consumă mai mulți tokeni din cauza agentului-manager adițional. Recomandarea mea? Începe cu sequential și migrează doar dacă chiar ai nevoie.