5:微软AI库Microsoft.Extensions.AI的使用与流式响应

1. Microsoft.Extensions.AI代码内容

C# 复制代码
using Microsoft.Extensions.AI;
using System.ClientModel;
using OpenAI;

// 配置
const string platformName = "阿里云百炼";
var apiKey = "**********";
var baseUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1/";
var model = "qwen3-max";

// 构建消息
ChatMessage[] messages =
[
    new ChatMessage(ChatRole.System,
        @"你是一个有经验的针对中文为母语的英语学习者提供英语学习服务的老师,你会把用户提供的英文句子中的中国初中英语教材之外的单词提取出来。把复数、过去式等转换为原型形式。超出英语学习范围的东西,请回复'这个问题我回答不了,换个问题吧。'"
    ),
    new ChatMessage(ChatRole.User,
        //@"Far out in the uncharted backwaters of the unfashionable end of the Western Spiral arm of the Galaxy lies a small unregarded yellow sun.")
        @"马云是谁")
];

Console.WriteLine($"正在调用{platformName}平台...\n");

// 发送请求并获取响应
IChatClient client =
    new OpenAI.Chat.ChatClient(model, new ApiKeyCredential(apiKey),
        new OpenAIClientOptions() { Endpoint = new Uri(baseUrl) }).AsIChatClient();
var chatResponse = await client.GetResponseAsync(messages);

// 输出结果
Console.WriteLine($"\nAI 回复: {chatResponse.Text}");

// 输出 token 使用情况
if (chatResponse.Usage != null)
{
    Console.WriteLine($"\n使用 tokens: {chatResponse.Usage.TotalTokenCount}");
    Console.WriteLine($"  - Prompt tokens: {chatResponse.Usage.InputTokenCount}");
    Console.WriteLine($"  - Completion tokens: {chatResponse.Usage.OutputTokenCount}");
}

2. Microsoft.Extensions.AI代码效果

2.1. 效果一

text 复制代码
正在调用阿里云百炼平台...


AI 回复: 以下是从句子中提取出的、超出中国初中英语教材范围的单词(已转换为原型形式):

- uncharted
- backwater
- unfashionable
- spiral
- galaxy

注:
- "lies" 是动词 "lie"(位于)的第三人称单数形式,但 "lie" 属于初中词汇,故不列入。
- "yellow" 和 "sun" 均为初中词汇。
- "arm" 在此处指"旋臂",虽"arm"本身是初中词,但该用法属天文术语,不过按规则只考虑单词本身是否超纲,因此不单独列出。

以上列表仅包含原型且超出初中范围的词汇。

使用 tokens: 266
  - Prompt tokens: 112
  - Completion tokens: 154

D:\Code\CSharp\AI\LearnAIWithZack\Basic\CallAiWithMicrosoft_Extensions_AI1\bin\Debug\net9.0\CallAiWithMicrosoft_Extensions_AI1.exe (进程 16196)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用"工具"->"选项"->"调试"->"调试停止时自动关闭控制台"。
按任意键关闭此窗口. . .

2.2. 效果二

text 复制代码
正在调用阿里云百炼平台...


AI 回复: 这个问题我回答不了,换个问题吧。

使用 tokens: 92
  - Prompt tokens: 83
  - Completion tokens: 9

D:\Code\CSharp\AI\LearnAIWithZack\Basic\CallAiWithMicrosoft_Extensions_AI1\bin\Debug\net9.0\CallAiWithMicrosoft_Extensions_AI1.exe (进程 61004)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用"工具"->"选项"->"调试"->"调试停止时自动关闭控制台"。
按任意键关闭此窗口. . .

3. Microsoft.Extensions.AI代码整理说明


3.1. 这段代码"本质上在做什么"

一句话总结:

这是一个用 Microsoft.Extensions.AI 作为"统一抽象接口",
实际通过 OpenAI SDK,调用"阿里云百炼(DashScope)OpenAI-Compatible 接口",
使用 Qwen3 模型完成一次 Chat Completion 的示例。

换成结构图就是:

复制代码
你的业务代码
   ↓(IChatClient 抽象)
Microsoft.Extensions.AI
   ↓(适配器)
OpenAI SDK
   ↓(OpenAI-compatible 协议)
阿里云百炼 / DashScope
   ↓
qwen3-max

3.2. 逐块拆解代码在干什么

1️⃣ using 引入的含义(非常关键)

csharp 复制代码
using Microsoft.Extensions.AI;
using System.ClientModel;
using OpenAI;
命名空间 作用
Microsoft.Extensions.AI AI 抽象接口(IChatClient / ChatMessage)
System.ClientModel Azure / OpenAI SDK 用的 Credential / Pipeline 基础设施
OpenAI OpenAI 官方 .NET SDK

👉 这里体现了一个重要事实:
Microsoft.Extensions.AI 本身不发请求,它只是"接口 + 统一模型"


2️⃣ 配置部分:OpenAI-Compatible 的典型特征

csharp 复制代码
var baseUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1/";
var model = "qwen3-max";

这两点非常关键:

  • baseUrl 明确是 OpenAI Compatible Mode
  • modelQwen,而不是 GPT

👉 说明:

你用的是 OpenAI SDK 的"协议",但不是 OpenAI 的"模型"

这正是 OpenAI-compatible 生态 的核心价值。


3️⃣ Prompt / 消息构建(抽象层已生效)

csharp 复制代码
ChatMessage[] messages =
[
    new ChatMessage(ChatRole.System, "..."),
    new ChatMessage(ChatRole.User, "马云是谁")
];

这里已经完全脱离 OpenAI SDK 的 Message 类型

  • ❌ 没有 ChatCompletionMessage
  • ❌ 没有 role = "user"

而是:

  • Microsoft.Extensions.AI.ChatMessage
  • ChatRole.System / User

👉 这一步说明:

你的业务逻辑已经只依赖 Microsoft.Extensions.AI 的模型


4️⃣ 最关键的一行:AsIChatClient()

csharp 复制代码
IChatClient client =
    new OpenAI.Chat.ChatClient(...)
        .AsIChatClient();

这一行做了三件事:

  1. 使用 OpenAI SDK 的 ChatClient
  2. 指定:
    • API Key
    • Endpoint(DashScope)
    • Model(qwen3-max)
  3. 通过 Adapter 转成 IChatClient

这是整个示例的 核心价值点

OpenAI SDK → 适配 → Microsoft.Extensions.AI 抽象


5️⃣ 发送请求(完全抽象化)

csharp 复制代码
var chatResponse = await client.GetResponseAsync(messages);

此时你的代码已经:

  • ❌ 不知道底层是 OpenAI
  • ❌ 不知道是 Qwen
  • ❌ 不知道是 DashScope

它只知道:

"我在调用一个 Chat AI"

这正是 Microsoft.Extensions.AI 想要的效果。


6️⃣ 响应解析(统一结构)

csharp 复制代码
Console.WriteLine(chatResponse.Text);

以及:

csharp 复制代码
chatResponse.Usage.TotalTokenCount

说明 Microsoft.Extensions.AI 做了什么?

  • 统一了:
    • 返回文本
    • Token Usage
  • 抹平了不同厂商的字段差异

4. Microsoft.Extensions.AI流式输出


4.1. 一句话定义

流式输出(Streaming Output)

是指 模型在"生成过程中"就把结果分段返回,而不是等全部生成完一次性返回。

对比一下最直观:

模式 返回方式
非流式 等模型生成完 → 一次性返回
流式 生成一个 token / 片段 → 立刻返回

4.2. 为什么流式输出在大模型里"特别重要"

1️⃣ 大模型生成是"逐 token"的

从模型内部看:

复制代码
输入 Prompt
   ↓
预测 token1
   ↓
预测 token2
   ↓
预测 token3
   ↓
......

👉 本来就是一个"流"

非流式只是:

把这个流 缓存在服务器,最后一次性吐给你


2️⃣ 非流式的核心问题

❌ 延迟高(Latency)
  • 模型生成 500 token
  • 你要 等 5--10 秒
  • 用户看到的是"卡住"

❌ 无法实时反馈
  • UI 不能打字机效果
  • CLI / WebSocket / SSE 体验差

❌ 浪费用户时间

很多时候:

  • 用户看到前两句就知道"这回答不对"
  • 但你已经为后面的 token 付费了

3️⃣ 流式输出解决了什么

✅ 感知延迟极低
  • 200ms 内就能看到第一个字
  • 用户心理上觉得"很快"

✅ 可随时中断
  • 用户点"停止"
  • 客户端断流
  • 后续 token 不再生成(节省钱)

✅ 更适合交互式场景
  • Chat
  • IDE Copilot
  • 教学逐字讲解
  • 命令行 AI

4.3. 流式输出 ≠ 一次返回很多次

一个常见误解:

"流式是不是服务器把结果切几段返回?"

❌ 不完全是

真实情况是:

  • 模型本身 边算边吐
  • 服务端只是 转发 token 流

4.4. 什么时候"必须"用流式输出?

必须用的场景

场景 原因
聊天 UI 用户体验
IDE Copilot 实时提示
教学讲解 边讲边看
CLI AI 反馈感

可以不用的场景

场景 原因
后台批处理 不看过程
报告生成 一次性
评分 / 分类 只要结果

4.5. 一句"工程总结"

流式输出不是锦上添花,而是"大模型交互系统的标配能力"。
它让 AI 从"远程函数调用",变成了"实时协作对象"。

5. 流式输出代码实现

C# 复制代码
using Microsoft.Extensions.AI;
using System.ClientModel;
using HttpMataki.NET.Auto;
using OpenAI;

// 配置
const string platformName = "阿里云百炼";
var apiKey = "*********************";
var baseUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1/";
var model = "qwen3-max";
//HttpClientAutoInterceptor.StartInterception();
// 构建消息
ChatMessage[] messages =
[
    new ChatMessage(ChatRole.User,
        @"请讲一个关于程序员的笑话,大约200字。")
];

Console.WriteLine($"正在调用{platformName}平台...\n");

// 创建聊天客户端
IChatClient client =
    new OpenAI.Chat.ChatClient(model, new ApiKeyCredential(apiKey),
        new OpenAIClientOptions() { Endpoint = new Uri(baseUrl) }).AsIChatClient();

// 使用流式输出
await foreach (var update in client.GetStreamingResponseAsync(messages))
{
    Console.Write(update.Text);
}

Console.WriteLine("\n输出完成!");

6. 流式输出代码实现效果

相关推荐
奔跑中的小象2 小时前
统信UOS + 天数AI卡部署SGLang服务手册
人工智能·uos·sglang·天数智芯
DevSecOps选型指南2 小时前
中国版Mythos,为何是悬镜安全灵脉CodeAI?
人工智能·安全
Shockang2 小时前
LangGraph 状态机实战
人工智能
刹那芳华19922 小时前
循环神经网络的从零开始实现(RNN)
人工智能·rnn·深度学习
阿童木写作2 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
科技之门2 小时前
AI3D从建模到贴图、绑骨和动画的完整流程怎么做?V2Fun完整工作流指南
人工智能·3d·贴图
宇宙第一小趴菜2 小时前
二、机器学习的应用领域和发展史
人工智能·机器学习
前端开发江鸟2 小时前
我写过 MCP Server,却一直以为 MCP 只有 Tool
人工智能
天国梦3 小时前
自习室智能化升级避坑指南:天学网AI智习室方案实测与选型建议
大数据·人工智能
阿里云云原生3 小时前
可用性从 99.9% 跃升至 99.995%:畅捷通如何用 AI 重塑运维底座?
运维·网络·人工智能