Guidance 是应用内帮助内容、引导计划与 AI 辅助会话的协调模块。它拥有页面/组件级 Markdown 指南、平台通用与租户覆盖选择、把已发布内容组织成有序多步的引导计划(Campaign),以及 Guidance Session 到 AIManage Conversation 的映射;模型、Provider、用量和生成消息本体仍归 AIManage。
1. 已实现能力
GuidanceContent统一持久化聚合与软删除;- RouteKey、可选 ComponentId、单 RequiredRole、TenantId、语言、内容版本和 Draft/Published;
- 创建、修订、发布、删除、列表、详情与上下文查询;
- 租户组件、租户页面、平台组件、平台页面四级匹配;
- 只在上下文查询中选择 Published,并按角色和语言过滤;
GuidanceAssistantSession统一租户聚合与用户所有权;- 由 route/component/language 生成稳定 SessionId;
- 页面、身份、角色和当前指南组成的 System Prompt;
- 助手配置默认失败关闭,缺 Workspace 明确失败;
- 同步消息和手写 NDJSON 流式消息;
- GuidanceContent 与 Session 的 SqlSugar/EF Core parity 基础;
GuidanceCampaign引导计划:有序多步、受众定向(角色/用户/全租户)、排期、Draft/Active/Paused/Archived 状态机、激活时预分配与首次交互隐式分配、服务端权威进度(幂等完成与受控豁免)、完成率分析。
当前没有不可变发布修订、history/diff/rollback/unpublish、发布审批、业务自然键唯一、ETag、独立助手权限/Feature、Prompt 刷新撤销、会话 TTL、Start 幂等/补偿、版本化流协议、Markdown 安全渲染合同和完整 HTTP 安全测试。
2. 真实运行结构
Application 通过自有 IAiSessionAdapter 隔离 AI 细节;Infrastructure 的 Adapter 仍直接引用 AIManage Application、IAIConversationStore 和消息 Handler。旧文档所说“模块不直接引用 AIManage”只适用于 Guidance Application/Content 边界,不适用于整个物理模块。
3. HTTP 路由
内容与助手路由:
| 方法与路由 | 用途 | 实现 |
|---|---|---|
POST /api/v1/guidance/contents | 创建 Draft | 生成 |
GET /api/v1/guidance/contents | 管理列表 | 生成 |
GET /api/v1/guidance/contents/{contentId} | 内容详情 | 生成 |
PUT /api/v1/guidance/contents/{contentId} | 同行修订并转 Draft | 生成 |
POST /api/v1/guidance/contents/{contentId}/publish | 转 Published | 生成 |
DELETE /api/v1/guidance/contents/{contentId} | 软删除 | 生成 |
GET /api/v1/guidance/contextual | 最佳已发布指南 | 生成 |
POST /api/v1/guidance/sessions | 创建/复用助手会话 | 生成 |
POST /api/v1/guidance/sessions/{sessionId}/messages | 同步消息 | 生成 |
POST /api/v1/guidance/sessions/{sessionId}/messages/stream | NDJSON 流 | 手写 |
此外还有一组引导计划路由(创建、列表、详情、更新、激活/暂停/归档、分析、当前用户可见计划、完成步骤、豁免),集中在 /api/v1/guidance/campaigns。计划路由的完整清单、状态机、受众与进度机制见引导计划、分配与进度。
九条非流式内容/助手路由由 Source Generator 生成。手写流端点要求认证和 userPolicy,设置 no-cache 与禁用代理缓冲,但也调用 DisableRequestTimeout,当前没有专用最大流时长。
4. 创建一条租户指南
// 普通租户显式使用当前租户,避免把平台空租户语义带入请求。var result = await sender.Send(new CreateGuide.Command( RouteKey: "/billing/invoices", ComponentId: null, Title: "发票列表操作", BodyMarkdown: "1. 先选择客户。\n2. 再核对开票状态。", RequiredRole: "Attorney", TenantId: currentTenantId, LanguageCode: LanguageCode.ZhCn), cancellationToken);
// 成功只创建 Draft;终端上下文查询尚不可见。if (result.IsFailure) return result.Error;
return result.Value!;普通租户省略 TenantId 时自动使用当前租户;平台租户省略时创建 TenantId=null 的平台通用内容。平台租户也能显式为任意租户创建内容。创建时未知 LanguageCode 不报错,而是归一化为 zh-CN。
5. 上下文选择
RequiredRole 只是单个字符串。角色比较忽略大小写;没有表达“任一/全部权限、部门、套餐、Feature、用户属性”的 Audience Policy。同一自然键可存在多个内容,Store 依靠排序选一个,而不是用数据库唯一约束阻止歧义。
6. 发布生命周期
Create 生成 Version=1 的 Draft。Publish 原地改成 Published;重复 Publish 返回 Conflict。Revise 更新 Title/Body、Version+1,并把同一行改回 Draft。线上原 Published 因此立即消失,直到再次发布;没有历史行或当前发布指针。
Delete 先由 Handler 读取并做平台/租户 Guard,再按全局 ID 软删。Store 返回成功不包含受影响数量,重复删除通常在 Handler 读取阶段得到 NotFound。
7. 管理读与终端读不是同一安全面
Contextual Query 正确限定 Published、租户/平台、角色与语言。GetById 却先按全局主键读取;EnsureCanRead 允许任意租户读取 TenantId=null 的平台内容,不检查 Status 或 RequiredRole。拥有通用 content View 的普通租户若得到 ID,可能读取平台 Draft 正文。
List 默认 IncludePlatform=true,也不按 RequiredRole 过滤,能返回平台 Draft 摘要。GA 必须拆分“终端已发布读”和“内容管理读”的资源、权限与 DTO。
8. 助手不是内容的自动降级路径
内容 API 在 AI 关闭时仍独立可用;但 Start Session 在 Guidance:EnableAiAssistant 关闭或 Workspace 缺失时直接失败,不会自动改成只返回指南。调用方可先调用 Contextual 作为非 AI 帮助,再按配置选择是否启动 Assistant。
所有助手请求使用 guidance/assistant Resource,权限目录已登记 guidance.assistant.use。Handler 在身份缺失时使用 UserId="0",而不是失败关闭。
9. 会话复用风险
SessionId 包含 userId 与 route/component/language 哈希,查询还绑定 TenantId/UserId,能阻止直接跨用户访问。但相同上下文会复用既有 AIManage Conversation,不更新 SystemPrompt。如果指南版本或用户角色变化,旧 Conversation 仍可能保存以前的受限正文。
并发 Start 还可能分别创建 Conversation 后竞争 Session 唯一键;Conversation 创建与 Session 插入没有显式补偿。InitialQuestion 失败时 Session 已创建,Command 却整体返回失败。
10. 章节路线
- 内容生命周期与持久化:聚合、字段、状态、版本、唯一性和 Markdown 边界;
- 上下文选择与授权:匹配优先级、角色、平台/租户读写和 Draft 泄漏;
- 引导计划、分配与进度:计划状态机、受众与排期、用户进度、权威完成与豁免、分析与持久化;
- 助手会话、Prompt 与安全:会话 ID、AIManage Adapter、旧 Prompt、隐私和一致性;
- 流式、测试、运维与 GA:NDJSON、故障、容量、指标、恢复与发布门禁。
11. GA 红线
- 终端 API 只读 Published 且 Audience 匹配内容;
- Draft 管理权限与普通内容读完全分离;
- 发布 Revision 不可变,修订不影响当前线上版本;
- 自然键、发布指针和并发更新有数据库/ETag 门禁;
- Markdown 的 HTML、URL、图片、CSP 和 Sanitizer 合同统一;
- 助手独立 Permission/Feature/Quota,并 RequireUserId;
- Prompt 最小化身份与角色数据,执行敏感内容政策;
- 指南/角色/权限变化能刷新或撤销旧会话;
- Conversation/Session 创建幂等、原子或可补偿;
- NDJSON 使用版本化 frame、稳定错误码、时限与大小上限;
- AIManage owner contract 承担 Workspace/Model/Usage/权限策略;
- 双 ORM、HTTP、并发、故障、隐私和恢复证据全部进入 GA 门禁。
12. 源码导航
# 内容与助手的生成路由,以及一条手写流路由。rg -n "GenerateEndpoint\(|messages/stream|application/x-ndjson" \ src/Platform/Guidance src/Hosts/BitzOrcas.Api/Endpoints/GuidanceEndpointGroup.cs -g '*.cs'
# 引导计划聚合根、状态机、分配与进度、权限与路由。rg -n "GuidanceCampaign|guidance.campaign|CampaignResource" \ src/Platform/Guidance -g '*.cs'
# 当前平台读、UserId fallback、无超时和直接 AIManage 依赖。rg -n "content.TenantId is null|UserId\?\.ToString|DisableRequestTimeout|AIManage.Application" \ src/Platform/Guidance src/Hosts/BitzOrcas.Api -g '*.cs' -g '*.csproj'
# 不可变发布与 Prompt 版本当前预期无命中。rg -n "PublishedRevision|PromptHash|ExpiresAt" \ src/Platform/Guidance -g '*.cs'