Foundry Agent Service & the SDK
Build and run the agent from code on the managed Foundry Agent Service — connect with the SDK, create an agent, run it over a thread, and meet the OpenAI-compatible Responses path. Python-primary, with the .NET equivalent noted.
Download starter repoOn this page▾
- Before you start: this is a billed Azure service
- About this series
- What you'll build
- Why this matters (the 5-minute business case)
- Concepts you'll use (2-minute primer)
- Prerequisites
- Step 1 — Connect to your project
- Step 2 — Create the agent
- Step 3 — Run it over a thread
- Step 4 — The OpenAI-compatible path (optional)
- Cost & cleanup
- Verified against
- What's next
Before you start: this is a billed Azure service
- Cost and account. An Azure subscription, a Foundry project, and a model deployment (from Lab 1). Running an agent makes model calls that bill per token. Clean up test agents at the end.
- Authored against the docs, not executed live. The code here is written against the official SDK docs and syntax-checked, not run against a live subscription during authoring. The Foundry/Agents SDK is at 2.x (beta) and method names move — pin your SDK version and verify against the docs for your version.
- Two languages. This lab leads with Python and notes the .NET equivalent. JS/TS and Java SDKs also exist.
About this series
This is Part 2 of the twelve-part Microsoft Foundry series. Lab 1 built a no-code agent in the portal. This lab builds and runs the same kind of agent from code with the Foundry SDK — the foundation every later lab plugs into.
What you'll build
You'll recreate the Acme Orders assistant in code and run it:
- Connect to your Foundry project with the SDK and
DefaultAzureCredential. - Create an agent — a model deployment + instructions (and later, tools).
- Run it over a thread, the managed conversation primitive.
- Read the result, and see the OpenAI-compatible Responses path.
By the end you'll understand the hosted execution model and have a code-defined agent — the thing the rest of the series extends.
Why this matters (the 5-minute business case)
Read this before handing the lab to your team.
The portal is for prototyping; code is for production. A portal agent can't be version-controlled, code-reviewed, tested in CI, or deployed through your pipelines. Moving the agent into the SDK is what turns a promising demo into real, maintainable software — and it's the point where an agent becomes a first-class part of your engineering process.
Three reasons this is a leadership-level concern:
- Code-defined agents are real software. In the SDK, an agent is text in version control — diffable, reviewable, testable, and deployable like anything else your team ships. That's the difference between an agent your team can operate and one trapped in a console.
- Managed runtime, no infrastructure. The Agent Service runs the agent, manages threads/state, and scales — you call an endpoint. For a team without a platform group, that removes most of the operational burden of shipping an agent.
- OpenAI wire-compatibility is portability. The Agent Service is built on the OpenAI Responses API and is wire-compatible with OpenAI agents. Code you write here is more portable and less locked-in than a proprietary surface — the same anti-lock-in theme as the multi-model catalog.
The honest caveats:
- The SDK is young (2.x beta) and moving. Method names (
create_versionvscreate_agent, the threads/runs vs Responses surfaces) differ across versions. Pin your version and budget for upgrades. - Managed means less control. You trade runtime knobs for not operating a runtime. Good for most teams; weigh it if you have hard environment requirements.
- It bills per call. Every run is model usage. Fine for production; tear down test loops.
A framing for a non-technical stakeholder: "Moving the agent into code makes it real software our team can test, review, and ship through our normal process — running on a managed service so we don't operate infrastructure."
Concepts you'll use (2-minute primer)
- `AIProjectClient` — the SDK entry point. You point it at your project endpoint and authenticate with
DefaultAzureCredential(no keys in code). - Agent — a model deployment + instructions (+ tools). You create it via the
.agentssurface. - Thread — the managed conversation: you add messages to a thread and run the agent against it; the service keeps the history.
- Run — one execution of the agent over a thread; you create it and read the result.
- The OpenAI-compatible client —
.get_openai_client()gives you an OpenAI-style client for the Responses API, evaluations, and model calls — the wire-compatible path.
One sentence: connect with `AIProjectClient`, create an agent, run it on a thread, read the result — on a managed, OpenAI-compatible service.
Prerequisites
| You need | Notes |
|---|---|
| A Foundry project + model deployment | From Lab 1 |
| Azure CLI + auth | az login; code uses DefaultAzureCredential |
| Python 3.10+ | A fresh virtualenv is recommended |
| The SDK | pip install azure-ai-projects azure-identity — pin versions |
| An IAM role | An appropriate role on the project resource (e.g., Azure AI User) |
Set your project endpoint as an env var (find it in the portal under your project's overview):
export FOUNDRY_PROJECT_ENDPOINT="https://<your-project>.services.ai.azure.com/api/projects/<name>"
az loginStep 1 — Connect to your project
import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
project = AIProjectClient(
endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=DefaultAzureCredential(),
)DefaultAzureCredential picks up your az login session locally and a managed identity in production — so there are no API keys in your code.
.NET equivalent: add theAzure.AI.ProjectsandAzure.IdentityNuGet packages and constructnew AIProjectClient(new Uri(endpoint), new DefaultAzureCredential()). The shapes mirror the Python SDK.
Step 2 — Create the agent
Create the Acme Orders assistant from your model deployment and an instruction:
agent = project.agents.create_version(
agent_name="acme-orders-assistant",
definition={
"model": "gpt-5-mini", # your model DEPLOYMENT name from Lab 1
"instructions": (
"You are the Acme Orders assistant. You help customers check the "
"status, total, and delivery date of their orders. Always ask for "
"an order ID if the customer hasn't provided one. Be concise and "
"friendly. If you don't have the information, say so plainly — "
"never guess an order's status."
),
},
)
print(agent.name)The exact creation call differs across SDK versions — newer builds usecreate_version(...)with a prompt-agent definition; some usecreate_agent(model=..., name=..., instructions=...). Pin your version and check the docs; the concept (model deployment + instructions) is stable.
Step 3 — Run it over a thread
Threads are the managed conversation primitive — create one, add a message, run the agent:
thread = project.agents.threads.create()
project.agents.messages.create(
thread_id=thread.id,
role="user",
content="What's the status of order AC-10231?",
)
run = project.agents.runs.create_and_process(
thread_id=thread.id,
agent_name="acme-orders-assistant",
)
# Read the messages back (newest last):
for msg in project.agents.messages.list(thread_id=thread.id):
print(msg.role, msg.content)create_and_process runs the agent and waits for it to finish. Send another message against the same `thread.id` and the service keeps the conversation in context — that managed continuity is what you'd otherwise build yourself.
Step 4 — The OpenAI-compatible path (optional)
Because the Agent Service is built on the Responses API, you can also drive it with an OpenAI-style client:
openai_client = project.get_openai_client()
response = openai_client.responses.create(
model="gpt-5-mini", # your deployment name
input="What's Acme's standard shipping time?",
)
print(response.output_text)This is the wire-compatibility payoff: code written against the OpenAI Responses shape ports with minimal changes, which is what keeps you from being locked into a proprietary surface.
Cost & cleanup
- Each run is model usage and bills per token — tear down test loops.
- Delete the test agent when you're done:
project.agents.delete_version(agent_name="acme-orders-assistant") # method name varies by version- Confirm in Cost Management that nothing unexpected is accruing.
If a lab created it and you're done, delete it today.
Verified against
- Microsoft Foundry Agent Service docs and the `azure-ai-projects` / Agents SDK 2.x (beta), June 2026;
.NETviaAzure.AI.Projects. - Creation/run/delete method names and the agent-definition shape vary across SDK versions; code is syntax-checked against the docs but not executed during authoring. Pin your version.
What's next
You have a code-defined agent on the managed runtime. Next:
- Lab 3 — Grounding with Foundry IQ: make the agent answer from your documents and data, with citations.
- From here the series adds capabilities to this agent: tools (Lab 4), memory (Lab 5), evaluation (Lab 6), safety (Lab 7), identity (Lab 8), and on through observability and the interoperability capstone.
Written by Wes Goldwater, Director of Engineering at Prosigliere.
Hands-on cloud & pragmatic AI from Goldwater.dev.