AIManage 是平台的 AI 连接与会话编排层。它保存租户工作区、Provider 凭据、模型元数据、用户对话和消息,使用 Microsoft.Extensions.AI.IChatClient 隔离应用层与具体 SDK,并在基础设施层用 Semantic Kernel 接入 OpenAI 兼容传输。RAG 与 Agent 也通过窄端口暴露,但当前聊天主路径没有自动调用它们。
1. 当前真实能力
已经实现:
- 租户工作区的创建、列表、更新、乐观并发控制与归档删除(
ManageWorkspace命令族); - 工作区内 Provider 的创建、列表、更新、删除、连通性探测(
TestProviderConnectivityCommand)与 Data Protection 凭据加密; AIModel聚合、模型配置增删改查与提供商模型目录管理;- 用户对话创建、分页列表、归档、删除、历史读取、消息追加和计数;
- 非流式聊天与 NDJSON 流式端点(增量下发,带类型化
kind帧协议); - Send 与 Stream 的对话实例所有权校验(任何 Provider 调用前绑定租户 + 用户,不匹配返回
AI.Conversation.NotOwner); - 基于
IAIMessageRequestCoordinator与必填RequestId的幂等请求(每个键一次 Provider 调用,Completed 重放不调 Provider); - 跨模块对话缝
IAIConversationPort/AIConversationMediatorPort(每次调用都走 Mediator 管线,授权、运行时许可、日志全部生效); - 最多 50 条历史消息构造和 32 个聊天客户端近似 LRU 缓存;
- 持久技能元数据注册表与进程本地 Markdown 技能文件扫描;
- Semantic Kernel
IChatClient适配器; - 默认失败关闭、按 Host 配置替换的 RAG 与 Agent 端口;
- SqlSugar / EF Core 共用 ORM 中立 Store 与 parity 测试;
- 全量端点基于
[GenerateEndpoint](ADR 0103)编译期零反射生成。
当前边界与演进项:Prompt/响应脱敏过滤、Prompt Injection 进阶防护、Token/费用预算账本、工具执行(Tool Call)动态审批流与 RAG 自动流水线增强。
2. 端到端结构
Contracts 拥有聚合、DTO、Store 契约、RAG 端口和治理目录;Application 编排用例、聊天上下文、客户端缓存和文件技能扫描;Infrastructure 实现四类持久化适配器、Semantic Kernel、RAG 与 Agent 桥。
3. 核心 HTTP 路由
| 方法与路由 | 用途 | 鉴权与治理 |
|---|---|---|
POST /api/ai/workspaces | 创建工作区 | ManageWorkspaceCommand + ai.workspace.manage |
GET /api/ai/workspaces | 当前租户工作区列表 | ListWorkspacesQuery + ai.workspace.view |
PUT /api/ai/workspaces/{workspaceId} | 更新工作区与默认模型 | UpdateWorkspaceCommand + 乐观并发校验 |
DELETE /api/ai/workspaces/{workspaceId} | 归档删除工作区 | DeleteWorkspaceCommand + 并发版本控制 |
GET /api/ai/workspaces/{workspaceId}/providers | Provider 列表 | ListProvidersQuery (租户/工作区隔离) |
POST /api/ai/workspaces/{workspaceId}/providers | 添加 Provider | CreateProviderCommand (ApiKey 密文持久化) |
PUT /api/ai/workspaces/{workspaceId}/providers/{providerId} | 更新 Provider | UpdateProviderCommand |
DELETE /api/ai/workspaces/{workspaceId}/providers/{providerId} | 删除 Provider | DeleteProviderCommand |
POST /api/ai/workspaces/{workspaceId}/providers/{providerId}/test | Provider 连通性探测 | TestProviderConnectivityCommand |
POST /api/ai/workspaces/{workspaceId}/providers/{providerId}/models | 创建模型配置 | CreateModelCommand |
PUT /api/ai/workspaces/{workspaceId}/providers/{providerId}/models/{modelId} | 更新模型配置 | UpdateModelCommand |
DELETE /api/ai/workspaces/{workspaceId}/providers/{providerId}/models/{modelId} | 删除模型配置 | DeleteModelCommand |
POST /api/ai/chat/conversations | 创建对话 | CreateConversationCommand + ai.conversation.use |
GET /api/ai/chat/conversations | 当前用户对话分页 | ListConversationsQuery (UserId 过滤) |
DELETE /api/ai/chat/conversations/{conversationId} | 删除对话 | DeleteConversationCommand + 所有权校验 |
GET /api/ai/chat/conversations/{conversationId}/history | 消息历史 | GetConversationHistoryQuery (租户+用户双校验) |
POST /api/ai/chat/conversations/{conversationId}/messages | 非流式聊天 | SendMessage.Command + RequestId 幂等 |
POST /api/ai/chat/conversations/{conversationId}/stream | NDJSON 增量流式聊天 | StreamAiMessageCommand + 类型化 kind 帧 |
GET /api/ai/skills | 当前租户启用技能 | ListSkillsQuery |
POST /api/ai/skills | 注册技能元数据 | CreateSkillCommand |
DELETE /api/ai/skills/{id} | 注销技能 | DeleteSkillCommand |
手写路由组应用认证与 userPolicy 限流;标准读写路由还使用请求超时。流式路由显式禁用请求超时。三个生成端点由 IAuthorizedRequest 管道处理资源动作;文件技能两条路由绕过 Mediator,因此没有 ai.skill.view/manage 的细粒度判断。
4. 一条真实非流式发送路径
// RequestId 是客户端幂等键;重试间保持不变。// ModelId 是调用方覆盖值;当前实现没有验证它是否登记在 AIModel 表中。var result = await mediator.Send(new SendMessage.Command( ConversationId: conversationId, RequestId: "turn-42", Content: "请把本周风险按优先级归纳为三点。", ModelId: "gpt-4o-mini"), cancellationToken);
if (result.IsFailure) return result.Error;
// 返回值是已保存的助手消息,不包含 Token、Provider、Model 或费用信息。MessageDto assistant = result.Value!;return assistant;真实顺序是:校验正文 → 读取对话并校验 TenantId/UserId(不匹配返回 AI.Conversation.NotOwner)→ 以对话内 TenantId 读取工作区和默认 Provider → 解析 ModelId → 通过 IAIMessageRequestCoordinator claim RequestId(重复键返回 AI.Message.RequestInProgress/PreviouslyFailed/RequestConflict,Completed 则重放)→ 保存用户消息 → 读取历史并截断 → 调用 Provider → 保存助手消息。SendMessage.Command 实现 INonTransactionalCommand,claim 与消息写入作为网络调用前后的有界短事务提交,而非一个长事务。
5. 资源授权与实例所有权
Send 与 Stream 实现 IAuthorizedRequest,声明 ResourceDescriptor(AIManagePermissions.Module, AIManagePermissions.ConversationResource) 与 AuthorizationAction.Use,因此授权管线在 Handler 运行前求值。两个 Handler 还注入 ICurrentUser,在任何 Provider 调用或消息写入前绑定 TenantId + UserId + ConversationId,不匹配返回 AI.Conversation.NotOwner(Forbidden)。历史查询读取对话后同时比较 TenantId 与 UserId。
6. 模型与执行参数并未闭环
模型选择优先级是请求 ModelId → 工作区 DefaultModelId → 硬编码 gpt-4o。随后固定使用 MaxOutputTokens=4096、Temperature=0.7。AIModel.MaxTokens、AIModel.Temperature 和 ModelType 虽可持久化,却没有被聊天用例读取;调用方也可提交任意模型字符串。
因此当前 AIModel 更接近“未来治理元数据”,不是已经强制执行的模型策略。生产接入前应把模型解析收敛为 tenant/workspace/provider/model 四元组,拒绝未登记模型,并记录实际 Provider、Model、参数、Token 和策略版本。
7. 章节路线
- 工作区、Provider 与模型:聚合、凭据、默认项、模型策略和租户约束;
- 对话、消息与安全边界:创建、历史、发送时序、所有权、幂等和隐私;
- 流式响应、客户端缓存与用量:NDJSON、首字节、取消、缓存、Token 与成本;
- 技能、RAG 与 Agent:两类技能、Semantic Kernel、失败关闭端口与真实接线状态;
- 测试、运维与商业 GA 门禁:测试证据、威胁模型、指标、故障演练和发布清单。
8. GA 红线
已交付:对话所有权(绑定租户 + 用户)、幂等 turn(RequestId + IAIMessageRequestCoordinator)、带类型化 kind 帧的增量流式、稳定不泄漏的流式错误合同。剩余红线:
- 创建对话必须验证工作区属于当前租户且已激活;
- 模型必须来自受管目录,执行参数、Token、费用和策略版本形成用量账本;
- Provider 凭据解密失败应失败关闭,并建立 Data Protection key ring 持久化、轮换和明文迁移;
- Provider 单默认项、模型归属和对话消息追加具备数据库约束与并发证据;
- 文件技能端点执行 skill 权限,技能注册验证入口,工具执行采用显式 allowlist 与逐次授权;
- Prompt、检索上下文、响应和日志执行数据分类、脱敏、内容安全与注入防护;
- RAG/Agent/技能能力只有在真实接线、租户隔离、观测和测试完成后才能标记可用;
- 增加 Provider 健康、超时、熔断、限额与可审计 fallback;
- 真实 HTTP、双 ORM、并发、故障、容量、恢复和安全测试全部进入发布门禁。
9. 源码导航
# 11 条手写路由与 3 条生成路由。rg -n "Map(Get|Post)|GenerateEndpoint\(" \ src/Hosts/BitzOrcas.Api/Endpoints/AIManageEndpoints.cs src/Platform/AIManage -g '*.cs'
# 暴露当前 ID-only 对话查询与固定执行参数。rg -n "c => c.Id == conversationId|MaxOutputTokens = 4096|Temperature = 0.7" \ src/Platform/AIManage -g '*.cs'
# 这些治理能力当前应无主路径命中。rg -n "IdempotencyKey|CostLedger|PromptInjection|ContentSafety|ToolCallApproval" \ src/Platform/AIManage -g '*.cs'