Skip to content

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

new CodeInterpreterTool()

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

new BingGroundingTool { ConnectionId = bingConnId }

Web search; cited sources.

new AzureAISearchTool { ConnectionId = searchConnId, IndexName = "my-index" }

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.

Cross-references