Workflows de Graph (ultra-revue)
Pour tout ce qui dépasse une boucle d'agent unique — relecteurs parallèles, vérifications contradictoires, pipelines multi-étapes — orchestrez les agents de codage comme un adk-graph StateGraph. C'est ainsi que fonctionnent la commande ultracode et l'exemple coding_graph.
Le modèle "ultra"
START → implement ──┬─▶ review:correctness ─┐
├─▶ review:edge-cases ─┤ (parallel, real agents)
└─▶ review:style ─┤
▼
synthesize ← deferred fan-in (runs once)
│
decision ──────────┤
┌── "revise" ◀──────────┘
▼ └──▶ "finalize" → END
revise ─▶ (back to the reviewers)
- implémenter / réviser sont des
CodingAgents complets (lecture/écriture/bash). - chaque relecteur est un
LlmAgenten lecture seule qui inspecte le code et retourne unVERDICT: approveouVERDICT: changesavec des notes. - synthétiser agrège les verdicts et les achemine vers
reviseoufinalize, borné par un plafond de tours + la limite de récursion du graphe.
Fan-out / fan-in dans adk-graph
Deux capacités de adk-graph rendent cela correct :
- Fan-out parallèle — plusieurs nœuds atteignables depuis un nœud amont s'exécutent simultanément dans la même super-étape.
- Barrière de fan-in — un nœud déclaré avec
add_deferred_node_fns'exécute exactement une fois, seulement après que tous ses chemins amont sont terminés (pas une fois par amont).
use adk_graph::graph::StateGraph;
use adk_graph::{DeferredNodeConfig, MergeStrategy};
use adk_graph::edge::{START, END};
let graph = StateGraph::with_channels(&["task", "round", "decision", "notes",
"rev_correctness", "rev_edge-cases", "rev_style"])
.add_node_fn("implement", /* coding agent */)
.add_node_fn("review_correctness", /* read-only reviewer */)
.add_node_fn("review_edge-cases", /* … */)
.add_node_fn("review_style", /* … */)
// fan-in: runs once, after all three reviewers finish
.add_deferred_node_fn("synthesize", /* aggregate verdicts */,
DeferredNodeConfig { merge_strategy: MergeStrategy::Collect, fan_in_timeout: None })
.add_node_fn("revise", /* coding agent applies notes */)
.add_node_fn("finalize", /* done */)
.add_edge(START, "implement")
.add_edge("implement", "review_correctness")
.add_edge("implement", "review_edge-cases")
.add_edge("implement", "review_style")
.add_edge("revise", "review_correctness") // loop fans out again
.add_edge("revise", "review_edge-cases")
.add_edge("revise", "review_style")
.add_edge("review_correctness", "synthesize") // fan-in
.add_edge("review_edge-cases", "synthesize")
.add_edge("review_style", "synthesize")
.add_conditional_edges("synthesize",
|s| s.get("decision").and_then(|v| v.as_str()).unwrap_or("finalize").to_string(),
[("revise", "revise"), ("finalize", "finalize")])
.add_edge("finalize", END)
.compile()?
.with_recursion_limit(16);
add_deferred_node_fn(etmark_deferredpour les nœuds personnalisés) apporte le fan-in au constructeur de baseStateGraph— auparavant, seul leGraphAgentBuilderde niveau supérieur pouvait déclarer un nœud différé. Sans cela, un agrégateur avec plusieurs arêtes amont se déclencherait dès que la première branche serait terminée.
Chaque nœud est une async fermeture qui exécute un Agent et écrit son résultat dans l'état du graphe ; l'arête conditionnelle lit decision pour boucler ou terminer. Voir l'implémentation complète et exécutable dans l'exemple coding_graph et la référence Graph Agents pour l'API générale.
Quand utiliser un graphe par rapport au harnais
- Travail d'Agent unique, linéaire/itératif → juste un
CodingAgent(les commandescode/goal). - Spécialistes parallèles, révision multi-étapes, réfutation contradictoire, essaims → un
adk-graphflux de travail (la commandeultracode).
Suivant : Exemples →