Develop Agents using the Azure AI Foundry platform, leveraging an extensive ecosystem of models, tools, and capabilities from OpenAI, Microsoft, and other LLM providers.
Note: This package is dedicated to performing CRUD operations on Agents and can be used to enable telemetry.
Product documentation | Samples | API reference documentation | Package (NuGet) | SDK source code
- Getting started
- Key concepts
- Additional concepts
- Examples
- Tracing
- Troubleshooting
- Next steps
- Contributing
To use Azure AI Agents capabilities, you must have an Azure subscription. This will allow you to create an Azure AI resource and get a connection URL.
Install the client library for .NET with NuGet:
dotnet add package Azure.AI.Projects.Agents --prerelease
You must have an Azure subscription. In order to take advantage of the C# 8.0 syntax, it is recommended that you compile using the .NET Core SDK 3.0 or higher with a language version of
latest.
To be able to create, update, and delete Agents, please use AgentAdministrationClient. It is a good practice to only allow these operations for users with elevated permissions, for example, administrators.
var projectEndpoint = System.Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT");
var modelDeploymentName = System.Environment.GetEnvironmentVariable("FOUNDRY_MODEL_NAME");
AgentAdministrationClient agentsClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential());When clients send REST requests to the endpoint, one of the query parameters is api-version. It allows us to select the API versions supporting different features. The current stable version is v1 (default).
The API version may be set by supplying the version parameter to the AgentAdministrationClientOptions constructor as shown in the example code below.
AgentAdministrationClientOptions options = new(version: AgentAdministrationClientOptions.ServiceVersion.V1);
AgentAdministrationClient agentsClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential(), options: options);The Azure.AI.Projects.Agents framework is organized so that for each call requiring a REST API request, there are synchronous and asynchronous counterparts, where the latter has the "Async" suffix. For example, the following code demonstrates the creation of a ProjectsAgentVersion object.
Synchronous call:
DeclarativeAgentDefinition agentDefinition = new(model: modelDeploymentName)
{
Instructions = "You are a prompt agent."
};
ProjectsAgentVersion agentVersion1 = agentsClient.CreateAgentVersion(
agentName: "myAgent1",
options: new(agentDefinition));
Console.WriteLine($"Agent created (id: {agentVersion1.Id}, name: {agentVersion1.Name}, version: {agentVersion1.Version})");
ProjectsAgentVersion agentVersion2 = agentsClient.CreateAgentVersion(
agentName: "myAgent2",
options: new(agentDefinition));
Console.WriteLine($"Agent created (id: {agentVersion2.Id}, name: {agentVersion2.Name}, version: {agentVersion2.Version})");Asynchronous call:
DeclarativeAgentDefinition agentDefinition = new(model: modelDeploymentName)
{
Instructions = "You are a prompt agent."
};
ProjectsAgentVersion agentVersion1 = await agentsClient.CreateAgentVersionAsync(
agentName: "myAgent1",
options: new(agentDefinition));
Console.WriteLine($"Agent created (id: {agentVersion1.Id}, name: {agentVersion1.Name}, version: {agentVersion1.Version})");
ProjectsAgentVersion agentVersion2 = await agentsClient.CreateAgentVersionAsync(
agentName: "myAgent2",
options: new(agentDefinition));
Console.WriteLine($"Agent created (id: {agentVersion2.Id}, name: {agentVersion2.Name}, version: {agentVersion2.Version})");In most of the code snippets we will show only the asynchronous sample for brevity. Please refer to the individual samples for both synchronous and asynchronous code.
When creating Agents, we need to supply Agent definitions to the constructor. To create a declarative prompt Agent, use the DeclarativeAgentDefinition:
DeclarativeAgentDefinition agentDefinition = new(model: modelDeploymentName)
{
Instructions = "You are a prompt agent."
};
ProjectsAgentVersion agentVersion1 = await agentsClient.CreateAgentVersionAsync(
agentName: "myAgent1",
options: new(agentDefinition));
Console.WriteLine($"Agent created (id: {agentVersion1.Id}, name: {agentVersion1.Name}, version: {agentVersion1.Version})");
ProjectsAgentVersion agentVersion2 = await agentsClient.CreateAgentVersionAsync(
agentName: "myAgent2",
options: new(agentDefinition));
Console.WriteLine($"Agent created (id: {agentVersion2.Id}, name: {agentVersion2.Name}, version: {agentVersion2.Version})");The code above will result in the creation of a ProjectsAgentVersion object, which is the data object containing the Agent's name and version.
Note: This is a preview feature; to use it the AAIP001 warning needs to be ignored.
#pragma warning disable AAIP001If the Agent Version is not ready for production, it may be created with the Draft flag set to true. The draft Agent version
is a string like draft-1784249270168. The draft will not be set as the Agent's latest version.
Create AgentAdministrationClient with the draft feature enabled:
var projectEndpoint = System.Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT");
var modelDeploymentName = System.Environment.GetEnvironmentVariable("FOUNDRY_MODEL_NAME");
AgentAdministrationClient agentsClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential());Create a draft version:
agentDefinition = new(model: modelDeploymentName)
{
Instructions = "You are a prompt agent which gives wrong answers with 0.1 probability."
};
ProjectsAgentVersion agentVersionDraft = await agentsClient.CreateAgentVersionAsync(
agentName: agent.Name,
options: new(agentDefinition)
{
Draft = true
}
);
Console.WriteLine($"Agent created draft name: {agentVersionDraft.Name}, version: {agentVersionDraft.Version}");
agent = await agentsClient.GetAgentAsync(agentName: agentVersion1.Name);
Console.WriteLine($"The latest version of agent \"{agent.Name}\" is still {agent.Versions.Latest.Version}.");By default, draft versions are not listed. To include them, includeDrafts needs to be set to true.
Console.WriteLine($"Here are \"release\" versions of the agent {agent.Name}:");
await foreach (ProjectsAgentVersion agentVersion in agentsClient.GetAgentVersionsAsync(agentName: agent.Name, includeDrafts: true))
{
Console.WriteLine($" {agentVersion.Version}, is draft: {agentVersion.Draft ?? false}");
}Hosted agents simplify custom agent deployment in a fully controlled environment (see more).
To create a hosted agent from an existing Docker image, please use the HostedAgentDefinition while creating the AgentVersion object.
private static HostedAgentDefinition GetAgentDefinition(string dockerImage)
{
HostedAgentDefinition agentDefinition = new(
versions: [new ProtocolVersionRecord(ProjectsAgentProtocol.Responses, "1.0.0")],
cpu: "0.5",
memory: "1Gi"
)
{
ContainerConfiguration = new(dockerImage),
};
return agentDefinition;
}The following code will deploy the hosted Agent.
Uri uriEndpoint = new(projectEndpoint);
AgentAdministrationClient agentsClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential());
HostedAgentDefinition agentDefinition = GetAgentDefinition(
dockerImage: dockerImage
);
ProjectsAgentVersionCreationOptions creationOptions = new(agentDefinition);
creationOptions.Metadata["enableVnextExperience"] = "true";
ProjectsAgentVersion agentVersion = await agentsClient.CreateAgentVersionAsync(
agentName: hostedAgentName,
options: creationOptions);
while (agentVersion.Status != AgentVersionStatus.Active && agentVersion.Status != AgentVersionStatus.Failed)
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
agentVersion = await agentsClient.GetAgentVersionAsync(agentName: agentVersion.Name, agentVersion: agentVersion.Version);
}
if (agentVersion.Status != AgentVersionStatus.Active)
{
throw new InvalidOperationException($"Agent deployment failed, status: {agentVersion.Status}.");
}Hosted Agents can also be deployed using local code. To deploy the Agent from code, please prepare the folder with the Agent code and dependencies. In the example below, we use C# source code.
- Create a project and add
Azure.AI.AgentServer.Responsespackage as a dependency.
dotnet new console --name EchoAgent --output EchoAgent
dotnet add package Azure.AI.AgentServer.Responses --prerelease- Populate the code in Program.cs
using Azure.AI.AgentServer.Responses;
using Azure.AI.AgentServer.Responses.Models;
ResponsesServer.Run<EchoHandler>();
public class EchoHandler : ResponseHandler
{
public override IAsyncEnumerable<ResponseStreamEvent> CreateAsync(
CreateResponse request,
ResponseContext context,
CancellationToken cancellationToken)
{
return new TextResponse(context, request,
createText: async ct =>
{
var input = await context.GetInputTextAsync(cancellationToken: ct);
return $"Echo: {input}";
});
}
}- Compile the application.
dotnet publishThis will create the publish output in the bin\Release\net%version%\publish\ folder, where %version% is the .NET version used to build the application.
4. Copy the contents of publish folder to Assets/AgentsCode.
Note: In this example we are uploading the project. It is also possible to place source codes and a C# project file to the Assets/AgentsCode folder. In this case we will need to set dependencyResolution: CodeDependencyResolution.RemoteBuild.
Prepare the metadata for Agent:
private static AgentVersionFromCodeMetadata GetAgentMetadata()
{
HostedAgentDefinition agentDefinition = new(
cpu: "0.5",
memory: "1Gi"
)
{
Versions = { new ProtocolVersionRecord(ProjectsAgentProtocol.Responses, "1.0.0") },
CodeConfiguration = new(
runtime: "dotnet_10",
entryPoint: ["dotnet", "EchoAgent.dll"],
dependencyResolution: CodeDependencyResolution.Bundled
),
};
AgentVersionFromCodeMetadata metadata = new(agentDefinition);
metadata.Metadata["enableVnextExperience"] = "true";
return metadata;
}Deploy the Agent.
AgentAdministrationClient agentsClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential());
ProjectsAgentVersion agentVersion = await agentsClient.CreateAgentVersionFromCodeAsync(
agentName: "myCodeAgent",
filePath: GetDirectory(Path.Combine(["AgentsCode"])),
metadata: GetAgentMetadata()
);
while (agentVersion.Status != AgentVersionStatus.Active && agentVersion.Status != AgentVersionStatus.Failed)
{
await Task.Delay(500);
agentVersion = await agentsClient.GetAgentVersionAsync(agentName: agentVersion.Name, agentVersion: agentVersion.Version);
}
if (agentVersion.Status != AgentVersionStatus.Active)
{
throw new InvalidOperationException($"The Agent deployment failed, status: {agentVersion.Status}");
}Hosted agents may be disabled. In this case, the task running in an existing session will complete, but no new tasks or session creations will be allowed. An attempt to create a session on a disabled Agent will result in a 403 error.
await agentsClient.DisableAgentAsync(agentVersion.Name);
// The new session cannot be created.
try
{
await agentsClient.CreateSessionAsync(agentVersion.Name, new VersionRefIndicator(agentVersion.Version));
throw new InvalidOperationException("Stopped Agent was unexpectedly able to create session.");
}
catch (ClientResultException ex)
{
if (ex.Status != 403)
{
throw;
}
Console.WriteLine(ex.Message);
}The disabled Agent may be enabled, and it will be able to accept requests and sessions again.
await agentsClient.EnableAgentAsync(agentVersion.Name);
ProjectAgentSession session2 = await agentsClient.CreateSessionAsync(agentVersion.Name, new VersionRefIndicator(agentVersion.Version));
Console.WriteLine($"The session {session2.AgentSessionId} was created.");Note: This is a preview feature; to use it the AAIP001 warning needs to be ignored.
In this example we will demonstrate management of External Agents step by step. External Agents are the third-party Agents hosted outside Foundry (for example, on GCP or AWS). Registration is metadata-only: Foundry records the agent definition to light up observability experiences (traces, evaluations) over customer-emitted OpenTelemetry data.
To create an External Agent, we need to provide the ExternalAgentDefinition with an OpenTelemetry agent identifier,
used to attribute customer-emitted spans to this Foundry agent, in the CreateAgentVersionAsync or CreateAgentVersion method.
ExternalAgentDefinition agentDefinition = new()
{
OtelAgentId = "sample-external-agent",
};
ProjectsAgentVersionCreationOptions agentOptions = new(agentDefinition)
{
Description = "External agent registered by the azure-ai-projects sample.",
Metadata = {
{ "sample", "external_agents_crud" },
{ "status", "created" }
}
};
ProjectsAgentVersion agentVersion = await agentsClient.CreateAgentVersionAsync(
agentName: "myExternalAgent1",
options: agentOptions);
Console.WriteLine($"Agent created (id: {agentVersion.Id}, name: {agentVersion.Name}, version: {agentVersion.Version})");Toolboxes allow us to store tools in Azure so that they can be retrieved and used by the Agents.
In the example below we create two versions of an MCP tool and save them to Azure.
MCPToolboxTool tool = new(serverLabel: "api-specs")
{
Name = "mcp-tool",
Description = "Sample MCP tool",
ServerUri = new Uri("https://gitmcp.io/Azure/azure-rest-api-specs"),
ToolCallApprovalPolicy = new McpToolCallApprovalPolicy(DefaultMcpToolCallApprovalPolicy.AlwaysRequireApproval)
};
ToolboxVersion toolBox1 = await toolboxClient.CreateVersionAsync(
name: toolboxName,
tools: [tool],
description: "Example toolbox created by the azure-ai-projects sample.",
metadata: new Dictionary<string, string> {
{"team", "Engineers"}
}
);
ToolboxVersion toolBox2 = await toolboxClient.CreateVersionAsync(
name: toolboxName,
tools: [tool],
description: "Another toolbox created by the azure-ai-projects sample.",
metadata: new Dictionary<string, string> {
{"team", "Data scientists"}
}
);
string status = "unknown status";
toolBox1.Metadata?.TryGetValue("team", out status);
Console.WriteLine($"Toolbox: {toolBox1.Name}, version: {toolBox1.Version}, (tools: {toolBox1.Tools.Count}) (team: {status}).");There are two objects which help to work with the Toolboxes: ToolboxRecord and ToolboxVersion. ToolboxRecord can be retrieved by
name, and it contains the default version of the Toolbox.
ToolboxRecord record = await toolboxClient.GetAsync(name: toolBox1.Name);
Console.WriteLine($"The default version for a toolbox {record.Name} is {record.DefaultVersion}");The name of the Toolbox and its version allow us to get the ToolboxVersion, which contains the tools that can be used by an Agent.
ToolboxVersion toolBox = await toolboxClient.GetVersionAsync(record.Name, record.DefaultVersion);
Console.WriteLine($"Retrieved toolbox: {toolBox.Name} ({toolBox.Id})");Sessions allow multiple users to use the same hosted Agent within their own sandboxed environment. In the example below we create two sessions for the same agent version.
string sessionId1 = Guid.NewGuid().ToString();
string sessionId2 = Guid.NewGuid().ToString();
ProjectAgentSession session1 = await agentsClient.CreateSessionAsync(
agentName: agentVersion.Name,
agentSessionId: sessionId1,
versionIndicator: new VersionRefIndicator(agentVersion.Version)
);
Console.WriteLine($"Created session with ID {session1.AgentSessionId}");
ProjectAgentSession session2 = await agentsClient.CreateSessionAsync(
agentName: agentVersion.Name,
agentSessionId: sessionId2,
versionIndicator: new VersionRefIndicator(agentVersion.Version)
);
Console.WriteLine($"Created session with ID {session2.AgentSessionId}");
while (session1.Status != AgentSessionStatus.Failed && session1.Status != AgentSessionStatus.Active)
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
session1 = await agentsClient.GetSessionAsync(agentName: agentVersion.Name, sessionId: session1.AgentSessionId);
}
while (session2.Status != AgentSessionStatus.Failed && session2.Status != AgentSessionStatus.Active)
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
session2 = await agentsClient.GetSessionAsync(agentName: agentVersion.Name, sessionId: session2.AgentSessionId);
}It is also possible to upload files to the session store, so that they will only be accessible inside their session.
To use this feature we need to create the AgentSessionFiles client:
ProjectsAgentVersion agentVersion = await agentsClient.GetAgentVersionAsync(
agentName: hostedAgentName,
agentVersion: hostedAgentVersion);
string sessionId = Guid.NewGuid().ToString("N");
ProjectAgentSession session = await agentsClient.CreateSessionAsync(
agentName: agentVersion.Name,
agentSessionId: sessionId,
versionIndicator: new VersionRefIndicator(agentVersion.Version)
);
AgentSessionFiles sessionClient = agentsClient.GetAgentSessionFiles(agentVersion.Name, session.AgentSessionId);
while (session.Status != AgentSessionStatus.Failed && session.Status != AgentSessionStatus.Active)
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
session = await agentsClient.GetSessionAsync(agentName: agentVersion.Name, sessionId: session.AgentSessionId);
}Note: This is a preview feature; to use it the AAIP001 warning needs to be ignored.
Skills can be used to provide portable packages of instructions for Agents. Azure.AI.Projects.Agents allows
managing skills in Microsoft Foundry. Skills may be created from a folder with instructions or on-the-fly.
AgentsSkill skillFromFile = await skillsClient.CreateSkillVersionFromFilesAsync("roll-dice", GetDirectory("roll-dice"));
Console.WriteLine($"Created skillfrom directory {skillFromFile.Name}, Id: {skillFromFile.Id}");
SkillInlineContent content = new(
description: "Calculates the sum of two numbers.",
instructions: """
To calculate the sum run
bash:
echo $((<first> + <second>))
powershell:
(<first> + <second>)
Replace <first> and <second> by the actual summation arguments.
"""
);
SkillVersion simpleSkill = await skillsClient.CreateSkillVersionAsync(name: "simple-skill", inlineContent: content);
Console.WriteLine($"Created skill {simpleSkill.Name}: {simpleSkill.Description}");For more information on skills, please see the Microsoft Learn page.
Note: This is a preview feature; to use it the AAIP001 warning needs to be ignored.
The hosted agent can be further configured by using the PatchAgentObject and PatchAgentObjectAsync methods.
- Retrieve the agent
ProjectsAgentVersion agentVersion = await agentsClient.GetAgentVersionAsync(
agentName: hostedAgentName,
agentVersion: hostedAgentVersion);
Console.WriteLine($"Retrieved agent {agentVersion.Name}, v. {agentVersion.Version}");- Create the skill.
SkillInlineContent content = new(
description: "Calculates the sum of two numbers.",
instructions: """
To calculate the sum run
bash:
echo $((<first> + <second>))
powershell:
(<first> + <second>)
Replace <first> and <second> by the actual summation arguments.
"""
);
SkillVersion simpleSkill = await skillsClient.CreateSkillVersionAsync(name: "simpleSkill", inlineContent: content);- We will configure the hosted agent so that it will route 74% of the traffic to the endpoint and will also make it aware of the skill we have created.
AgentEndpointConfiguration config = new()
{
VersionSelector = new([new FixedRatioVersionSelectionRule(agentVersion: agentVersion.Version, trafficPercentage: 74)]),
ProtocolConfiguration = new()
{
Responses = new()
}
};
AgentCard card = new(version: "1", [new AgentCardSkill(id: simpleSkill.Id, name: SKILL)]);
PatchAgentOptions patchOptions = new()
{
AgentEndpoint = config,
AgentCard = card
};
ProjectsAgentRecord patchedRecord = await agentsClient.PatchAgentAsync(
agentName: hostedAgentName,
patchAgentOptions: patchOptions);
Console.WriteLine($"The Agent {patchedRecord.Name} was patched.");The most probable reason for an error during session creation is the failure of a main script in the agent container.
The hosted agent container logs can be streamed using AgentAdministrationClient methods GetSessionLogStream
and GetSessionLogStreamAsync.
ProjectAgentSession session = await agentsClient.CreateSessionAsync(
agentName: agentVersion.Name,
versionIndicator: new VersionRefIndicator(agentVersion.Version)
);
SessionLogEvent logEvent = await agentsClient.GetSessionLogStreamAsync(agentName: agentVersion.Name, agentVersion: agentVersion.Version, sessionId: session.AgentSessionId);
Console.WriteLine(logEvent.Data);Agent performance may be improved by optimizing the models used, skill text, system prompt, and tool descriptions. The AgentOptimizationJobs client allows
managing these tasks.
var projectEndpoint = System.Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT");
var modelDeploymentName = System.Environment.GetEnvironmentVariable("FOUNDRY_MODEL_NAME");
var anotherModelDeploymentName = System.Environment.GetEnvironmentVariable("FOUNDRY_MODEL_NAME2");
AgentAdministrationClient agentsClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: new DefaultAzureCredential());
AgentOptimizationJobs jobsClient = agentsClient.GetAgentOptimizationJobs();
AgentOptimizationJobCandidates candidatesClient = agentsClient.GetAgentOptimizationJobCandidatesClient();An Agent optimization job accepts optimization criteria, evaluators, and several models as parameters. It also accepts baselines used as an optimization starting point. Several models need to be defined for different purposes:
OptimizationModelConfiguration- reads the Agent evaluation result and reason and creates the improved target description: system prompt, tool description or skill.evaluationModel- used for Agent evaluation.ModelSearchSpace- the models considered during Agent optimization.
AgentOptimizationConfiguration conf = new(
evaluationConfiguration: new(
trainingSet: GetDataset(0, 7),
evaluators: [new AgentOptimizationEvaluator(name: "builtin.meteor_score")],
evaluationModel: new(modelDeploymentName)
)
{
ValidationSet = GetDataset(7, 3),
},
candidateSearchConfiguration: new()
{
MaxCandidates = 3,
},
agentOptimizationSpace: new()
{
TargetAttributes = { TargetAttribute.Skills, TargetAttribute.Instructions, TargetAttribute.Model },
ModelSearchSpace = { modelDeploymentName, anotherModelDeploymentName }
}
);
AgentOptimizationJob job = new(optimizationModelConfiguration: new(modelDeploymentName), optimizationConfiguration: conf)
{
DisplayName = "Sample agent optimization",
TargetConfiguration = new AgentOptimizationFoundryAgentTargetConfiguration(name: agentVersion.Name)
{
Version = agentVersion.Version,
},
};
OperationResult jobOperation = await jobsClient.CreateAsync(waitUntilCompleted: true, job: job, operationId: null, cancellationToken: default);
AgentOptimizationJob submittedJob = AgentOptimizationJob.FromClientResult(await jobOperation.UpdateStatusAsync());
Console.WriteLine($"Submitted optimization job: {submittedJob.Id}");After the job has completed, the optimization candidates may be listed along with the optimized parameters:
await foreach (AgentOptimizationCandidate candidate in candidatesClient.GetCandidatesAsync(jobId: submittedJob.Id, expand: [AgentOptimizationCandidateExpand.Mutations]))
{
Console.WriteLine("======================================================");
if (candidate.Status == AgentOptimizationCandidateStatus.Failed)
{
Console.WriteLine($"The candidate {candidate.CandidateId} has failed.");
}
else
{
Console.WriteLine($"Candidate ID: {candidate.CandidateId}, Candidate name: {candidate.Name ?? "<no name>"}, Candidate evaluation ID: {candidate.Evaluation.EvalId}, Score: {candidate.Evaluation.Score}.");
if (candidate.Output is AgentOptimizationAgentCandidateOutput agentOutput)
{
DisplayMutations(agentOutput.Mutations);
}
else if (candidate.Output != null)
{
throw new InvalidOperationException($"The candidate {candidate.CandidateId} has unexpected output: {candidate.Output.Type}");
}
}
Console.WriteLine("======================================================");
}Note: Tracing functionality is in preliminary preview and is subject to change. Spans, attributes, and events may be modified in future versions.
Environment variable values: All tracing-related environment variables accept
true(case-insensitive) or1as equivalent enabling values.
Tracing requires enabling GenAI-specific OpenTelemetry support. One way to do this is to set the AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING environment variable value to true. You can also enable the feature with the following code:
AppContext.SetSwitch("Azure.Experimental.EnableGenAITracing", true);Precedence: If both the
AppContextswitch and the environment variable are set, theAppContextswitch takes priority. No exception is thrown on conflict. If neither is set, the value defaults tofalse.
Important: When you enable Azure.Experimental.EnableGenAITracing, the SDK automatically enables the Azure.Experimental.EnableActivitySource flag, which is required for the OpenTelemetry instrumentation to function.
You can add an Application Insights Azure resource to your Microsoft Foundry project. If one was enabled, you can get the Application Insights connection string, configure your AI Projects client, and observe traces in Azure Monitor. Typically, you might want to start tracing before you create a client or Agent.
First, set the APPLICATIONINSIGHTS_CONNECTION_STRING environment variable to point to your Azure Monitor resource.
For tracing to Azure Monitor from your application, the preferred option is to use Azure.Monitor.OpenTelemetry.AspNetCore. Install the package with NuGet:
dotnet add package Azure.Monitor.OpenTelemetry.AspNetCore
More information about using the Azure.Monitor.OpenTelemetry.AspNetCore package can be found here.
Another option is to use Azure.Monitor.OpenTelemetry.Exporter package. Install the package with NuGet:
dotnet add package Azure.Monitor.OpenTelemetry.Exporter
Here is an example how to set up tracing to Azure Monitor using Azure.Monitor.OpenTelemetry.Exporter:
var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("Azure.AI.Projects.*")
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("AgentTracingSample"))
.AddAzureMonitorTraceExporter().Build();For tracing to console from your application, install the OpenTelemetry.Exporter.Console with NuGet:
dotnet add package OpenTelemetry.Exporter.Console
Here is an example how to set up tracing to console:
var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("Azure.AI.Projects.*") // Add the required sources name
.SetResourceBuilder(OpenTelemetry.Resources.ResourceBuilder.CreateDefault().AddService("AgentTracingSample"))
.AddConsoleExporter() // Export traces to the console
.Build();Content recording controls whether message contents and tool call related details, such as parameters and return values, are captured with the traces. This data may include sensitive user information.
To enable content recording, set the OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT environment variable to true. Alternatively, you can control content recording with the following code:
AppContext.SetSwitch("Azure.Experimental.TraceGenAIMessageContent", false);If neither the environment variable nor the AppContext switch is set, content recording defaults to false.
Precedence: If both the
AppContextswitch and the environment variable are set, theAppContextswitch takes priority. No exception is thrown on conflict.
Any operation that fails will throw a ClientResultException. The exception's Status will hold the HTTP response status code. The exception's Message contains a detailed message that may be helpful in diagnosing the issue:
try
{
ProjectsAgentVersion agent = await agentsClient.GetAgentVersionAsync(
agentName: "agent_which_dies_not_exist", agentVersion: "1");
}
catch (ClientResultException e) when (e.Status == 404)
{
Console.WriteLine($"Exception status code: {e.Status}");
Console.WriteLine($"Exception message: {e.Message}");
}To further diagnose and troubleshoot issues, you can enable logging following the Azure SDK logging documentation. This allows you to capture additional insights into request and response details, which can be particularly helpful when diagnosing complex issues.
Beyond the introductory scenarios discussed, the AI Agents client library offers support for additional scenarios to help take advantage of the full feature set of the AI services. To help explore some of these scenarios, the AI Agents client library offers a set of samples to serve as an illustration for common scenarios. Please see the Samples.
See the Azure SDK CONTRIBUTING.md for details on building, testing, and contributing to this library.
