멀티 에이전트 오케스트레이션 패턴 템플릿 (SPEC §6, R5; 트렌드 보고서 Tier 2.5).
빌딩 블록은 기존 프리미티브뿐이다 — 조건부 엣지 + 노드(워커) + :messages 채널. 신규
추상화 없이, 자주 쓰는 멀티 에이전트 형태를 미리 조립한 컴파일된 그래프로 제공한다.
supervisor (오케스트레이터-워커)
오케스트레이터 노드가 LLM으로 다음 워커를 고르고(또는 종료), 조건부 엣지가 해당 워커로
라우팅한다. 워커는 결과를 :messages에 append하고 오케스트레이터로 복귀한다. max_steps로
라운드 폭주를 막는다.
workers = [
%{name: :researcher, description: "gathers facts", run: &MyApp.research/2},
%{name: :writer, description: "writes the answer", run: &MyApp.write/2}
]
graph = ElGraph.Orchestration.supervisor(llm, workers, system: "...")
ElGraph.invoke(graph, %{messages: [ElGraph.LLM.user("Write a report")]})magentic (task-ledger)
magentic/3 is supervisor/3 plus a task ledger and a stall guard
(magentic-one pattern). The ledger (:ledger channel) records every worker the
orchestrator chooses; when the same worker is picked more than :max_stalls
times in a row the run is forced to terminate, defusing the classic
"agent loops forever" failure.
Cross-agent handoff
In both templates worker results flow back to the orchestrator purely via the
shared :messages channel — a worker appends its output and the orchestrator
reads the full transcript on its next turn. Direct, out-of-band handoff between
agents is also expressible without new orchestration code: have a worker emit on
the signal bus (ElGraph.Skills.SignalReAct :emit) and have the target worker
subscribe — the bus delivers the payload independently of the :messages
transcript. The orchestration templates here deliberately stick to :messages;
the signal bus is the escape hatch when you need agent-to-agent side-channels.
Summary
Types
magentic 작업 원장 — 작업(task) + 누적 사실(facts) + 진행(chosen/stalls). (magentic-one 패턴)
워커 스펙: 노드 이름(atom) + 설명 + 실행 함수((state, ctx) -> 상태 업데이트).
Functions
group-chat 그래프를 빌드한다 — 스피커 선택 정책으로 매 턴 발화자를 고른다.
magentic(task-ledger) 그래프를 빌드한다 — supervisor/3 + 작업 원장 + 정체(stall) 가드.
오케스트레이터-워커 그래프를 빌드한다.
Types
@type ledger() :: %{ task: String.t() | nil, chosen: [atom()], facts: [String.t()], stalls: non_neg_integer() }
magentic 작업 원장 — 작업(task) + 누적 사실(facts) + 진행(chosen/stalls). (magentic-one 패턴)
@type worker() :: %{ name: atom(), description: String.t(), run: (map(), ElGraph.Ctx.t() -> map()) }
워커 스펙: 노드 이름(atom) + 설명 + 실행 함수((state, ctx) -> 상태 업데이트).
Functions
@spec group_chat( [worker()], keyword() ) :: ElGraph.Graph.t()
group-chat 그래프를 빌드한다 — 스피커 선택 정책으로 매 턴 발화자를 고른다.
opts: :select((state -> agent_name | :end) 순수 정책 — 미지정 시 :rounds회
라운드로빈), :rounds(기본 6), :max_steps.
@spec magentic({module(), term()}, [worker()], keyword()) :: ElGraph.Graph.t()
magentic(task-ledger) 그래프를 빌드한다 — supervisor/3 + 작업 원장 + 정체(stall) 가드.
오케스트레이터가 매 턴 다음 워커를 고르고, 선택을 원장(:ledger.chosen)에 기록한다.
동일 워커를 :max_stalls회를 초과해 연속 선택하면(기본 2) 강제 종료한다 —
"에이전트 무한 루프" 실패를 막는 결정적·테스트 가능한 가드다.
opts: :system(시스템 프롬프트 보강), :max_stalls(기본 2), :max_steps(기본 25).
@spec supervisor({module(), term()}, [worker()], keyword()) :: ElGraph.Graph.t()
오케스트레이터-워커 그래프를 빌드한다.
opts: :system(오케스트레이터 시스템 프롬프트 보강), :max_steps(기본 25).