要参与 Agent 365 生态系统,请为您的代理添加 Agent 365 可观测性功能。 Agent 365 可观测性构建于OpenTelemetry (OTel)之上,提供一个统一框架,用于在所有代理平台上持续且安全地捕获遥测数据。 通过实现这一必需组件,你可以让IT管理员在Microsoft管理中心监控代理的活动,并允许安全团队使用Defender和Purview进行合规和威胁检测。
主要优势
-
端到端可视化:为每一次代理调用(包括会话、工具调用和异常)捕捉全面的遥测数据,实现跨平台的完整追踪。
-
安全与合规赋能:将统一审计日志输入Defender和Purview,为您的代理提供先进的安全场景和合规报告。
-
跨平台灵活性:基于 OTel 标准构建,支持多种运行时和平台,例如 Copilot Studio、Foundry 和未来的代理框架。
- 为管理员提高运作效率:在 Microsoft 365 管理中心提供集中式监控,减少故障排除时间,并通过基于角色的访问控制改进 IT 团队对代理的管理治理。
受支持的代理
以下代理类型支持 Agent 365 可观测性:
Installation
使用这些命令为代理 365 支持的语言安装可观测性模块。
安装核心可观测性和运行时包。 使用 Agent 365 可观测性的所有代理都需要这些包。
pip install microsoft-agents-a365-observability-core
pip install microsoft-agents-a365-runtime
如果代理使用 Microsoft Agents Hosting 包,请安装托管集成包。 它提供中间件,能够从TurnContext自动填充上下文信息和作用域,并包括用于可观测性导出器的令牌缓存。
pip install microsoft-agents-a365-observability-hosting
如果代理使用其中一个受支持的 AI 框架,请安装相应的自动检测扩展,以在不手动检测代码的情况下自动捕获遥测数据。 有关配置详细信息,请参阅 自动检测。
# For Semantic Kernel
pip install microsoft-agents-a365-observability-extensions-semantic-kernel
# For OpenAI Agents SDK
pip install microsoft-agents-a365-observability-extensions-openai
# For Microsoft Agent Framework
pip install microsoft-agents-a365-observability-extensions-agent-framework
# For LangChain
pip install microsoft-agents-a365-observability-extensions-langchain
安装核心可观测性和运行时包。 使用 Agent 365 可观测性的所有代理都需要这些包。
npm install @microsoft/agents-a365-observability
npm install @microsoft/agents-a365-runtime
如果代理使用 @microsoft/agents-hosting 包,请安装托管集成包。 它提供中间件,能够从TurnContext自动填充上下文信息和作用域,并包括用于可观测性导出器的令牌缓存。
npm install @microsoft/agents-a365-observability-hosting
如果代理使用其中一个受支持的 AI 框架,请安装相应的自动检测扩展,以在不手动检测代码的情况下自动捕获遥测数据。 有关配置详细信息,请参阅 自动检测。
// For OpenAI Agents SDK
npm install @microsoft/agents-a365-observability-extensions-openai
// For LangChain
npm install @microsoft/agents-a365-observability-extensions-langchain
安装核心可观测性和运行时包。 使用 Agent 365 可观测性的所有代理都需要此软件包。
dotnet add package Microsoft.Agents.A365.Observability.Runtime
如果你的代理使用Microsoft.Agents.A365.Observability.Hosting NuGet 包,请安装托管集成包。 它提供自动从TurnContext填充上下文信息的中间件,并包括对可观察性导出器的令牌缓存。
dotnet add package Microsoft.Agents.A365.Observability.Hosting
如果代理使用其中一个受支持的 AI 框架,请安装相应的自动检测扩展,以在不手动检测代码的情况下自动捕获遥测数据。 有关配置详细信息,请参阅 自动检测。
// For Semantic Kernel
dotnet add package Microsoft.Agents.A365.Observability.Extensions.SemanticKernel
// For OpenAI
dotnet add package Microsoft.Agents.A365.Observability.Extensions.OpenAI
// For Agent Framework
dotnet add package Microsoft.Agents.A365.Observability.Extensions.AgentFramework
Configuration
请使用以下设置为您的代理启用并自定义Agent 365可观察性。
将环境变量ENABLE_A365_OBSERVABILITY_EXPORTER设置为true以实现可观测性。 在 Agent 365 SDK 2.0 及以后版本中,导出器始终使用服务对服务(S2S)路由,并使用已配置的仅应用 token_resolver 进行身份验证。 如果你启用导出器而不使用解析器,Python会保留控制台导出器的备援,不会将遥测数据发送给Agent 365。
from microsoft_agents_a365.observability.core import configure
def token_resolver(agent_id: str, tenant_id: str) -> str | None:
# Return a validated app-only observability token for this agent and tenant.
return "<app-only-observability-token>"
configure(
service_name="my-agent-service",
service_namespace="my.namespace",
token_resolver=token_resolver,
)
令牌解析器不包括在记录到控制台的日志中。
可以通过将Agent365ExporterOptions实例传递给exporter_options以自定义导出程序的行为。 提供 exporter_options 时,它优先于 token_resolver 和 cluster_category 参数。
from microsoft_agents_a365.observability.core import configure, Agent365ExporterOptions
configure(
service_name="my-agent-service",
service_namespace="my.namespace",
exporter_options=Agent365ExporterOptions(
cluster_category="prod",
token_resolver=token_resolver,
),
suppress_invoke_agent_input=True,
)
下表描述了configure()的可选参数。
| 参数 |
Description |
Default |
logger_name |
用于调试和控制台日志输出的Python记录器的名称。 |
microsoft_agents_a365.observability.core |
exporter_options |
一个 Agent365ExporterOptions 实例,用于配置令牌解析程序和群集类别。 |
None |
suppress_invoke_agent_input |
当True时,抑制InvokeAgent跨度上的输入消息。 |
False |
下表描述了的 Agent365ExporterOptions可选属性。
| 财产 |
Description |
Default |
use_s2s_endpoint |
已弃用并被忽略。 Agent 365 SDK 2.0及以后版本始终使用S2S路由,即使该值为 False。 |
False (已忽略) |
max_queue_size |
批处理处理器的最大队列大小。 |
2048 |
scheduled_delay_ms |
导出批处理之间的延迟(以毫秒为单位)。 |
5000 |
exporter_timeout_ms |
导出操作的超时(以毫秒为单位)。 |
30000 |
max_export_batch_size |
导出操作的最大批大小。 |
512 |
将环境变量ENABLE_A365_OBSERVABILITY_EXPORTER设置为true以实现可观测性。 在 Agent 365 SDK 2.0 及以后版本中,导出器始终使用 S2S 路由,并通过配置的仅应用令牌解析器进行身份验证。 如果你在没有解析器的情况下启用 Agent 365 导出器,配置就会失败。
import { ObservabilityManager } from '@microsoft/agents-a365-observability';
// Define a token resolver that returns a validated app-only observability token.
const tokenResolver = (agentId, tenantId) => {
// Your app-only token resolution logic here.
return "your-token";
};
// Advanced configuration with builder pattern
const builder = ObservabilityManager.configure(builder =>
builder
.withService('my-agent-service', '1.0.0')
.withTokenResolver((agentId, tenantId) => {
return tokenResolver(agentId, tenantId);
})
);
builder.start();
作为环境变量的替代方法,可以通过配置提供程序的withConfigurationProvider方法以编程方式配置可观测性。 如果还使用单个生成器方法(例如 withExporterOptions 或 withClusterCategory),则各个生成器方法优先于配置提供程序中的值。
import { ObservabilityManager } from '@microsoft/agents-a365-observability';
import { ObservabilityConfiguration } from '@microsoft/agents-a365-observability';
const configProvider = new ObservabilityConfiguration({
isObservabilityExporterEnabled: () => true,
// Set log levels as pipe-separated values (for example, 'info|warn|error')
observabilityLogLevel: () => 'info|warn|error',
});
const builder = ObservabilityManager.configure(builder =>
builder
.withService('my-agent-service', '1.0.0')
.withConfigurationProvider(configProvider)
.withTokenResolver((agentId, tenantId) => {
return tokenResolver(agentId, tenantId);
})
);
builder.start();
可以通过将Agent365ExporterOptions实例传递给withExporterOptions以自定义导出程序的行为。 这个选项允许你控制批处理和超时。 它不会改变导出路线。
import {
ObservabilityManager,
Agent365ExporterOptions,
} from '@microsoft/agents-a365-observability';
import { ClusterCategory } from '@microsoft/agents-a365-runtime';
const exporterOptions = new Agent365ExporterOptions();
exporterOptions.maxQueueSize = 10;
const builder = ObservabilityManager.configure(builder =>
builder
.withService('my-agent-service', '1.0.0')
.withClusterCategory(ClusterCategory.prod)
.withExporterOptions(exporterOptions)
.withTokenResolver(tokenResolver)
);
builder.start();
下表描述了的 Agent365ExporterOptions可选属性。
| 财产 |
Description |
Default |
useS2SEndpoint |
已弃用并被忽略。 Agent 365 SDK 2.0及以后版本始终使用S2S路由,即使该值为 false。 |
true (已忽略) |
maxQueueSize |
批处理处理器的最大队列大小。 |
2048 |
scheduledDelayMilliseconds |
导出批处理之间的延迟(以毫秒为单位)。 |
5000 |
exporterTimeoutMilliseconds |
整个导出操作的超时(以毫秒为单位)。 |
90000 |
httpRequestTimeoutMilliseconds |
对后端的每个 HTTP 请求的超时(以毫秒为单位)。 |
30000 |
maxExportBatchSize |
导出操作的最大批大小。 |
512 |
你也可以提供一个自定义日志器来实现该ILogger接口(info, warn, errorevent, )。 通过使用withCustomLogger将其传递给构建器。
const builder = ObservabilityManager.configure(builder =>
builder
.withService('my-agent-service', '1.0.0')
.withCustomLogger({
info: (message, ...args) => { /* your logging logic */ },
warn: (message, ...args) => { /* your logging logic */ },
error: (message, ...args) => { /* your logging logic */ },
event: (eventName, success, durationMs, message, details) => { /* your logging logic */ }
})
.withTokenResolver((agentId, tenantId) => {
return tokenResolver(agentId, tenantId);
})
);
builder.start();
在EnableAgent365Exporter中设置true到appsettings.json。 在 Agent 365 SDK 2.0 及以后版本中,导出器始终使用 S2S 路由,并通过配置的仅应用令牌解析器进行身份验证。 如果你在未指定 TokenResolver 或 ContextualTokenResolver 的情况下启用导出器,导出器构建会失败。
在 Program.cs 中,将 Agent365ExporterOptions 添加到服务集合。 此更改配置跟踪导出程序用于检索令牌的委托。
通过使用 AddA365Tracing()添加与可观测性相关的依赖关系。
using Microsoft.Agents.A365.Observability.Runtime;
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Exporters;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(sp =>
{
return new Agent365ExporterOptions
{
TokenResolver = async (agentId, tenantId) =>
{
// Return a cached, validated app-only observability token for this agent and tenant.
var token = await tokenProvider.GetObservabilityTokenAsync(agentId, tenantId);
return token;
}
};
});
builder.AddA365Tracing();
可以通过将配置委托和导出程序类型传递给 AddA365Tracing()自定义导出程序行为。
builder.AddA365Tracing(
configure: tracingBuilder =>
{
// Use the builder to add extensions (e.g., WithSemanticKernel(), WithOpenAI())
},
agent365ExporterType: Agent365ExporterType.Agent365ExporterAsync
);
下表描述了的 Agent365ExporterOptions可选属性。
| 财产 |
Description |
Default |
UseS2SEndpoint |
已弃用并被忽略。 Agent 365 SDK 2.0及以后版本始终使用S2S路由,即使该值为 false。 |
false (已忽略) |
MaxQueueSize |
批处理处理器的最大队列大小。 |
2048 |
ScheduledDelayMilliseconds |
导出批处理之间的延迟(以毫秒为单位)。 |
5000 |
ExporterTimeoutMilliseconds |
导出操作的超时(以毫秒为单位)。 |
30000 |
MaxExportBatchSize |
导出操作的最大批大小。 |
512 |
行李属性
使用 BaggageBuilder 设置在请求中贯穿所有范围的上下文信息。
SDK实现了一个 SpanProcessor ,将所有非空行李条目复制到新开始的跨度,且不覆盖现有属性。
from microsoft_agents_a365.observability.core import BaggageBuilder
with (
BaggageBuilder()
.tenant_id("tenant-123")
.agent_id("agent-456")
.conversation_id("conv-789")
.build()
):
# Any spans started in this context will receive these as attributes
pass
要从BaggageBuilder自动填充TurnContext,请使用populate包中的microsoft-agents-a365-observability-hosting助手。 此帮助程序会自动从活动中提取调用方、代理、租户、通道和聊天详细信息。
from microsoft_agents.hosting.core.turn_context import TurnContext
from microsoft_agents_a365.observability.core import BaggageBuilder
from microsoft_agents_a365.observability.hosting.scope_helpers.populate_baggage import populate
builder = BaggageBuilder()
populate(builder, turn_context)
with builder.build():
# Baggage is auto-populated from the TurnContext activity
pass
import { BaggageBuilder } from '@microsoft/agents-a365-observability';
// Create and apply baggage context
const baggageScope = new BaggageBuilder()
// Core identifiers
.tenantId('tenant-123')
.agentId('agent-456')
.conversationId('conv-789')
.build();
// Execute operations within the baggage context
baggageScope.run(() => {
// All spans created within this context will inherit the baggage values
// Invoke another agent
const agentScope = InvokeAgentScope.start(request, scopeDetails, agentDetails);
// ... agent logic
// Execute tools
const toolScope = ExecuteToolScope.start(request, toolDetails, agentDetails);
// ... tool logic
});
要从BaggageBuilder自动填充TurnContext,请使用fromTurnContext包中的@microsoft/agents-a365-observability-hosting助手。 此帮助程序会自动从活动中提取调用方、代理、租户、通道和聊天详细信息。
import { BaggageBuilder } from '@microsoft/agents-a365-observability';
import { BaggageBuilderUtils } from '@microsoft/agents-a365-observability-hosting';
const baggageScope = BaggageBuilderUtils.fromTurnContext(new BaggageBuilder(), context)
.invokeAgentServer(context.activity.serviceUrl, 3978)
.build();
await baggageScope.run(async () => {
// Baggage is auto-populated from the TurnContext activity
});
using Microsoft.Agents.A365.Observability.Runtime.Common;
using var baggageScope = new BaggageBuilder()
.TenantId("tenant-123")
.AgentId("agent-456")
.ConversationId("conv-789")
.Build();
// Any spans started in this context will receive them as attributes.
若要从 BaggageBuilder 自动填充 ITurnContext,请使用 FromTurnContext 包中的 Microsoft.Agents.A365.Observability.Hosting 扩展方法。 此方法会自动从活动中提取调用方、代理、租户、通道和聊天详细信息。
using Microsoft.Agents.A365.Observability.Runtime.Common;
using Microsoft.Agents.A365.Observability.Hosting.Extensions;
using var baggageScope = new BaggageBuilder()
.FromTurnContext(turnContext)
.Build();
行李中间件
如果代理使用托管集成包,请注册行李中间件,以便为每个传入请求自动填充行李。 此步骤无需在每个活动处理程序中手动调用 BaggageBuilder 。
在适配器中间件集上注册 BaggageMiddleware 。 它会自动从每个传入的 TurnContext 消息中提取调用方、代理、租户、通道和会话详细信息,并将请求包装在上下文范围内。
from microsoft_agents_a365.observability.hosting import BaggageMiddleware
adapter.use(BaggageMiddleware())
或者,您可以使用 ObservabilityHostingManager 配置行李中间件以及其他托管功能:
from microsoft_agents_a365.observability.hosting import ObservabilityHostingManager, ObservabilityHostingOptions
options = ObservabilityHostingOptions(enable_baggage=True)
ObservabilityHostingManager.configure(adapter.middleware_set, options)
中间件会跳过异步响应(ContinueConversation 事件)的上下文信息设置,以避免覆盖原始请求已经设置的上下文信息。
在适配器上注册 BaggageMiddleware 。 它会自动从每个传入的 TurnContext 消息中提取调用方、代理、租户、通道和会话详细信息,并将请求包装在上下文范围内。
import { BaggageMiddleware } from '@microsoft/agents-a365-observability-hosting';
// Option 1: Register middleware directly on the adapter
adapter.use(new BaggageMiddleware());
或者,您可以使用 ObservabilityHostingManager 配置行李中间件以及其他托管功能:
import { ObservabilityHostingManager } from '@microsoft/agents-a365-observability-hosting';
const manager = new ObservabilityHostingManager();
manager.configure(adapter, { enableBaggage: true });
中间件会跳过异步响应(ContinueConversation 事件)的上下文信息设置,以避免覆盖原始请求已经设置的上下文信息。
在适配器上注册 BaggageTurnMiddleware 。 它会自动从每个传入的 ITurnContext 消息中提取调用方、代理、租户、通道和会话详细信息,并将请求包装在上下文范围内。
using Microsoft.Agents.A365.Observability.Hosting.Middleware;
adapter.Use(new BaggageTurnMiddleware());
中间件会跳过异步响应(ContinueConversation 事件)的上下文信息设置,以避免覆盖原始请求已经设置的上下文信息。
如果需要 HTTP 级上下文信息(例如,在 Bot Framework 管道运行之前设置租户和代理 ID),请使用 ObservabilityBaggageMiddleware 扩展方法在 ASP.NET Core 管道中注册 UseObservabilityRequestContext。 必须提供一个解析程序函数,用于从 HTTP 上下文中提取租户 ID 和代理 ID。
using Microsoft.Agents.A365.Observability.Hosting.Middleware;
app.UseObservabilityRequestContext((httpContext) =>
{
// Extract tenant and agent IDs from your request context
var tenantId = GetTenantIdFromContext(httpContext);
var agentId = GetAgentIdFromContext(httpContext);
return (tenantId, agentId);
});
令牌解析器
当你在 Agent 365 SDK 2.0 及以后版本中使用 Agent 365 导出器时,提供一个令牌解析器,返回导出代理实例的最终仅应用可观察性令牌。 导出器总是将遥测数据发送到S2S路由,而不会回退到委派的路由。 Agent 365 注册的代理实例无需 Agent365.Observability.OtelWrite 许可或管理员同意即可通过此路径导出。
使用两步联邦托管身份(FMI)交换以获得仅应用令牌:
- 为
api://AzureADTokenExchange/.default 获取一个蓝图 client_credentials 令牌,并将 fmi_path 设置为代理实例客户端 ID。
- 获取一个用于
api://9b975845-388f-4429-889e-eab1ef63949c/.default 的 agent-instanceclient_credentials 令牌。 将步骤1的令牌传递为 client_assertion,并设 client_assertion_type 为 urn:ietf:params:oauth:client-assertion-type:jwt-bearer。
完整的认证设置请参见 Agent 365 启用:使用 S2S。 完整的令牌服务实现,请参见 Agent 365 的 Node.js、Python 和 .NET 示例。
你的解析器必须:
- 为导出代理实例和租户返回一个仅限应用令牌。 切勿返回中间蓝图断言、蓝图令牌、用户令牌或OBO令牌。
- 在返回令牌之前验证该令牌。 接受
idtyp=app。 如果 idtyp 不存在,则只接受具有非空 roles 声明或其值等于 sub 的非空 oid 声明的标记。 拒绝具有 idtyp 声明或其他 9b975845-388f-4429-889e-eab1ef63949c 值的代币、已过期的代币,以及其 api://9b975845-388f-4429-889e-eab1ef63949c 不是 aud 或 scp 的代币。
- 缓存令牌并在其过期前刷新它。 导出器在每个导出批次中,会针对每个租户和代理身份组合调用一次解析器。
Note
从 SDK 1.x 迁移: SDK 2.0 移除了可观察性导出的委派令牌交换。 将代理中委派的令牌代码替换为仅应用的解析器,如下示例所示。 那些仍用SDK 1.x并通过委派路由导出的代理,仍然需要委派 Agent365.Observability.OtelWrite 权限和管理员同意。 该 a365 setup all 命令不会为蓝图代理配置该权限。 要授予此权限,请参阅 授予许可。
从你的 token_resolver 呼叫 AgenticTokenCache.refresh_observability_token(agent_id, tenant_id, acquire_app_only_obs_token)。 缓存将可观测性/.default范围传递给你的获取回调,并返回缓存中的令牌。
from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.hosting.token_cache_helpers import AgenticTokenCache
cache = AgenticTokenCache()
async def acquire_app_only_obs_token(
agent_id: str,
tenant_id: str,
scopes: list[str],
) -> str:
# Run the FMI exchange described earlier, validate the token, and return it.
return "<app-only-observability-token>"
async def token_resolver(agent_id: str, tenant_id: str) -> str:
return await cache.refresh_observability_token(
agent_id, tenant_id, acquire_app_only_obs_token
)
configure(
service_name="my-agent-service",
service_namespace="my.namespace",
token_resolver=token_resolver,
)
Python 还支持一个同步解析器,会从线程安全缓存中获取并返回令牌。 Agent 365 的样本采用了该模式,避免了在导出线程上运行异步解析器的限制。
要从 SDK 1.x 迁移,请删除请求可观测性作用域的 AGENT_APP.auth.exchange_token 调用和传递 AgenticTokenStruct 的 AgenticTokenCache.register_observability 调用。 在 SDK 2.0 中,register_observability 是一个已弃用的 no-op。
将 withTokenResolver 与 AgenticTokenCacheInstance.RefreshObservabilityToken(agentId, tenantId, acquireAppOnlyObsToken) 配合使用。 获取回调接收 (agentId, tenantId, scopes) 并返回最终的应用专用可观测性令牌。 读取缓存令牌。AgenticTokenCacheInstance.getObservabilityToken(agentId, tenantId)
import { ObservabilityManager } from '@microsoft/agents-a365-observability';
import { AgenticTokenCacheInstance } from '@microsoft/agents-a365-observability-hosting';
async function acquireAppOnlyObsToken(
agentId: string,
tenantId: string,
scopes: readonly string[]
): Promise<string> {
// Run the FMI exchange described earlier, validate the token, and return it.
return "<app-only-observability-token>";
}
const builder = ObservabilityManager.configure(builder =>
builder
.withService('my-agent-service', '1.0.0')
.withTokenResolver(async (agentId, tenantId) => {
await AgenticTokenCacheInstance.RefreshObservabilityToken(
agentId, tenantId, acquireAppOnlyObsToken
);
return AgenticTokenCacheInstance.getObservabilityToken(agentId, tenantId);
})
);
builder.start();
要从 SDK 1.x 迁移,请删除请求可观测范围的 agentApplication.authorization.exchangeToken 调用,并将 RefreshObservabilityToken(agentId, tenantId, context, authorization, scopes) 替换为示例中的解析器形式。 SDK 2.0 取消了委派的重载:TypeScript 调用者会收到编译错误,未进行类型检查的调用者会获得一次性错误日志且无令牌。
使用 AddAgenticTracingExporter() 注册 IExporterTokenCache<ObservabilityTokenResolver> 和从缓存读取令牌的导出程序选项。
using Microsoft.Agents.A365.Observability.Hosting;
builder.Services.AddAgenticTracingExporter();
在代理应用中,通过调用 RegisterObservability(agentId, tenantId, resolver, scopes)来注册代理和租户的应用专用解析器。 以代理和租户中先完成首次注册者为准。
using Microsoft.Agents.A365.Observability.Hosting.Caching;
using Microsoft.Agents.A365.Observability.Runtime.Common;
using Microsoft.Agents.Builder;
using Microsoft.Agents.Builder.App;
using Microsoft.Agents.Builder.State;
using System.Threading;
using System.Threading.Tasks;
public class MyAgent : AgentApplication
{
private readonly IExporterTokenCache<ObservabilityTokenResolver> _agentTokenCache;
public MyAgent(AgentApplicationOptions options, IExporterTokenCache<ObservabilityTokenResolver> agentTokenCache)
: base(options)
{
_agentTokenCache = agentTokenCache;
}
protected async Task MessageActivityAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
var agentId = turnContext.Activity.Recipient.AgenticAppId;
var tenantId = turnContext.Activity.Recipient.TenantId;
_agentTokenCache.RegisterObservability(
agentId,
tenantId,
AcquireAppOnlyObservabilityTokenAsync,
EnvironmentUtils.GetObservabilityAuthenticationScope());
using var baggageScope = new BaggageBuilder()
.TenantId(tenantId)
.AgentId(agentId)
.Build();
// Handle the message.
}
private static Task<string?> AcquireAppOnlyObservabilityTokenAsync(
string agentId,
string tenantId,
string[] observabilityScopes)
{
// Run the FMI exchange described earlier, validate the token, and return it.
return Task.FromResult<string?>("<app-only-observability-token>");
}
}
如果你直接管理一个 AgenticTokenCache 实例,调用 RefreshObservabilityToken(agentId, tenantId, resolver) 以使用默认的可观测性作用域,或者调用 RefreshObservabilityToken(agentId, tenantId, resolver, scopes) 以显式传递作用域。
要从 SDK 1.x 迁移,请用示例中的仅应用解析器替换 IExporterTokenCache<AgenticTokenStruct> 和传递 AgenticTokenStruct 的 RegisterObservability 调用。 不要用 ExchangeTurnTokenAsync 来做可观测性导出。 在 SDK 2.0 中,AgenticTokenStruct 注册重载已过时,并会导致编译错误。
自动检测
自动检测会自动侦听代理框架(SDK)现有的跟踪遥测信号,并将其转发到代理 365 可观测性服务。 此功能消除了开发者手动编写监控代码的需求,简化了设置,并确保了性能跟踪的一致性。
多个SDK和平台支持自动仪器化:
Note
对自动检测的支持因平台和 SDK 实现而异。
语义内核
自动插桩需要使用 baggage 构建器。 通过使用 BaggageBuilder 设置代理 ID 和租户 ID。
安装此包。
pip install microsoft-agents-a365-observability-extensions-semantic-kernel
配置可观测性
from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.extensions.semantickernel.trace_instrumentor import SemanticKernelInstrumentor
# Configure observability
configure(
service_name="my-semantic-kernel-agent",
service_namespace="ai.agents"
)
# Enable auto-instrumentation
instrumentor = SemanticKernelInstrumentor()
instrumentor.instrument()
# Your Semantic Kernel code is now automatically traced
将依赖项添加到服务集合。
using Microsoft.Agents.A365.Observability.Extensions.SemanticKernel;
builder.AddA365Tracing(configure: config => config.WithSemanticKernel());
通过使用 AgentId 设置 TenantId 和 BaggageBuilder。 确保您在创建ChatCompletionAgent时使用的ID与传递给BaggageBuilder的代理ID相匹配。
using Microsoft.Agents.A365.Observability.Extensions.SemanticKernel;
using Microsoft.Agents.A365.Observability.Runtime.Common;
public class MyAgent
{
public async Task<AgentResponse> ProcessUserRequest(string userInput)
{
using var baggageScope = new BaggageBuilder()
.AgentId(<your-agent-id>) // NOTE: This will be the agent ID with which the TokenResolver delegate is invoked.
.TenantId(<your-tenant-id>) // NOTE: This will be the tenant ID with which the TokenResolver delegate is invoked.
.Build();
var chatCompletionAgent = new ChatCompletionAgent
{
// NOTE: This will be the agent ID with which the TokenResolver delegate is invoked. Should match above.
Id = <your-agent-id>,
...
};
}
}
OpenAI
自动插桩需要使用 baggage 构建器。 通过使用 BaggageBuilder 设置代理 ID 和租户 ID。
安装此包。
pip install microsoft-agents-a365-observability-extensions-openai
配置可观测性
from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.extensions.openai import OpenAIAgentsTraceInstrumentor
# Configure observability
configure(
service_name="my-openai-agent",
service_namespace="ai.agents"
)
# Enable auto-instrumentation
instrumentor = OpenAIAgentsTraceInstrumentor()
instrumentor.instrument()
# Your OpenAI Agents code is now automatically traced
安装此包。
npm install @microsoft/agents-a365-observability-extensions-openai
配置可观测性
import { ObservabilityManager } from '@microsoft/agents-a365-observability';
import { OpenAIAgentsTraceInstrumentor } from '@microsoft/agents-a365-observability-extensions-openai';
// Configure observability first
const sdk = ObservabilityManager.configure((builder) =>
builder
.withService('My Agent Service', '1.0.0')
);
// Create and enable the instrumentor
const instrumentor = new OpenAIAgentsTraceInstrumentor({
enabled: true,
tracerName: 'openai-agents-tracer',
tracerVersion: '1.0.0'
});
sdk.start();
instrumentor.enable();
将依赖项添加到服务集合。
using Microsoft.Agents.A365.Observability.Extensions.OpenAI;
builder.AddA365Tracing(configure: config => config.WithOpenAI());
通过使用 AgentId 设置 TenantId 和 BaggageBuilder。 对于工具的调用,可以在Trace()实例上使用ChatToolCall开始跟踪。
using Microsoft.Agents.A365.Observability.Extensions.OpenAI;
using Microsoft.Agents.A365.Observability.Runtime.Common;
public class MyAgent
{
public async Task<AgentResponse> ProcessUserRequest(string userInput)
{
using var baggageScope = new BaggageBuilder()
.AgentId(<your-agent-id>) // NOTE: This will be the agent ID with which the TokenResolver delegate is invoked.
.TenantId(<your-tenant-id>) // NOTE: This will be the tenant ID with which the TokenResolver delegate is invoked.
.Build();
// NOTE: This will be the agent and tenant ID with which the TokenResolver delegate will be invoked.
using var scope = chatToolCall.Trace(agentId: <your-agent-id>, <your-tenant-id>);
}
}
代理框架
自动插桩需要使用 baggage 构建器。 通过使用 BaggageBuilder 设置代理 ID 和租户 ID。
安装此包。
pip install microsoft-agents-a365-observability-extensions-agent-framework
配置可观测性
from microsoft_agents_a365.observability.core import configure
from microsoft_agents_a365.observability.extensions.agentframework import (
AgentFrameworkInstrumentor,
)
# Configure observability
configure(
service_name="AgentFrameworkTracingWithAzureOpenAI",
service_namespace="AgentFrameworkTesting",
)
# Enable auto-instrumentation
AgentFrameworkInstrumentor().instrument()
将依赖项添加到服务集合。
using Microsoft.Agents.A365.Observability.Extensions.AgentFramework;
builder.AddA365Tracing(configure: config => config.WithAgentFramework());
通过使用 AgentId 设置 TenantId 和 BaggageBuilder。
using Microsoft.Agents.A365.Observability.Runtime.Common;
public class MyAgent : AgentApplication
{
protected async Task MessageActivityAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
using var baggageScope = new BaggageBuilder()
.AgentId(<your-agent-id>) // NOTE: This will be the agent ID with which the TokenResolver delegate is invoked.
.TenantId(<your-tenant-id>) // NOTE: This will be the tenant ID with which the TokenResolver delegate is invoked.
.Build();
}
}
LangChain 框架
Note
LangChain 框架的自动检测还支持 LangGraph 和 深度智能体。 相同的扩展会自动捕获使用任何这些框架构建的智能体的遥测数据。
自动检测需要使用行李生成器。 设置代理 ID 和租户 ID,使用 BaggageBuilder。
安装此包。
pip install microsoft-agents-a365-observability-extensions-langchain
配置可观测性
from microsoft_agents_a365.observability.core.config import configure
from microsoft_agents_a365.observability.extensions.langchain import CustomLangChainInstrumentor
# Configure observability
configure(
service_name="my-langchain-agent",
service_namespace="ai.agents"
)
# Enable auto-instrumentation
CustomLangChainInstrumentor()
# Your LangChain code is now automatically traced
安装此包。
npm install @microsoft/agents-a365-observability-extensions-langchain
配置可观测性
import { ObservabilityManager } from '@microsoft/agents-a365-observability';
import { LangChainTraceInstrumentor } from '@microsoft/agents-a365-observability-extensions-langchain';
import * as LangChainCallbacks from '@langchain/core/callbacks/manager';
// Configure observability first
const sdk = ObservabilityManager.configure((builder) =>
builder
.withService('My Agent Service', '1.0.0')
);
sdk.start();
// Enable LangChain auto-instrumentation
LangChainTraceInstrumentor.instrument(LangChainCallbacks);
// Your LangChain code is now automatically traced
手动仪器
使用Agent 365可观察性SDK来了解代理的内部工作原理。
SDK 提供可以启动的范围: InvokeAgentScope、 ExecuteToolScope、 InferenceScope和 OutputScope。
代理调用
在开始代理程序时使用此范围。 通过调用代理范围,你可以捕获当前代理、代理用户数据等属性。
from microsoft_agents_a365.observability.core import (
InvokeAgentScope,
InvokeAgentScopeDetails,
AgentDetails,
CallerDetails,
UserDetails,
Channel,
Request,
ServiceEndpoint,
)
agent_details = AgentDetails(
agent_id="agent-456",
agent_name="My Agent",
agent_description="An AI agent powered by Azure OpenAI",
agentic_user_id="auid-123",
agentic_user_email="agent@contoso.com",
agent_blueprint_id="blueprint-789",
tenant_id="tenant-123",
)
scope_details = InvokeAgentScopeDetails(
endpoint=ServiceEndpoint(hostname="myagent.contoso.com", port=443),
)
request = Request(
content="User asks a question",
session_id="session-42",
conversation_id="conv-xyz",
channel=Channel(name="msteams"),
)
caller_details = CallerDetails(
user_details=UserDetails(
user_id="user-123",
user_email="jane.doe@contoso.com",
user_name="Jane Doe",
),
)
with InvokeAgentScope.start(request, scope_details, agent_details, caller_details):
# Perform agent invocation logic
response = call_agent(...)
import {
InvokeAgentScope,
InvokeAgentScopeDetails,
AgentDetails,
CallerDetails,
UserDetails,
Channel,
Request,
ServiceEndpoint,
} from '@microsoft/agents-a365-observability';
// Use the same agentDetails instance across all scopes in a request
const agentDetails: AgentDetails = {
agentId: 'agent-456',
agentName: 'Email Assistant',
agentDescription: 'An AI agent powered by Azure OpenAI',
agentAuid: 'auid-123',
agentEmail: 'agent@contoso.com',
agentBlueprintId: 'blueprint-789',
tenantId: 'tenant-123',
};
const scopeDetails: InvokeAgentScopeDetails = {
endpoint: { host: 'myagent.contoso.com', port: 443 } as ServiceEndpoint,
};
// Use the same request instance across all scopes in a request
const request: Request = {
content: 'Please help me organize my emails',
sessionId: 'session-42',
conversationId: 'conv-xyz',
channel: { name: 'msteams' } as Channel,
};
// Optional: Caller details (human user, or agent-to-agent)
const callerDetails: CallerDetails = {
userDetails: {
userId: 'user-123',
userEmail: 'jane.doe@contoso.com',
userName: 'Jane Doe',
} as UserDetails,
};
const scope = InvokeAgentScope.start(request, scopeDetails, agentDetails, callerDetails);
try {
await scope.withActiveSpanAsync(async () => {
// Record input messages
scope.recordInputMessages(['Please help me organize my emails', 'Focus on urgent items']);
// Your agent invocation logic here
const response = await invokeAgent(request.content);
// Record output messages
scope.recordOutputMessages(['I found 15 urgent emails', 'Here is your organized inbox']);
});
} catch (error) {
scope.recordError(error as Error);
throw error;
} finally {
scope.dispose();
}
如果代理使用 @microsoft/agents-a365-observability-hosting 包,则可以使用 ScopeUtils.populateInvokeAgentScopeFromTurnContext 创建范围,其中代理详细信息、调用方详细信息和通道信息会自动从 TurnContext 中派生。
import { InvokeAgentScopeDetails, AgentDetails, ServiceEndpoint } from '@microsoft/agents-a365-observability';
import { ScopeUtils } from '@microsoft/agents-a365-observability-hosting';
const agentDetails: AgentDetails = { agentId: 'agent-456' };
const scopeDetails: InvokeAgentScopeDetails = {
endpoint: { host: 'myagent.contoso.com', port: 443 } as ServiceEndpoint,
};
const scope = ScopeUtils.populateInvokeAgentScopeFromTurnContext(
agentDetails,
scopeDetails,
context, // TurnContext
authToken // authentication token string
);
try {
await scope.withActiveSpanAsync(async () => {
// Agent details, caller details, and channel are auto-populated from context
const response = await invokeAgent(context.activity.text);
scope.recordOutputMessages([response]);
});
} finally {
scope.dispose();
}
using System;
using System.Threading.Tasks;
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Contracts;
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Scopes;
public class MyAgent
{
public async Task<AgentResponse> ProcessUserRequest(string userInput)
{
var agentDetails = new AgentDetails(
agentId: "agent-456",
agentName: "MyAgent",
agentDescription: "Handles user requests.",
agenticUserId: "auid-123",
agenticUserEmail: "agent@contoso.com",
agentBlueprintId: "blueprint-789",
tenantId: "tenant-123"
);
var scopeDetails = new InvokeAgentScopeDetails(
endpoint: new Uri("https://myagent.contoso.com")
);
var request = new Request(
content: userInput,
sessionId: "session-abc",
channel: new Channel("msteams"),
conversationId: "conv-xyz"
);
var callerDetails = new CallerDetails(
userDetails: new UserDetails(
userId: "user-123",
userEmail: "jane.doe@contoso.com",
userName: "Jane Doe"
)
);
// Start the scope
using var scope = InvokeAgentScope.Start(
request: request,
scopeDetails: scopeDetails,
agentDetails: agentDetails,
callerDetails: callerDetails
);
// Record input messages
scope.RecordInputMessages(new[] { userInput });
// ... your agent logic here ...
var output = $"Processed: {userInput}";
scope.RecordOutputMessages(new[] { output });
return new AgentResponse { Content = output };
}
}
public class AgentResponse
{
public string Content { get; set; }
}
以下示例展示了如何在代理工具执行中添加可观测性跟踪。 该跟踪记录可采集遥测数据,用于监控和审计。
from microsoft_agents_a365.observability.core import (
ExecuteToolScope,
ToolCallDetails,
Request,
ServiceEndpoint,
)
# Use the same agent_details and request instances from the InvokeAgentScope example above
tool_details = ToolCallDetails(
tool_name="summarize",
tool_type="function",
tool_call_id="tc-001",
arguments="{'text': '...'}",
description="Summarize provided text",
endpoint=ServiceEndpoint(hostname="tools.contoso.com", port=8080),
)
with ExecuteToolScope.start(request, tool_details, agent_details) as scope:
result = run_tool(tool_details)
scope.record_response(result)
import { ExecuteToolScope, ToolCallDetails } from '@microsoft/agents-a365-observability';
// Use the same agentDetails and request instances from the InvokeAgentScope example above
const toolDetails: ToolCallDetails = {
toolName: 'email-search',
arguments: JSON.stringify({ query: 'from:boss@company.com', limit: 10 }),
toolCallId: 'tool-call-456',
description: 'Search emails by criteria',
toolType: 'function',
endpoint: {
host: 'tools.contoso.com',
port: 8080, // Will be recorded since not 443
protocol: 'https'
},
};
const scope = ExecuteToolScope.start(request, toolDetails, agentDetails);
try {
return await scope.withActiveSpanAsync(async () => {
// Execute the tool
const result = await searchEmails(toolDetails.arguments);
// Record the tool execution result
scope.recordResponse(result);
return result;
});
} catch (error) {
scope.recordError(error as Error);
throw error;
} finally {
scope.dispose();
}
如果代理使用 @microsoft/agents-a365-observability-hosting 包,请使用 ScopeUtils.populateExecuteToolScopeFromTurnContext 来创建作用域,从 TurnContext 自动派生代理详细信息。
import { ToolCallDetails } from '@microsoft/agents-a365-observability';
import { ScopeUtils } from '@microsoft/agents-a365-observability-hosting';
const toolDetails: ToolCallDetails = {
toolName: 'email-search',
arguments: JSON.stringify({ query: 'from:boss@company.com' }),
toolCallId: 'tool-call-456',
toolType: 'function',
};
const scope = ScopeUtils.populateExecuteToolScopeFromTurnContext(
toolDetails,
context, // TurnContext
authToken // authentication token string
);
try {
await scope.withActiveSpanAsync(async () => {
const result = await searchEmails(toolDetails.arguments);
scope.recordResponse(JSON.stringify(result));
});
} finally {
scope.dispose();
}
using System;
using System.Threading.Tasks;
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Contracts;
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Scopes;
// Use the same agentDetails and request instances from the InvokeAgentScope example above
var toolCallDetails = new ToolCallDetails(
toolName: "summarize",
arguments: "{\"text\": \"...\"}",
toolCallId: "tc-001",
description: "Summarize provided text",
toolType: "function",
endpoint: new Uri("https://tools.contoso.com:8080")
);
using var scope = ExecuteToolScope.Start(
request: request,
details: toolCallDetails,
agentDetails: agentDetails
);
// ... your tool logic here ...
scope.RecordResponse("{\"summary\": \"The text was summarized.\"}");
推断
以下示例演示如何使用可观测性跟踪检测 AI 模型推理调用,以捕获令牌使用情况、模型详细信息和响应元数据。
from microsoft_agents_a365.observability.core import (
InferenceScope,
InferenceCallDetails,
InferenceOperationType,
)
# Use the same agent_details and request instances from the InvokeAgentScope example above
inference_details = InferenceCallDetails(
operationName=InferenceOperationType.CHAT,
model="gpt-4o-mini",
providerName="azure-openai",
inputTokens=123,
outputTokens=456,
finishReasons=["stop"],
)
with InferenceScope.start(request, inference_details, agent_details) as scope:
completion = call_llm(...)
scope.record_output_messages([completion.text])
scope.record_input_tokens(completion.usage.input_tokens)
scope.record_output_tokens(completion.usage.output_tokens)
import { InferenceScope, InferenceDetails, InferenceOperationType } from '@microsoft/agents-a365-observability';
// Use the same agentDetails and request instances from the InvokeAgentScope example above
const inferenceDetails: InferenceDetails = {
operationName: InferenceOperationType.CHAT,
model: 'gpt-4o-mini',
providerName: 'azure-openai',
};
const scope = InferenceScope.start(request, inferenceDetails, agentDetails);
try {
return await scope.withActiveSpanAsync(async () => {
// Record input messages
scope.recordInputMessages(['Summarize the following emails for me...']);
// Call the LLM
const response = await callLLM();
// Record detailed telemetry with granular methods
scope.recordOutputMessages(['Here is your email summary...']);
scope.recordInputTokens(145);
scope.recordOutputTokens(82);
scope.recordFinishReasons(['stop']);
return response.text;
});
} catch (error) {
scope.recordError(error as Error);
throw error;
} finally {
scope.dispose();
}
如果代理使用@microsoft/agents-a365-observability-hosting包,则可以使用ScopeUtils.populateInferenceScopeFromTurnContext创建作用域,其中代理详细信息会自动从TurnContext派生。
import { InferenceDetails, InferenceOperationType } from '@microsoft/agents-a365-observability';
import { ScopeUtils } from '@microsoft/agents-a365-observability-hosting';
const inferenceDetails: InferenceDetails = {
operationName: InferenceOperationType.CHAT,
model: 'gpt-4o-mini',
providerName: 'azure-openai',
};
const scope = ScopeUtils.populateInferenceScopeFromTurnContext(
inferenceDetails,
context, // TurnContext
authToken // authentication token string
);
try {
await scope.withActiveSpanAsync(async () => {
const response = await callLLM();
scope.recordOutputMessages([response.text]);
scope.recordInputTokens(response.usage.inputTokens);
scope.recordOutputTokens(response.usage.outputTokens);
});
} finally {
scope.dispose();
}
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Contracts;
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Scopes;
// Use the same agentDetails and request instances from the InvokeAgentScope example above
var inferenceDetails = new InferenceCallDetails(
operationName: InferenceOperationType.Chat,
model: "gpt-4o-mini",
providerName: "Azure OpenAI",
inputTokens: 123,
outputTokens: 456,
finishReasons: new[] { "stop" }
);
using var scope = InferenceScope.Start(
request: request,
details: inferenceDetails,
agentDetails: agentDetails
);
// ... your inference logic here ...
scope.RecordOutputMessages(new[] { "AI response message" });
scope.RecordInputTokens(123);
scope.RecordOutputTokens(456);
输出
将此范围用于异步方案,在这种情况下 InvokeAgentScope, ExecuteToolScope或者 InferenceScope 无法同步捕获输出数据。 开始 OutputScope 作为子跨度,以便在父范围完成后记录最终输出消息。
from microsoft_agents_a365.observability.core import (
OutputScope,
Response,
SpanDetails,
)
# Use the same agent_details and request instances from the InvokeAgentScope example above
# Get the parent context from the originating scope
parent_context = invoke_scope.get_context()
response = Response(messages=["Here is your organized inbox with 15 urgent emails."])
with OutputScope.start(
request,
response,
agent_details,
span_details=SpanDetails(parent_context=parent_context),
):
# Output messages are recorded automatically from the response
pass
import { OutputScope, OutputResponse, SpanDetails } from '@microsoft/agents-a365-observability';
// Use the same agentDetails and request instances from the InvokeAgentScope example above
// Get the parent context from the originating scope
const parentContext = invokeScope.getSpanContext();
const response: OutputResponse = {
messages: ['Here is your organized inbox with 15 urgent emails.'],
};
const scope = OutputScope.start(
request,
response,
agentDetails,
undefined, // userDetails
{ parentContext } as SpanDetails
);
// Output messages are recorded automatically from the response
scope.dispose();
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Contracts;
using Microsoft.Agents.A365.Observability.Runtime.Tracing.Scopes;
// Use the same agentDetails and request instances from the InvokeAgentScope example above
// Get the parent context from the originating scope
var parentContext = invokeScope.GetActivityContext();
var response = new Response(new[] { "Here is your organized inbox with 15 urgent emails." });
using var scope = OutputScope.Start(
request: request,
response: response,
agentDetails: agentDetails,
spanDetails: new SpanDetails(parentContext: parentContext)
);
// Output messages are recorded automatically from the response
本地验证
为了验证你是否成功集成了可观测性SDK,请检查你的代理生成的控制台日志和可观测性SDK的日志。
将 ENABLE_A365_OBSERVABILITY_EXPORTER 环境变量设置为 false。 这个设置会导出跨度(traces)到控制台。
若要调查导出失败,请在应用程序启动时通过设置ENABLE_A365_OBSERVABILITY_EXPORTERtrue和配置调试日志记录来启用详细日志记录:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("microsoft_agents_a365.observability.core").setLevel(logging.DEBUG)
# Or target only the exporter:
logging.getLogger(
"microsoft_agents_a365.observability.core.exporters.agent365_exporter"
).setLevel(logging.DEBUG)
关键日志消息:
DEBUG Token resolved for agent {agentId} tenant {tenantId}
DEBUG Exporting {n} spans to {url}
DEBUG HTTP 200 - correlation ID: abc-123
ERROR Token resolution failed: {error}
ERROR HTTP 401 exporting spans - correlation ID: abc-123
INFO No spans with tenant/agent identity found; nothing exported.
将 ENABLE_A365_OBSERVABILITY_EXPORTER 环境变量设置为 false。 这个设置会导出跨度(traces)到控制台。
若要调查导出失败,请在 .env 或 shell 中设置环境变量:
# Enable the Agent365 exporter
ENABLE_A365_OBSERVABILITY_EXPORTER=true
# Enable verbose logging
A365_OBSERVABILITY_LOG_LEVEL=info|warn|error
查看控制台输出,查找类似的信息:
[INFO] [Agent365Exporter] Exporting 245 spans
[INFO] [Agent365Exporter] Partitioned into 3 identity groups (2 spans skipped)
[INFO] [Agent365Exporter] Token resolved successfully via tokenResolver
[EVENT] export-group succeeded in 98ms {"tenantId":"...","agentId":"...","correlationId":"abc-123"}
[ERROR] [Agent365Exporter] Failed with status 401, correlation ID: abc-123
[WARN] export-partition-span-missing-identity: 5 spans skipped due to missing tenant or agent ID
(可选)使用自定义记录器将导出事件记录到文件中:
import { setLogger, ExporterEventNames } from '@microsoft/agents-a365-observability';
setLogger({
info: (msg, ...args) => myLogger.info(msg, ...args),
warn: (msg, ...args) => myLogger.warn(msg, ...args),
error: (msg, ...args) => myLogger.error(msg, ...args),
event: (eventType: ExporterEventNames, isSuccess: boolean, durationMs: number,
message?: string, details?: Record<string, string>) => {
myLogger.info({ eventType, isSuccess, durationMs, message, ...details });
}
});
在EnableAgent365Exporter中设置false到appsettings.json。 这个设置会导出跨度(traces)到控制台。
若要调查导出失败,请在appsettings.json中配置详细日志记录。
{
"EnableAgent365Exporter": "True",
"Logging": {
"LogLevel": {
"Microsoft.Agents.A365.Observability": "Debug"
}
}
}
或设置环境变量:
EnableAgent365Exporter=True
A365_OBSERVABILITY_DOMAIN_OVERRIDE=https://your-test-endpoint.example.com
A365_OBSERVABILITY_SCOPE_OVERRIDE=https://api.powerplatform.com/.default
关键日志消息:
info: Agent365ExporterCore: Obtained token for agent {agentId} tenant {tenantId}.
info: Agent365ExporterCore: Sending {count} spans to {requestUri} for agent {agentId} tenant {tenantId}.
info: Agent365ExporterCore: HTTP {statusCode} exporting spans. 'x-ms-correlation-id': '{correlationId}'.
error: Agent365Exporter: Exception exporting spans: {exception}
warn: Agent365ExporterCore: No token obtained for agent {agentId} tenant {tenantId}. Skipping export.
Note
如果您未在 DI 中注册 ILoggerFactory,导出程序会自动回退到控制台记录器。
查看导出的日志
要查看Microsoft Purview或Microsoft Defender中的代理遥测数据,请确保您满足以下要求:
验证以备商店发布
Important
若要成功进行存储验证,代理必须实现InvokeAgentScope和InferenceScopeExecuteToolScope作用域。 发布需要具有这三个范围。
发布之前,请使用控制台日志通过实现所需的invoke agent、execute toolinference范围和output范围来验证代理的可观测性集成。 然后将你的客服日志与以下属性列表进行比较,以确认所有必需属性都存在。 可以在每个范围或通过行李生成器中捕捉属性,并根据需要添加可选属性。
有关商店发布要求的更多信息,请参见 商店验证指南。
InvokeAgentScope 属性
以下列表总结了启动 InvokeAgentScope 时记录的必需和可选遥测属性。
"attributes": {
"error.type": "Optional",
"microsoft.a365.agent.blueprint.id": "Required",
"gen_ai.agent.description": "Optional",
"gen_ai.agent.id": "Required",
"gen_ai.agent.name": "Required",
"microsoft.a365.agent.platform.id": "Optional",
"microsoft.agent.user.email": "Required",
"microsoft.agent.user.id": "Required",
"gen_ai.agent.version": "Optional",
"microsoft.a365.caller.agent.blueprint.id": "Optional",
"microsoft.a365.caller.agent.id": "Optional",
"microsoft.a365.caller.agent.name": "Optional",
"microsoft.a365.caller.agent.platform.id": "Optional",
"microsoft.a365.caller.agent.user.email": "Optional",
"microsoft.a365.caller.agent.user.id": "Optional",
"microsoft.a365.caller.agent.version": "Optional",
"client.address": "Required",
"user.id": "Required",
"user.name": "Optional",
"user.email": "Required",
"microsoft.channel.link": "Optional",
"microsoft.channel.name": "Required",
"gen_ai.conversation.id": "Required",
"microsoft.conversation.item.link": "Optional",
"gen_ai.input.messages": "Required",
"gen_ai.operation.name": "Required",
"gen_ai.output.messages": "Required",
"server.address": "Required",
"server.port": "Required",
"microsoft.session.id": "Optional",
"microsoft.session.description": "Optional",
"microsoft.tenant.id": "Required"
}
以下列表总结了启动 ExecuteToolScope 时记录的必需和可选遥测属性。
"attributes": {
"error.type": "Optional",
"microsoft.a365.agent.blueprint.id": "Required",
"gen_ai.agent.description": "Optional",
"gen_ai.agent.id": "Required",
"gen_ai.agent.name": "Required",
"microsoft.a365.agent.platform.id": "Optional",
"microsoft.agent.user.email": "Required",
"microsoft.agent.user.id": "Required",
"gen_ai.agent.version": "Optional",
"client.address": "Required",
"user.id": "Required",
"user.name": "Optional",
"user.email": "Required",
"microsoft.channel.link": "Optional",
"microsoft.channel.name": "Required",
"gen_ai.conversation.id": "Required",
"microsoft.conversation.item.link": "Optional",
"gen_ai.operation.name": "Required",
"gen_ai.tool.call.arguments": "Required",
"gen_ai.tool.call.id": "Required",
"gen_ai.tool.call.result": "Required",
"gen_ai.tool.description": "Optional",
"gen_ai.tool.name": "Required",
"gen_ai.tool.type": "Required",
"server.address": "Optional",
"server.port": "Optional",
"microsoft.session.id": "Optional",
"microsoft.session.description": "Optional",
"microsoft.tenant.id": "Required"
}
InferenceScope 属性
以下列表总结了启动 InferenceScope 时记录的必需和可选遥测属性。
"attributes": {
"error.type": "Optional",
"microsoft.a365.agent.blueprint.id": "Required",
"gen_ai.agent.description": "Optional",
"gen_ai.agent.id": "Required",
"gen_ai.agent.name": "Required",
"microsoft.a365.agent.platform.id": "Optional",
"microsoft.a365.agent.thought.process": "Optional",
"microsoft.agent.user.email": "Required",
"microsoft.agent.user.id": "Required",
"gen_ai.agent.version": "Optional",
"client.address": "Required",
"user.id": "Required",
"user.name": "Optional",
"user.email": "Required",
"microsoft.channel.link": "Optional",
"microsoft.channel.name": "Required",
"gen_ai.conversation.id": "Required",
"microsoft.conversation.item.link": "Optional",
"gen_ai.input.messages": "Required",
"gen_ai.operation.name": "Required",
"gen_ai.output.messages": "Required",
"gen_ai.provider.name": "Required",
"gen_ai.request.model": "Required",
"gen_ai.response.finish_reasons": "Optional",
"gen_ai.usage.input_tokens": "Optional",
"gen_ai.usage.output_tokens": "Optional",
"server.address": "Optional",
"server.port": "Optional",
"microsoft.session.description": "Optional",
"microsoft.session.id": "Optional",
"microsoft.tenant.id": "Required"
}
OutputScope 属性
以下列表总结了启动 OutputScope 时记录的必需和可选遥测属性。 将此范围用于父范围无法同步捕获输出数据的异步场景。
"attributes": {
"microsoft.a365.agent.blueprint.id": "Required",
"gen_ai.agent.description": "Optional",
"gen_ai.agent.id": "Required",
"gen_ai.agent.name": "Required",
"microsoft.a365.agent.platform.id": "Optional",
"microsoft.agent.user.email": "Required",
"microsoft.agent.user.id": "Required",
"gen_ai.agent.version": "Optional",
"client.address": "Required",
"user.id": "Required",
"user.name": "Optional",
"user.email": "Required",
"microsoft.channel.link": "Optional",
"microsoft.channel.name": "Required",
"gen_ai.conversation.id": "Required",
"microsoft.conversation.item.link": "Optional",
"gen_ai.operation.name": "Required",
"gen_ai.output.messages": "Required",
"microsoft.session.id": "Optional",
"microsoft.session.description": "Optional",
"microsoft.tenant.id": "Required"
}
使用可观测性测试代理
在代理中实现可观测性后,对其进行测试以确保它正确捕获遥测数据。 按照 测试指南 搭建环境。 然后,主要关注 “查看可观测性日志 ”部分,以验证可观测性实现是否按预期工作。
验证:
- 转到:
https://admin.cloud.microsoft/#/agents/all
- 选择您的代理人 > 活动
- 你会看到会话记录和工具调用
Troubleshooting
本节描述实现和使用可观察性时常见的问题。
可观测性数据不出现
症状:
- 代理程序正在运行
- 管理中心没有遥测
- 看不到代理活动
根本原因:
解决方案: 请尝试以下步骤来解决问题:
验证是否启用了可观测性导出程序
必须显式启用 Agent 365 导出工具。 禁用后,SDK 会回退到控制台导出程序,不会将遥测数据发送到服务。 有关配置详细信息,请参阅 “配置”。
检查令牌解析器配置
导出器需要一个有效的令牌解析器,为每次导出请求返回一个仅限应用的可观测性令牌。 如果解析器缺失、未返回令牌或抛出,导出不会发送请求。 确保你的代码实现了令牌解析器。 有关详细信息,请参阅 令牌解析程序。
检查日志中的错误
启用详细的日志记录,并使用 az webapp log tail 命令 搜索日志以查找与可观测性相关的错误。 有关如何为每个平台启用日志记录的详细信息,请参阅 “在本地验证”。
# Look for observability-related errors
az webapp log tail --name <your-app-name> --resource-group <your-resource-group> | Select-String "observability"
验证遥测导出
确认遥测数据按预期生成并导出。
- 添加控制台导出程序并检查遥测是否在本地生成。 有关如何使用控制台导出程序并验证输出的详细信息,请参阅 本地验证。
缺少租户 ID 或代理 ID — 范围被跳过
症状: 系统以无提示方式删除范围,从不导出它们。 某些 SDK 会记录跳过的跨度计数或类似“找不到租户/代理标识的跨度”的消息。其他则会在不记录的情况下删除它们。
解决方法:
- 在导出之前,SDK 会根据租户和代理标识来分隔跨度。 系统会删除缺少租户 ID 或代理 ID 的跨度,且绝不会将其发送到服务。
- 在创建范围之前,请确保
BaggageBuilder 使用租户 ID 和代理 ID 进行设置。 这些值通过 OpenTelemetry 上下文传播,并附加到在挂件范围内创建的所有跨度。 有关特定于平台的 API,请参阅 Baggage 属性。
- 在使用行李中间件或从托管集成包的轮次上下文帮助程序来填充这些 ID 时,请确认
TurnContext活动具有有效的代理身份收件人。
令牌解析失败——导出已跳过或未经授权
症状: 令牌解析器返回 null,返回空令牌,或抛出错误。 导出失败时没有发送请求,导出器也没有回退到委派的路由。
解决方法:
- 提供一个解析器,返回导出代理实例和租户的最终仅应用可观测令牌。
- 请确保使用
BaggageBuilder正确的租户 ID 和代理 ID,因为这些值将传递给令牌解析程序。
- 检查针对特定语言的启动行为。 Node.js 在没有解析器的情况下启用 Agent 365 导出器时配置失败。.NET 导出器构建失败,未配置解析器时 Python 退回控制台导出器。
- 确认你的解析器在返回该令牌前已经验证了该令牌。 它必须拒绝带有
scp 声明的委托代币和为错误受众签发的代币。
HTTP 401 未授权
症状: 导出失败并出现 HTTP 401。 导出程序不会重试此错误。
解决方法:
- 验证令牌受众是否为
9b975845-388f-4429-889e-eab1ef63949c 或 api://9b975845-388f-4429-889e-eab1ef63949c。
- 检查令牌解析器是否返回的是委派用户令牌、带有
scp 声明的令牌、错误受众的令牌,或过期的令牌。
- 确认解析器返回的是最终的代理实例令牌,而不是中间蓝图断言。
HTTP 403 禁止访问
症状: 导出失败并出现 HTTP 403。 导出程序不会重试此错误。
根源: HTTP 403 错误可能有不同的原因。 按顺序检查以下解决方法。
解决方法:
许可证丢失 — 验证租户是否在 Microsoft 365 管理中心 中分配了以下许可证之一:
-
测试 - Microsoft 365 E7
-
Microsoft 365 E7
-
Microsoft Agent 365 Frontier
代理实例未注册——S2S 路由只接受来自 Agent 365 已注册代理实例且不含 Agent365.Observability.OtelWrite 角色的纯应用令牌。 否则,返回HTTP 403 insufficient_scope。 对于蓝图代理,a365 setup all 会注册该代理实例。 要重试失败的注册,请运行 a365 setup all --agent-registration-only。 仅创建 Microsoft Entra 身份并不会注册代理实例。
令牌并非仅限应用 ——确认令牌中不包含 scp 声明。 S2S 路线需要一个仅限应用的令牌。
未注册身份缺少应用角色 ——未注册身份,包括自定义引擎代理使用的标准应用注册,都需要 Agent365.Observability.OtelWrite 应用角色。 要授予许可,请参见 “授予许可”。
委派路由上的 SDK 1.x 代理——委派路由需要委派 Agent365.Observability.OtelWrite 权限和管理员同意,但 a365 setup all 不会为蓝图代理配置这些权限和管理员同意。 升级到 SDK 2.0,或者 授予权限。
代理ID与令牌不匹配 ——参见 HTTP 403禁止——代理ID不匹配。
HTTP 403 禁止访问 - 代理 ID 不匹配
症状:导出失败并显示 HTTP 403,服务器消息类似于以下内容:403 Forbidden,在调用 Agent 365 跟踪端点时 agent-ID-mismatch 失败。
根本原因: 设置代理详细信息时,使用 蓝图客户端 ID 而不是 代理实例客户端 ID 时,会出现此错误。 导出 URL 中的代理 ID 与令牌授权的标识不匹配,因此跟踪终结点将拒绝请求。
解决方法:
- 验证是否已将租户 ID 添加到代理 365 允许的租户列表。
- 使用 代理实例客户端 ID (而不是蓝图客户端 ID)设置代理详细信息。
- 验证生成的导出 URL - 如果启用记录器,则会记录该 URL。 确认 URL 中的代理 ID 与代理实例客户端 ID 匹配。
- 若要为每个 SDK 启用诊断日志记录,请参阅 本地验证。
HTTP 429 或 5xx 错误 - 暂时性错误
症状: 导出失败,出现暂时性 HTTP 状态代码,例如 429 或 5xx。
解决方法:
- 这些错误通常是暂时性的,可以自行解决。 Python和 JavaScript SDK 会自动在 HTTP 408、429 和 5xx 错误状态代码重试,最多三次,使用指数退避。 .NET SDK 不会自动重试。
- 如果错误仍然存在,请检查服务运行状况仪表板。
- 请考虑通过增加批之间的计划延迟或增加最大导出批大小来降低导出频率。 有关每个平台的配置选项,请参阅
Agent365ExporterOptions“配置”中的表。
导出超时
症状: 导出尝试超时。
解决方法:
- 检查与可观测性终结点的网络连接。
- 超时默认值因平台而异。 默认 HTTP 请求超时为 30 秒。 某些 SDK 还有一个单独的整体导出操作超时设置,涵盖整个导出过程,包括重试。 有关每个平台的确切属性和默认值,请参阅
Agent365ExporterOptions“配置”中的表。
- 如果超时频繁发生,请在导出程序选项中增加相关的超时值。
导出成功,但遥测不会显示在 Defender 或 Purview 中
Symptoms: 日志显示成功导出,但遥测在Microsoft Defender或Microsoft Purview中不可见。
解决方法:
- 验证是否满足查看导出日志的先决条件。 对于 Purview,必须启用审核。 对于Defender,必须配置高级搜寻。 有关详细信息,请参阅 查看导出的日志。
- 成功导出后,遥测数据可能需要几分钟才能显示。 等待数据出现,然后进一步调查。
若要了解有关测试可观测性的详细信息,请参阅:
相关内容