04 - Kodowanie wieloagentowe: LangGraph, CrewAI i AutoGen
Wyobraź sobie, że stoisz przed złożonym zadaniem: wdrożeniem systemu uwierzytelniania od podstaw dla aplikacji korporacyjnej, wraz z OAuth2, RBAC, dziennikiem audytu i testami integracyjnymi i dokumentacja. Pojedynczy agent AI, niezależnie od jego możliwości, poradziłby sobie z zarządzaniem... przepełnione okno kontekstowe, sprzeczne obowiązki i wysokie ryzyko błędów kaskadowe. Rozwiązanie nie jest silniejszym czynnikiem: jest jednym zespół agentów specjaliści współpracujących, weryfikujących się wzajemnie i paralelizujących pracę.
To jest paradygmat Kodowanie wieloagentowe: systemy, w których wielu agentów AI autonomiczni ludzie współpracują przy wykonywaniu zadań związanych z tworzeniem oprogramowania, które przekraczają możliwości jednego pojedynczy model. W 2025 r. w tej przestrzeni zdominowały trzy ramy: LangGraf ze stanową architekturą grafów, ZałogaAI z jej modelem opartym na rolach intuicyjny, tj AutoGen (obecnie AG2) z podejściem konwersacyjnym. Do tych Dodano natywny system Claude Code z równoległymi agentami podrzędnymi.
Ten artykuł jest zaawansowanym, szczegółowym omówieniem wszystkich czterech systemów: architekturami i przykładami kodu działające, szczegółowe porównanie i praktyczny przewodnik, aby wybrać odpowiedni dla swojego przypadku użycia. Jeśli znasz już podstawowe koncepcje kodowania wibracyjnego i chcesz skorzystać z własnych, agentycznych przepływów pracy do następnego poziomu, jesteś we właściwym miejscu.
Czego się nauczysz
- ponieważ pojedynczy agent AI nie wystarczy do złożonych zadań programistycznych
- LangGraph: Architektura grafów, StateGraph, węzły, krawędzie i punkty kontrolne
- CrewAI: agenci bazujący na rolach, Zadania, Procesy sekwencyjne i równoległe, Narzędzia
- AutoGen/AG2: agenci konwersacyjni, GroupChat, sandbox wykonywania kodu
- Claude Code: podagenci, narzędzia zadań i wzorce wykonywania równoległego
- Szczegółowe porównanie: kiedy używać jakiego frameworka
- Architektura gotowa do produkcji dla prawdziwych zespołów
- Krytyczne wyzwania: zanieczyszczenie kontekstu, propagacja błędów, zarządzanie kosztami
- Najlepsze praktyki dotyczące wyspecjalizowanych agentów i strategie awaryjne
ponieważ jeden agent to za mało
Zanim zagłębimy się w frameworki, ważne jest, aby zrozumieć podstawowy problem, jaki stwarza kodowanie wieloagentowe rozwiązuje problem. Pojedynczy agent AI, niezależnie od stopnia zaawansowania, ma ograniczenia cechy strukturalne, które wyraźnie ujawniają się w złożonych zadaniach rozwojowych.
Pierwszym ograniczeniem jest okno kontekstowe. Nawet w przypadku modeli, które obsługują 200 tys. tokenów, typowe zadanie przedsiębiorstwa wymaga jednoczesnego pamiętania o: istniejąca baza kodu, specyfikacje funkcjonalne, wzorce architektoniczne, testy z zapisu, dokumentację do aktualizacji i ograniczenia bezpieczeństwa. Wszystko to przewyższa szybko możliwości jednego, spójnego kontekstu.
Drugim ograniczeniem jest specjalizacja. Agent generalistyczny ma tendencję robić wszystko przeciętnie, a nie niektóre rzeczy doskonale. Agent specjalizujący się w bezpieczeństwie wie dokładnie, jakich wzorców szukać i jakie standardy zastosować, podczas gdy ktoś specjalizujący się w testowaniu zna wzorce testowe dla każdego typu komponentu.
Trzecia granica to sprawdzać krzyżowo. Pisze jeden agent kod, a następnie „testowanie” to w zasadzie sprawdzanie pracy z tym samym błąd poznawczy, z jakim go wytworzył. Dwóch oddzielnych agentów, jeden wdrażający, drugi wdrażający recenzje, przedstawiają naprawdę różne perspektywy.
Zasada rozdziału ról
W zespołach programistycznych podział ról (programista, recenzent kodu, QA, inżynier bezpieczeństwa, autor tekstów technicznych) nie jest biurokracją: jest zabezpieczeniem poznawczym. Systemy wieloagentowe stosują tę samą zasadę do kodu generowanego przez sztuczną inteligencję, systematyczne zmniejszanie martwych punktów każdego pojedynczego agenta.
Badania przeprowadzone w 2025 r. potwierdzają tę intuicję: kod wygenerowany przez sztuczną inteligencję ma wskaźnik: znacznie większe luki w zabezpieczeniach, jeśli są tworzone przez pojedynczych, nienadzorowanych agentów (Veracode 2025 zgłasza 2,74 razy więcej luk w zabezpieczeniach niż kod ludzki). Systemy wieloagentowa współpraca z dedykowanymi agentami recenzującymi znacznie zmniejsza tę lukę.
LangGraph: Stateful Graph Orchestration
LangGraph, opracowany przez zespół LangChain, stanowi naturalną ewolucję podejścia do łańcuchów liniowych w kierunku cykliczne grafy stanowe. Podstawowa intuicja oraz że złożone przepływy pracy agentów nie są liniowe: wymagają pętli, bifurkacji warunkowych, równoległość i trwałość stanu pomiędzy jednym przejściem a drugim.
Sam zespół LangChain wyraźnie przekazał w 2025 r.: „Używaj LangGraph dla agentów, nie LangChain.” Wybór ten odzwierciedla ważną prawdę architektoniczną: systemy agentowe Nowoczesne systemy to w zasadzie maszyny, a nie kolejne rurociągi.
Podstawowe pojęcia LangGraph
LangGraph opiera się na czterech kluczowych koncepcjach, które należy opanować przed rozpoczęciem budowy efektywne systemy wieloagentowe:
- Wykres stanu: główny wykres definiujący strukturę przepływu pracy, np typ stanu współdzielonego pomiędzy węzłami
- Państwo: TypedDict (lub model Pydantic) reprezentujący informacje dzielone pomiędzy wszystkie węzły grafu
- Węzły: Funkcje Pythona, które odbierają stan, wykonują operację (często połączenie z LLM) i zwracaj aktualizacje statusu
- Krawędzie: połączenia między węzłami, które mogą być stałe lub warunkowe w oparciu o stan obecny
from typing import TypedDict, Annotated, List
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage, AIMessage
import operator
# ============================================================
# 1. DEFINIZIONE DELLO STATO CONDIVISO
# ============================================================
class CodingState(TypedDict):
"""Stato condiviso tra tutti gli agenti del sistema."""
task_description: str
requirements: List[str]
generated_code: str
test_code: str
review_comments: List[str]
security_issues: List[str]
final_code: str
iteration_count: int
status: str # "planning", "coding", "testing", "reviewing", "done"
# ============================================================
# 2. INIZIALIZZAZIONE DEI MODELLI
# ============================================================
# Planner: usa Opus per ragionamento complesso
planner_model = ChatAnthropic(model="claude-opus-4-6")
# Developer: usa Sonnet per code generation veloce
developer_model = ChatAnthropic(model="claude-sonnet-4-6")
# Reviewer: usa Sonnet per analisi critica
reviewer_model = ChatAnthropic(model="claude-sonnet-4-6")
# ============================================================
# 3. DEFINIZIONE DEI NODI (AGENTI)
# ============================================================
def planner_agent(state: CodingState) -> dict:
"""Agente pianificatore: decompone il task in requirements."""
prompt = f"""Sei un software architect senior.
Task: {state['task_description']}
Analizza il task e produci una lista di requisiti tecnici specifici.
Formato: una lista puntata di requisiti chiari e implementabili.
"""
response = planner_model.invoke([HumanMessage(content=prompt)])
requirements = [
line.strip().lstrip("- ")
for line in response.content.split("\n")
if line.strip().startswith("-")
]
return {
"requirements": requirements,
"status": "coding"
}
def developer_agent(state: CodingState) -> dict:
"""Agente sviluppatore: implementa il codice dai requirements."""
requirements_text = "\n".join(f"- {r}" for r in state["requirements"])
prompt = f"""Sei un senior Python developer.
Implementa il seguente codice rispettando tutti i requisiti:
Task originale: {state['task_description']}
Requisiti:
{requirements_text}
Codice esistente (se presente):
{state.get('generated_code', 'Nessun codice precedente')}
Note del reviewer (se presenti):
{chr(10).join(state.get('review_comments', []))}
Produci SOLO il codice Python, senza spiegazioni.
"""
response = developer_model.invoke([HumanMessage(content=prompt)])
return {
"generated_code": response.content,
"status": "testing"
}
def test_writer_agent(state: CodingState) -> dict:
"""Agente test writer: scrive unit test per il codice generato."""
prompt = f"""Sei un QA engineer specializzato in Python testing.
Scrivi unit test completi per il seguente codice usando pytest:
{state['generated_code']}
Requisiti dei test:
- Copertura minima: 80%
- Testa happy path e edge cases
- Include test per casi di errore
- Usa fixtures dove appropriato
Produci SOLO il codice dei test, senza spiegazioni.
"""
response = developer_model.invoke([HumanMessage(content=prompt)])
return {
"test_code": response.content,
"status": "reviewing"
}
def code_reviewer_agent(state: CodingState) -> dict:
"""Agente code reviewer: analizza codice e test per qualità."""
prompt = f"""Sei un senior code reviewer con 10+ anni di esperienza.
Rivedi il seguente codice e i suoi test:
CODICE:
{state['generated_code']}
TEST:
{state['test_code']}
Analizza per:
1. Correttezza logica
2. qualità del codice (SOLID, DRY, KISS)
3. Completezza dei test
4. Performance
5. Leggibilita e manutenibilità
Se ci sono problemi critici, rispondimi con "NEEDS_REVISION:" seguito dai problemi.
Se il codice e accettabile, rispondimi con "APPROVED:" seguito da eventuali suggerimenti minor.
"""
response = reviewer_model.invoke([HumanMessage(content=prompt)])
comments = [response.content]
needs_revision = response.content.startswith("NEEDS_REVISION:")
return {
"review_comments": comments,
"iteration_count": state.get("iteration_count", 0) + 1,
"status": "coding" if needs_revision else "security_check"
}
def security_agent(state: CodingState) -> dict:
"""Agente sicurezza: verifica vulnerabilità nel codice."""
prompt = f"""Sei un security engineer specializzato in application security.
Analizza il seguente codice per vulnerabilità di sicurezza:
{state['generated_code']}
Cerca specificamente:
- Injection vulnerabilities (SQL, Command, Path traversal)
- Insecure deserialization
- Hardcoded secrets o credenziali
- Insecure random number generation
- Race conditions
- Input validation gaps
Lista SOLO i problemi trovati. Se nessun problema, scrivi "SECURITY_OK".
"""
response = reviewer_model.invoke([HumanMessage(content=prompt)])
issues = []
if response.content.strip() != "SECURITY_OK":
issues = [response.content]
return {
"security_issues": issues,
"final_code": state['generated_code'] if not issues else "",
"status": "done" if not issues else "coding"
}
# ============================================================
# 4. ROUTING CONDIZIONALE
# ============================================================
def route_after_review(state: CodingState) -> str:
"""Decide il prossimo nodo dopo la code review."""
if state["status"] == "coding" and state.get("iteration_count", 0) < 3:
return "developer"
elif state["status"] == "security_check":
return "security"
else:
# Max iterazioni raggiunte
return "security"
def route_after_security(state: CodingState) -> str:
"""Decide se il codice e pronto o necessità un'altra iterazione."""
if state["security_issues"] and state.get("iteration_count", 0) < 3:
return "developer"
return END
# ============================================================
# 5. COSTRUZIONE DEL GRAFO
# ============================================================
def build_coding_graph() -> StateGraph:
graph = StateGraph(CodingState)
# Aggiunta nodi
graph.add_node("planner", planner_agent)
graph.add_node("developer", developer_agent)
graph.add_node("test_writer", test_writer_agent)
graph.add_node("reviewer", code_reviewer_agent)
graph.add_node("security", security_agent)
# Entry point
graph.set_entry_point("planner")
# Edges fissi
graph.add_edge("planner", "developer")
graph.add_edge("developer", "test_writer")
graph.add_edge("test_writer", "reviewer")
# Edges condizionali
graph.add_conditional_edges(
"reviewer",
route_after_review,
{
"developer": "developer",
"security": "security"
}
)
graph.add_conditional_edges(
"security",
route_after_security,
{
"developer": "developer",
END: END
}
)
return graph
# ============================================================
# 6. ESECUZIONE CON CHECKPOINTING
# ============================================================
checkpointer = MemorySaver()
app = build_coding_graph().compile(checkpointer=checkpointer)
# Esecuzione del sistema
config = {"configurable": {"thread_id": "project-auth-001"}}
initial_state = {
"task_description": """
Implementa un sistema di autenticazione JWT in Python con:
- Login con username/password
- Generazione access token (15 min) e refresh token (7 giorni)
- Middleware per proteggere endpoint
- Revoca token (blacklist in Redis)
""",
"requirements": [],
"generated_code": "",
"test_code": "",
"review_comments": [],
"security_issues": [],
"final_code": "",
"iteration_count": 0,
"status": "planning"
}
result = app.invoke(initial_state, config=config)
print(f"Codice finale generato dopo {result['iteration_count']} iterazioni")
print(f"Problemi di sicurezza rilevati: {len(result['security_issues'])}")
Ten przykład pokazuje, jak LangGraph radzi sobie ze złożonym przepływem pracy programistycznej automatyczne pętle recenzji. The punkt kontrolny i cecha krytyczna dla produkcji: pozwala zapisać stan wykresu i wznowić wykonanie w przypadku błędów, bez zaczynania od zera.
LangGraph: Mocne strony
- Kontrola granulowana: każdy aspekt przepływu jest programowalny
- Trwałość stanu: Zintegrowane punkty kontrolne dla długich przepływów pracy
- Człowiek w pętli: możliwość pauzy do zatwierdzenia przez człowieka
- Wykonanie równoległe: węzły mogą działać równolegle
- Transmisja strumieniowa: dane wyjściowe w czasie rzeczywistym z każdego węzła
- Testowana produkcja: wykorzystywane w produkcji przez setki firm w 2025 roku
CrewAI: agenci bazujący na rolach dla zespołów wirtualnych
CrewAI przyjmuje zasadniczo inne podejście do LangGraph: zamiast myśleć w kategoriach wykresów i stanów, prosi Cię o myślenie w kategoriach zespoły i role. Każdy agent jest członkiem zespołu o określonej specjalizacji i jasnym celu oraz zestaw dostępnych narzędzi. Ten model mentalny jest bardziej intuicyjny dla tych, którzy go posiadają Doświadczenie w zarządzaniu zespołami deweloperskimi.
W wersji 1.1.0 2025 CrewAI wprowadziło separację między Załogi (orkiestracja wysokiego poziomu) e Przepływy (szczegółowa kontrola przepływu pracy), oferując elastyczność LangGraph z prostotą modelu opartego na rolach.
Architektura CrewAI
Cztery podstawowe elementy CrewAI to:
- Agenci: podmiot AI z rolami, celami i historią, które definiują jego własne „osobowość” i obszar specjalizacji
- Zadania: konkretne działanie z opisem, oczekiwanym_wyjściem i przypisany do konkretnego agenta
- Narzędzia: dodatkowe możliwości agenta (we/wy plików, wyszukiwanie w Internecie, wykonanie kodu, dostęp do bazy danych)
- Załoga: zespół, który koordynuje agentów i zadania za pomocą procesu (sekwencyjne lub równoległe)
from crewai import Agent, Task, Crew, Process
from crewai.tools import CodeInterpreterTool, FileReadTool, FileWriteTool
from crewai_tools import GithubSearchTool
from langchain_anthropic import ChatAnthropic
# ============================================================
# 1. CONFIGURAZIONE MODELLI
# ============================================================
opus_llm = ChatAnthropic(model="claude-opus-4-6", temperature=0.1)
sonnet_llm = ChatAnthropic(model="claude-sonnet-4-6", temperature=0.2)
# ============================================================
# 2. DEFINIZIONE DEGLI STRUMENTI
# ============================================================
code_executor = CodeInterpreterTool()
file_reader = FileReadTool()
file_writer = FileWriteTool()
# ============================================================
# 3. DEFINIZIONE DEGLI AGENTI (MEMBRI DEL TEAM)
# ============================================================
tech_lead = Agent(
role="Tech Lead e Software Architect",
goal="""Analizzare i requisiti tecnici, definire l'architettura ottimale
e decomporre il lavoro in task specifici e implementabili.""",
backstory="""Hai 15 anni di esperienza in software architecture.
Hai guidato la transizione a microservizi per 3 startup unicorn.
Sei noto per la capacità di bilanciare pragmatismo e qualità tecnica.""",
llm=opus_llm,
verbose=True,
allow_delegation=True
)
senior_developer = Agent(
role="Senior Python Developer",
goal="""Implementare codice Python di alta qualità, pulito, testabile
e conforme alle best practices SOLID e alle specifiche del tech lead.""",
backstory="""Sei un Python developer con 8 anni di esperienza.
Contribuisci a progetti open source importanti.
Scrivi codice che altri developer amano leggere e mantenere.""",
llm=sonnet_llm,
verbose=True,
tools=[code_executor, file_writer],
allow_code_execution=True
)
qa_engineer = Agent(
role="QA Engineer e Test Specialist",
goal="""Verificare la correttezza del codice attraverso test exhaustivi,
trovare edge cases e garantire la copertura dei test al 90%+.""",
backstory="""Hai un background in matematica e sei ossessionato dalla
correttezza del software. Hai trovato bug critici in sistemi che erano
in produzione da anni. Non ti fidi del codice senza prove.""",
llm=sonnet_llm,
verbose=True,
tools=[code_executor],
allow_code_execution=True
)
code_reviewer = Agent(
role="Senior Code Reviewer",
goal="""Analizzare criticamente il codice per qualità, manutenibilità,
performance e conformità agli standard del team.""",
backstory="""Hai revisionato oltre 10.000 pull request nella tua carriera.
Hai un occhio infallibile per code smells, anti-pattern e problemi
di design che si manifestano solo in produzione.""",
llm=sonnet_llm,
verbose=True,
tools=[file_reader]
)
# ============================================================
# 4. DEFINIZIONE DEI TASK
# ============================================================
architecture_task = Task(
description="""
Analizza il seguente requisito e produci un documento di architettura:
REQUISITO: {task_description}
Il documento deve includere:
1. Diagramma dei componenti (in testo/ASCII)
2. Stack tecnologico raccomandato con giustificazioni
3. Struttura delle directory del progetto
4. Interfacce principali (classi/funzioni pubbliche)
5. Considerazioni su scalabilità e manutenibilità
6. Lista prioritizzata di task di implementazione
""",
expected_output="""Un documento di architettura dettagliato in markdown,
con diagrammi ASCII, struttura del progetto e lista di task.""",
agent=tech_lead
)
implementation_task = Task(
description="""
Implementa il codice Python basandoti sul documento di architettura
fornito dal Tech Lead.
Requisiti di implementazione:
- Segui esattamente le interfacce definite nell'architettura
- Usa type hints per tutte le funzioni pubbliche
- Aggiungi docstring in formato Google style
- Gestisci tutti i casi di errore con eccezioni custom
- Salva il codice in file separati per modulo
""",
expected_output="""Codice Python completo e funzionante, organizzato in moduli,
con type hints, docstring e gestione degli errori.""",
agent=senior_developer,
context=[architecture_task] # dipende dall'output dell'architettura
)
testing_task = Task(
description="""
Scrivi test completi per il codice implementato.
Requisiti:
- Framework: pytest con pytest-cov
- Copertura target: 90%
- Include unit test, integration test e test parametrici
- Testa happy path, edge cases e scenari di errore
- Usa mocking per dipendenze esterne
- Esegui i test per verificare che passino tutti
""",
expected_output="""File di test pytest completi che passano tutti,
con report di copertura al 90%+.""",
agent=qa_engineer,
context=[implementation_task]
)
review_task = Task(
description="""
Conduci una code review approfondita del codice e dei test prodotti.
Analizza per:
1. Rispetto dei principi SOLID
2. Presenza di code smells o anti-pattern
3. Correttezza logica e completezza
4. Performance e uso della memoria
5. Sicurezza (injection, validazione input, secrets)
6. qualità della documentazione
Produci un report con: problemi CRITICI, WARNINGS e SUGGESTIONS.
Per ogni problema, includi il file/riga e la fix raccomandata.
""",
expected_output="""Report di code review strutturato con categorie CRITICAL,
WARNING e SUGGESTION, con fix raccomandate per ogni problema.""",
agent=code_reviewer,
context=[implementation_task, testing_task]
)
# ============================================================
# 5. CREW - ASSEMBLAGGIO DEL TEAM
# ============================================================
coding_crew = Crew(
agents=[tech_lead, senior_developer, qa_engineer, code_reviewer],
tasks=[architecture_task, implementation_task, testing_task, review_task],
process=Process.sequential, # o Process.hierarchical per delega automatica
verbose=True,
memory=True, # abilita memoria condivisa tra agenti
embedder={
"provider": "anthropic",
"config": {"model": "claude-3-haiku-20240307"}
}
)
# ============================================================
# 6. AVVIO DEL CREW
# ============================================================
result = coding_crew.kickoff(inputs={
"task_description": """
Implementa un sistema di rate limiting per API REST con:
- Algoritmo token bucket per controllo del flusso
- Storage su Redis per distribuzione multi-instance
- Configurazione per-endpoint e per-user
- Header HTTP standard (X-RateLimit-*)
- Dashboard di monitoring con metriche Prometheus
"""
})
print(result.raw)
Charakterystycznym elementem CrewAI 2025 jest opcja allow_code_execution=True
na agentach: umożliwia wykonanie kodu w bezpiecznej, samozarządzającej się piaskownicy
błędów i inteligentne ponawianie prób. Jeśli kod zgłosi wyjątek, agent otrzyma komunikat
komunikat o błędzie i spróbuj go naprawić samodzielnie (maks max_retry_limit,
domyślnie 2).
CrewAI: Mocne strony
- Niska krzywa uczenia się: model mentalny zespołu/roli jest intuicyjny
- Zintegrowane wykonanie kodu: zabezpiecz piaskownicę z automatyczną ponowną próbą
- Wspólna pamięć: agenci pamiętają kontekst poprzednich rozmów
- Wsparcie MCP: dwukierunkowa integracja z serwerami MCP (2025)
- Funkcje korporacyjne: obserwowalność, dziennik audytu, płaszczyzna kontroli SaaS
- Przepływy: w razie potrzeby szczegółowa kontrola złożonych przepływów pracy
AutoGen/AG2: Agenci konwersacyjni do pojawiających się zadań
AutoGen (przemianowany na AG2 przez społeczność, która kontynuowała rozwój po rozbieżności przez Microsoft w 2024 r.) przyjmuje zupełnie inny paradygmat: konwersacyjny wieloagentowy. Zamiast definiować stałe przepływy pracy i sztywne role, agenci komunikują się ze sobą za pośrednictwem komunikatów w języku naturalnym i pojawiających się zachowań złożone z prostych interakcji.
To podejście jest szczególnie skuteczne w przypadku zadań, w których nie ma ścieżki rozwiązania i definiowalne a priori: złożone problemy debugowania, badania i wdrażanie innowacyjne rozwiązania lub zadania wymagające negocjacji pomiędzy sprzecznymi ograniczeniami.
Architektura AG2: AssistantAgent i UserProxyAgent
Podstawowym elementem AG2 jest moment obrotowy AsystentAgenta (agent AI) tj Agent proxy użytkownika (pełnomocnik do wykonania). Można wykonać UserProxyAgent kodu w lokalnym piaskownicy, dostarczając prawdziwą informację zwrotną do AssistantAgent, który może następnie iteruj rozwiązanie w oparciu o rzeczywiste wyniki wykonania.
import autogen
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager
from autogen.coding import LocalCommandLineCodeExecutor
import os
# ============================================================
# 1. CONFIGURAZIONE LLM
# ============================================================
config_list = [
{
"model": "claude-sonnet-4-6",
"api_key": os.environ["ANTHROPIC_API_KEY"],
"api_type": "anthropic",
}
]
llm_config = {
"config_list": config_list,
"temperature": 0.1,
"timeout": 120,
}
opus_config = {
"config_list": [{
"model": "claude-opus-4-6",
"api_key": os.environ["ANTHROPIC_API_KEY"],
"api_type": "anthropic",
}],
"temperature": 0.1,
}
# ============================================================
# 2. CODE EXECUTOR - SANDBOX LOCALE
# ============================================================
executor = LocalCommandLineCodeExecutor(
timeout=60,
work_dir="/tmp/autogen_workspace",
# Blocca comandi pericolosi
execution_policies={
"rm": False,
"curl": False,
"wget": False,
}
)
# ============================================================
# 3. DEFINIZIONE DEGLI AGENTI
# ============================================================
# Agente Software Architect - usa Opus per alta capacità di ragionamento
architect = AssistantAgent(
name="SoftwareArchitect",
system_message="""Sei un software architect senior con 15 anni di esperienza.
Il tuo ruolo e:
1. Analizzare i requisiti e proporre architetture solide
2. Definire le interfacce tra componenti
3. Identificare rischi tecnici e proporre mitigazioni
4. Guidare le decisioni tecniche del team
Quando proponi un'architettura, usa sempre diagrammi ASCII e spiega le
motivazioni delle scelte. Rispondi con "TERMINATE" quando il task e completo.""",
llm_config=opus_config,
)
# Agente Developer - implementa il codice
developer = AssistantAgent(
name="PythonDeveloper",
system_message="""Sei un senior Python developer.
Il tuo ruolo e:
1. Implementare il codice seguendo le specifiche dell'architetto
2. Scrivere codice pulito con type hints e docstring
3. Gestire gli errori in modo robusto
4. Rispettare i principi SOLID e DRY
Usa sempre blocchi di codice Python validi quando scrivi implementazioni.
Rispondi con "TERMINATE" solo quando il developer AND il reviewer approvano.""",
llm_config=llm_config,
)
# Agente Tester - scrive e verifica i test
tester = AssistantAgent(
name="QATester",
system_message="""Sei un QA engineer specializzato in Python testing.
Il tuo ruolo e:
1. Scrivere test pytest esaustivi per il codice del developer
2. Eseguire i test nella sandbox e riportare i risultati
3. Identificare edge cases non coperti
4. Garantire copertura 85%+
Produci sempre test eseguibili che posso verificare nella sandbox.""",
llm_config=llm_config,
)
# Agente Reviewer - code review critica
reviewer = AssistantAgent(
name="CodeReviewer",
system_message="""Sei un code reviewer senior con focus su qualità e sicurezza.
Il tuo ruolo e:
1. Analizzare il codice per code smells e anti-pattern
2. Verificare la sicurezza (OWASP Top 10)
3. Suggerire refactoring migliorativi
4. Approvare o richiedere modifiche
Concludi ogni review con "APPROVED" o "NEEDS_WORK: [lista problemi]".""",
llm_config=llm_config,
)
# UserProxy con esecuzione codice - fa da ponte tra agenti e sandbox
code_executor_proxy = UserProxyAgent(
name="CodeExecutor",
human_input_mode="NEVER", # completamente automatico
max_consecutive_auto_reply=5,
code_execution_config={
"executor": executor,
},
is_termination_msg=lambda msg: "TERMINATE" in msg.get("content", ""),
)
# ============================================================
# 4. GROUP CHAT - ORCHESTRAZIONE DELLA CONVERSAZIONE
# ============================================================
group_chat = GroupChat(
agents=[architect, developer, tester, reviewer, code_executor_proxy],
messages=[],
max_round=20, # massimo 20 round di conversazione
# Strategia di selezione del prossimo parlante
speaker_selection_method="auto",
# Ordine preferito per strutturare la conversazione
allowed_or_disallowed_speaker_transitions={
architect: [developer],
developer: [tester, code_executor_proxy],
tester: [code_executor_proxy, reviewer],
code_executor_proxy: [developer, tester, reviewer],
reviewer: [developer, architect],
},
speaker_transitions_type="allowed",
)
# Manager che orchestra la group chat
manager = GroupChatManager(
groupchat=group_chat,
llm_config=llm_config,
system_message="""Sei il project manager di questo team di sviluppo.
Orchestri la conversazione per garantire che il task venga completato
in modo efficiente e che ogni agente contribuisca nel momento opportuno.""",
)
# ============================================================
# 5. AVVIO DELLA CONVERSAZIONE
# ============================================================
task = """
Sviluppa un sistema di caching intelligente in Python con le seguenti caratteristiche:
- Cache LRU (Least Recently Used) con TTL configurabile per entry
- Backend multipli: in-memory, Redis, o filesystem
- Decorator @cache per applicazione trasparente alle funzioni
- Statistiche di hit/miss in tempo reale
- Thread-safe per applicazioni concorrenti
Architettura, implementazione, test e code review completi.
"""
chat_result = code_executor_proxy.initiate_chat(
manager,
message=task,
summary_method="reflection_with_llm",
)
print("\n=== SOMMARIO FINALE ===")
print(chat_result.summary)
AG2: Mocne strony
- Prawdziwe wykonanie kodu: kod naprawdę działa w piaskownicy, agenci widzą rzeczywiste wyniki
- Pojawiająca się elastyczność: przepływy pracy dostosowują się do problemu, nie odwrotnie
- Protokół AG-UI: dynamiczne frontendy ze streamingiem w czasie rzeczywistym (2025)
- Otwarta telemetria: pełna obserwowalność przepływów pracy agentów
- Człowiek w pętli: łatwo konfigurowalny za pomocą
human_input_mode - Obsługa TypeScriptu: Microsoft AutoGen w wersji 0.4 z natywną obsługą
Kod Claude: Podagenci i wykonanie równoległe
Claude Code ma natywny system wieloagentowy, który działa w zasadniczo inny sposób z frameworków Pythona, które widzieliśmy do tej pory. Instead of orchestrating LLM models via API, Claude Code zacznij Oddzielne instancje Claude (podagenci) bezpośrednio z terminala, każdy z własnym, czystym oknem kontekstowym i możliwością operowania na systemie plików w izolowany sposób.
Takie podejście ma znaczące zalety: brak frameworka, narzut związany z integracją natywny z narzędziami terminalowymi i możliwością równoległego uruchamiania zadań w systemach z wieloma rdzeniami. Narzędzie Zadanie i kluczowy mechanizm: uruchom sub-agenta za pomocą określony monit i czeka na wynik przed kontynuowaniem (lub, jeśli zadania są niezależne, uruchamia je wszystkie równolegle).
# Code Reviewer Agent
## Ruolo
Senior code reviewer con focus su qualità, sicurezza e manutenibilità.
## Competenze
- Principi SOLID e design patterns
- OWASP Top 10 e sicurezza applicativa
- Performance optimization
- Clean code e refactoring
## Processo di Review
1. Leggi TUTTI i file modificati prima di commentare
2. Identifica problemi per categoria: CRITICAL, WARNING, SUGGESTION
3. Per ogni problema: specifica file, riga e fix raccomandata
4. Verifica che i test coprano i casi di errore
5. Controlla presenza di hardcoded secrets o credenziali
## Output Atteso
Report strutturato in markdown con sezioni:
- Executive Summary
- CRITICAL Issues (bloccanti per il merge)
- WARNINGS (da risolvere prima della prossima release)
- SUGGESTIONS (miglioramenti opzionali)
- Security Checklist
# Security Auditor Agent
## Ruolo
Security engineer specializzato in application security e OWASP.
## Competenze
- OWASP Top 10 (2025 edition)
- Analisi di codice Python, JavaScript e SQL
- Threat modeling
- Dependency vulnerability scanning
## Checklist di Sicurezza
### Input Validation
- [ ] Tutti gli input utente sono validati e sanitizzati
- [ ] Nessuna query SQL costruita con concatenazione di stringhe
- [ ] Path traversal prevenuto con realpath/pathlib
### Authentication & Authorization
- [ ] Password hashing con bcrypt/argon2 (no MD5/SHA1)
- [ ] JWT firmati con chiavi di lunghezza adeguata
- [ ] RBAC implementato correttamente
### Secrets Management
- [ ] Nessun hardcoded secret nel codice
- [ ] Variabili d'ambiente usate per credenziali
- [ ] .gitignore include file di configurazione sensibili
### Dependencies
- [ ] Nessuna dipendenza con CVE critiche note
- [ ] requirements.txt con versioni pin-nate
## Output
- Lista vulnerabilità con CVSS score stimato
- Fix raccomandate con esempi di codice
- Priorità: CRITICAL (fix immediata), HIGH, MEDIUM, LOW
# Esempio di prompt per orchestrazione multi-agent in Claude Code
# (questo e il contenuto di un file CLAUDE.md o di un prompt interattivo)
# --- ESEMPIO 1: SEQUENTIAL MULTI-AGENT ---
# Il task tool lancia sub-agent e attende i risultati in sequenza
Implementa le seguenti feature per il modulo auth/:
1. Usa il Task tool per lanciare il sub-agent "planner":
- Input: "Analizza auth/ e crea un piano di implementazione per
aggiungere 2FA con TOTP (RFC 6238)"
- Attendi il piano completo
2. Usa il Task tool per lanciare il sub-agent "developer":
- Input: "Implementa il piano seguente: [output del planner]"
- Attendi l'implementazione completa
3. Usa il Task tool per lanciare PARALLELAMENTE:
- Sub-agent "code-reviewer": rivedi il codice in auth/
- Sub-agent "security-auditor": verifica la sicurezza di auth/
(lancia entrambi contemporaneamente, attendi entrambi)
4. Applica le fix per tutti i problemi CRITICAL trovati
---
# --- ESEMPIO 2: PARALLEL WORKTREE ISOLATION ---
# Task indipendenti su worktree separati per massima parallelizzazione
Esegui queste task IN PARALLELO su worktree separati:
Task A (worktree: feature/user-service):
- Implementa UserService con CRUD completo
- Scrivi unit test con 90% coverage
- Commit: "feat: add UserService with full CRUD"
Task B (worktree: feature/email-service):
- Implementa EmailService con template system
- Integra con SendGrid API
- Scrivi integration test
- Commit: "feat: add EmailService with SendGrid"
Task C (worktree: feature/notification-service):
- Implementa NotificationService (email + push + SMS)
- Usa UserService e EmailService come dipendenze
- Scrivi test end-to-end
- Commit: "feat: add NotificationService"
Dopo che tutti e tre i worktree sono completati:
- Mergia in ordine: A, B, C
- Risolvi eventuali conflitti
- Esegui la test suite completa
---
# --- ESEMPIO 3: AGENTE CON MEMORIA CONDIVISA ---
# Uso di file come meccanismo di comunicazione inter-agent
Prima di iniziare, crea il file /tmp/project-context.md con:
- Stack tecnologico del progetto
- Convenzioni di naming
- Pattern architetturali in uso
- Dipendenze principali
Ogni sub-agent che lanci deve:
1. Leggere /tmp/project-context.md all'inizio
2. Aggiornare /tmp/progress.md con lo stato dei propri task
3. Salvare output strutturati in /tmp/agent-outputs/[nome]/
Questo garantisce coerenza tra agenti paralleli senza conflitti di merge.
Lekcja z incydentu Replit (2025)
W 2025 r. Replit udokumentował przypadek wyeliminowania autonomicznego agenta
produkcyjnej bazy danych podczas zadania „czyszczenia”. To wydarzenie ma
podkreślił potrzebę jawnego skonfigurowania limitów poleceń
destrukcyjny. W Claude Code jest to obsługiwane poprzez sekcję deny
in .claude/settings.json: Zawsze blokuj rm -rf,
DROP TABLE, git push --force i podobne.
Podagenci dziedziczą te same ograniczenia, co agent nadrzędny.
Szczegółowe porównanie: który framework wybrać
Wybór ram zależy od konkretnego kontekstu. Nie ma ogólnego zwycięzcy: każde narzędzie sprawdza się w różnych scenariuszach. Poniższa tabela podsumowuje różnice klucz, który pomoże w podjęciu decyzji.
| Kryterium | LangGraf | ZałogaAI | AG2 (automatyczna generacja) | Claude'a Koda |
|---|---|---|---|---|
| Paradygmat | Wykres stanowy | Zespoły oparte na rolach | Konwersacyjny | Rodzimy subagent |
| Krzywa uczenia się | Wysoka (teoria grafów) | Niski (intuicyjny) | Przeciętny | Niski |
| Kontrola przepływu | Maksymalny | Średnio-wysoki | Powstające | Średni |
| Wykonanie kodu | Za pomocą narzędzi | Zintegrowany (piaskownica) | Zintegrowany (lokalny) | Rodzimy Bashu |
| Trwałość stanu | Natywne punkty kontrolne | Zintegrowana pamięć | Wiadomości na czacie | System plików |
| Równoległość | Węzły równoległe | Proces.równoległy | Asynchronizacja GroupChat | Natywne narzędzie do zadań |
| Obserwowalność | LangSmitha | Firma CrewAI | OtwórzTelemetrię | Dzienniki natywne |
| Człowiek w pętli | Natywne przerwanie | Oddzwonienia | human_input_mode |
Interaktywny |
| Ekosystem | LangChain | Niezależny | Microsoftu/AG2 | Antropiczny |
| Idealny dla | Złożone przepływy pracy z logiką warunkową | Wirtualne zespoły ze zdefiniowanymi rolami | Zadania eksploracyjne z wykonaniem kodu | Automatyzacja CLI i istniejące projekty |
Praktyczne zalecenia
- Wybierz LangGraph jeśli masz złożone przepływy pracy z wieloma rozwidleniami warunkowe, potrzebujesz niezawodnej trwałości stanu między sesjami i masz zespół kto rozumie pojęcia maszyn stanowych i grafów skierowanych.
- Wybierz CrewAI jeśli chcesz szybko rozpocząć pracę z wieloma agentami, Twój zespół jest przyzwyczajony do myślenia w kategoriach ról organizacyjnych, a Ty tego potrzebujesz zintegrowane wykonanie kodu z automatycznym zarządzaniem błędami.
- Wybierz AG2 jeśli zadanie ma charakter eksploracyjny i nie masz predefiniowanego przepływu pracy, potrzebujesz prawdziwych wielorundowych rozmów z realnym wykonaniem kodu, i jesteś w ekosystemie Microsoft (Azure, TypeScript).
- Wybierz Claude'a Code'a jeśli już pracujesz z Claudem, chcesz korzystać z wielu agentów bez dodatkowych frameworków, a Twój główny przypadek użycia i automatyzacja zadań rozwój na istniejących bazach kodu.
Architektura gotowa do produkcji dla prawdziwych zespołów
A multi-agent system in production requires ranging architectural considerations wykraczające poza prostą orkiestrację agentów. Firmy, które je wdrożyły systemów w 2025 r. wyciągnęły pewne ważne wnioski, które warto poznać wcześniej zacząć.
Skonsolidowane wzorce architektoniczne
Badania przeprowadzone w roku 2025 pokazują, że najskuteczniejsze wzorce kodowania wieloagentowego w produkcja to trzy:
- Wzór nadzorcy: agent koordynatora deleguje zadania agentom specjalizować i agregować wyniki. Idealny dla LangGraph z routingiem warunkowym.
- Wzory rurociągów: agentów w kolejności, w której wyjście jednego
staje się wejściem następnego. Naturalne w CrewAI z
contexti zadania pracownicy. - Wzór peer-to-peer: agentów, którzy swobodnie komunikują się ze sobą bez centralnego koordynatora. Naturalnie w AG2 z GroupChat.
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.postgres import PostgresSaver
from typing import TypedDict, Optional
import logging
import time
logger = logging.getLogger(__name__)
class ProductionCodingState(TypedDict):
task_id: str
task_description: str
generated_code: str
test_results: str
review_status: str
error_count: int
max_errors: int
last_error: Optional[str]
start_time: float
max_execution_time: float # secondi
# ============================================================
# ERROR HANDLING - Nodo dedicato alla gestione errori
# ============================================================
def error_handler(state: ProductionCodingState) -> dict:
"""Gestisce errori e decide se riprovare o terminare."""
error_count = state.get("error_count", 0) + 1
logger.error(
f"Task {state['task_id']}: errore #{error_count} - {state.get('last_error', 'unknown')}"
)
if error_count >= state["max_errors"]:
logger.critical(f"Task {state['task_id']}: max errori raggiunto, terminazione")
return {"error_count": error_count, "review_status": "FAILED"}
# Exponential backoff prima del retry
wait_time = min(2 ** error_count, 30)
logger.info(f"Retry in {wait_time}s...")
time.sleep(wait_time)
return {"error_count": error_count, "review_status": "RETRY"}
# ============================================================
# TIMEOUT MANAGEMENT
# ============================================================
def check_timeout(state: ProductionCodingState) -> str:
"""Verifica se il task ha superato il timeout massimo."""
elapsed = time.time() - state["start_time"]
if elapsed > state["max_execution_time"]:
logger.warning(
f"Task {state['task_id']}: timeout dopo {elapsed:.1f}s "
f"(max: {state['max_execution_time']}s)"
)
return "timeout"
return "continue"
# ============================================================
# COST TRACKING - Tracciamento costi in tempo reale
# ============================================================
class CostTracker:
# Prezzi Anthropic (USD per 1M token, Feb 2026)
PRICES = {
"claude-opus-4-6": {"input": 15.0, "output": 75.0},
"claude-sonnet-4-6": {"input": 3.0, "output": 15.0},
"claude-haiku-4-5": {"input": 0.25, "output": 1.25},
}
def __init__(self, budget_usd: float):
self.budget = budget_usd
self.spent = 0.0
self.calls = 0
def track(self, model: str, input_tokens: int, output_tokens: int) -> None:
prices = self.PRICES.get(model, {"input": 3.0, "output": 15.0})
cost = (input_tokens * prices["input"] + output_tokens * prices["output"]) / 1_000_000
self.spent += cost
self.calls += 1
if self.spent > self.budget * 0.8:
logger.warning(f"Costo task: ${self.spent:.4f} (80% del budget ${self.budget})")
def check_budget(self) -> bool:
"""Ritorna True se il budget e ancora disponibile."""
return self.spent < self.budget
def report(self) -> dict:
return {
"total_cost_usd": round(self.spent, 4),
"budget_remaining_usd": round(self.budget - self.spent, 4),
"api_calls": self.calls,
"budget_utilization_pct": round(self.spent / self.budget * 100, 1)
}
# ============================================================
# PERSISTENZA PRODUCTION CON POSTGRESQL
# ============================================================
# Il checkpointing su PostgreSQL garantisce durabilita del workflow
# anche in caso di crash dell'applicazione
def create_production_app(db_connection_string: str):
"""Crea un'applicazione LangGraph con persistenza PostgreSQL."""
# PostgresSaver per persistenza production-grade
checkpointer = PostgresSaver.from_conn_string(db_connection_string)
checkpointer.setup() # crea le tabelle se non esistono
graph = StateGraph(ProductionCodingState)
# ... aggiunta nodi e edges ...
return graph.compile(checkpointer=checkpointer)
# ============================================================
# CIRCUIT BREAKER - Protezione contro failure a cascata
# ============================================================
class CircuitBreaker:
"""Implementa il Circuit Breaker pattern per agenti inaffidabili."""
def __init__(self, failure_threshold: int = 5, recovery_time: int = 60):
self.failure_count = 0
self.failure_threshold = failure_threshold
self.recovery_time = recovery_time
self.last_failure_time = 0
self.state = "CLOSED" # CLOSED=normale, OPEN=blocco, HALF-OPEN=test
def call(self, func, *args, **kwargs):
"""Chiama la funzione attraverso il circuit breaker."""
if self.state == "OPEN":
if time.time() - self.last_failure_time > self.recovery_time:
self.state = "HALF-OPEN"
logger.info("Circuit breaker: passaggio a HALF-OPEN")
else:
raise Exception("Circuit breaker OPEN: servizio non disponibile")
try:
result = func(*args, **kwargs)
if self.state == "HALF-OPEN":
self.state = "CLOSED"
self.failure_count = 0
logger.info("Circuit breaker: recupero riuscito, ritorno a CLOSED")
return result
except Exception as e:
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = "OPEN"
logger.error(f"Circuit breaker OPEN dopo {self.failure_count} errori")
raise
Wyzwania i ograniczenia kodowania wieloagentowego
Systemy wieloagentowe w produkcji stwarzają nieoczywiste wyzwania, które dopiero się pojawiają z doświadczeniem. Znajomość ich z wyprzedzeniem stanowi różnicę między solidnym systemem i taki, który przerywa produkcję w najgorszym momencie.
5 głównych wyzwań
- Kontekst Zanieczyszczenie: gdy agent uwzględnia informacje na swoich wynikach nieistotne lub hałaśliwe, które negatywnie wpływają na kolejnych agentów. Rozwiązanie: zdefiniuj dane wyjściowe schematu strukturalnego (JSON/Pydantic) zamiast wolnego tekstu.
- Propagacja błędów: wzmacniany jest błąd w agencie nadrzędnym poprzez rurociąg, generując wyniki, które są coraz bardziej odległe od prawdy. Rozwiązanie: walidacja wyników na każdym etapie z walidacją schematu i rezerwą.
- Eksplozja kosztów: może wygenerować pętlę przeglądu, która nie jest zbieżna setki wywołań API i koszty rzędu kilkudziesięciu dolarów za zadanie. Rozwiązanie: śledzenie budżetu z twardymi limitami i wyłącznikiem automatycznym.
- Niespójność między agentami: dwóch agentów może zatrudniać różnych pracowników w tym samym punkcie architektonicznym, generując niespójny kod. Rozwiązanie: wspólne dokument stanu jawnego lub dokumentu kontekstu wspólnego.
- Złożoność monitorowania: powyżej 5 agentów debugowanie staje się wykładniczo bardziej złożone. Rozwiązanie: śledzenie rozproszone z identyfikatorem korelacji dla każdego zadania i ujednoliconą strukturę dziennika.
Ważna statystyka, o której warto pamiętać: badania przeprowadzone w 2025 r. pokazują, że wykracza to poza nią Zarządzanie 75% systemów wieloagentowych staje się trudne w przypadku ich przekroczenia 5, głównie ze względu na wykładniczy wzrost złożoności debugowania i monitorowanie. Zawsze zaczynaj od minimalnej potrzebnej liczby agentów.
Najlepsze praktyki dotyczące skutecznych systemów wieloagentowych
1. Specjalizacja chirurgiczna agentów
Każdy agent musi to mieć jedną podstawową odpowiedzialność i zestaw
minimum narzędzi niezbędnych do jego wykonania. Agent, który robi wszystko i w praktyce a
agent, który nie robi nic dobrego. W definicji system_message lub
z backstory, bądź konkretny: „jesteś inżynierem bezpieczeństwa specjalizującym się w
OWASP Top 10” i nieskończenie skuteczniejsze niż „czy jesteś ekspertem ds. bezpieczeństwa”.
2. Dane wyjściowe schematu strukturalnego
Użyj modeli Pydantic lub schematu JSON, aby zdefiniować wyniki oczekiwane od każdego agenta.
Dowolny tekst wprowadza niejednoznaczność, która wzmacnia się w potoku.
Środek wytwarzający a ReviewReport z polami
critical_issues: List[Issue] i nieskończenie bardziej niezawodny niż jeden
który generuje nieustrukturyzowany tekst do zinterpretowania przez następnego agenta.
3. Monitorowanie i obserwowalność
W środowisku produkcyjnym każde wywołanie agenta musi być śledzone za pomocą: znacznika czasu, używany model, token wejścia/wyjścia, koszt, opóźnienie i status. Do użytku LangGraph LangSmitha; w przypadku CrewAI korzystaj z obserwowalności przedsiębiorstwa; dla AG2 użyj OpenTelemetry. W przypadku systemów niestandardowych należy zawsze organizować dzienniki według identyfikatora korelacji.
4. Awaryjna i pełna wdzięku degradacja
Każdy agent krytyczny musi mieć rezerwę: prostszy agent (plus model ekonomiczne), odpowiedź w pamięci podręcznej lub ścieżka eskalacji człowieka. System musi nadal działać, nawet w sposób pogorszony, nawet w przypadku awarii agenta.
5. Ograniczone iteracje z wymuszoną zbieżnością
Każda pętla przeglądu musi mieć maksymalny limit iteracji.
Teoretycznie nie można zagwarantować konwergencji – pyta recenzent
zawsze się zmieniają i programista, który zawsze lekko je wdraża
w przeciwnym razie mógłby działać w nieskończoność. Zawsze ustawione max_iterations
i zaakceptuj „najlepsze dostępne”, gdy limit zostanie osiągnięty.
from pydantic import BaseModel, Field
from typing import List, Literal, Optional
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage
# ============================================================
# OUTPUT SCHEMA STRUTTURATI - Eliminano ambiguità tra agenti
# ============================================================
class Issue(BaseModel):
"""Singolo problema identificato nella code review."""
file_path: str = Field(description="Path del file con il problema")
line_number: Optional[int] = Field(default=None, description="Numero di riga")
severity: Literal["CRITICAL", "HIGH", "MEDIUM", "LOW"]
category: Literal["security", "logic", "performance", "style", "test_coverage"]
description: str = Field(description="Descrizione chiara del problema")
suggested_fix: str = Field(description="Fix raccomandata con esempio di codice")
class CodeReviewReport(BaseModel):
"""Report strutturato di code review."""
approved: bool = Field(description="True se il codice può essere mergato")
summary: str = Field(description="Sommario esecutivo in 2-3 frasi")
critical_issues: List[Issue] = Field(default_factory=list)
warnings: List[Issue] = Field(default_factory=list)
suggestions: List[Issue] = Field(default_factory=list)
security_score: int = Field(ge=0, le=100, description="Score sicurezza 0-100")
quality_score: int = Field(ge=0, le=100, description="Score qualità 0-100")
test_coverage_estimate: float = Field(
ge=0.0, le=1.0,
description="Stima copertura test (0.0-1.0)"
)
class SecurityAuditReport(BaseModel):
"""Report di security audit strutturato."""
has_critical_vulnerabilities: bool
owasp_findings: List[Issue] = Field(default_factory=list)
hardcoded_secrets: List[str] = Field(default_factory=list)
vulnerable_dependencies: List[str] = Field(default_factory=list)
remediation_priority: Literal["immediate", "high", "medium", "low"]
cvss_score_estimate: float = Field(ge=0.0, le=10.0)
# ============================================================
# UTILIZZO: agente con output strutturato
# ============================================================
def code_reviewer_with_schema(code: str) -> CodeReviewReport:
"""Agente code reviewer che produce output strutturato."""
model = ChatAnthropic(model="claude-sonnet-4-6")
# Usa structured output per garantire formato corretto
structured_model = model.with_structured_output(CodeReviewReport)
prompt = f"""Conduci una code review approfondita del seguente codice Python:
{code}
Analizza per: correttezza logica, qualità, sicurezza, performance e copertura test."""
report = structured_model.invoke([HumanMessage(content=prompt)])
return report
# ============================================================
# UTILIZZO NEL GRAFO LANGGRAPH
# ============================================================
def reviewer_node(state: dict) -> dict:
"""Nodo LangGraph che usa output strutturato."""
report = code_reviewer_with_schema(state["generated_code"])
return {
"review_approved": report.approved,
"critical_issues": [issue.model_dump() for issue in report.critical_issues],
"security_score": report.security_score,
"quality_score": report.quality_score,
# Il prossimo agente riceve dati strutturati, non testo ambiguo
"review_report": report.model_dump()
}
Wnioski: Przyszłość systemów wieloagentowych w roku 2026
Kodowanie wieloagentowe w 2025 r. przeszło od weryfikacji koncepcji do narzędzia gotowy do produkcji. LangGraph dominuje w przypadku złożonych i kontrolowanych przepływów pracy, CrewAI dla zespołów wirtualnych ze zdefiniowanymi rolami, AG2 do zadań eksploracyjnych rzeczywiste wykonanie kodu, a Claude Code do natywnej automatyzacji w ekosystemie Antropiczny.
Najważniejszym trendem na rok 2026 jest standaryzacja protokołów międzyagentowe: Model Context Protocol (MCP) i Agent-to-Agent (A2A) pojawiają się jako de facto standardy, które pozwolą agentom z różnych frameworków komunikować się ze sobą. Niedaleka przyszłość, w której agent LangGraph może wezwać specjalistę CrewAI który z kolei korzysta z narzędzia AG2, to nie science fiction: jest to już częściowo możliwe.
Dla programistów, którzy chcą zacząć od razu, rada jest praktyczna: nie zaczynaj z najbardziej wyrafinowanych frameworków. Zacznij od użycia dwóch agentów (programista + recenzent). narzędzie, które znasz najlepiej, mierz wyniki i tylko zwiększaj złożoność gdy problem naprawdę tego wymaga. Złota zasada inżynierii oprogramowania ma zastosowanie również tutaj: najlepszy i najprostszy system wieloagentowy, który rozwiązuje twój problem.
Zalecane kolejne kroki
- Poprzedni artykuł: prawa Agentyczne przepływy pracy: rozkładanie problemów dla sztucznej inteligencji aby zrozumieć, jak uporządkować zadania przed ich zrównolegleniem
- Następny artykuł: idź do Przetestuj kod wygenerowany przez sztuczną inteligencję dla strategii zapewniania jakości specyficznych dla kodu generowanego przez sztuczną inteligencję
- Bezpieczeństwo: prawa Bezpieczeństwo w kodowaniu Vibe do zarządzania lukami w systemach wieloagentowych
- Konkret Claude'a: dowiedz się więcej Kod Claude: Rozwój agenta terminalowego aby uzyskać szczegółowe informacje na temat natywnego systemu sub-agenta
Seria Vibe Coding i Agentic Development
To już czwarty artykuł z tej serii. Poprzednie artykuły obejmują paradygmat kodowania wibracji, Claude Code z terminala i rozkład Przepływy pracy agenta. Przyszłe artykuły będą dotyczyć testowania kodu wygenerowanego przez sztuczną inteligencję, szybka inżynieria dla IDE, bezpieczeństwo kodowania wibracyjnego i przyszłość rozwoju agenta w 2026 r.







