Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

embr-foundry-multi-agent-sample

A planner → executor → reviewer multi-agent orchestrator running as a single Python app on Embr. Three Foundry agents collaborate to handle one user task, with a feedback loop until the Reviewer ships an answer or max iterations is hit.

This sample is the "bounded 2–5 agent orchestrator" shape — a small, scoped pattern that's currently the only multi-agent topology with reliable production results (per Microsoft strategy/research docs). It deliberately avoids open-ended swarms, hand-offs, and dynamic agent allocation.

What it demonstrates

Agent Foundry name Tools Role
Planner embr-multi-agent-planner none Decompose task into 1–5 steps, return JSON
Executor embr-multi-agent-executor lookup_fact, do_math Run each step, optionally calling a tool
Reviewer embr-multi-agent-reviewer none Decide ship-or-revise, synthesize final answer

The orchestration loop lives in app/orchestrator.py:

for i in range(max_iterations):
    plan = planner(task, prior_feedback)
    step_results = [executor(step) for step in plan.steps]   # tools resolved here
    review = reviewer(task, plan, step_results)
    if review.verdict == "ship": return review.final_answer
    feedback = review.reason
return last_review.final_answer  # max-iterations

Each agent is created lazily on first use and reused-by-name across cold starts. All three share the same AgentsClient and the same service principal credential.

Required environment variables

Var Required Purpose
FOUNDRY_PROJECT_ENDPOINT yes Foundry project endpoint, e.g. https://{name}.services.ai.azure.com/api/projects/{project}
FOUNDRY_MODEL_DEPLOYMENT yes Foundry model deployment name (e.g. gpt-5.4-mini-1)
AZURE_TENANT_ID on Embr SP tenant id
AZURE_CLIENT_ID on Embr SP client id
AZURE_CLIENT_SECRET on Embr SP client secret
EMBR_AGENT_FORCE_RECREATE no If 1, recreate all three agents on every cold start

Run locally

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
az login
export FOUNDRY_PROJECT_ENDPOINT="https://{name}.services.ai.azure.com/api/projects/{project}"
export FOUNDRY_MODEL_DEPLOYMENT="gpt-5.4-mini-1"
uvicorn app.main:app --reload --port 8000

Then open http://localhost:8000 and try:

What is 17 * 23 plus the number of departments at Embr Corp?

The Planner should produce two steps: one calling do_math, one calling lookup_fact("departments"). The Reviewer synthesizes the final number.

You can also POST directly:

curl -s http://localhost:8000/api/run \
  -H 'content-type: application/json' \
  -d '{"task":"What is 17 * 23 plus the number of departments at Embr Corp?","max_iterations":2}' \
  | jq .

API

Method + path Purpose
GET /health {"status":"ok"}
GET /api/config model, shape, auth mode, Foundry host, agent names
GET /api/agents {planner_id, executor_id, reviewer_id} (creates on first call — surfaces 3× cold-start)
POST /api/run body {task, max_iterations?} → full trace {final_answer, verdict, iteration_count, iterations[...], latency_ms}

Deploy to Embr

embr quickstart deploy embr-devs/embr-foundry-multi-agent-sample -i 120233234

Then set env vars (replace placeholders with your SP credentials):

PROJ=<projectId>; ENV=<environmentId>
embr variables set FOUNDRY_PROJECT_ENDPOINT 'https://...services.ai.azure.com/api/projects/proj-default' -p $PROJ -e $ENV
embr variables set FOUNDRY_MODEL_DEPLOYMENT 'gpt-5.4-mini-1' -p $PROJ -e $ENV
embr variables set AZURE_TENANT_ID '<tenant-guid>' -p $PROJ -e $ENV
embr variables set AZURE_CLIENT_ID '<sp-client-id>' -p $PROJ -e $ENV
embr variables set AZURE_CLIENT_SECRET '<sp-client-secret>' -p $PROJ -e $ENV

Embr platform findings

This sample was built specifically to surface gaps Embr needs to close before "real" multi-agent workloads run well on the platform:

  1. 3-agent cold-start cost is linear. Each list_agents() round-trip is ~500ms–2s of AAD + Foundry latency, and we do one per role on first use. With three agents, the first request after a deploy/restart pays ~3× the single-agent cost. Embr has no warm-pool / pre-warm primitive — the app has to either eagerly construct all agents at boot (slowing startup) or pay the cost on the first user request.
  2. In-app orchestration only. All inter-agent state (plans, step results, reviewer feedback, iteration counter) lives in app memory. There is no durable workflow, no checkpoint, no resumable run primitive on Embr today. An app restart mid-task drops the entire run.
  3. Same SP creds across all agents. Planner, Executor, and Reviewer share one ClientSecretCredential. Embr exposes neither managed identity nor per-agent identity scoping, so there's no way to grant the Executor a narrower set of tool/data permissions than the Planner — a common ask for "least-privilege per agent" in customer-facing systems.
  4. Long-running requests hit ingress timeouts. The orchestrator runs the full plan → execute → review loop synchronously inside the HTTP request thread. Two iterations × three steps × tool round-trips can easily exceed 30–60s, which butts up against ingress / proxy timeouts. Embr has no async-job / fan-out primitive to offload this — see the worker sample for the related finding.

File layout

embr-foundry-multi-agent-sample/
├── app/
│   ├── __init__.py
│   ├── agents.py         # 3 agent factories + shared AgentsClient + creds
│   ├── orchestrator.py   # planner → executor → reviewer loop
│   ├── tools.py          # lookup_fact, do_math
│   ├── main.py           # FastAPI: /api/run, /api/agents, /api/config
│   └── static/index.html # dark/mono trace UI
├── embr.yaml             # Python 3.12, port 8000, /health
├── requirements.txt
└── README.md

About

Embr POC #5: in-app multi-agent orchestration (planner / executor / reviewer) using Foundry Agents SDK

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages