惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cisco Blogs
Schneier on Security
Schneier on Security
T
Tor Project blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tenable Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
Security Latest
Security Latest
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
Scott Helme
Scott Helme
Webroot Blog
Webroot Blog
Project Zero
Project Zero
Google Online Security Blog
Google Online Security Blog
The Last Watchdog
The Last Watchdog
Spread Privacy
Spread Privacy
Hacker News: Ask HN
Hacker News: Ask HN
PCI Perspectives
PCI Perspectives
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
W
WeLiveSecurity
Attack and Defense Labs
Attack and Defense Labs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News | PayPal Newsroom
Help Net Security
Help Net Security
The Hacker News
The Hacker News
H
Heimdal Security Blog
O
OpenAI News
S
Security @ Cisco Blogs
N
News and Events Feed by Topic
Cyberwarzone
Cyberwarzone
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - 叶小钗
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
I
Intezer
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
Security Affairs
P
Proofpoint News Feed
S
Secure Thoughts
腾讯CDC
Google DeepMind News
Google DeepMind News
量子位
罗磊的独立博客

博客园 - Artech

[MAF预定义的AIContextProvider-05]CompactionProvider——采用多种策略压缩对话历史 [MAF预定义的AIContextProvider-04]Mem0Provider——长期记忆基于的云端解决方案 [MAF预定义的AIContextProvider-03]ChatHistoryMemoryProvider——赋予Agent从经验中学习的能力 [MAF预定义的AIContextProvider-02]AgentSkillsProvider——将Agent Skills引入MAF [MAF预定义的AIContextProvider-01]TextSearchProvider——RAG在MAF中的实现 [MAF预定义ChatClient中间件-09]MessageInjectingChatClient-赋予工具消息注入的能力 [MAF预定义ChatClient中间件-08]OpenTelemetryChatClient-实现链路跟踪和性能监控 [MAF预定义ChatClient中间件-07]PerServiceCallChatHistoryPersistingChatClient——基于ReAct循环的一步一存档 [MAF预定义ChatClient中间件-06]利用ImageGeneratingChatClient开发专业图片生成Agent [MAF预定义ChatClient中间件-05]动态修改ChatOptions和请求消息 [MAF预定义ChatClient中间件-04]ReducingChatClient——精减对话历史又不丢失基本语义 [MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间 [MAF预定义ChatClient中间件-02]FunctionInvokingChatClient——实现ReAct循环和人机交互的大功臣 [MAF预定义ChatClient中间件-01]LoggingChatClient——在调用LLM前后输出日志 [MAF的Agent管道详解-07]利用AIAgent中间件构建Agent管道 [MAF的Agent管道详解-06]ChatClientAgent对IChatClient和输入输出增强管道的整合 [MAF的Agent管道详解-06]ChatClientAgent对IChatClient和输入输出增强管道的整合 - Artech [MAF的Agent管道详解-05]对话历史的持久化和输入输出的增强 [MAF的Agent管道详解-04]如何让LLM按照要求的结构输出数据? [MAF的Agent管道详解-02]IChatClient管道如何完美连接大模型? [MAF的Agent管道详解-01]塑智能体边界,从AIAgent抽象类开始 [对比学习LangChain和MAF-04]针对消息的设计 [对比学习LangChain和MAF-03]完全不同的Agent设计哲学 [对比学习LangChain和MAF-02]基本编程模式的差异(下篇) [对比学习LangChain和MAF-01]基本编程模式的差异(上篇) 这是一篇测试文章 我所理解的Python元模型 除了按值和引用,方法参数的第三种传递方式 方法的三种调用形式 可以调用Null的实例方法吗? 自定义Key类型的字典无法序列化的N种解决方案 为什么ASP.NET Core的路由处理器可以使用一个任意类型的Delegate 深入解析ASP.NET Core MVC的模块化设计[下篇] 深入解析ASP.NET Core MVC的模块化设计[上篇] ASP.NET Core MVC应用模型的构建[4]: Action的选择 ASP.NET Core MVC应用模型的构建[3]: Controller的收集 ASP.NET Core MVC应用模型的构建[2]: 定制应用模型 ASP.NET Core MVC应用模型的构建[1]: 应用的蓝图 基于HTTP2/3的流模式消息交换如何实现? 编写高效的代码,你应该了解Array、Memory、ReadOnlySequence . . . WebAssembly核心编程[4]: Memory WebAssembly核心编程[3]: Module 与 Instance WebAssembly核心编程[2]:类型系统 WebAssembly核心编程[1]:wasm模块实例化的N种方式 WebAssembly入门笔记[4]:利用Global传递全局变量 WebAssembly入门笔记[3]:利用Table传递引用
[MAF的Agent管道详解-03]连接LLM的IChatClient对象
Artech · 2026-05-28 · via 博客园 - Artech

IChatClient管道的最末端是一个与LLM进行交互的IChatClient对象,这个对象负责将最终的请求发送给LLM并返回响应结果。这个IChatClient对象的具体类型取决于我们使用的是什么模型以及模型的部署方式。系统提供了很多这样的IChatClient实现来支持不同的模型和部署方式。对于目前主流的LLM,我们都可以直接利用其客户端来创建一个对应的IChatClient对象.

1. 为三种OpenAI客户端创建IChatClient对象

OpenAIClientAzureOpenAIClient是一个与OpenAI的API进行交互的客户端,我们可以指定模型名称调用其GetChatClient方法来获取一个对应的ChatClient对象。虽然名字雷同,但是这个ChatClient类型可没有实现IChatClient接口,我们需要调用为它定义的扩展方法AsIChatClient来将它转换成一个实现了IChatClient接口的对象。

public class AzureOpenAIClient
{
    public override ChatClient GetChatClient(string deploymentName);
    public override ResponsesClient GetResponsesClient();
}

public class OpenAIClient
{
    public virtual ChatClient GetChatClient(string model);
    public virtual ResponsesClient GetResponsesClient();
}

public static class OpenAIClientExtensions
{
    public static IChatClient AsIChatClient(this ChatClient chatClient);
    public static IChatClient AsIChatClient(this ResponsesClient responseClient, string? defaultModelId = null);
}

前面说过,GetChatClient返回的ChatClient对象采用基于文本补全的无状态的Completion API来与模型进行交互,如果需要采用有状态的Responses API,需要调用GetResponsesClient方法来获取一个ResponsesClient对象。系统依然为ResponsesClient对象定义了一个AsIChatClient的扩展方法来将它转换成一个实现了IChatClient接口的对象。

如果使用的是基于Microsoft Foundry的AIProjectClient客户端。由于它的基类是ClientConnectionProviderExtensions,我们可以调用其扩展方法GetProjectOpenAIClient得到一个ProjectOpenAIClient对象。由于ProjectOpenAIClient继承自OpenAIClient,我们同样可以调用为它定义的AsIChatClient扩展方法来将它转换成一个实现了IChatClient接口的对象。

public class AIProjectClient : ClientConnectionProvider

public static class ClientConnectionProviderExtensions
{
    public static ProjectOpenAIClient GetProjectOpenAIClient(
        this ClientConnectionProvider connectionProvider, 
        ProjectOpenAIClientOptions options = null);
}

public class ProjectOpenAIClient : OpenAIClient

2. 模拟Agent的ReAct循环

接下来我们看看一个利用OpenAIClient创建的IChatClient对象在调用LLM的时候,提供的请求和响应内容是什么样子的。下面的代码模拟了一个Agent内部的执行流程(ReAct循环),我们使用这个Agent来根据苏州的天气给出一些着装建议。我们根据OpenAIClient创建了对应的IChatClient对象,整个流程涉及两次针对它的调用。两次调用使用同一个ChatOptions对象,我们为这个ChatOptions设置了系统指令(你是一个深谙养身之道的时尚顾问)并注册了一个用于查询天气的工具GetWeather

using dotenv.net;
using Microsoft.Extensions.AI;
using OpenAI;
using System.ClientModel;
using System.ComponentModel;

DotEnv.Load();
var model = Environment.GetEnvironmentVariable("MODEL")!;
var apiKey = Environment.GetEnvironmentVariable("API_KEY")!;
var openAIUrl = Environment.GetEnvironmentVariable("OPENAI_URL")!;
var openAIClient = new OpenAIClient(
    credential: new ApiKeyCredential(key: apiKey),
    options: new OpenAIClientOptions
    {
        Endpoint = new Uri(openAIUrl)
    });

var chatClient = openAIClient.GetResponsesClient().AsIChatClient(defaultModelId:model);
var options = new ChatOptions
{   
    Instructions = "你是一个深谙养身之道的时尚顾问。",
    Tools = [AIFunctionFactory.Create(GetWeather)]
};
var message = new ChatMessage(role: ChatRole.User, content: "根据苏州的天气给我一些着装建议。");
List<ChatMessage> messages = [message];

// First turn: user -> assistant (with function call)
var response = await chatClient.GetResponseAsync(
    messages: messages,
    options: options);
messages.AddRange(response.Messages);

var functionCall = response.Messages.Last().Contents.OfType<FunctionCallContent>().Single();
var tool = options.Tools.Single(t => t.Name == functionCall.Name);
var toolResult = await ((AIFunction)tool).InvokeAsync(new AIFunctionArguments(functionCall.Arguments));
var toolResultMessage = new ChatMessage(ChatRole.Tool, [new FunctionResultContent(functionCall.CallId, toolResult)]);
messages.Add(toolResultMessage);

// Second turn: user -> assistant (with tool result)
response = await chatClient.GetResponseAsync(
    messages: messages,
    options: options);

Console.WriteLine(response.Messages.Last().Text);
static string GetWeather([Description("Location for weather query")] string location) => $"{location} 当前晴朗,气温为25°C。";

我们指定查询(根据苏州的天气给我一些着装建议)和ChatOptions调用IChatClient对象。LLM经过推理任务需要调用工具函数GetWeather来获取苏州的天气信息,所以响应消息的内容列表会包含一个FunctionCallContent。在手工将响应消息添加到消息列表中后,我们利用FunctionCallContent从注册的工具列表中找到对应的工具。

我们将LLM提供的输入参数从FunctionCallContent提取出来后,调用工具函数GetWeather得到对应的结果。接下来我们针对工具的返回结果创建一个角色为ToolChatMessage对象,并将它添加到消息列表中。最后我们再次调用IChatClient对象来获取LLM的最终回复。此时LLM就可以根据工具的返回结果来生成最终如下所示的答案:

好的,我们就顺着苏州此刻**25°C、晴朗**的状态,从**养身 + 时尚**两个角度来搭配。

---

## 🌤️ 今日苏州着装总思路
**关键词:清爽透气、遮阳不闷、早晚微调**

25°C 属于非常舒适的温度,但苏州湿度通常不低,**选对面料比堆叠衣服更重要**。

---

## 👕 上装建议
- **首选**:
  - 棉麻衬衫(浅色系:米白、浅灰、雾蓝)
  - 薄款针织或天丝T恤
- **养身理由**:
  - 棉麻、天丝透气吸湿,减少湿热闷汗,对皮肤和气血运行更友好
- **小技巧**:
  - 避免紧身、化纤材质,容易“闷火生湿”

---

## 👖 下装建议
- **推荐**:
  - 九分直筒裤 / 轻薄阔腿裤
  - 膝下A字裙或真丝半裙
- **颜色**:
  - 浅卡其、灰绿、烟粉色,有“降燥感”
- **养身点**:
  - 不勒腹、不裹腿,有助于脾胃与下肢血液循环

---

## 👟 鞋履选择
- **白色/浅色透气运动鞋**
- **软底乐福鞋 / 平底凉鞋(包后跟更养脚)**
- 避免全天穿完全平底或过硬的鞋,对足底经络不友好

---

## 🧥 随身加一件(很关键)
- **薄开衫 / 防晒衬衫**
  - 室内空调 + 早晚微风时护住肩颈
  - 肩颈保暖 = 少落枕、少疲劳

---

## 🕶️ 配饰与养身小细节
- **帽子或遮阳伞**:防晒就是防“耗气”
- **天然材质包袋**:帆布、草编,更符合当下季节气场
- **配色不宜过于浓烈**:春夏交替,宜“柔不宜躁”

---

如果你愿意告诉我:
- 是**上班 / 休闲 / 约会 / 出游**
- 或偏**中性、优雅、运动风**

我可以直接帮你搭一整套「今天就能穿出门」的苏州限定穿搭 🌿

这是第一轮调用LLM提供的请求和得到的响应内容:

{
  "model": "gpt-5.2-chat",
  "tools": [
    {
      "type": "function",
      "name": "_Main_g_GetWeather_0_1",
      "description": "",
      "parameters": {
        "type": "object",
        "required": [
          "location"
        ],
        "properties": {
          "location": {
            "description": "Location for weather query",
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "strict": null
    }
  ],
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "根据苏州的天气给我一些着装建议。"
        }
      ]
    }
  ],
  "instructions": "你是一个深谙养身之道的时尚顾问。"
}
{
  "id": "resp_08fd9fcf3071918b006a000a00f53081938f105b04d924cb63",
  "object": "response",
  "created_at": 1778387456,
  "status": "completed",
  "background": false,
  "completed_at": 1778387457,
  "content_filters": [
    {
      "blocked": false,
      "source_type": "prompt",
      "content_filter_raw": [],
      "content_filter_results": {
        "hate": {
          "filtered": false,
          "severity": "safe"
        },
        "sexual": {
          "filtered": false,
          "severity": "safe"
        },
        "violence": {
          "filtered": false,
          "severity": "safe"
        },
        "self_harm": {
          "filtered": false,
          "severity": "safe"
        }
      },
      "content_filter_offsets": {
        "start_offset": 0,
        "end_offset": 49,
        "check_offset": 0
      }
    },
    {
      "blocked": false,
      "source_type": "completion",
      "content_filter_raw": [],
      "content_filter_results": {
        "hate": {
          "filtered": false,
          "severity": "safe"
        },
        "sexual": {
          "filtered": false,
          "severity": "safe"
        },
        "violence": {
          "filtered": false,
          "severity": "safe"
        },
        "self_harm": {
          "filtered": false,
          "severity": "safe"
        }
      },
      "content_filter_offsets": {
        "start_offset": 0,
        "end_offset": 1170,
        "check_offset": 0
      }
    }
  ],
  "error": null,
  "frequency_penalty": 0.0,
  "incomplete_details": null,
  "instructions": "你是一个深谙养身之道的时尚顾问。",
  "max_output_tokens": null,
  "max_tool_calls": null,
  "model": "gpt-5.2-chat",
  "output": [
    {
      "id": "rs_08fd9fcf3071918b006a000a0152f88193b91826c5aa30181a",
      "type": "reasoning",
      "summary": []
    },
    {
      "id": "fc_08fd9fcf3071918b006a000a01c6548193b850d9b453ce47f8",
      "type": "function_call",
      "status": "completed",
      "arguments": "{\"location\":\"苏州\"}",
      "call_id": "call_kYGZgvSLCPipLqtmiIqfnIDT",
      "name": "_Main_g_GetWeather_0_1"
    }
  ],
  "parallel_tool_calls": true,
  "presence_penalty": 0.0,
  "previous_response_id": null,
  "prompt_cache_key": null,
  "prompt_cache_retention": null,
  "reasoning": {
    "effort": "medium",
    "summary": null
  },
  "safety_identifier": null,
  "service_tier": "default",
  "store": true,
  "temperature": 1.0,
  "text": {
    "format": {
      "type": "text"
    },
    "verbosity": "medium"
  },
  "tool_choice": "auto",
  "tools": [
    {
      "type": "function",
      "description": null,
      "name": "_Main_g_GetWeather_0_1",
      "parameters": {
        "type": "object",
        "required": [
          "location"
        ],
        "properties": {
          "location": {
            "description": "Location for weather query",
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "strict": false
    }
  ],
  "top_logprobs": 0,
  "top_p": 0.85,
  "truncation": "disabled",
  "usage": {
    "input_tokens": 83,
    "input_tokens_details": {
      "cached_tokens": 0
    },
    "output_tokens": 43,
    "output_tokens_details": {
      "reasoning_tokens": 0
    },
    "total_tokens": 126
  },
  "user": null,
  "metadata": {}
}

这是第二轮调用LLM提供的请求和得到的响应内容:

{
  "model": "gpt-5.2-chat",
  "tools": [
    {
      "type": "function",
      "name": "_Main_g_GetWeather_0_1",
      "description": "",
      "parameters": {
        "type": "object",
        "required": [
          "location"
        ],
        "properties": {
          "location": {
            "description": "Location for weather query",
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "strict": null
    }
  ],
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "根据苏州的天气给我一些着装建议。"
        }
      ]
    },
    {
      "type": "reasoning",
      "id": "rs_08fd9fcf3071918b006a000a0152f88193b91826c5aa30181a",
      "summary": []
    },
    {
      "type": "function_call",
      "id": "fc_08fd9fcf3071918b006a000a01c6548193b850d9b453ce47f8",
      "status": "completed",
      "call_id": "call_kYGZgvSLCPipLqtmiIqfnIDT",
      "name": "_Main_g_GetWeather_0_1",
      "arguments": "{\"location\":\"苏州\"}"
    },
    {
      "type": "function_call_output",
      "call_id": "call_kYGZgvSLCPipLqtmiIqfnIDT",
      "output": "\"苏州 当前晴朗,气温为25°C。\""
    }
  ],
  "instructions": "你是一个深谙养身之道的时尚顾问。"
}
{
  "id": "resp_08fd9fcf3071918b006a000a025fbc8193a1219305fbea8789",
  "object": "response",
  "created_at": 1778387458,
  "status": "completed",
  "background": false,
  "completed_at": 1778387467,
  "content_filters": [
    {
      "blocked": false,
      "source_type": "completion",
      "content_filter_raw": [],
      "content_filter_results": {
        "hate": {
          "filtered": false,
          "severity": "safe"
        },
        "sexual": {
          "filtered": false,
          "severity": "safe"
        },
        "violence": {
          "filtered": false,
          "severity": "safe"
        },
        "self_harm": {
          "filtered": false,
          "severity": "safe"
        }
      },
      "content_filter_offsets": {
        "start_offset": 0,
        "end_offset": 1912,
        "check_offset": 0
      }
    }
  ],
  "error": null,
  "frequency_penalty": 0.0,
  "incomplete_details": null,
  "instructions": "你是一个深谙养身之道的时尚顾问。",
  "max_output_tokens": null,
  "max_tool_calls": null,
  "model": "gpt-5.2-chat",
  "output": [
    {
      "id": "msg_08fd9fcf3071918b006a000a02c53c819385543898398da88e",
      "type": "message",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "annotations": [],
          "logprobs": [],
          "text": "...(同上面展示的LLM最终回复内容)..."
        }
      ],
      "role": "assistant"
    }
  ],
  "parallel_tool_calls": true,
  "presence_penalty": 0.0,
  "previous_response_id": null,
  "prompt_cache_key": null,
  "prompt_cache_retention": null,
  "reasoning": {
    "effort": "medium",
    "summary": null
  },
  "safety_identifier": null,
  "service_tier": "default",
  "store": true,
  "temperature": 1.0,
  "text": {
    "format": {
      "type": "text"
    },
    "verbosity": "medium"
  },
  "tool_choice": "auto",
  "tools": [
    {
      "type": "function",
      "description": null,
      "name": "_Main_g_GetWeather_0_1",
      "parameters": {
        "type": "object",
        "required": [
          "location"
        ],
        "properties": {
          "location": {
            "description": "Location for weather query",
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "strict": false
    }
  ],
  "top_logprobs": 0,
  "top_p": 0.85,
  "truncation": "disabled",
  "usage": {
    "input_tokens": 157,
    "input_tokens_details": {
      "cached_tokens": 0
    },
    "output_tokens": 612,
    "output_tokens_details": {
      "reasoning_tokens": 0
    },
    "total_tokens": 769
  },
  "user": null,
  "metadata": {}
}