Bitzsoft.Integrations.AgentFramework
1.0.0-alpha.10
dotnet add package Bitzsoft.Integrations.AgentFramework --version 1.0.0-alpha.10
NuGet\Install-Package Bitzsoft.Integrations.AgentFramework -Version 1.0.0-alpha.10
<PackageReference Include="Bitzsoft.Integrations.AgentFramework" Version="1.0.0-alpha.10" />
<PackageVersion Include="Bitzsoft.Integrations.AgentFramework" Version="1.0.0-alpha.10" />
<PackageReference Include="Bitzsoft.Integrations.AgentFramework" />
paket add Bitzsoft.Integrations.AgentFramework --version 1.0.0-alpha.10
#r "nuget: Bitzsoft.Integrations.AgentFramework, 1.0.0-alpha.10"
#:package Bitzsoft.Integrations.AgentFramework@1.0.0-alpha.10
#addin nuget:?package=Bitzsoft.Integrations.AgentFramework&version=1.0.0-alpha.10&prerelease
#tool nuget:?package=Bitzsoft.Integrations.AgentFramework&version=1.0.0-alpha.10&prerelease
Bitzsoft.Integrations.AgentFramework
Microsoft Agent Framework 的 Provider-neutral DI 集成。包直接公开官方
Microsoft.Agents.AI.AIAgent、ChatClientAgent 和 AgentSession,不再用
Semantic Kernel 聊天包装器冒充 Agent Framework。
版本与兼容性
dotnet add package Bitzsoft.Integrations.AgentFramework
- 目标框架:
net8.0;net10.0; - Microsoft Agent Framework:
Microsoft.Agents.AI1.15.0正式版; - 模型抽象:
Microsoft.Extensions.AI.IChatClient; - 不依赖 Semantic Kernel;
- 不保存模型端点、API Key 或租户凭据。
AI 包维持 .NET 8 起步,不为 .NET 5 宿主伪造兼容性。仍运行 .NET 5 的业务系统应把 Agent 能力部署为独立 .NET 8/10 服务,通过受控 HTTP、MCP 或 A2A 边界调用。
设计边界
本包负责把宿主的 IChatClient 组装成官方 AIAgent,并提供企业会话持久化 Seam:
- 模型供应商、endpoint、凭据、重试和模型级日志属于
IChatClient; - Agent 名称、描述和开发者指令属于
AgentOptions; - 工具由宿主通过工厂注入;
- 会话使用 Agent Framework 原生
AgentSession; - 默认使用官方
ToolApprovalAgent中间件处理工具审批队列和会话内审批规则; IAgentSessionCoordinator负责租户隔离、租约、恢复、Run 和乐观并发保存;- Store 和分布式租约由宿主接数据库、Redis 或企业数据平台;
- 工作流、多 Agent 编排、Hosting、A2A、MCP client 与 Foundry connector 直接使用微软 官方扩展包,本包不复制其 API。
Agent 以 transient 注册,工具工厂会在当前解析 scope 中执行,避免把请求级或租户级 业务服务捕获到根容器。会话状态不依赖 Agent DI 生命周期;需要持久化时使用协调器, 不要把已解析的 Agent、MCP 连接或工具缓存到其创建 scope 之外。
这种分层允许 OpenAI、Azure OpenAI、DeepSeek、通义千问、Ollama 或其他 Microsoft.Extensions.AI Provider 使用相同 Agent 注册代码。
注册默认 Agent
先注册一个 IChatClient。下面使用本仓库的 OpenAI-compatible 客户端作为示例:
// 模型层负责 Provider、租户凭据、遥测和请求审计。
services.AddBitzChatClient(options =>
{
options.ProviderId = "approved-provider";
options.ProfileId = "deepseek";
options.ModelId = "approved-model";
options.EnableTelemetry = true;
});
// Agent 层只配置身份、指令、工具和审批中间件。
services.AddBitzsoftAIAgent(options =>
{
options.Name = "customer-support";
options.Description = "Answers questions from approved support sources.";
options.Instructions =
"Use only approved tools and sources. "
+ "Ask for human approval before any side effect.";
});
EnableToolApprovalMiddleware 默认为 true,此时解析的 AIAgent 是官方
ToolApprovalAgent,内部仍使用 ChatClientAgent。完全可信、只读且无需审批队列的
场景可以显式关闭;不要仅为减少一次中间件调用而关闭安全能力。
业务代码直接依赖官方抽象:
public sealed class SupportService(AIAgent agent)
{
public async Task<string> AskAsync(
string question,
CancellationToken cancellationToken)
{
var response = await agent.RunAsync(
question,
cancellationToken: cancellationToken);
return response.Text;
}
}
完整最小示例
以下示例使用开发环境的进程内凭据与会话 Store;生产替换方式见后文:
using Bitzsoft.Integrations.AgentFramework;
using Bitzsoft.Integrations.AgentFramework.Sessions;
using Bitzsoft.Integrations.AI;
using Bitzsoft.Integrations.Core;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
// 仅开发/测试:生产环境应接入 Vault/KMS 和数据库/Redis。
services.AddInMemoryIntegrationCredentials();
services.AddInMemoryBitzAgentSessions(options =>
{
options.LeaseDuration = TimeSpan.FromMinutes(2);
options.MaxSerializedStateBytes = 16 * 1024 * 1024;
});
// 注册模型;API Key 不进入 Options。
services.AddBitzChatClient(options =>
{
options.ProviderId = "deepseek-dev";
options.ProfileId = "deepseek";
options.ModelId = "deepseek-chat";
});
// 默认启用官方 ToolApprovalAgent;本示例没有写操作工具。
services.AddBitzsoftAIAgent(options =>
{
options.Name = "customer-support";
options.Description = "只读客户支持助手";
options.Instructions =
"只依据已授权资料回答;资料不足时明确说明,不得编造。";
});
await using var provider = services.BuildServiceProvider(
new ServiceProviderOptions { ValidateScopes = true });
// 写入 tenant-a 的开发模型密钥。
var credentialStore = provider.GetRequiredService<
InMemoryIntegrationCredentialStore>();
using (var credential = new IntegrationCredential(
[
new(AICredentialFieldNames.ApiKey, "<从 User Secrets 读取的 API Key>")
]))
{
credentialStore.Set(
new IntegrationCredentialKey(
tenantId: "tenant-a",
providerKey: "AI:deepseek-dev",
environment: IntegrationEnvironments.Development),
credential);
}
// Agent、Coordinator 和业务依赖都在当前请求 Scope 中解析。
using var scope = provider.CreateScope();
var contextAccessor = scope.ServiceProvider.GetRequiredService<
IIntegrationContextAccessor>();
using (contextAccessor.Push(new IntegrationContext(
tenantId: "tenant-a",
environment: IntegrationEnvironments.Development,
correlationId: Guid.NewGuid().ToString("N"))))
{
var agent = scope.ServiceProvider.GetRequiredService<AIAgent>();
var coordinator = scope.ServiceProvider.GetRequiredService<
IAgentSessionCoordinator>();
// sessionId 是租户内稳定会话 ID;协调器负责租约、恢复、CAS 保存。
var result = await coordinator.RunAsync(
agent,
agentName: "customer-support",
sessionId: "conversation-42",
messages:
[
new ChatMessage(
ChatRole.User,
"客户反馈无法下载电子发票,应如何排查?")
]);
Console.WriteLine(result.Response.Text);
Console.WriteLine($"Saved session version: {result.SessionVersion}");
}
流式响应
// 必须完整消费异步流,协调器才会持久化最终会话状态。
await foreach (var update in agent.RunStreamingAsync(
"Summarize the incident.",
cancellationToken: cancellationToken))
{
await output.WriteAsync(update.Text, cancellationToken);
}
AgentResponseUpdate 不只有文本;工具调用、审批请求和其他内容应按其内容类型处理,
不能只拼接 Text 后假定 Agent 已成功完成全部动作。
命名 Agent 与多模型
为不同职责注册独立的 keyed IChatClient,再把 Agent 绑定到对应 key:
// 不同职责使用独立模型 Key、Agent Key、权限和成本中心。
services.AddKeyedSingleton<IChatClient>(
"finance-model",
financeChatClient);
services.AddBitzsoftAIAgent(
"finance",
options =>
{
options.Name = "finance";
options.Description = "Read-only finance analysis.";
options.Instructions =
"Never post journals or approve payments.";
},
chatClientServiceKey: "finance-model");
var financeAgent =
serviceProvider.GetRequiredKeyedService<AIAgent>("finance");
模型选择发生在 IChatClient 注册层。不要给单个 Agent 增加一个会被静默忽略的
model 字符串参数;不同模型应是不同的命名客户端/Agent,以便单独授权、限流和核算。
工具
// 工具工厂在当前 Scope 执行,可以安全解析请求级业务服务。
services.AddBitzsoftAIAgent(
options =>
{
options.Name = "knowledge";
options.Description = "Searches the approved knowledge base.";
options.Instructions = "Cite the retrieved source.";
},
serviceProvider =>
{
var search = serviceProvider
.GetRequiredService<ApprovedKnowledgeSearch>();
var payment = serviceProvider
.GetRequiredService<ApprovedPaymentService>();
return new List<AITool>
{
// 只读工具仍必须在业务服务内部校验租户和数据权限。
AIFunctionFactory.Create(search.SearchAsync),
// 有副作用工具必须进入官方审批队列。
new ApprovalRequiredAIFunction(
AIFunctionFactory.Create(payment.SubmitAsync))
};
});
所有模型生成的工具参数都必须视为不可信输入。查询工具应再次执行租户、字段和数据范围
授权;写入、付款、发信、删除、发布等有副作用工具应包装为
ApprovalRequiredAIFunction。默认 ToolApprovalAgent 会协调审批请求,但实际执行边界
仍必须重新校验审批主体、参数和幂等键。不要仅靠系统提示词授权,也不要配置
“全部工具永久自动批准”规则。
会话与持久化
生产协调器
业务层不应自行重复“读取—反序列化—运行—序列化—写入”流程。本包的协调器会在模型 调用前取得会话租约,并在调用完成后用 expectedVersion 原子保存:
// 协调器不提供生产 Store;宿主必须显式注册数据库和分布式租约实现。
services.AddBitzAgentSessionCoordinator(options =>
{
options.LeaseDuration = TimeSpan.FromMinutes(2);
options.MaxSerializedStateBytes = 16 * 1024 * 1024;
});
services.AddSingleton<IAgentSessionStore, DatabaseAgentSessionStore>();
services.AddSingleton<IAgentSessionLeaseManager, RedisAgentSessionLeaseManager>();
每次操作必须设置 IntegrationContext。最终存储键包含
tenant + environment + region + agent + session:
// 当前上下文参与会话存储键,禁止跨租户恢复状态。
using var contextScope = contextAccessor.Push(
new IntegrationContext(
tenantId,
region,
environment,
correlationId));
var result = await coordinator.RunAsync(
agent,
agentName: "customer-support",
sessionId: conversationId,
messages: [new ChatMessage(ChatRole.User, question)],
cancellationToken: cancellationToken);
agentName 必须与当前 Agent 的 Name 一致,防止把一种 Agent 的状态恢复给另一种
Agent。调用成功后可记录 result.SessionVersion,但不要把序列化状态或审批内容写入普通
日志。
流式会话
// 提前 break 或取消会使本次流式状态不保存。
await foreach (var update in coordinator.RunStreamingAsync(
agent,
"customer-support",
conversationId,
[new ChatMessage(ChatRole.User, question)],
cancellationToken: cancellationToken))
{
await output.WriteAsync(update.Text, cancellationToken);
}
只有完整消费异步流后会保存新会话状态。调用方提前停止、取消或流式执行失败时不会提交 不完整状态;租约仍会释放。最后一个 update 之后的持久化失败会作为枚举异常返回,因此 调用方必须等待枚举自然结束,不能在收到文本后立即丢弃枚举器。
开发与测试
services.AddInMemoryBitzAgentSessions();
进程内实现支持租户隔离、CAS 和单进程互斥,但不支持重启恢复或多节点,不能作为生产 Store。生产实现至少需要:
IAgentSessionStore.SaveAsync/DeleteAsync原子比较expectedVersion;IAgentSessionLeaseManager在句柄存活期间自动续租,进程失联后按LeaseDuration自动释放;- KMS 管理的静态加密、访问审计和保留/删除策略;
- serialized state 完整性保护,防止消息角色或审批状态被篡改;
- 部署时绑定 Agent/Schema 版本,升级不兼容时执行迁移或显式失效;
- 上下文压缩、摘要或归档策略,避免会话无限增长;
- 有副作用工具使用业务幂等键。模型完成但进程在保存前崩溃时属于结果不确定场景, 会话租约无法替代业务幂等。
MaxSerializedStateBytes 默认 16 MiB,可按存储能力调整或设为 null。该限制只作用于
会话状态,与 RequestLogging 的完整兆级请求/响应记录策略无关。
日志与可观测性
Agent Framework 自身支持 middleware 与 OpenTelemetry。本包不重复记录一份 Agent
正文;请求/响应审计应在 IChatClient 管道统一完成,以免同一提示词落两份日志。
使用 Bitzsoft.Integrations.AI 时可接入
Bitzsoft.Integrations.RequestLogging。普通模型请求与响应默认完整记录,不强制限制或
截断兆级正文;token/API Key 等凭据交换必须抑制,业务定义的 secret/PII 字段必须脱敏。
生产环境应另外配置日志访问控制、静态加密、保留期和删除流程。
OpenTelemetry 默认不应导出提示词、工具参数和响应正文。只有在受控开发环境明确开启 sensitive data,并确认 exporter、采样与保留策略后才允许采集。
安全检查清单
- 系统指令只能来自受控配置,不能拼接最终用户输入;
- RAG 文档和 MCP/A2A 消息同样是不可信内容,必须防 prompt injection;
- 工具在执行边界做身份、租户、资源和参数授权;
- 有副作用工具需要人审、幂等键与结果核对;
- 模型输出在进入 HTML、SQL、Shell、模板或文件路径前必须验证/编码;
- session 与 continuation token 视为敏感数据;
- 对成本、并发、工具轮次和上下文长度设置宿主策略;
- 在上线前用真实模型测试拒答、越权、提示词注入、工具参数污染与取消。
当前未封装
本包当前不封装 Workflows、multi-agent orchestration、Agent Hosting、Foundry Hosted Agent、A2A client/server、DevUI、Evaluation 或 Agent Harness。这些功能在微软官方包中 已经有稳定或快速演进的实现,重复包一层商业价值低、升级成本高。出现明确 ToB 场景时, 优先提供企业策略 Adapter(审批、租户隔离、持久化、审计),而不是复制官方 API。
官方资料
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Bitzsoft.Integrations.Core (>= 1.0.0-alpha.10)
- Microsoft.Agents.AI (>= 1.15.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Options (>= 10.0.10)
-
net8.0
- Bitzsoft.Integrations.Core (>= 1.0.0-alpha.10)
- Microsoft.Agents.AI (>= 1.15.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Options (>= 10.0.10)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Bitzsoft.Integrations.AgentFramework:
| Package | Downloads |
|---|---|
|
Bitzsoft.Integrations.All
Bitzsoft 第三方集成聚合包 — net5.0 包含传统连接器,net8.0+ 额外包含受上游 TFM 限制的 AI 模块 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-alpha.10 | 35 | 7/26/2026 |
| 1.0.0-alpha.9 | 62 | 7/12/2026 |
| 1.0.0-alpha.8 | 307 | 7/1/2026 |
| 1.0.0-alpha.7 | 75 | 6/16/2026 |
| 1.0.0-alpha.6 | 70 | 6/16/2026 |
| 1.0.0-alpha.5 | 64 | 6/14/2026 |
| 1.0.0-alpha.4 | 68 | 6/14/2026 |
| 1.0.0-alpha.3 | 63 | 6/7/2026 |
| 1.0.0-alpha.2 | 69 | 5/29/2026 |
| 1.0.0-alpha.1 | 67 | 5/28/2026 |