Foundry Agent Service
Key Points
- Foundry Agent Service = managed agent runtime. Handles thread state, tool execution, runs.
- Built-in tools: code interpreter, file search (RAG), Bing search, Azure AI Search, OpenAPI.
- vs self-hosted Agent Framework: managed thread storage, scaled runs, integrated evals.
- Trade-off: vendor-coupled; Foundry-only.
- For greenfield Azure agent apps: solid choice.
Concept
[Your app]
│
│ projectClient.GetAgentsClient()
▼
[Foundry Agent Service]
│
├─ Threads (persistent conversations)
├─ Agents (instructions + tools + model)
├─ Runs (execution of agent over thread)
└─ Built-in tools
Create agent
var agentsClient = projectClient.GetAgentsClient();
var agent = await agentsClient.CreateAgentAsync(new()
{
Name = "TripPlanner",
Model = "gpt-4o-mini",
Instructions = "You are a helpful travel planner.",
Tools = [
new CodeInterpreterTool(),
new FileSearchTool { VectorStoreIds = [vectorStoreId] },
new BingGroundingTool { ConnectionId = bingConnId }
]
});
Threads
var thread = await agentsClient.CreateThreadAsync();
await agentsClient.CreateMessageAsync(thread.Id, MessageRole.User, "Plan a 5-day Rome trip");
Threads persist across runs; client just sends new messages.
Runs
var run = await agentsClient.CreateRunAsync(thread.Id, agent.Id);
while (run.Status is "queued" or "in_progress" or "requires_action")
{
if (run.Status is "requires_action" && run.RequiredAction is SubmitToolOutputsAction action)
{
// Custom tools require client-side execution
var outputs = action.SubmitToolOutputs.ToolCalls.Select(c => /* execute */).ToList();
run = await agentsClient.SubmitToolOutputsAsync(thread.Id, run.Id, outputs);
}
else
{
await Task.Delay(500);
run = await agentsClient.GetRunAsync(thread.Id, run.Id);
}
}
var messages = await agentsClient.GetMessagesAsync(thread.Id);
Polling-based. Streaming option also available.
Built-in tools
Code interpreter
Sandboxed Python. Agent writes + executes code; returns stdout, files, plots.
File search (RAG)
var fileStore = await projectClient.GetVectorStoresClient().CreateAsync(...);
await fileStore.UploadFileAsync(stream, "doc.pdf");
new FileSearchTool { VectorStoreIds = [fileStore.Id] }
Auto-chunks, embeds, indexes. Agent retrieves automatically.
Bing grounding
Web search; cited sources.
Azure AI Search
RAG over existing Azure AI Search index.
OpenAPI
new OpenApiTool
{
Spec = openApiSpecJson,
Auth = new OpenApiManagedIdentityAuth { Audience = "..." }
};
Agent calls any REST API defined by OpenAPI spec.
Custom function tools
Same as AIFunction; client-side execution via requires_action flow above.
Streaming
await foreach (var update in agentsClient.CreateRunStreamingAsync(thread.Id, agent.Id))
{
/* token / status updates */
}
Evaluations
var evalRun = await projectClient.GetEvaluationsClient().CreateRunAsync(new()
{
AgentId = agent.Id,
Dataset = ...,
Metrics = ["groundedness", "relevance"]
});
Run evals over agent → metrics → dashboard.
Compared to Agent Framework
| Aspect | Foundry Agent Service | Agent Framework (self-hosted) |
|---|---|---|
| Hosting | Managed | Your code |
| Thread state | Foundry stores | Your DB |
| Built-in tools | Many | None (via MCP) |
| Code interpreter | ✅ | DIY |
| Cost | Per-run + tokens | Token-only |
| Vendor lock-in | High | Low |
For greenfield Azure agent app with built-in tools needed: Foundry. For portable code: Agent Framework.
Costs
- Tokens (model usage).
- Tool execution (code interpreter has compute cost).
- Storage (threads, files).
Senior considerations
- Built-in tools save time but lock to Foundry.
- Polling vs streaming: streaming better UX.
- Thread cleanup: archive old threads to save storage.
- Eval runs: regression tracking.
- Hybrid: use Foundry for some agents; Agent Framework for others.