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 LlmAgent de solo lectura que inspecciona el código y devuelve un VERDICT: approve o un VERDICT: changes con notas.
  • synthesize agrega los veredictos y enruta a revise o finalize, 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_fn se 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 (y mark_deferred para nodos personalizados) aporta fan-in al constructor central de StateGraph — anteriormente solo el GraphAgentBuilder de 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 comandos code / goal).
  • Especialistas paralelos, revisión multi-etapa, refutación adversaria, enjambres → un flujo de trabajo adk-graph (el comando ultracode).

Siguiente: Ejemplos →