Flujos de trabajo de grafos (ultra-review)
Para cualquier cosa más allá de un solo bucle de agent — revisores paralelos, verificaciones adversarias, pipelines de múltiples etapas — orquestar agentes de codificación como un adk-graph StateGraph. Así es como el comando ultracode y el ejemplo coding_graph funcionan.
El patrón "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)
- implement / revise son
CodingAgents completos (read/write/bash). - cada reviewer es un
LlmAgentde solo lectura que inspecciona el código y devuelve unVERDICT: approveo unVERDICT: changescon notas. - synthesize agrega los veredictos y enruta a
reviseofinalize, limitado por un tope de rondas + el límite de recursión del grafo.
Fan-out / fan-in en adk-graph
Dos adk-graph capacidades hacen que esto sea correcto:
- Parallel fan-out — varios nodos accesibles desde un nodo upstream se ejecutan concurrentemente en el mismo super-paso.
- Fan-in barrier — un nodo declarado con
add_deferred_node_fnse ejecuta exactamente una vez, solo después de que todas sus rutas upstream se completen (no una vez por upstream).
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(ymark_deferredpara nodos personalizados) aporta fan-in al constructor central deStateGraph— anteriormente solo elGraphAgentBuilderde nivel superior podía declarar un nodo diferido. Sin esto, un agregador con múltiples bordes upstream se activaría tan pronto como la primera rama terminara.
Cada nodo es un async closure que ejecuta un agent y escribe su resultado en el estado del grafo; el borde condicional lee decision para hacer un bucle o finalizar. Consulte la implementación completa y ejecutable en el ejemplo coding_graph y la referencia de Graph Agents para la API general.
Cuándo usar un grafo frente al harness
- Trabajo de agente único, lineal/iterativo → solo un
CodingAgent(los comandoscode/goal). - Especialistas paralelos, revisión multi-etapa, refutación adversaria, enjambres → un flujo de trabajo
adk-graph(el comandoultracode).
Siguiente: Ejemplos →