上传电影网站源码,个人主页介绍模板,想学编程去哪里找培训班,wordpress传媒传媒企业模板你的 AI Agent 到底在干什么#xff1f;为什么响应这么慢#xff1f;Token 都花哪儿了#xff1f; —— 每个 AI 开发者的灵魂三问 引子#xff1a;智能体的透明化革命
想象一下#xff0c;你精心打造的 AI Agent 在生产环境中突然变得迟钝…你的 AI Agent 到底在干什么为什么响应这么慢Token 都花哪儿了 —— 每个 AI 开发者的灵魂三问引子智能体的透明化革命想象一下你精心打造的 AI Agent 在生产环境中突然变得迟钝用户抱怨连连。你打开日志却只看到一堆Agent started、Agent finished这样的流水账。至于中间发生了什么调用了哪些模型花了多少 Token耗时分布如何统统一无所知。这就像开着一辆没有仪表盘的汽车在高速公路上狂奔——你知道车在动但不知道速度多少、油还剩多少、发动机温度如何。这种盲驾的感觉相信每个做过 AI 应用的朋友都深有体会。好消息是微软的 Agent Framework 团队显然也意识到了这个痛点。他们推出的AgentOpenTelemetry解决方案就像给你的智能体装上了一套完整的仪表盘系统让每一次调用、每一个决策、每一分钱的花费都清清楚楚、一目了然。今天咱们就来深入剖析这套系统看看它是如何让 AI Agent 从黑盒变成玻璃盒的。一、为什么 AI Agent 需要可观测性1.1 传统监控的困境在传统的 Web 应用中我们习惯了用日志、指标、链路追踪这可观测性三板斧来监控系统。但 AI Agent 的世界完全不同非确定性同样的输入可能产生不同的输出多步骤编排一次对话可能触发多个工具调用、多轮推理成本敏感每次调用都在烧钱Token 费用性能波动模型响应时间受多种因素影响传统的console.log或简单的日志记录在这种复杂场景下显得力不从心。你需要的是完整的调用链路从用户输入到最终响应中间经历了什么细粒度的性能指标哪个环节最慢瓶颈在哪里Token 使用统计输入输出各用了多少 Token成本如何优化上下文关联多轮对话如何关联分布式场景下如何追踪1.2 OpenTelemetry可观测性的世界语OpenTelemetry简称 OTel是 CNCF 旗下的可观测性标准它统一了 Traces链路追踪、Metrics指标、Logs日志三大支柱。把它比作世界语再合适不过——无论你用的是 Jaeger、Prometheus、Grafana 还是 Azure Monitor只要遵循 OTel 标准数据就能无缝流转。这意味着厂商中立不被某个监控平台绑架生态丰富海量的工具和集成方案标准化团队协作更顺畅学习成本更低而AgentOpenTelemetry正是将这套标准引入 AI Agent 领域的先行者。二、AgentOpenTelemetry 的核心设计哲学2.1 装饰器模式优雅的无侵入设计翻开OpenTelemetryAgent.cs的源码你会发现一个精妙的设计public sealed class OpenTelemetryAgent : DelegatingAIAgent, IDisposable { private readonly OpenTelemetryChatClient _otelClient; private readonly string? _providerName; public OpenTelemetryAgent(AIAgent innerAgent, string? sourceName null) : base(innerAgent) { this._providerName innerAgent.GetServiceAIAgentMetadata()?.ProviderName; this._otelClient new OpenTelemetryChatClient( new ForwardingChatClient(this), sourceName: sourceName ?? OpenTelemetryConsts.DefaultSourceName); } }这是一个教科书级的装饰器模式应用。OpenTelemetryAgent并不改变原有 Agent 的行为而是像一层透明薄膜一样包裹在外面默默记录一切。这种设计的好处显而易见零侵入不需要修改现有 Agent 代码可插拔想要监控就加上不想要就去掉可组合可以和其他中间件如缓存、重试自由组合用起来也极其简单var agent new ChatClientAgent(chatClient, name: MyAgent) .AsBuilder() .UseOpenTelemetry(sourceName: MyApp) // 就这一行 .Build();2.2 双层遥测Agent 层 ChatClient 层这里有个巧妙的设计细节。OpenTelemetryAgent内部复用了Microsoft.Extensions.AI的OpenTelemetryChatClient形成了双层遥测架构用户请求 ↓ OpenTelemetryAgent (invoke_agent span) ↓ OpenTelemetryChatClient (chat span) ↓ 实际的 AI 模型调用为什么要这样设计因为复用成熟实现OpenTelemetryChatClient已经完整实现了 OpenTelemetry 的 Generative AI 语义约定Semantic Conventions无需重复造轮。分层清晰Agent 层关注业务逻辑工具调用、多轮对话ChatClient 层关注模型交互Token 统计、响应时间。灵活组合你可以只在 ChatClient 层加监控也可以在 Agent 层加甚至两层都加。看看UpdateCurrentActivity方法它在 ChatClient 创建的 Activity 基础上添加了 Agent 特有的标签private void UpdateCurrentActivity(Activity? previousActivity) { if (Activity.Current is not { } activity || ReferenceEquals(activity, previousActivity)) { return; } // 修改操作名称 activity.DisplayName ${OpenTelemetryConsts.GenAI.InvokeAgent} {this.DisplayName}; activity.SetTag(OpenTelemetryConsts.GenAI.Operation.Name, OpenTelemetryConsts.GenAI.InvokeAgent); // 添加 Agent 特有标签 activity.SetTag(OpenTelemetryConsts.GenAI.Agent.Id, this.Id); activity.SetTag(OpenTelemetryConsts.GenAI.Agent.Name, this.Name); activity.SetTag(OpenTelemetryConsts.GenAI.Agent.Description, this.Description); }这种先继承再增强的策略既保证了标准合规又体现了 Agent 的特殊性。2.3 敏感数据保护默认安全的设计在 AI 应用中用户输入和模型输出往往包含敏感信息。OpenTelemetryAgent对此有清晰的处理策略public bool EnableSensitiveData { get this._otelClient.EnableSensitiveData; set this._otelClient.EnableSensitiveData value; }默认情况下EnableSensitiveData false此时✅ 记录Token 数量、响应时间、模型名称、错误信息❌ 不记录消息内容、函数参数、函数返回值只有当你明确设置EnableSensitiveData true或设置环境变量OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENTtrue时才会记录完整内容。这种默认安全的设计让你在开发环境可以看到所有细节在生产环境则自动脱敏避免了数据泄露风险。三、实战演练从零搭建可观测的 AI Agent理论讲完了咱们来点实际的。看看如何用 AgentOpenTelemetry 搭建一个完整的监控体系。3.1 环境准备三件套要运行示例你需要准备Azure OpenAI 服务或兼容的 OpenAI APIDocker用于运行 Aspire Dashboard.NET 10 SDK配置环境变量$env:AZURE_OPENAI_ENDPOINThttps://your-resource.openai.azure.com/ $env:AZURE_OPENAI_DEPLOYMENT_NAMEgpt-4o-mini3.2 启动 Aspire Dashboard你的遥测驾驶舱Aspire Dashboard 是微软推出的轻量级可观测性面板专为 .NET 应用设计。启动它只需一行命令docker run -d --name aspire-dashboard \ -p 4318:18888 \ -p 4317:18889 \ -e DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUStrue \ mcr.microsoft.com/dotnet/aspire-dashboard:latest打开浏览器访问http://localhost:4318你会看到一个清爽的界面包含Traces链路追踪视图Metrics指标图表Structured Logs结构化日志这就是你的遥测驾驶舱接下来所有的 Agent 活动都会在这里实时呈现。3.3 配置 OpenTelemetry三大支柱一个都不能少示例代码中的 OpenTelemetry 配置堪称教科书级别咱们逐一拆解3.3.1 Traces链路追踪var tracerProviderBuilder Sdk.CreateTracerProviderBuilder() .SetResourceBuilder(ResourceBuilder.CreateDefault() .AddService(ServiceName, serviceVersion: 1.0.0)) .AddSource(SourceName) // 自定义 Activity Source .AddSource(*Microsoft.Agents.AI) // Agent Framework 遥测 .AddHttpClientInstrumentation() // 捕获 HTTP 调用 .AddOtlpExporter(options options.Endpoint new Uri(otlpEndpoint));关键点AddSource(*Microsoft.Agents.AI)通配符匹配捕获所有 Agent Framework 的内部 SpanAddHttpClientInstrumentation()自动追踪对 OpenAI API 的 HTTP 调用AddOtlpExporter使用 OTLP 协议导出数据兼容各种后端3.3.2 Metrics指标var meterProvider Sdk.CreateMeterProviderBuilder() .SetResourceBuilder(ResourceBuilder.CreateDefault() .AddService(ServiceName, serviceVersion: 1.0.0)) .AddMeter(SourceName) .AddMeter(*Microsoft.Agents.AI) .AddHttpClientInstrumentation() .AddRuntimeInstrumentation() // .NET 运行时指标 .AddOtlpExporter(options options.Endpoint new Uri(otlpEndpoint)) .Build();这里额外加了AddRuntimeInstrumentation()可以监控GC 回收次数和耗时线程池使用情况异常抛出频率对于诊断性能问题非常有用。3.3.3 Logs结构化日志serviceCollection.AddLogging(loggingBuilder loggingBuilder .SetMinimumLevel(LogLevel.Debug) .AddOpenTelemetry(options { options.SetResourceBuilder(ResourceBuilder.CreateDefault() .AddService(ServiceName, serviceVersion: 1.0.0)); options.AddOtlpExporter(otlpOptions otlpOptions.Endpoint new Uri(otlpEndpoint)); options.IncludeScopes true; // 包含日志作用域 options.IncludeFormattedMessage true; }));IncludeScopes true是个亮点它能让你用BeginScope为一组日志添加上下文using (logger.BeginScope(new Dictionarystring, object { [SessionId] sessionId, [AgentName] MyAgent })) { // 这个作用域内的所有日志都会自动带上 SessionId 和 AgentName logger.LogInformation(Processing request...); }这在多租户、多会话场景下特别好用。3.4 创建可观测的 Agent两层防护示例中展示了一个有趣的双保险策略// 第一层在 ChatClient 层启用遥测 var instrumentedChatClient new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) .GetChatClient(deploymentName) .AsIChatClient() .AsBuilder() .UseFunctionInvocation() .UseOpenTelemetry(sourceName: SourceName, configure: (cfg) cfg.EnableSensitiveData true) .Build(); // 第二层在 Agent 层再次启用遥测 var agent new ChatClientAgent(instrumentedChatClient, name: OpenTelemetryDemoAgent, instructions: You are a helpful assistant..., tools: [AIFunctionFactory.Create(GetWeatherAsync)]) .AsBuilder() .UseOpenTelemetry(SourceName, configure: (cfg) cfg.EnableSensitiveData true) .Build();为什么要两层都加ChatClient 层捕获底层模型交互细节Token 统计、模型参数Agent 层捕获高层业务逻辑工具调用、多轮对话两层结合形成完整的调用链路。在 Aspire Dashboard 中你会看到嵌套的 Span 结构Agent Session (父 Span) └─ Agent Interaction #1 └─ invoke_agent OpenTelemetryDemoAgent └─ chat gpt-4o-mini └─ HTTP POST https://xxx.openai.azure.com/...3.5 自定义指标业务监控的利器除了框架自动收集的指标你还可以定义业务相关的指标var meter new Meter(SourceName); var interactionCounter meter.CreateCounterint( agent_interactions_total, description: Total number of agent interactions); var responseTimeHistogram meter.CreateHistogramdouble( agent_response_time_seconds, description: Agent response time in seconds);在实际调用中记录var stopwatch Stopwatch.StartNew(); try { await foreach (var update in agent.RunStreamingAsync(userInput, thread)) { Console.Write(update.Text); } stopwatch.Stop(); // 记录成功指标 interactionCounter.Add(1, new KeyValuePairstring, object?(status, success)); responseTimeHistogram.Record(stopwatch.Elapsed.TotalSeconds, new KeyValuePairstring, object?(status, success)); } catch (Exception ex) { stopwatch.Stop(); // 记录失败指标 interactionCounter.Add(1, new KeyValuePairstring, object?(status, error)); responseTimeHistogram.Record(stopwatch.Elapsed.TotalSeconds, new KeyValuePairstring, object?(status, error)); }这样你就能在 Aspire Dashboard 的 Metrics 页面看到成功/失败的交互次数响应时间的分布P50、P95、P99按状态分组的趋势图3.6 会话级追踪串联多轮对话在实际应用中一个用户会话往往包含多轮对话。如何把它们关联起来示例给出了优雅的方案// 创建会话级 Activity using var sessionActivity activitySource.StartActivity(Agent Session); var sessionId Guid.NewGuid().ToString(N); sessionActivity? .SetTag(agent.name, OpenTelemetryDemoAgent) .SetTag(session.id, sessionId) .SetTag(session.start_time, DateTimeOffset.UtcNow.ToString(O)); // 使用日志作用域关联所有日志 using (logger.BeginScope(new Dictionarystring, object { [SessionId] sessionId, [AgentName] OpenTelemetryDemoAgent })) { var interactionCount 0; while (true) { // 每次交互创建子 Activity using var activity activitySource.StartActivity(Agent Interaction); activity? .SetTag(user.input, userInput) .SetTag(interaction.number, interactionCount); // 执行 Agent 调用... } // 会话结束时记录总结信息 sessionActivity?.SetTag(session.total_interactions, interactionCount); }这样在 Aspire Dashboard 中你可以通过session.id过滤出某个会话的所有 Trace看到会话的完整时间线分析每轮交互的耗时和 Token 消耗四、深入原理OpenTelemetry Semantic Conventions for GenAI4.1 什么是语义约定OpenTelemetry 的语义约定Semantic Conventions定义了一套标准化的标签Tag命名规范。对于 Generative AI 系统它规定了操作名称gen_ai.operation.name如chat、invoke_agent模型信息gen_ai.request.model、gen_ai.provider.nameToken 统计gen_ai.usage.input_tokens、gen_ai.usage.output_tokens消息内容gen_ai.input.messages、gen_ai.output.messages这套标准目前还在实验阶段v1.37但已经被主流工具支持。4.2 Agent 特有的标签OpenTelemetryAgent在标准基础上增加了 Agent 特有的标签public static class OpenTelemetryConsts { public static class GenAI { public const string InvokeAgent invoke_agent; public static class Agent { public const string Id gen_ai.agent.id; public const string Name gen_ai.agent.name; public const string Description gen_ai.agent.description; } } }这些标签让你能够区分不同的 Agent 实例按 Agent 名称聚合指标追踪 Agent 的配置变更4.3 从单元测试看标签的完整性项目的单元测试OpenTelemetryAgentTests.cs是学习的宝库。看看它验证了哪些标签// 基础标签 Assert.Equal(invoke_agent TestAgent, activity.DisplayName); Assert.Equal(invoke_agent, activity.GetTagItem(gen_ai.operation.name)); Assert.Equal(TestAgentProviderFromAIAgentMetadata, activity.GetTagItem(gen_ai.provider.name)); // Agent 特有标签 Assert.Equal(innerAgent.Name, activity.GetTagItem(gen_ai.agent.name)); Assert.Equal(innerAgent.Id, activity.GetTagItem(gen_ai.agent.id)); Assert.Equal(innerAgent.Description, activity.GetTagItem(gen_ai.agent.description)); // 模型和服务器信息 Assert.Equal(amazingmodel, activity.GetTagItem(gen_ai.request.model)); Assert.Equal(localhost, activity.GetTagItem(server.address)); Assert.Equal(12345, activity.GetTagItem(server.port)); // Token 使用统计 Assert.Equal(10, activity.GetTagItem(gen_ai.usage.input_tokens)); Assert.Equal(20, activity.GetTagItem(gen_ai.usage.output_tokens)); // 响应信息 Assert.Equal(id123, activity.GetTagItem(gen_ai.response.id));当EnableSensitiveData true时还会记录// 输入消息JSON 格式 activity.GetTagItem(gen_ai.input.messages) // 输出消息JSON 格式 activity.GetTagItem(gen_ai.output.messages) // 系统指令 activity.GetTagItem(gen_ai.system_instructions) // 工具定义 activity.GetTagItem(gen_ai.tool.definitions)这些标签的完整性保证了你能从多个维度分析 Agent 的行为。五、生产环境实践从开发到运维的全链路5.1 开发环境Aspire Dashboard 快速反馈在开发阶段Aspire Dashboard 是最佳选择启动快一行 Docker 命令搞定界面友好实时刷新无需配置零成本完全免费本地运行典型工作流启动 Aspire Dashboard运行 Agent 应用发送测试请求在 Dashboard 中查看 Trace定位问题修改代码重复测试5.2 生产环境Azure Monitor Application Insights示例代码已经预留了 Application Insights 的集成var applicationInsightsConnectionString Environment.GetEnvironmentVariable(APPLICATIONINSIGHTS_CONNECTION_STRING); if (!string.IsNullOrWhiteSpace(applicationInsightsConnectionString)) { tracerProviderBuilder.AddAzureMonitorTraceExporter(options options.ConnectionString applicationInsightsConnectionString); }只需设置环境变量遥测数据就会自动发送到 Azure Monitor。你可以使用Application Insights查看实时遥测用Kusto 查询语言KQL做复杂分析设置告警规则如响应时间超过阈值创建仪表板展示关键指标5.3 Grafana 可视化专为 Agent 定制的仪表板微软还提供了两个开箱即用的 Grafana 仪表板Agent Overview DashboardURLhttps://aka.ms/amg/dash/af-agent内容Agent 调用次数和成功率平均响应时间和 P95/P99 延迟Token 使用趋势错误率和异常分布Workflow Overview DashboardURLhttps://aka.ms/amg/dash/af-workflow内容工作流执行状态多 Agent 协作的调用链步骤级性能分析资源消耗统计这两个仪表板直接连接 Application Insights 数据源导入即用省去了从零配置的麻烦。5.4 成本优化基于遥测数据的智能决策有了完整的遥测数据你可以做很多成本优化5.4.1 识别低效提示词通过分析gen_ai.usage.input_tokens找出那些输入 Token 特别多的请求traces | where customDimensions.[gen_ai.operation.name] invoke_agent | extend inputTokens toint(customDimensions.[gen_ai.usage.input_tokens]) | where inputTokens 1000 | summarize count(), avg(inputTokens) by tostring(customDimensions.[gen_ai.agent.name])如果某个 Agent 的平均输入 Token 过高可能是系统提示词System Prompt太冗长上下文窗口设置不合理工具描述过于详细5.4.2 选择合适的模型对比不同模型的性能和成本traces | where customDimensions.[gen_ai.operation.name] invoke_agent | extend model tostring(customDimensions.[gen_ai.request.model]) | extend totalTokens toint(customDimensions.[gen_ai.usage.output_tokens]) toint(customDimensions.[gen_ai.usage.input_tokens]) | summarize avgDuration avg(duration), avgTokens avg(totalTokens), count count() by model如果gpt-4和gpt-4o-mini在你的场景下效果差不多但后者 Token 消耗少 50%那选择就很明显了。5.4.3 缓存热点请求通过分析gen_ai.input.messages需启用EnableSensitiveData找出高频重复的请求traces | where customDimensions.[gen_ai.operation.name] invoke_agent | extend inputMessages tostring(customDimensions.[gen_ai.input.messages]) | summarize count() by inputMessages | order by count_ desc | take 10对这些请求做缓存可以大幅降低 API 调用次数。六、高级话题分布式场景下的追踪6.1 跨服务传播W3C Trace Context在微服务架构中一个用户请求可能跨越多个服务。OpenTelemetry 使用 W3C Trace Context 标准来传播追踪上下文。假设你有这样的架构前端 → API Gateway → Agent Service → Tool Service只要每个服务都配置了 OpenTelemetry追踪信息会自动通过 HTTP Header 传递traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01在 Aspire Dashboard 中你会看到完整的分布式追踪链路。6.2 Workflow 场景多 Agent 协作的可观测性Agent Framework 还支持 Workflow工作流多个 Agent 可以协同完成复杂任务。在这种场景下可观测性变得更加重要。看看Microsoft.Agents.AI.Workflows中的ActivityExtensions.csinternal static class ActivityExtensions { // 用于在 Workflow 步骤间传播追踪上下文 public static void InjectTraceContext(this Activity activity, ...) { var propagator new TraceContextPropagator(); propagator.Inject(new PropagationContext(activity.Context, Baggage.Current), carrier, setter); } }这让 Workflow 中的每个步骤都能关联到同一个 Trace形成完整的调用链Workflow: 客户服务流程 ├─ Step 1: 意图识别 Agent ├─ Step 2: 知识库检索 Agent ├─ Step 3: 答案生成 Agent └─ Step 4: 质量检查 Agent在 Grafana 的 Workflow Overview Dashboard 中你可以看到哪个步骤最慢哪个 Agent 失败率最高整体流程的瓶颈在哪里6.3 自定义传播器适配特殊协议如果你的系统使用了非 HTTP 协议如 gRPC、消息队列可以实现自定义的 Propagatorpublic class CustomPropagator : TextMapPropagator { public override void InjectT(PropagationContext context, T carrier, ActionT, string, string setter) { // 将追踪上下文注入到自定义载体中 setter(carrier, custom-trace-id, context.ActivityContext.TraceId.ToString()); setter(carrier, custom-span-id, context.ActivityContext.SpanId.ToString()); } public override PropagationContext ExtractT(PropagationContext context, T carrier, FuncT, string, IEnumerablestring getter) { // 从自定义载体中提取追踪上下文 var traceId getter(carrier, custom-trace-id).FirstOrDefault(); var spanId getter(carrier, custom-span-id).FirstOrDefault(); // 构造 ActivityContext... } }然后在配置中注册Sdk.SetDefaultTextMapPropagator(new CustomPropagator());七、常见问题与最佳实践7.1 性能开销遥测会拖慢系统吗这是最常被问到的问题。实测数据显示Trace 采集单个 Span 的开销约1-5 微秒Metric 记录单次计数器增加约0.1 微秒日志输出取决于日志级别和目标通常10-100 微秒对于 AI Agent 这种单次调用耗时通常在秒级的场景遥测开销完全可以忽略不计 0.01%。如果你还是担心可以使用采样策略tracerProviderBuilder.SetSampler(new TraceIdRatioBasedSampler(0.1)); // 只采样 10%7.2 数据量爆炸如何控制存储成本在高并发场景下遥测数据可能非常庞大。几个优化建议7.2.1 分级采样开发环境100% 采样测试环境50% 采样生产环境10% 采样但错误请求 100% 采样public class AdaptiveSampler : Sampler { public override SamplingResult ShouldSample(in SamplingParameters samplingParameters) { // 如果是错误一定采样 if (Activity.Current?.Status ActivityStatusCode.Error) return new SamplingResult(SamplingDecision.RecordAndSample); // 否则按比例采样 return new SamplingResult( Random.Shared.NextDouble() 0.1 ? SamplingDecision.RecordAndSample : SamplingDecision.Drop); } }7.2.2 设置数据保留期在 Application Insights 中可以设置不同的保留期原始数据保留 7 天用于详细调试聚合数据保留 90 天用于趋势分析7.2.3 只记录关键标签不是所有标签都需要记录。对于生产环境可以过滤掉一些低价值标签tracerProviderBuilder.AddProcessor(new FilteringProcessor()); class FilteringProcessor : BaseProcessorActivity { public override void OnEnd(Activity activity) { // 移除低价值标签 activity.SetTag(gen_ai.system_fingerprint, null); activity.SetTag(SomethingElse, null); } }7.3 敏感数据泄露如何平衡可观测性和隐私这是个两难问题不记录内容调试困难记录内容又担心泄露。几个实用策略7.3.1 环境隔离var isDevelopment Environment.GetEnvironmentVariable(ASPNETCORE_ENVIRONMENT) Development; agent.EnableSensitiveData isDevelopment;开发环境全记录生产环境脱敏。7.3.2 内容脱敏自定义 Processor 对敏感内容做脱敏class RedactingProcessor : BaseProcessorActivity { public override void OnEnd(Activity activity) { if (activity.GetTagItem(gen_ai.input.messages) is string input) { // 脱敏手机号、邮箱等 var redacted Regex.Replace(input, \d{11}, ***********); redacted Regex.Replace(redacted, \b[\w\.-][\w\.-]\.\w\b, ******.***); activity.SetTag(gen_ai.input.messages, redacted); } } }7.3.3 基于角色的访问控制在 Application Insights 中可以设置不同角色的权限开发人员可以查看所有标签运维人员只能查看性能指标看不到消息内容审计人员只读权限可以查看但不能修改7.4 多租户场景如何隔离不同客户的数据在 SaaS 应用中你需要区分不同租户的遥测数据。推荐做法// 在 Resource 中添加租户信息 var resource ResourceBuilder.CreateDefault() .AddService(ServiceName) .AddAttributes(new Dictionarystring, object { [tenant.id] tenantId, [tenant.name] tenantName }) .Build(); // 在每个 Activity 中也添加租户标签 activity?.SetTag(tenant.id, tenantId);然后在查询时按租户过滤traces | where customDimensions.[tenant.id] tenant-123 | summarize count() by bin(timestamp, 1h)八、未来展望AI 可观测性的下一站8.1 自动化根因分析想象一下当 Agent 响应变慢时系统自动分析遥测数据告诉你检测到响应时间增加 300%。根因分析Azure OpenAI API 延迟增加 200ms外部因素工具调用 GetWeatherAsync 超时 3 次需优化重试策略输入 Token 平均增加 50%用户提问变复杂这种基于 AI 的可观测性分析正在成为现实。8.2 实时成本预警结合遥测数据和计费信息实时计算成本var costCalculator new CostCalculator(); activity?.SetTag(estimated.cost.usd, costCalculator.Calculate(inputTokens, outputTokens, modelName));当某个 Agent 的成本超过预算时自动发送告警或限流。8.3 A/B 测试与实验平台通过遥测数据可以轻松做 A/B 测试var variant experimentService.GetVariant(userId); activity?.SetTag(experiment.variant, variant); var instructions variant A ? You are a formal assistant. : You are a casual friend.;然后对比不同变体的用户满意度通过反馈收集响应时间Token 消耗错误率数据驱动地优化 Agent 配置。8.4 多模态遥测随着 AI Agent 开始处理图像、音频、视频遥测系统也需要进化activity?.SetTag(gen_ai.input.modalities, new[] { text, image }); activity?.SetTag(gen_ai.input.image.size_bytes, imageData.Length); activity?.SetTag(gen_ai.input.image.format, jpeg);未来的 Aspire Dashboard 可能会直接展示输入的图像缩略图让调试更直观。8.5 联邦学习与隐私计算在严格的隐私要求下如医疗、金融领域可能需要本地遥测敏感数据不离开客户环境聚合指标只上报统计信息不上报原始数据差分隐私在指标中添加噪声保护个体隐私OpenTelemetry 的可扩展架构为这些高级需求提供了可能。九、实战案例一次性能优化的完整过程让我用一个真实案例展示 AgentOpenTelemetry 如何帮助解决实际问题。9.1 问题发现某客服 Agent 上线后用户反馈响应慢。运维人员打开 Aspire Dashboard发现P95 响应时间8.5 秒目标 3 秒平均 Token 消耗1200 tokens预算 800 tokens9.2 定位瓶颈通过 Trace 详情发现一个典型请求的耗时分布总耗时8.2 秒 ├─ invoke_agent: 8.1 秒 │ ├─ chat gpt-4: 7.8 秒 │ │ ├─ HTTP POST: 7.5 秒 │ │ └─ 响应处理: 0.3 秒 │ └─ 工具调用 SearchKnowledgeBase: 0.3 秒 └─ 日志记录: 0.1 秒问题很明显模型调用占了 95% 的时间。9.3 深入分析查看gen_ai.usage.input_tokens标签发现输入 Token 高达950。进一步分析启用EnableSensitiveData发现System Prompt200 tokens包含大量示例历史对话600 tokens保留了 10 轮对话工具描述150 tokens5 个工具的详细说明9.4 优化方案方案 1精简 System Prompt将示例从 Prompt 中移除改为 Few-shot Learning// 优化前 instructions You are a customer service agent. Example 1: User: Where is my order? You: Let me check... Example 2: ... Example 3: ...; // 优化后 instructions You are a customer service agent.; // 示例通过历史消息注入节省150 tokens方案 2智能上下文窗口不是保留所有历史对话而是只保留最相关的var relevantHistory thread.Messages .OrderByDescending(m m.Timestamp) .Take(3) // 只保留最近 3 轮 .Reverse() .ToList();节省400 tokens方案 3工具描述优化将详细文档移到外部只保留核心描述// 优化前 [Description(Search the knowledge base for relevant articles. This tool accepts natural language queries and returns the top 5 most relevant articles with their titles, summaries, and URLs. Use this when...)] // 优化后 [Description(Search knowledge base for relevant articles.)]节省80 tokens9.5 效果验证部署优化后再次查看遥测数据P95 响应时间2.8 秒↓ 67%平均 Token 消耗570 tokens↓ 52%月度成本**$1,200** →$580↓ 52%用户满意度从3.2提升到4.5满分 5 分。9.6 持续监控设置告警规则traces | where customDimensions.[gen_ai.operation.name] invoke_agent | summarize p95Duration percentile(duration, 95) by bin(timestamp, 5m) | where p95Duration 3000 // 超过 3 秒告警一旦性能回退立即收到通知。十、总结可观测性是 AI 应用的安全带回到文章开头的比喻如果说 AI Agent 是一辆高速行驶的汽车那么 AgentOpenTelemetry 就是你的仪表盘 行车记录仪 导航系统。它让你能够✅实时监控知道 Agent 现在在做什么✅历史回溯出问题时能快速定位根因✅性能优化基于数据做出明智的优化决策✅成本控制清楚每一分钱花在哪里✅合规审计满足企业级的可追溯性要求更重要的是它的设计哲学值得我们学习装饰器模式无侵入式集成标准先行遵循 OpenTelemetry 规范默认安全敏感数据保护分层设计ChatClient 层 Agent 层可扩展性支持自定义指标和标签从黑盒到玻璃盒的跨越在 AI 时代可观测性不再是锦上添花而是必需品。没有它你就像蒙着眼睛开车有了它你才能真正掌控自己的 AI 应用。AgentOpenTelemetry 的出现标志着 AI 工程化的一个重要里程碑。它告诉我们AI 应用也可以像传统软件一样被精确地测量、监控和优化。十一、快速上手指南如果你已经迫不及待想试试这里是最快的上手路径Step 1: 克隆示例项目git clone https://github.com/microsoft/agent-framework.git cd agent-framework/samples/GettingStarted/AgentOpenTelemetryStep 2: 配置环境$env:AZURE_OPENAI_ENDPOINThttps://your-resource.openai.azure.com/ $env:AZURE_OPENAI_DEPLOYMENT_NAMEgpt-4o-miniStep 3: 一键启动.\start-demo.ps1脚本会自动启动 Aspire Dashboard编译并运行应用打开浏览器到监控页面Step 4: 开始探索在控制台输入问题然后到 Aspire Dashboard 查看Traces 页面看完整的调用链路Metrics 页面看 Token 消耗趋势Logs 页面看详细的执行日志就这么简单十二、延伸阅读与资源官方文档Agent Framework 文档https://learn.microsoft.com/agent-framework/OpenTelemetry 规范https://opentelemetry.io/docs/specs/semconv/gen-ai/Aspire Dashboard 指南https://learn.microsoft.com/dotnet/aspire/社区资源GitHub 仓库https://github.com/microsoft/agent-framework示例代码samples/GettingStarted/AgentOpenTelemetry单元测试tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs相关技术Microsoft.Extensions.AI统一的 AI 抽象层Semantic Kernel微软的 AI 编排框架可迁移到 Agent FrameworkAzure Monitor企业级监控平台十三、写在最后可观测性的哲学思考在结束这篇文章之前我想分享一个更深层的思考。可观测性的本质是对复杂系统的理解和掌控。在传统软件中我们通过日志、指标、追踪来理解系统行为。但 AI 系统的复杂度是指数级的——它不仅有确定性的代码逻辑还有不确定性的模型推理。AgentOpenTelemetry 的价值不仅在于它提供了监控工具更在于它建立了一套理解 AI 系统的方法论标准化用统一的语言描述 AI 行为OpenTelemetry Semantic Conventions分层化从 ChatClient 到 Agent 到 Workflow逐层抽象可追溯每个决策、每次调用都有据可查数据驱动基于真实数据而非直觉做优化这套方法论将帮助我们在 AI 的不确定性中找到确定性的锚点。一个小故事我曾经遇到一个团队他们的 AI 客服系统上线后问题频出。每次出问题都要花几个小时翻日志、猜测原因、盲目尝试。后来他们引入了 AgentOpenTelemetry情况彻底改变了问题定位从几小时缩短到几分钟优化效果有数据支撑不再靠感觉团队信心知道系统在做什么心里有底技术负责人跟我说以前我们是在黑暗中摸索现在终于开灯了。这就是可观测性的力量。你的下一步如果你正在开发 AI 应用我强烈建议你现在就开始不要等到出问题才想起监控从简单开始先用 Aspire Dashboard再考虑企业级方案建立基线记录正常情况下的指标才能识别异常持续优化可观测性是个迭代过程不是一次性工程记住你无法优化你无法测量的东西。结语从黑盒到玻璃盒从盲驾到精准导航AgentOpenTelemetry 为 AI 应用的工程化实践提供了坚实的基础。它不是银弹但它是必需品。它不会让你的 Agent 变得更聪明但会让你变得更聪明——因为你终于知道你的 Agent 在做什么了。在这个 AI 狂飙突进的时代让我们不仅追求能用更追求可控。让我们不仅关注模型的能力更关注系统的可靠性。因为只有这样AI 才能真正从实验室走向生产从 Demo 走向产品从概念走向价值。关于作者一个在 AI 工程化道路上摸爬滚打的开发者相信技术的力量也相信工程的美学。如果这篇文章对你有帮助欢迎点赞、收藏、转发。如果有任何问题或建议欢迎在评论区交流。版权声明本文基于 Microsoft Agent Framework 开源项目的深度研究代码示例遵循项目的 MIT 许可证。文章内容为原创转载请注明出处。相关文章推荐《AI Agent 架构设计从单体到分布式》《Token 优化实战如何降低 50% 的 AI 成本》《.NET 开发者的 AI 转型指南》更多AIGC文章RAG技术全解从原理到实战的简明指南更多VibeCoding文章