使用 Dapr AI 包,您可以从 .NET 应用程序与 Dapr AI 工作负载进行交互。
目前,Dapr 提供对话 API 来与大语言模型进行交互。要开始使用此工作负载,请阅读 Dapr 对话 AI 操作指南。
This is the multi-page printable view of this section. Click here to print.
使用 Dapr AI 包,您可以从 .NET 应用程序与 Dapr AI 工作负载进行交互。
目前,Dapr 提供对话 API 来与大语言模型进行交互。要开始使用此工作负载,请阅读 Dapr 对话 AI 操作指南。
Dapr AI 客户端包允许您与 Dapr 边车提供的 AI 功能进行交互。
DaprConversationClient 是 Dapr 客户端的专用版本,专门用于与 Dapr Conversation API 交互。它可以与 DaprClient 和其他 Dapr 客户端一起注册,不会产生任何问题。
它维护用于与 Dapr 边车通信的 TCP 套接字形式的网络资源访问。
为获得最佳性能,请创建一个 DaprConversationClient 的单一长期实例,并在整个应用程序中提供对该共享实例的访问。DaprConversationClient 实例是线程安全的,旨在共享使用。
利用依赖注入功能可以更好地实现这一点。注册方法支持注册为单例、作用域实例或瞬态(意味着每次注入时都会重新创建),但同时也支持注册以使用 IConfiguration 的值或其他注入的服务,这在每个类中从头创建客户端时是不切实际的。
避免为每次操作创建一个 DaprConversationClient。
可以通过在调用 .Build() 创建客户端本身之前调用 DaprConversationClientBuilder 类上的方法来配置 DaprConversationClient。每个 DaprConversationClient 的设置是独立的,在调用 .Build() 后无法更改。
var daprConversationClient = new DaprConversationClientBuilder()
.UseDaprApiToken("abc123") // 指定用于向其他 Dapr 边车进行身份验证的 API 令牌
.Build();
DaprConversationClientBuilder 包含以下设置:
JsonSerializerOptions 对象GrpcChannelOptions 对象HttpClient 实例的工厂方法HttpClient 实例使用的超时时间SDK 将读取以下环境变量以配置默认值:
DAPR_HTTP_ENDPOINT:用于查找 Dapr 边车的 HTTP 端点,例如:https://dapr-api.mycompany.comDAPR_GRPC_ENDPOINT:用于查找 Dapr 边车的 gRPC 端点,例如:https://dapr-grpc-api.mycompany.comDAPR_HTTP_PORT:如果未设置 DAPR_HTTP_ENDPOINT,则用于查找 Dapr 边车的 HTTP 本地端点DAPR_GRPC_PORT:如果未设置 DAPR_GRPC_ENDPOINT,则用于查找 Dapr 边车的 gRPC 本地端点DAPR_API_TOKEN:用于设置 API 令牌Dapr 使用 CancellationToken 进行取消操作依赖于 gRPC 通道选项的配置。如果您需要自己配置这些选项,请确保启用 ThrowOperationCanceledOnCancellation 设置。
var daprConversationClient = new DaprConversationClientBuilder()
.UseGrpcChannelOptions(new GrpcChannelOptions { ... ThrowOperationCanceledOnCancellation = true })
.Build();
DaprConversationClient 进行取消操作DaprConversationClient 上的 API 执行异步操作并接受可选的 CancellationToken 参数。这遵循了 .NET 用于可取消操作的标准实践。请注意,当发生取消时,无法保证远程端点停止处理请求,只能保证客户端已停止等待完成。
当操作被取消时,它将抛出 OperationCancelledException。
DaprConversationClient使用内置的扩展方法在依赖注入容器中注册 DaprConversationClient 可以带来以下好处:一次性注册长期服务、集中复杂配置,并通过在可能的情况下重用类似的长期资源(例如 HttpClient 实例)来提高性能。
有三种重载可用,为开发人员在其场景中配置客户端提供了最大的灵活性。如果尚未注册 IHttpClientFactory,每种方法都会代表您注册它,并配置 DaprConversationClientBuilder 在创建 HttpClient 实例时使用它,以尽可能重用同一实例并避免套接字耗尽和其他问题。
在第一种方法中,开发人员不进行任何配置,DaprConversationClient 使用默认设置进行配置。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDaprConversationClient(); // 注册 `DaprConversationClient` 以按需注入
var app = builder.Build();
使用 ConversationInput 和 ConversationOptions 向您的对话组件发送提示:
var inputs = new[]
{
new ConversationInput(new IConversationMessage[]
{
new SystemMessage("You are a helpful assistant."),
new UserMessage("Summarize the following text...")
})
};
var options = new ConversationOptions("my-conversation-component")
{
Temperature = 0.2
};
var response = await daprConversationClient.ConverseAsync(inputs, options);
您可以使用 ConversationOptions.ResponseFormat 提供 JSON 架构,以将响应强制转换为特定格式。此功能需要 Dapr 运行时 v1.17.0 或更高版本。
using Google.Protobuf.WellKnownTypes;
var responseFormat = new Struct
{
Fields =
{
["type"] = new Value { StringValue = "object" },
["properties"] = new Value
{
StructValue = new Struct
{
Fields =
{
["answer"] = new Value
{
StructValue = new Struct
{
Fields =
{
["type"] = new Value { StringValue = "string" }
}
}
}
}
}
},
["required"] = new Value
{
ListValue = new ListValue { Values = { new Value { StringValue = "answer" } } }
}
}
};
var options = new ConversationOptions("my-conversation-component")
{
ResponseFormat = responseFormat
};
如果您的对话组件支持提示缓存,您可以使用 ConversationOptions.PromptCacheRetention 请求缓存保留窗口。此功能需要 Dapr 运行时 v1.17.0 或更高版本。
var options = new ConversationOptions("my-conversation-component")
{
PromptCacheRetention = TimeSpan.FromMinutes(30)
};
当组件和运行时支持时,响应包含可选的令牌使用统计。使用数据可在 ConversationResponseResult.Usage 上获得,包括总数和详细细分:
var response = await daprConversationClient.ConverseAsync(inputs, options);
var result = response.Outputs[0];
if (result.Usage is not null)
{
var totalTokens = result.Usage.TotalTokens;
var promptCachedTokens = result.Usage.PromptTokensDetails?.CachedTokens;
var reasoningTokens = result.Usage.CompletionTokensDetails?.ReasoningTokens;
}
有时开发人员需要使用上面详述的各种配置选项来配置创建的客户端。这是通过传入 DaprConversationClientBuiler 的重载来完成的,该重载公开了配置必要选项的方法。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDaprConversationClient((_, daprConversationClientBuilder) => {
// 设置 API 令牌
daprConversationClientBuilder.UseDaprApiToken("abc123");
// 指定非标准的 HTTP 端点
daprConversationClientBuilder.UseHttpEndpoint("http://dapr.my-company.com");
});
var app = builder.Build();
最后,开发人员可能需要从另一个服务检索信息以填充这些配置值。该值可能从 DaprClient 实例、供应商特定的 SDK 或某个本地服务提供,但只要它也在 DI 中注册,就可以通过最后一个重载将其注入到此配置操作中:
var builder = WebApplication.CreateBuilder(args);
// 注册一个从某处检索机密的虚构服务
builder.Services.AddSingleton<SecretService>();
builder.Services.AddDaprConversationClient((serviceProvider, daprConversationClientBuilder) => {
// 从服务提供程序检索 `SecretService` 的实例
var secretService = serviceProvider.GetRequiredService<SecretService>();
var daprApiToken = secretService.GetSecret("DaprApiToken").Value;
// 配置 `DaprConversationClientBuilder`
daprConversationClientBuilder.UseDaprApiToken(daprApiToken);
});
var app = builder.Build();
要开始使用 Dapr AI .NET SDK 客户端,请从 NuGet 安装 Dapr.AI 包:
dotnet add package Dapr.AI
DaprConversationClient 维护对用于与 Dapr 边车通信的 TCP 套接字形式的网络资源的访问。
AddDaprAiConversation() 方法会将 Dapr 客户端注册到 ASP.NET Core 依赖注入容器中,这是使用此包的推荐方式。此方法接受一个可选的选项委托来配置 DaprConversationClient,以及一个 ServiceLifetime 参数,允许您为注册的服务指定不同的生命周期,而不是默认的 Singleton 值。
以下示例假定所有默认值都可以接受,足以注册 DaprConversationClient:
services.AddDaprAiConversation();
可选的配置委托用于通过在 DaprConversationClientBuilder 上指定选项来配置 DaprConversationClient,如下例所示:
services.AddSingleton<DefaultOptionsProvider>();
services.AddDaprAiConversation((serviceProvider, clientBuilder) => {
//注入一个服务以从中获取值
var optionsProvider = serviceProvider.GetRequiredService<DefaultOptionsProvider>();
var standardTimeout = optionsProvider.GetStandardTimeout();
//在客户端构建器上配置值
clientBuilder.UseTimeout(standardTimeout);
});
除了使用依赖注入,也可以使用静态客户端构建器来构建 DaprConversationClient。
为了获得最佳性能,请创建一个单一的长期存活的 DaprConversationClient 实例,并在整个应用程序中提供对该共享实例的访问。DaprConversationClient 实例是线程安全的,旨在共享使用。
避免为每次操作创建一个 DaprConversationClient。
可以通过在调用 .Build() 创建客户端之前,在 DaprConversationClientBuilder 类上调用方法来配置 DaprConversationClient。每个 DaprConversationClient 的设置是独立的,在调用 .Build() 后无法更改。
var daprConversationClient = new DaprConversationClientBuilder()
.UseJsonSerializerSettings( ... ) //配置 JSON 序列化器
.Build();
有关通过构建器配置 Dapr 客户端时可用选项的更多信息,请参阅 .NET 文档。
测试 Dapr AI .NET SDK。浏览示例以查看 Dapr 的实际效果:
| SDK 示例 | 描述 |
|---|---|
| SDK 示例 | 克隆 SDK 存储库以试用一些示例并开始使用。 |
.NET SDK 的这一部分允许您与会话 API 交互,以从大型语言模型发送和接收消息。
要开始使用此 SDK,请从 NuGet 安装 Dapr.AI 和 Dapr.AI.Microsoft.Extensions 包:
dotnet add package Dapr.AI
dotnet add package Dapr.AI.Microsoft.Extensions
DaprChatClient 是 IChatClient 接口的基于 Dapr 的实现,该接口由
Microsoft.Extensions.AI.Abstractions 包提供,使用 Dapr 的[对话构建块]({{ ref conversation-overview.md }})。它允许
开发者针对 Microsoft 提供的抽象类型进行开发,同时提供与 Dapr 对话构建块的最大一致性。由于这两种方法都采用 OpenAI 的 API 方式,
预计它们在未来会日益趋同。
Dapr.AI.Microsoft.Extensions 包实现了 Microsoft.Extensions.AI 抽象,为
.NET 应用程序中的 AI 服务提供统一的 API。Microsoft.Extensions.AI 旨在为
不同的 AI 提供商和场景提供一致的编程模型。有关 Microsoft.Extensions.AI 的详细信息,请参阅
官方文档。
可以使用多个扩展方法将 DaprChatClient 注册到依赖注入容器中。首先,
确保注册来自 NuGet 的 Dapr.AI 包中的 DaprConversationClient:
services.AddDaprConversationClient();
然后使用您的对话组件名称注册 DaprChatClient:
services.AddDaprChatClient("my-conversation-component");
您可以通过 DaprChatClientOptions 配置 DaprChatClient,尽管当前实现仅
为组件名称本身提供配置。这预计在未来的版本中会发生变化。
services.AddDaprChatClient("my-conversation-component", options =>
{
// 在此处配置其他选项
});
您还可以配置服务生命周期(默认为 ServiceLifetime.Scoped):
services.AddDaprChatClient("my-conversation-component", ServiceLifetime.Singleton);
注册后,您可以在您的服务中注入和使用 IChatClient:
public class ChatService(IChatClient chatClient)
{
public async Task<IReadOnlyList<string>> GetResponseAsync(string message)
{
var response = await chatClient.GetResponseAsync([
new ChatMessage(ChatRole.User,
"Please write me a poem in iambic pentameter about the joys of using Dapr to develop distributed applications with .NET")
]);
return response.Messages.Select(msg => msg.Text).ToList();
}
}
DaprChatClient 尚不支持流式响应,使用相应的 GetStreamingResponseAsync
方法将抛出 NotImplemenetedException。一旦 Dapr 运行时
支持此功能,这预计在未来的版本中会发生变化。
客户端通过 Microsoft.Extensions.AI 工具集成支持函数调用。注册到对话的
工具将自动可供大语言模型使用。
string GetCurrentWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny today!" : "It's raining today!";
var toolChatOptions = new ChatOptions { Tools = [AIFunctionFactory.Create(GetCurrentWeather, "weather")] };
var toolResponse = await chatClient.GetResponseAsync("What's the weather like today?", toolChatOptions);
foreach (var toolResp in toolResponse.Messages)
{
Console.WriteLine(toolResp);
}
DaprChatClient 与 Dapr 的错误处理集成,并在发生问题时抛出适当的异常。
底层的 Dapr 对话组件可以通过 Dapr 对话构建块配置来配置元数据和参数。
DaprChatClient 在调用对话组件时将遵循这些设置。
服务生命周期:为 DaprChatClient 注册使用 ServiceLifetime.Scoped 或 ServiceLifetime.Singleton,以避免不必要地创建多个实例。
错误处理:始终将调用包装在适当的 try-catch 块中,以处理 Dapr 特定和常规异常。
资源管理:DaprChatClient 通过其基类正确实现了 IDisposable,因此在使用依赖注入时会自动管理资源。
配置:正确配置您的 Dapr 对话组件以确保最佳性能和可靠性。