引言
关注.NET AI
和.NET Vector
原生开发已有半年之久了,其核心组件在历经这半年预发布期的持续迭代后,终于于5月16日和5月20日逐步发布了。。在此之前,基于预发布版本撰写的文章和调试工作常常受限于功能的缺失,许多特性无法正常调用,只能通过下载源代码进行调试。
如今,随着正式版的发布,这些库为 .NET
原生 AI
开发提供了强大的基础,支持开发者构建可扩展、可维护且具备互作性的 AI
驱动型应用程序。
什么是 AI 和 Vector Data Extensions
AI
和 Vector Data Extensions
是一组专为 .NET
设计的库,旨在处理 AI
模型和矢量存储相关任务。它们通过提供共享的抽象和实用工具,帮助开发者在 .NET
生态系统中无缝集成 AI
功能。
- 以下是这些库的核心组成部分:
库名称 | 功能描述 |
---|---|
Microsoft.Extensions.AI.Abstractions | 定义 AI 模型的常见类型和抽象 |
Microsoft.Extensions.AI | 提供 AI 扩展的实用工具 |
Microsoft.Extensions.VectorData.Abstractions | 为向量存储提供交换类型和抽象 |
❝
很有意思的是,虽然本次发布的这三个库都是第一个正式版本,但是正式版的版本号是从 9.5.0 开始,大家一定要注意,如下图所示:
Microsoft.Extensions.AI
Microsoft.Extensions.AI.Abstractions
Microsoft.Extensions.VectorData.Abstractions
- 这些库作为更高级别组件的基础构建块,致力于实现以下目标:
应用目标及说明
构建库 vs. 构建应用程序
- 构建开发基础库 :保持对特定
AI
或矢量系统的不可知性至关重要。仅依赖共享抽象可以避免将用户绑定到某一特定提供商,同时确保库与其他库的互作性,从而提升生态系统的灵活性和兼容性。 - 构建应用程序 :开发者可以更自由地选择具体实现,享受一致
API
带来的便利,轻松切换或组合不同提供商,而无需大幅调整代码。
❝
AI
和Vector Data Extensions
为开发者提供了关键的构建块,使其能够更轻松地在应用程序中实现高级 AI 功能,例如结构化输出、工具调用和可观察性等。这些库通过一致的抽象,助力开发者打造强大、可维护且生产就绪的解决方案,满足特定需求。
AI 和 Vector Data Extensions 的应用
依赖注入配置
现代 .NET
应用程序依赖于依赖注入(DI
)来管理服务的配置和生命周期。AI
和 Vector Data
扩展库专为与 DI
模型保持一致而设计。
无论是本地开发还是生产环境,这些扩展都能无缝注册到现有的 DI
容器中,使 AI
组件与其他应用程序部分一样易于组合和配置,如下代码需要安装:
dotnet add package Microsoft.SemanticKernel --version 1.54.0
dotnet add package Microsoft.SemanticKernel.Connectors.InMemory --version 1.54.0
dotnet add package Microsoft.SemanticKernel.Connectors.Ollama --version 1.54.0-preview
dotnet add package Microsoft.SemanticKernel.Connectors.Qdrant --version 1.54.0-preview
dotnet add package Microsoft.SemanticKernel.Plugins.OpenApi --version 1.54.0-preview
dotnet add package OllamaSharp --version 5.1.19
using Microsoft.Extensions.AI;
using OllamaSharp;
// 添加聊天客户端
builder.Services.AddChatClient(sp => new OpenAI.OpenAIClient("OpenAIKey").GetChatClient("ModelName").AsIChatClient())
.UseLogging()
.UseOpenTelemetry();
// 添加嵌入生成器
builder.Services.AddEmbeddingGenerator(sp => new OllamaApiClient("http://localhost:11434/", defaultModel: "text-embedding-3-small"))
.UseLogging()
.UseOpenTelemetry();
// 添加 SQLite 集合,假设 Product 类已定义
builder.Services.AddQdrantCollection<int, Product>("Products", "localhost");
多模型和向量存储多样化
❝
无论是在本地开发与生产环境中使用不同模型提供商,还是构建依赖多种模型的代理,
AI
和Vector Data Extensions
都能提供一致的API
。随着官方和社区支持的软件包生态系统不断扩展,集成不同模型和向量数据库变得更加简单高效,这进一步提高了多模型之间和向量存储提供商之间的可迁移性,确保了开发过程的灵活性与应用的广泛适应性。
如下的演示中,我通过配置Ollama环境,结合 phi3:latest
模型来完成,有条件的同学可以试试Azure AI。
using Microsoft.Extensions.AI;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.Qdrant;
using OllamaSharp;
using Qdrant.Client;
IChatClient chatClient = new OllamaApiClient("http://localhost:11434/", "phi3:latest");
// 有条件的同学可以试试Azure AI
// IChatClient chatClient = : new AzureOpenAIClient("YOUR-AZURE-OPENAI-ENDPOINT", new DefaultAzureCredential()).GetChatClient("gpt-4.1").AsIChatClient();
await foreach (ChatResponseUpdate message in chatClient.GetStreamingResponseAsync("What is AI?"))
{
Console.Write($"{message.Text}");
}
IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator = new OllamaApiClient("http://localhost:11434/", "phi3:latest");
//IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator = new AzureOpenAIClient("YOUR-AZURE-OPENAI-ENDPOINT", new DefaultAzureCredential()).GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
Embedding<float> embedding = await embeddingGenerator.GenerateAsync("What is AI?");
// 大家也可以使用Sqlite,此处不做演示
// VectorStoreCollection<ulong, Product> collection = new SqliteCollection<int, Product>("Data Source=products.db", "products", new SqliteCollectionOptions { EmbeddingGenerator = embeddingGenerator})
VectorStoreCollection<ulong, Product> collection = new QdrantCollection<ulong, Product>(
new QdrantClient("localhost"),
"products",
true,
new QdrantCollectionOptions { EmbeddingGenerator = embeddingGenerator });
await collection.EnsureCollectionExistsAsync();
await collection.UpsertAsync(new Product
{
Id = 1,
Name = "Test",
TenantId = 5,
Embedding = embedding
});
Console.Write("向量写入成功");
Console.ReadKey();
record Product
{
[VectorStoreKey]
public ulong Id { get; set; }
[VectorStoreData]
public required string Name { get; set; }
[VectorStoreData]
public int TenantId { get; set; }
[VectorStoreVector(Dimensions: 3072)]
public Embedding<float>? Embedding { get; set; }
}
运行结果
请注意 Product 实体的声明
-
VectorStoreKey:用于标记数据模型中唯一键的属性。
record Product
{
[VectorStoreKey]
public int Key { get; set; }
} -
VectorStoreData:属性用于标记数据字段,可以指定是否支持索引或全文搜索。
[VectorStoreData(IsIndexed = true)]
public string HotelName { get; set; } -
VectorStoreVector:属性用于标记向量字段,指定向量的维度、距离函数(如余弦相似度)等。
[VectorStoreVector(Dimensions = 1536, DistanceFunction = DistanceFunction.CosineSimilarity)]
public ReadOnlyMemory<float> DescriptionEmbedding { get; set; }
注意向量存储尚未完整发布
如下图所示,Qdrant、Pipecone、Mongodb、Weaviate、SQL Server等,都处于preview版本,我相信不用太久,这些原生支持的正式版都会发布出来。
多模态处理
生成式 AI
模型不仅限于处理文本,还能应对图像、音频等多种数据类型。虽然模型输出通常是非结构化的,与应用程序的集成较为复杂,但是现在许多模型已支持结构化输出,可以根据预定义的架构(如 JSON
)格式化响应,从而提升输出的可靠性和可预测性。
为此,AI
扩展库提供了灵活的基础,用于表示不同格式的数据。AI
扩展库与结构化输出无缝协作,让模型响应能够直接映射到 C#
类型。
以下是一个处理收据图像并提取数据的示例:
using Microsoft.Extensions.AI;
using OllamaSharp;
Uri imageUri = new Uri("https://images.cnblogs.com/cnblogs_com/blogs/272929/galleries/2447197/o_250526033729_qrcode_for_gh_5d49c4cbffe5_258.jpgg");
List<AIContent> content = [
new TextContent("Process this receipt"),
new UriContent(imageUri, mediaType: "image/jpeg")
];
ChatMessage message = new ChatMessage(ChatRole.User, content);
IChatClient chatClient = new OllamaApiClient("http://localhost:11434/", "phi3:latest");
ChatResponse<Receipt> response = await chatClient.GetResponseAsync<Receipt>(message);
response.TryGetResult(out Receipt? receiptData);
Console.WriteLine($"Merchant: {receiptData.Merchant} | Total: {receiptData.Total} | Category: {receiptData.Category}");
Console.ReadKey();
record Item(string Name, float Price);
enum Category { Food, Electronics, Clothing, Services };
record Receipt(string Merchant, List<Item> Items, float Total, Category Category);
运行结果
辅助功能集成
为了确保系统的可靠性和性能,还需要通过日志记录、缓存和可观测性等功能进行增强,可以通过插入自己的 ILogger
、IDistributedCache
以及 OpenTelemetry
兼容的工具,无需从头构建。
以下是一个简单的启用示例:
using Microsoft.Extensions.AI;
using OllamaSharp;
using System.ComponentModel;
using System.Text.Json;
using ChatMessage = Microsoft.Extensions.AI.ChatMessage;
IChatClient chatClient = new OllamaApiClient("http://localhost:11434/", "phi3:latest");
IChatClient chatClient1 = new ChatClientBuilder(chatClient)
.UseLogging()
.UseDistributedCache()
.UseOpenTelemetry()
.Build();
自定义扩展
例如,您可以通过以下方式实现调用频率限制:
using Microsoft.Extensions.AI;
using OllamaSharp;
using System.ComponentModel;
using System.Text.Json;
using System.Threading.RateLimiting;
using ChatMessage = Microsoft.Extensions.AI.ChatMessage;
IChatClient chatClient = new OllamaApiClient("http://localhost:11434/", "phi3:latest");
RateLimiter rateLimiter = new ConcurrencyLimiter(new()
{
PermitLimit = 1,
QueueLimit = int.MaxValue
});
IChatClient client = new ChatClientBuilder(chatClient)
.UseDistributedCache()
// 功能新增
.Use(async (messages, options, nextAsync, cancellationToken) =>
{
using RateLimitLease lease = await rateLimiter.AcquireAsync(permitCount: 1, cancellationToken).ConfigureAwait(false);
if (!lease.IsAcquired)
throw new InvalidOperationException("Unable to acquire lease.");
await nextAsync(messages, options, cancellationToken);
})
.UseOpenTelemetry()
.Build();
❝
这种方式允许可以不改变核心逻辑的情况下,灵活添加自定义行为。
Function Call
AI
模型虽能处理数据并理解自然语言,但无法独立执行行动。为了实现有意义的交互,它们需要访问外部工具和系统。Function Call
功能应运而生,许多现代生成式 AI
模型已支持此功能,允许模型根据用户意图自动调用函数。
AI
扩展库让这一功能在应用程序中变得简单易用。以下示例展示了如何将 CalculateTax
方法注册为 AI
可调用函数,模型会根据用户请求自动触发:
using Microsoft.Extensions.AI;
using OllamaSharp;
using System.ComponentModel;
using System.Text.Json;
using ChatMessage = Microsoft.Extensions.AI.ChatMessage;
[Description("Calculate tax given a receipt and tax rate")]
float CalculateTax(Receipt receipt, float taxRate)
{
return receipt.Total * (1 + taxRate);
}
IChatClient chatClient = new OllamaApiClient("http://localhost:11434/", "llama3.2:latest");
IChatClient functionChatClient =
chatClient
.AsBuilder()
.UseFunctionInvocation()
.Build();
Receipt receiptData = new Receipt(
"Test Merchant",
new List<Item>
{
new Item("Item 1", 10.00f),
new Item("Item 2", 20.00f),
new Item("Item 3", 30.00f)
},
60.00f,
Category.Food
);
ChatMessage message = new ChatMessage(ChatRole.User, [
new TextContent("Here is information from a recent purchase"),
new TextContent($"{JsonSerializer.Serialize(receiptData)}"),
new TextContent("What is the total price after tax given a tax rate of 10%?")
]);
ChatResponse<ReceiptTotal> response = await functionChatClient.GetResponseAsync<ReceiptTotal>(message, new ChatOptions { Tools = [AIFunctionFactory.Create(CalculateTax)] });
response.TryGetResult(out ReceiptTotal? receiptTotal);
Console.WriteLine($"SubTotal: {receiptTotal.SubTotal} | TaxAmount: {receiptTotal.TaxAmount} | TaxRate: {receiptTotal.TaxRate} | Total: {receiptTotal.Total}");
Console.ReadKey();
record ReceiptTotal(float SubTotal, float TaxAmount, float TaxRate, float Total);
record Item(string Name, float Price);
enum Category { Food, Electronics, Clothing, Services };
record Receipt(string Merchant, List<Item> Items, float Total, Category Category);
运行结果
❝
此处需要特别注意:要换一个模型,我使用的是
llama3.2:latest
,因为这个模型支持工具调用。如果继续使用 phi3,则会报如下错误:
搜索功能
根据具体的业务场景和数据模型,需要更高级的搜索能力。Vector Data Extension
提供了丰富的搜索功能,包括多种相似性指标、向量搜索、混合搜索以及筛选支持,查询过程被极大简化:
- 传入纯文本
- 抽象层自动处理嵌入生成、应用相似性指标
- 筛选
- 返回最相关结果
以下示例展示了如何搜索与自然语言查询匹配的产品,并按租户过滤:
using Microsoft.Extensions.AI;
using Microsoft.Extensions.VectorData;
using OllamaSharp;
using Microsoft.SemanticKernel.Connectors.Qdrant;
using Navyblue.BaseLibrary;
using Qdrant.Client;
IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator = new OllamaApiClient("http://localhost:11434/", "phi3:latest");
VectorStoreCollection<ulong, Product> collection =new QdrantCollection<ulong, Product>(
new QdrantClient("localhost"),
"products",
true,
new QdrantCollectionOptions { EmbeddingGenerator = embeddingGenerator });
string query = "Test";
await foreach (VectorSearchResult<Product> result in collection.SearchAsync(query, top: 5, new() { Filter = r => r.TenantId == 5 }))
{
Console.WriteLine(result.Record.ToJson());
}
record Product
{
[VectorStoreKey]
public ulong Id { get; set; }
[VectorStoreData]
public required string Name { get; set; }
[VectorStoreData]
public int TenantId { get; set; }
[VectorStoreVector(Dimensions: 3072)]
public Embedding<float>? Embedding { get; set; }
}
运行结果
生态系统
AI
和 Vector Data
扩展库的采用率持续攀升,仅在短短几个月内,下载量已超过 300 万次,近 100 个公共 NuGet
包依赖于它们。以下是一些官方和社区项目的应用示例:
应用示例 | 描述 |
---|---|
库 | 模型上下文协议(MCP)、AI 评估、Pieces |
代理框架 | Semantic Kernel、AutoGen |
SDK | Azure OpenAI、OllamaSharp、Anthropic、Google、HuggingFace、Sqlite、Qdrant、CosmosDB、AzureSQL |
UI 组件 | DevExpress、Syncfusion、Progress Telerik |
模型上下文协议 (MCP) C# SDK
MCP 是一种开放标准,充当 AI
模型的通用适配器,使模型能够通过一致的标准化接口与外部数据源、工具和 API
交互,从而简化集成过程。
我们与 Anthropic
合作提供了官方 MCP C# SDK
。该 SDK
构建在 AIContent
、AIFunction
和 IChatClient
等共享 AI
抽象之上,便于 MCP
客户端和服务器定义和调用工具:
var mcpClient = await McpClientFactory.CreateAsync(clientTransport, mcpClientOptions, loggerFactory);
var tools = await mcpClient.ListToolsAsync();
var response = await _chatClient.GetResponseAsync<List<TripOption>>(messages, new ChatOptions { Tools = [.. tools ] });
评估
Microsoft.Extensions.AI.Evaluation
库旨在简化 AI
评估流程与应用程序的集成。它提供了一个强大的框架,用于评估 AI
应用程序并自动评估其性能。评估功能它确保了系统的安全性、可靠性以及与预期行为的符合性,这些工具能够无缝集成到开发工作流程中,支持对 AI
系统的持续监控和改进。在构建可信赖的 AI
应用程序中至关重要。
基于 Microsoft.Extensions.AI
抽象构建的评估库由以下 NuGet 包组成:
Microsoft.Extensions.AI.Evaluation
: 用于支持评估的核心抽象和类型。Microsoft.Extensions.AI.Evaluation.Quality
: 包含根据相关性和完整性等指标,评估应用程序中 LLM 响应质量的评估器。这些评估员直接使用 LLM 来执行评估。Microsoft.Extensions.AI.Evaluation.Safety
: 包含使用Azure AI Foundry
评估服务执行评估的评估器,例如ProtectedMaterialEvaluator
和ContentHarmEvaluator
Microsoft.Extensions.AI.Evaluation.Reporting
: 包含对缓存LLM
响应、存储评估结果以及从该数据生成报告的支持。Microsoft.Extensions.AI.Evaluation.Reporting.Azure
: 报告库支持,用于缓存 LLM 响应并将评估结果存储在 Azure 存储容器中。Microsoft.Extensions.AI.Evaluation.Console
: 用于生成报告和管理评估数据的命令行工具。
按照如下步骤生成报告
dotnet tool install --local Microsoft.Extensions.AI.Evaluation.Console
dotnet tool run aieval report --path <path\to\your\cache\storage> --output report.html
打开report.html,如下所示:
开发者可以通过评估,根据真实场景和质量标准,系统地测试和验证 AI 模型,
Semantic Kernel
Semantic Kernel
提供高级组件,简化了 AI
在应用程序中的集成。随着 AI Agent
时代的到来,Agent 需要访问模型、数据和工具以高效执行任务。
Semantic Kernel
允许开发者利用熟悉的 AI 扩展(如 IChatClient
)构建代理。
以下示例展示了如何在 Semantic Kernel
的 Agent Framework
中使用 IChatClient
作为代理基础:
using System.ComponentModel;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.VectorData;
using OllamaSharp;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
[Description("Calculate tax given a receipt and tax rate")]
float CalculateTax(Receipt receipt, float taxRate)
{
return receipt.Total * (1 + taxRate);
}
IKernelBuilder builder = Kernel.CreateBuilder();
// Add your IChatClient
builder.Services.AddChatClient(new OllamaApiClient("http://localhost:11434/", "llama3.2:latest"))
.UseFunctionInvocation()
.Build();
#pragma warning disable SKEXP0001 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。
builder.Plugins.AddFromFunctions(
nameof(CalculateTax),
[AIFunctionFactory.Create(CalculateTax).AsKernelFunction()]);
#pragma warning restore SKEXP0001 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。
Kernel kernel = builder.Build();
ChatCompletionAgent agent = new ChatCompletionAgent
{
Name = "TravelAgent",
Description = "A travel agent that helps users with travel plans",
Instructions = "Help users come up with a travel itinerary",
Kernel = kernel,
Arguments = new KernelArguments(
new PromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
})
};
ChatMessageContent[] result = await agent.InvokeAsync([]).ToArrayAsync();
Console.WriteLine(result.LongLength);
Console.ReadKey();
record ReceiptTotal(float SubTotal, float TaxAmount, float TaxRate, float Total);
record Item(string Name, float Price);
enum Category { Food, Electronics, Clothing, Services };
record Receipt(string Merchant, List<Item> Items, float Total, Category Category);
运行结果:
Semantic Kernel
还为向量数据库提供了一组统一的连接器,这些连接器基于 Vector Data
扩展构建,通过一致的编程模型简化了集成。
AI 开发库
AI Dev Gallery
专为 Windows 开发人员设计,作为 .NET AI
开发的综合游乐场,有助于将 AI 功能集成到应用和项目中。它提供了一个完全离线的环境,让开发者能够探索、试验和实现 AI
功能,无需依赖云服务。
它的功能包括:
- 探索由本地 AI 模型提供支持的超过 25 个交互式示例
- 从 Hugging Face 和 GitHub 轻松浏览、下载和运行模型
- 查看 C# 源代码,只需单击一下即可导出独立的 Visual Studio 项目
❝
AI Dev Gallery 目前提供公共预览版
主页面
主页面
案例页面
案例页面
这个页面在浏览的时候会被阻止,大家可以集思广益来解决这个问题。
通过模型界面可以下载相应的模型:
模型界面
AI Dev Gallery
建立在 AI
和 Vector Data
扩展之上,为模型和数据集成奠定了坚实基础,同时利用以下组件:
组件 | 描述 |
---|---|
Microsoft.ML.Tokenizers | 用于高效的文本预处理和分词 |
System.Numerics.Tensors | 用于模型输出的高性能处理 |
这些组件共同使 AI Dev Gallery
成为本地端到端 AI
实验和开发的强大工具。