ChatClientAgent管道由三部分组成面向LLM的ChatClient管道中预定义了一个LoggingChatClient中间件Agent中间件管道中预定义了一个LoggingAgent中间件除了所处位置决定的调用时机不同外它们的设计和实现方法几乎一摸一样。所以我们以LoggingChatClient——在LLM调用前后输出日志这篇文章一样的结构来介绍LoggingAgent中间件。该中间件它在调用Agent前后输出日志帮助我们更好地了解Agent的执行过程。它会记录每次调用的输入和输出以及调用的时间戳等信息。这对于调试和监控Agent的行为非常有用。1. 利用LoggingAgent中间件来记录针对LLM的调用如果将LoggingAgent这个中间件来装饰现有的AIAgent那么针对后者的调用情况会以日志的形式记录下来。我们可以通过设置不同的日志级别来控制输出的详细程度。在如下的演示程序中我们利用创建了一个基于OpenAIClient的AIAgent对象。在调用AsBuilder扩展方法将AIAgentBuilder构建出来后通过调用UseLogging方法来注册LoggingAgent中间件并且传入一个ILoggerFactory对象来控制日志的输出。我们在创建ILoggerFactory对象的时候设置了日志级别为Debug。usingdotenv.net;usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Logging;usingOpenAI;usingSystem.ClientModel;DotEnv.Load();varmodelEnvironment.GetEnvironmentVariable(MODEL)!;varapiKeyEnvironment.GetEnvironmentVariable(API_KEY)!;varopenAIUrlEnvironment.GetEnvironmentVariable(OPENAI_URL)!;varloggerFactorynewServiceCollection().AddLogging(logginglogging.SetMinimumLevel(LogLevel.Debug).AddConsole()).BuildServiceProvider().GetRequiredServiceILoggerFactory();varagentnewOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{EndpointnewUri(openAIUrl)}).GetChatClient(model:model).AsAIAgent().AsAIAgent().AsBuilder().UseLogging(loggerFactory).Build();awaitagent.RunAsync(评价一下林则徐的楷书200字以内);LoggingAgent的RunAsync方法会在调用前输出一条日志表示正在调用Agent并且会记录调用的输入内容在调用完成后会输出另一条日志表示调用已经完成并且会记录调用的输出内容。通过这些日志我们可以清楚地看到每次调用的输入和输出以及调用的时间戳等信息。dbug: LoggingAgent[1723383095] RunAsync invoked. dbug: LoggingAgent[1553703230] RunAsync completed.如果我们将日志等级设置为更低的Trace级别那么LoggingAgent还会输出更详细的日志信息包括调用的输入内容和输出内容等。varloggerFactorynewServiceCollection().AddLogging(logginglogging.SetMinimumLevel(LogLevel.Trace).AddConsole()).BuildServiceProvider().GetRequiredServiceILoggerFactory();输出trce: LoggingAgent[805843669] RunAsync invoked: [{role:user,contents:[{$type:text,text:评价一下林则徐的楷书200字以内}]}]. Options: null. Metadata: {providerName:openai}. trce: LoggingAgent[384896670] RunAsync completed: {messages:[{createdAt:2026-05-29T01:51:4300:00,role:assistant,contents:[{$type:text,text:林则徐楷书以唐楷为基融合欧体之严谨方峻与颜体之雄浑端重形成刚柔并济的独特风貌。其用笔一丝不苟点画精到竖笔挺立如松柏捺画含蓄而力沉结字匀称疏朗于工整中见灵动气象。尤为可贵的是其书风与人格高度统一字里行间透出“无欲则刚”的清正骨气既显传统士大夫的深厚学养又饱含“苟利国家生死以”的凛然节操。这种将个人修养、时代精神注入笔墨的境界使其超越了纯粹技法层面成为晚清文人书法的典范。}],messageId:d9ea27a1f0c7436097d5ac6892100c2b}],agentId:2f904288a3c24dd39d80ca5bfde40fec,responseId:d9ea27a1f0c7436097d5ac6892100c2b,createdAt:2026-05-29T01:51:4300:00,finishReason:stop,usage:{inputTokenCount:16,outputTokenCount:158,totalTokenCount:174,additionalCounts:{}}}.2. LoggingAgentLoggingAgent直接继承自DelegatingAIAgent是一个非常简单的中间件实现它直接利用构造函数传入的ILogger对象来输出日志信息。DelegatingAIAgent在没有出错的情况下只会输出等级分别为Debug和Trace的日志信息如果最低日志等级设置为Debug那么就只会输出调用前和调用后的日志如果最低日志等级设置为Trace那么就会输出更详细的日志信息包括调用的输入内容和输出内容等。Trace等级的日志的内容以JSON形式输出所以它提供了一个JsonSerializerOptions属性来控制日志中输入输出内容的序列化方式。我们可以通过设置这个属性来控制日志中输入输出内容的格式比如是否使用驼峰命名、是否忽略空值等。publicsealedclassLoggingAgent:DelegatingAIAgent{publicJsonSerializerOptionsJsonSerializerOptions{get;set;}publicLoggingAgent(AIAgentinnerAgent,ILoggerlogger);protectedoverrideasyncTaskAgentResponseRunCoreAsync(IEnumerableChatMessagemessages,AgentSession?sessionnull,AgentRunOptions?optionsnull,CancellationTokencancellationTokendefault(CancellationToken));}针对RunAsync的日志输出采用如下的逻辑在调用innerClient的RunAsync方法之前输出一条Debug/Trace等级的日志表示正在调用LLM并且会记录调用的输入内容在成功调用并得到响应之后输出另一条Debug/Trace等级的日志表示调用已经完成并且会记录调用的输出内容如果调用过程中发生了异常那么会输出一条Error等级的日志表示调用失败并且会记录异常信息针对RunStreamingAsync(的日志输出采用如下的逻辑在调用innerClient的RunStreamingAsync(方法之前输出一条Debug/Trace等级的日志表示正在调用LLM并且会记录调用的输入内容如果调用失败那么会输出一条Error等级的日志表示调用失败并且会记录异常信息RunStreamingAsync(会对返回的IAsyncEnumerableAgentResponseUpdate(进行迭代对于每一次迭代如果成功获取到一个AgentResponseUpdate(并且最低日志等级设置为Trace那么会输出一条Trace等级的日志表示获取到了一个更新并且会记录这个更新的内容如果在迭代过程中发生了异常那么会输出一条Error等级的日志表示迭代失败并且会记录异常信息在迭代完成之后输出一条Debug等级的日志表示调用已经完成对于我们前面演示的例子如果我们将日志等级设置为Trace那么在调用RunStreamingAsync(方法时我们就可以看到每一次迭代获取到的AgentResponseUpdate(的内容都被记录在日志中了这对于调试和监控Agent的行为非常有用。由于这种情况下输出内容容量可能会非常大所以当我们将日志等级设置为Trace时得评估一下日志对性能带来得影响。usingdotenv.net;usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Logging;usingOpenAI;usingSystem.ClientModel;DotEnv.Load();varmodelEnvironment.GetEnvironmentVariable(MODEL)!;varapiKeyEnvironment.GetEnvironmentVariable(API_KEY)!;varopenAIUrlEnvironment.GetEnvironmentVariable(OPENAI_URL)!;varloggerFactorynewServiceCollection().AddLogging(logginglogging.SetMinimumLevel(LogLevel.Trace).AddConsole()).BuildServiceProvider().GetRequiredServiceILoggerFactory();varagentnewOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{EndpointnewUri(openAIUrl)}).GetChatClient(model:model).AsAIAgent().AsAIAgent().AsBuilder().UseLogging(loggerFactory).Build();awaitforeach(varupdateinagent.RunStreamingAsync(世界上最深的淡水湖是哪个在10字内作答)){}输出trce: LoggingAgent[805843669] RunStreamingAsync invoked: [{role:user,contents:[{$type:text,text:世界上最深的淡水湖是哪个在10字内作答}]}]. Options: null. Metadata: {providerName:openai}. trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:text,text:}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:text,text:贝}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:text,text:加尔湖}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00,finishReason:stop} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:usage,details:{inputTokenCount:17,outputTokenCount:4,totalTokenCount:21,additionalCounts:{}}}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00,finishReason:stop} dbug: LoggingAgent[1553703230] RunStreamingAsync completed.3. 利用Source Generator生成日志输出代码日志是典型得高频操作尤其是当我们将日志等级设置得很低得时候更是如此所以针对日志输出的每一个微小的细节都会高倍放大比如字符串拼接和值类型转换成引用类型导致的装箱等。在此方面Source Generator就能派上用场了。我们可以利用Source Generator来生成日志输出的代码从而避免手写日志输出代码可能带来的性能问题。Microsoft.Extensions.Logging库已经提供了一个名为LoggerMessageAttribute的Source Generator我们可以利用它来生成日志输出的代码。LoggingAgent涉及的日志输出被定义成对应的方法并在这些方法上使用LoggerMessageAttribute特性来标记日志的级别和消息模板。LoggerMessageAttribute特性会告诉Source Generator生成对应的日志输出代码从而避免了手写日志输出代码可能带来的性能问题。这也是LoggingAgent被定义成partial类的原因。publicpartialclassLoggingAgent:DelegatingAIAgent{[LoggerMessage(LogLevel.Debug,{MethodName} invoked.)]privatepartialvoidLogInvoked(stringmethodName);[LoggerMessage(LogLevel.Trace,{MethodName} invoked: {Messages}. Options: {Options}. Metadata: {Metadata}.)]privatepartialvoidLogInvokedSensitive(stringmethodName,stringmessages,stringoptions,stringmetadata);[LoggerMessage(LogLevel.Debug,{MethodName} completed.)]privatepartialvoidLogCompleted(stringmethodName);[LoggerMessage(LogLevel.Trace,{MethodName} completed: {Response}.)]privatepartialvoidLogCompletedSensitive(stringmethodName,stringresponse);[LoggerMessage(LogLevel.Trace,RunStreamingAsync received update: {Update})]privatepartialvoidLogStreamingUpdateSensitive(stringupdate);[LoggerMessage(LogLevel.Debug,{MethodName} canceled.)]privatepartialvoidLogInvocationCanceled(stringmethodName);[LoggerMessage(LogLevel.Error,{MethodName} failed.)]privatepartialvoidLogInvocationFailed(stringmethodName,Exceptionerror);}4. UseLogging扩展方法UseLogging是一个AIAgentBuilder(的扩展方法它提供了一种简便的方式来注册LoggingAgent中间件。我们只需要在构建AIAgent对象的时候调用UseLogging方法并传入一个ILoggerFactory对象来控制日志的输出就可以轻松地创建并注册LoggingAgent中间件了。除此之外UseLogging方法还提供了一个可选的configure参数它允许我们在注册LoggingAgent中间件的时候对其进行一些额外的配置比如设置JsonSerializerOptions属性来控制日志中输入输出内容的序列化方式等。publicstaticclassLoggingAgentBuilderExtensions{publicstaticAIAgentBuilderUseLogging(thisAIAgentBuilderbuilder,ILoggerFactory?loggerFactorynull,ActionLoggingAgent?configurenull);}
[MAF预定义Agent中间件-01]LoggingAgent——在Agent调用前后输出日志
ChatClientAgent管道由三部分组成面向LLM的ChatClient管道中预定义了一个LoggingChatClient中间件Agent中间件管道中预定义了一个LoggingAgent中间件除了所处位置决定的调用时机不同外它们的设计和实现方法几乎一摸一样。所以我们以LoggingChatClient——在LLM调用前后输出日志这篇文章一样的结构来介绍LoggingAgent中间件。该中间件它在调用Agent前后输出日志帮助我们更好地了解Agent的执行过程。它会记录每次调用的输入和输出以及调用的时间戳等信息。这对于调试和监控Agent的行为非常有用。1. 利用LoggingAgent中间件来记录针对LLM的调用如果将LoggingAgent这个中间件来装饰现有的AIAgent那么针对后者的调用情况会以日志的形式记录下来。我们可以通过设置不同的日志级别来控制输出的详细程度。在如下的演示程序中我们利用创建了一个基于OpenAIClient的AIAgent对象。在调用AsBuilder扩展方法将AIAgentBuilder构建出来后通过调用UseLogging方法来注册LoggingAgent中间件并且传入一个ILoggerFactory对象来控制日志的输出。我们在创建ILoggerFactory对象的时候设置了日志级别为Debug。usingdotenv.net;usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Logging;usingOpenAI;usingSystem.ClientModel;DotEnv.Load();varmodelEnvironment.GetEnvironmentVariable(MODEL)!;varapiKeyEnvironment.GetEnvironmentVariable(API_KEY)!;varopenAIUrlEnvironment.GetEnvironmentVariable(OPENAI_URL)!;varloggerFactorynewServiceCollection().AddLogging(logginglogging.SetMinimumLevel(LogLevel.Debug).AddConsole()).BuildServiceProvider().GetRequiredServiceILoggerFactory();varagentnewOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{EndpointnewUri(openAIUrl)}).GetChatClient(model:model).AsAIAgent().AsAIAgent().AsBuilder().UseLogging(loggerFactory).Build();awaitagent.RunAsync(评价一下林则徐的楷书200字以内);LoggingAgent的RunAsync方法会在调用前输出一条日志表示正在调用Agent并且会记录调用的输入内容在调用完成后会输出另一条日志表示调用已经完成并且会记录调用的输出内容。通过这些日志我们可以清楚地看到每次调用的输入和输出以及调用的时间戳等信息。dbug: LoggingAgent[1723383095] RunAsync invoked. dbug: LoggingAgent[1553703230] RunAsync completed.如果我们将日志等级设置为更低的Trace级别那么LoggingAgent还会输出更详细的日志信息包括调用的输入内容和输出内容等。varloggerFactorynewServiceCollection().AddLogging(logginglogging.SetMinimumLevel(LogLevel.Trace).AddConsole()).BuildServiceProvider().GetRequiredServiceILoggerFactory();输出trce: LoggingAgent[805843669] RunAsync invoked: [{role:user,contents:[{$type:text,text:评价一下林则徐的楷书200字以内}]}]. Options: null. Metadata: {providerName:openai}. trce: LoggingAgent[384896670] RunAsync completed: {messages:[{createdAt:2026-05-29T01:51:4300:00,role:assistant,contents:[{$type:text,text:林则徐楷书以唐楷为基融合欧体之严谨方峻与颜体之雄浑端重形成刚柔并济的独特风貌。其用笔一丝不苟点画精到竖笔挺立如松柏捺画含蓄而力沉结字匀称疏朗于工整中见灵动气象。尤为可贵的是其书风与人格高度统一字里行间透出“无欲则刚”的清正骨气既显传统士大夫的深厚学养又饱含“苟利国家生死以”的凛然节操。这种将个人修养、时代精神注入笔墨的境界使其超越了纯粹技法层面成为晚清文人书法的典范。}],messageId:d9ea27a1f0c7436097d5ac6892100c2b}],agentId:2f904288a3c24dd39d80ca5bfde40fec,responseId:d9ea27a1f0c7436097d5ac6892100c2b,createdAt:2026-05-29T01:51:4300:00,finishReason:stop,usage:{inputTokenCount:16,outputTokenCount:158,totalTokenCount:174,additionalCounts:{}}}.2. LoggingAgentLoggingAgent直接继承自DelegatingAIAgent是一个非常简单的中间件实现它直接利用构造函数传入的ILogger对象来输出日志信息。DelegatingAIAgent在没有出错的情况下只会输出等级分别为Debug和Trace的日志信息如果最低日志等级设置为Debug那么就只会输出调用前和调用后的日志如果最低日志等级设置为Trace那么就会输出更详细的日志信息包括调用的输入内容和输出内容等。Trace等级的日志的内容以JSON形式输出所以它提供了一个JsonSerializerOptions属性来控制日志中输入输出内容的序列化方式。我们可以通过设置这个属性来控制日志中输入输出内容的格式比如是否使用驼峰命名、是否忽略空值等。publicsealedclassLoggingAgent:DelegatingAIAgent{publicJsonSerializerOptionsJsonSerializerOptions{get;set;}publicLoggingAgent(AIAgentinnerAgent,ILoggerlogger);protectedoverrideasyncTaskAgentResponseRunCoreAsync(IEnumerableChatMessagemessages,AgentSession?sessionnull,AgentRunOptions?optionsnull,CancellationTokencancellationTokendefault(CancellationToken));}针对RunAsync的日志输出采用如下的逻辑在调用innerClient的RunAsync方法之前输出一条Debug/Trace等级的日志表示正在调用LLM并且会记录调用的输入内容在成功调用并得到响应之后输出另一条Debug/Trace等级的日志表示调用已经完成并且会记录调用的输出内容如果调用过程中发生了异常那么会输出一条Error等级的日志表示调用失败并且会记录异常信息针对RunStreamingAsync(的日志输出采用如下的逻辑在调用innerClient的RunStreamingAsync(方法之前输出一条Debug/Trace等级的日志表示正在调用LLM并且会记录调用的输入内容如果调用失败那么会输出一条Error等级的日志表示调用失败并且会记录异常信息RunStreamingAsync(会对返回的IAsyncEnumerableAgentResponseUpdate(进行迭代对于每一次迭代如果成功获取到一个AgentResponseUpdate(并且最低日志等级设置为Trace那么会输出一条Trace等级的日志表示获取到了一个更新并且会记录这个更新的内容如果在迭代过程中发生了异常那么会输出一条Error等级的日志表示迭代失败并且会记录异常信息在迭代完成之后输出一条Debug等级的日志表示调用已经完成对于我们前面演示的例子如果我们将日志等级设置为Trace那么在调用RunStreamingAsync(方法时我们就可以看到每一次迭代获取到的AgentResponseUpdate(的内容都被记录在日志中了这对于调试和监控Agent的行为非常有用。由于这种情况下输出内容容量可能会非常大所以当我们将日志等级设置为Trace时得评估一下日志对性能带来得影响。usingdotenv.net;usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Logging;usingOpenAI;usingSystem.ClientModel;DotEnv.Load();varmodelEnvironment.GetEnvironmentVariable(MODEL)!;varapiKeyEnvironment.GetEnvironmentVariable(API_KEY)!;varopenAIUrlEnvironment.GetEnvironmentVariable(OPENAI_URL)!;varloggerFactorynewServiceCollection().AddLogging(logginglogging.SetMinimumLevel(LogLevel.Trace).AddConsole()).BuildServiceProvider().GetRequiredServiceILoggerFactory();varagentnewOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{EndpointnewUri(openAIUrl)}).GetChatClient(model:model).AsAIAgent().AsAIAgent().AsBuilder().UseLogging(loggerFactory).Build();awaitforeach(varupdateinagent.RunStreamingAsync(世界上最深的淡水湖是哪个在10字内作答)){}输出trce: LoggingAgent[805843669] RunStreamingAsync invoked: [{role:user,contents:[{$type:text,text:世界上最深的淡水湖是哪个在10字内作答}]}]. Options: null. Metadata: {providerName:openai}. trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:text,text:}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:text,text:贝}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:text,text:加尔湖}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00,finishReason:stop} trce: LoggingAgent[1513570378] RunStreamingAsync received update: {role:assistant,contents:[{$type:usage,details:{inputTokenCount:17,outputTokenCount:4,totalTokenCount:21,additionalCounts:{}}}],agentId:80b29c13d58344928730074396dd37fc,responseId:462019f99bad4e9f868f8f166085bb46,messageId:462019f99bad4e9f868f8f166085bb46,createdAt:2026-05-29T02:04:0200:00,finishReason:stop} dbug: LoggingAgent[1553703230] RunStreamingAsync completed.3. 利用Source Generator生成日志输出代码日志是典型得高频操作尤其是当我们将日志等级设置得很低得时候更是如此所以针对日志输出的每一个微小的细节都会高倍放大比如字符串拼接和值类型转换成引用类型导致的装箱等。在此方面Source Generator就能派上用场了。我们可以利用Source Generator来生成日志输出的代码从而避免手写日志输出代码可能带来的性能问题。Microsoft.Extensions.Logging库已经提供了一个名为LoggerMessageAttribute的Source Generator我们可以利用它来生成日志输出的代码。LoggingAgent涉及的日志输出被定义成对应的方法并在这些方法上使用LoggerMessageAttribute特性来标记日志的级别和消息模板。LoggerMessageAttribute特性会告诉Source Generator生成对应的日志输出代码从而避免了手写日志输出代码可能带来的性能问题。这也是LoggingAgent被定义成partial类的原因。publicpartialclassLoggingAgent:DelegatingAIAgent{[LoggerMessage(LogLevel.Debug,{MethodName} invoked.)]privatepartialvoidLogInvoked(stringmethodName);[LoggerMessage(LogLevel.Trace,{MethodName} invoked: {Messages}. Options: {Options}. Metadata: {Metadata}.)]privatepartialvoidLogInvokedSensitive(stringmethodName,stringmessages,stringoptions,stringmetadata);[LoggerMessage(LogLevel.Debug,{MethodName} completed.)]privatepartialvoidLogCompleted(stringmethodName);[LoggerMessage(LogLevel.Trace,{MethodName} completed: {Response}.)]privatepartialvoidLogCompletedSensitive(stringmethodName,stringresponse);[LoggerMessage(LogLevel.Trace,RunStreamingAsync received update: {Update})]privatepartialvoidLogStreamingUpdateSensitive(stringupdate);[LoggerMessage(LogLevel.Debug,{MethodName} canceled.)]privatepartialvoidLogInvocationCanceled(stringmethodName);[LoggerMessage(LogLevel.Error,{MethodName} failed.)]privatepartialvoidLogInvocationFailed(stringmethodName,Exceptionerror);}4. UseLogging扩展方法UseLogging是一个AIAgentBuilder(的扩展方法它提供了一种简便的方式来注册LoggingAgent中间件。我们只需要在构建AIAgent对象的时候调用UseLogging方法并传入一个ILoggerFactory对象来控制日志的输出就可以轻松地创建并注册LoggingAgent中间件了。除此之外UseLogging方法还提供了一个可选的configure参数它允许我们在注册LoggingAgent中间件的时候对其进行一些额外的配置比如设置JsonSerializerOptions属性来控制日志中输入输出内容的序列化方式等。publicstaticclassLoggingAgentBuilderExtensions{publicstaticAIAgentBuilderUseLogging(thisAIAgentBuilderbuilder,ILoggerFactory?loggerFactorynull,ActionLoggingAgent?configurenull);}