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
LlmAgentsomente leitura que inspeciona o código e retorna umVERDICT: approveouVERDICT: changescom anotações. - sintetizar agrega os veredictos e os encaminha para
reviseoufinalize, 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_fnexecuta 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(emark_deferredpara nós personalizados) traz a convergência para o builderStateGraphprincipal — anteriormente, apenas o de nível superiorGraphAgentBuilderpoderia 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 comandoscode/goal). - Especialistas paralelos, revisão em várias etapas, refutação adversarial, enxames →
um fluxo de trabalho
adk-graph(o comandoultracode).
Próximo: Exemplos →