Workflows de Grafo (ultra-revisão)

Para qualquer coisa além de um único loop de agent — revisores paralelos, verificações adversariais, pipelines multiestágio — orquestre agents de codificação como um adk-graph StateGraph. É assim que o comando ultracode e o exemplo coding_graph funcionam.

O padrão "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)
  • implementar / revisar são CodingAgents completos (read/write/bash).
  • cada revisor é um LlmAgent somente leitura que inspeciona o código e retorna um VERDICT: approve ou VERDICT: changes com anotações.
  • sintetizar agrega os veredictos e os encaminha para revise ou finalize, limitado por um limite de rodadas + o limite de recursão do grafo.

Fan-out / fan-in em adk-graph

Duas capacidades adk-graph tornam isso correto:

  • Expansão paralela — vários nós alcançáveis a partir de um nó upstream executam concorrentemente no mesmo super-passo.
  • Barreira de convergência — um nó declarado com add_deferred_node_fn executa exatamente uma vez, somente depois que todos os seus caminhos upstream forem concluídos (não uma 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 (e mark_deferred para nós personalizados) traz a convergência para o builder StateGraph principal — anteriormente, apenas o de nível superior GraphAgentBuilder poderia declarar um nó adiado. Sem ele, um agregador com múltiplas arestas upstream seria acionado assim que o primeiro ramo terminasse.

Cada nó é um closure async que executa um agent e escreve seu resultado no estado do grafo; a aresta condicional lê decision para fazer um loop ou finalizar. Veja a implementação completa e executável no exemplo coding_graph e a referência Graph Agents para a API geral.

Quando usar um grafo vs. o harness

  • Agente único, trabalho linear/iterativo → apenas um CodingAgent (os comandos code / goal).
  • Especialistas paralelos, revisão em várias etapas, refutação adversarial, enxames → um fluxo de trabalho adk-graph (o comando ultracode).

Próximo: Exemplos →