> ## Documentation Index
> Fetch the complete documentation index at: https://arize-ax.mintlify.site/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Microsoft Agent Framework for C#

> Trace Microsoft Agent Framework agents in C# with OpenTelemetry GenAI and send spans to Arize AX.

[Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/overview/?pivots=programming-language-csharp) is Microsoft's open-source SDK for building AI agents. Its C# SDK emits OpenTelemetry spans using GenAI semantic conventions. Arize AX ingests these spans directly and displays agent, model, and tool activity without an OpenInference processor.

## Prerequisites

* .NET 10 SDK
* An Arize AX account ([sign up](https://arize.com/sign-up/))
* An `OPENAI_API_KEY` from the [OpenAI Platform](https://platform.openai.com/api-keys)

## Launch Arize AX

1. Sign in to your [Arize AX account](https://app.arize.com/).
2. From **Space Settings**, copy your **Space ID** and **API Key**. You will set them as `ARIZE_SPACE_ID` and `ARIZE_API_KEY` below.

## Install

Create a console project and add the Microsoft Agent Framework OpenAI connector and the OpenTelemetry Protocol exporter:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
dotnet new console --framework net10.0 --name MicrosoftAgentFramework
cd MicrosoftAgentFramework
dotnet add package Microsoft.Agents.AI.OpenAI --version 1.24.0
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --version 1.19.1
```

## Configure credentials

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export ARIZE_SPACE_ID="<your-space-id>"
export ARIZE_API_KEY="<your-api-key>"
export ARIZE_PROJECT_NAME="microsoft-agent-framework-csharp-example"
export OPENAI_API_KEY="<your-openai-api-key>"
```

## Setup tracing

The example configures an OTLP gRPC exporter for Arize AX, adds the project name as a resource attribute, and instruments one agent with a `GetWeather` function tool. GPT-6.1 Sol requires the Responses API for tool calling, so the agent uses `GetResponsesClient()` ([OpenAI model documentation](https://developers.openai.com/api/docs/models/gpt-6.1-sol)).

<Callout type="warning">
  `EnableSensitiveData = true` records prompts, responses, tool arguments, and tool results. Use it only when that data is appropriate for your Arize AX project and its retention policy. Set it to `false` to omit message content.
</Callout>

<CodeGroup>
  ```csharp C# theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  #pragma warning disable OPENAI001

  using System.ComponentModel;
  using Microsoft.Agents.AI;
  using Microsoft.Extensions.AI;
  using OpenAI;
  using OpenAI.Responses;
  using OpenTelemetry;
  using OpenTelemetry.Resources;
  using OpenTelemetry.Trace;

  const string sourceName = "Microsoft.AgentFramework.Sample";
  var apiKey = Environment.GetEnvironmentVariable("ARIZE_API_KEY")!;
  var spaceId = Environment.GetEnvironmentVariable("ARIZE_SPACE_ID")!;
  var projectName = Environment.GetEnvironmentVariable("ARIZE_PROJECT_NAME")
      ?? "microsoft-agent-framework-csharp-example";
  var openAiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;

  using var tracerProvider = Sdk.CreateTracerProviderBuilder()
      .SetResourceBuilder(ResourceBuilder.CreateDefault()
          .AddService("microsoft-agent-framework-csharp")
          .AddAttributes(new Dictionary<string, object>
          {
              ["openinference.project.name"] = projectName
          }))
      .AddSource(sourceName)
      .AddOtlpExporter(options =>
      {
          options.Endpoint = new Uri("https://otlp.arize.com:443");
          options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
          options.Headers = $"authorization={apiKey},"+
                            $"arize-space-id={spaceId}," +
                            "arize-interface=dotnet";
      })
      .Build();

  Console.WriteLine("Arize AX tracing initialized.");

  var openAiClient = new OpenAIClient(openAiKey);

  var agent = openAiClient.GetResponsesClient().AsAIAgent(
          model: "gpt-6.1-sol",
          name: "weather-agent",
          instructions:
              "You are a concise weather assistant. Always call the GetWeather " +
              "tool once before answering.",
          tools: [AIFunctionFactory.Create(WeatherTools.GetWeather)])
      .AsBuilder()
      .UseOpenTelemetry(
          sourceName, telemetry => telemetry.EnableSensitiveData = true)
      .Build();
  ```
</CodeGroup>

The agent instrumentation emits the agent invocation, chat client, and function execution spans. The tracer provider listens to the same source name passed to `UseOpenTelemetry` and exports those spans directly to Arize AX.

## Add a tool

Create `WeatherTools.cs` for the function tool used by the agent:

<CodeGroup>
  ```csharp C# theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  static class WeatherTools
  {
      [Description("Returns the current weather for a city.")]
      public static string GetWeather(
          [Description("The city to check.")] string city) =>
          $"Sunny and 72°F in {city}.";
  }
  ```
</CodeGroup>

## Run Microsoft Agent Framework

Add the agent invocation to the end of `Program.cs`:

<CodeGroup>
  ```csharp C# theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  var result = await agent.RunAsync("What is the weather in San Francisco?");
  Console.WriteLine(result);
  ```
</CodeGroup>

Run the project from the `MicrosoftAgentFramework` directory:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
dotnet run --project MicrosoftAgentFramework.csproj
```

### Expected output

```text wrap theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
Arize AX tracing initialized for Microsoft Agent Framework (C#).
Sunny and 72°F in San Francisco.
```

## Verify in Arize AX

1. Open your Arize AX space and select project **`microsoft-agent-framework-csharp-example`**.
2. You should see a trace with an `invoke_agent` root span, chat spans for the model calls, and an `execute_tool` span for `GetWeather`. The model spans include provider, model, token usage, and message attributes.
3. If no traces appear, see [Troubleshooting](#troubleshooting).

Confirm spans are actually reaching your Arize AX project. Use whichever fits your workflow — the skill and CLI work for any framework; the SDK check is shown for each language.

<Tabs>
  <Tab title="Arize skill (agent)">
    Install the [Arize Skills](https://github.com/Arize-ai/arize-skills) plugin and let your coding agent check for you:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    npx skills add Arize-ai/arize-skills
    ```

    Then prompt your agent:

    > Use the `arize-trace` skill to export and analyze recent traces from my project. Confirm spans are arriving, and summarize any errors or latency issues.
  </Tab>

  <Tab title="AX CLI">
    Export recent spans for your project — any rows mean traces are landing:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    ax spans export "$ARIZE_PROJECT_NAME" --space "$ARIZE_SPACE_ID" \
      --limit 5 --stdout | jq 'length'
    ```

    A non-zero count confirms spans reached Arize AX. Run `ax auth login` first if you have not authenticated. See the [`ax spans` reference](/docs/api-clients/cli/spans).
  </Tab>

  <Tab title="SDK">
    Query the project's spans and check that at least one came back.

    <CodeGroup>
      ```python Python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      import os
      from arize import ArizeClient

      client = ArizeClient(api_key=os.environ["ARIZE_API_KEY"])
      resp = client.spans.list(
          project=os.environ["ARIZE_PROJECT_NAME"],
          space=os.environ["ARIZE_SPACE_ID"],
          limit=5,
      )
      count = len(resp.spans)
      print(
          f"{count} span(s) found" if count else "No spans yet — recheck setup"
      )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      // Reads ARIZE_API_KEY from the environment.
      import { listSpans } from "@arizeai/ax-client";

      const { data: spans } = await listSpans({
        project: process.env.ARIZE_PROJECT_NAME!,
        space: process.env.ARIZE_SPACE_ID!,
        limit: 5,
      });
      const count = spans.length;
      console.log(
        count ? `${count} span(s) found` : "No spans yet — recheck setup",
      );
      ```

      ```go Go theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
      client, err := arize.NewClient(
          arize.Config{APIKey: os.Getenv("ARIZE_API_KEY")},
      )
      if err != nil {
          log.Fatal(err)
      }
      resp, err := client.Spans.List(ctx, spans.ListRequest{
          Project: os.Getenv("ARIZE_PROJECT_NAME"),
          Space:   os.Getenv("ARIZE_SPACE_ID"),
          Limit:   5,
      })
      if err != nil {
          log.Fatal(err)
      }
      fmt.Printf("%d span(s) found\n", len(resp.Spans))
      ```
    </CodeGroup>

    SDK span references: [Python](/docs/api-clients/python/version-8/client-resources/spans) · [TypeScript](/docs/api-clients/typescript/version-1/client-resources/spans) · [Go](/docs/api-clients/go/version-2/client-resources/spans).
  </Tab>
</Tabs>

## Troubleshooting

* **No traces in Arize AX.** Confirm `ARIZE_SPACE_ID` and `ARIZE_API_KEY` are set in the same shell that runs `dotnet run`, and confirm the exporter endpoint and headers match the example.
* **No agent spans.** The source name passed to `UseOpenTelemetry` must match the source registered with `.AddSource(sourceName)`.
* **Wrong project.** Confirm the `openinference.project.name` resource attribute is set to the value of `ARIZE_PROJECT_NAME`.
* **Prompts or tool content are missing.** Set `EnableSensitiveData = true` for the agent's OpenTelemetry configuration. This also records those values in traces, so enable it only when appropriate.
* **`401` from OpenAI.** Verify `OPENAI_API_KEY` is valid and can access `gpt-6.1-sol`. Replace the model with one available to your account if needed.
* **Package restore or build fails.** Confirm the .NET 10 SDK is installed and that the package versions in the project file match the versions shown above.

## Resources

<CardGroup>
  <Card icon="book-open" href="https://learn.microsoft.com/en-us/agent-framework/overview/?pivots=programming-language-csharp" title="Microsoft Agent Framework Documentation" horizontal />

  <Card icon="book-open" href="https://learn.microsoft.com/en-us/agent-framework/agents/observability?pivots=programming-language-csharp" title="Microsoft Agent Framework Observability" horizontal />

  <Card icon="github" href="https://github.com/microsoft/agent-framework" title="Microsoft Agent Framework GitHub" horizontal />
</CardGroup>
