Skip to content
bitzorcas
中EN

Reference

Guidance 助手会话、Prompt 与安全

深入解释 Guidance SessionId、AIManage Conversation 映射、配置开关、System Prompt 构建、会话复用、角色撤销、跨模块原子性、隐私与模型治理。

Last updated

Guidance Assistant 不是独立大模型实现。Application 组装页面上下文,经 IAiSessionAdapter 交给 Infrastructure;Adapter 创建或复用 AIManage Conversation,并保存一条 Guidance Session 映射。

1. 启用条件

Adapter 每次 Start/Send/Stream 都读取 Guidance:EnableAiAssistant,只有可解析为 true 才继续。Start 还要求 Guidance:AiWorkspaceId;为兼容旧配置会回退 Guidance:WorkspaceId。

启用助手的最小主机配置
{
"Guidance": {
"EnableAiAssistant": true,
"AiWorkspaceId": "workspace-guidance-prod"
}
}

缺开关返回 Guidance.Assistant.Disabled,缺 Workspace 返回 Guidance.Assistant.WorkspaceRequired。这是失败关闭,不是回退到内容响应;非 AI 客户端应独立调用 Contextual API。

2. Start 时序

"GuidanceAiSession set""AIManage ConversationStore""GuidanceAiSessionAdapter""GuidanceContextBuilder""GuidanceContentStore""StartGuidanceSession.Handler""GuidanceAiSession set""AIManage ConversationStore""GuidanceAiSessionAdapter""GuidanceContextBuilder""GuidanceContentStore""StartGuidanceSession.Handler"alt["不存在"]opt["InitialQuestion 非空"]"用户"route/component/language/question/modelFindBestMatch(current tenant/roles)build system promptstable session id + promptfind tenant/user/sessionCreateConversationAsyncAdd GuidanceAssistantSessionSendMessageAsyncsession + guide + optional message"用户"

Content 可以为空,Assistant 仍会用页面/身份上下文创建会话。产品需决定“无权威指南时允许通用问答”还是失败关闭;当前 Prompt 只要求模型承认找不到指南。

3. SessionId

GuidanceSessionId.Create 把 Trim 后的 route、component 或 (page)、language 用 | 拼接,SHA-256 后 Base64Url,再返回 guidance-{userId}-{hash}。TenantId 不在 hash 中,但实体查询同时绑定 TenantId 与 UserId。

同一用户不同组件生成不同会话
var grid = GuidanceSessionId.Create(
userId, "/billing/invoices", "grid", LanguageCode.ZhCn);
var form = GuidanceSessionId.Create(
userId, "/billing/invoices", "form", LanguageCode.ZhCn);
// SessionId 不包含原始路由斜杠,两个组件也不会复用同一 Prompt。
Debug.Assert(grid != form);
Debug.Assert(!grid.Contains('/'));

SessionId 是确定性的,不是调用幂等令牌。它会把数字 UserId 暴露在前缀中,也没有 TenantId/PromptVersion/GuideVersion;不要把不可猜测性当作授权。

4. Session 持久化

GuidanceAssistantSession 是 TenantAggregateRoot<string>,唯一索引 (TenantId, UserId, SessionId),保存 ConversationId、RouteKey、ComponentId 和 CreateTime,并支持软删除字段。

它不保存 LanguageCode(只隐含在 hash)、GuideId/Version、PromptHash、WorkspaceId、ModelId、LastUsedAt、ExpiresAt 或关闭原因。模块也没有会话列表、关闭、删除和清理用例。

5. Prompt 内容

Builder 固定使用中文系统指令,随后明文加入 RouteKey、ComponentId、LanguageCode、TenantId、UserId、Roles;若有指南,再加入 Title、ContentVersion 和最多 16,000 字符 BodyMarkdown。

当前 System Prompt 的结构
你是 BitzOrcas 法律 SaaS 的应用内页面向导助手。
=== 当前上下文 ===
RouteKey: /billing/invoices
TenantId: tenant-100
UserId: 100
Roles: Attorney
=== 本页操作指南 ===
Title: 发票列表操作
Version: 3
<最多 16000 字符 Markdown>

这些数据会进入 AIManage 和最终 Provider 路径。TenantId/UserId 原值通常不是回答所需,Roles 也可能敏感;GA 前要用最小化 token 或抽象 Audience,而不是默认外发内部标识。

6. Prompt 注入与内容信任

指南由管理员编辑,但仍可能包含恶意/误写指令。Builder 只是把 Markdown 拼在 System Prompt 中,没有结构化隔离、内容签名、策略过滤或注入检测。模型也不应获得执行页面动作、读取 Secret 或访问任意工具的能力。

指南是产品权威内容,不代表其中每个字符串都可以成为高优先级系统指令。推荐把正文作为明确 delimit 的引用资料,并让安全策略与系统指令保持更高优先级。

7. 旧 Prompt 风险

Start 每次都会重新查询当前指南并构建 Prompt,但 Adapter 先查现有 Session;存在时直接返回,不更新 AIManage Conversation。于是指南 Revise/Delete、RequiredRole 变化、用户角色撤销或 Workspace 变更都不会刷新旧 Prompt。

角色被撤销的用户仍可用原 Session 继续问答,而旧 Conversation 可能保存之前的受限正文。这是 P0 安全缺口。Session 必须绑定 GuideRevision/PolicyVersion,并在每次使用时重验或被事件主动撤销。

8. 跨模块创建窗口

Start 先 CreateConversationAsync,再 sessions.AddAsync。两者属于不同模块/存储边界,没有显式事务或补偿。Session 插入失败会留下孤儿 Conversation。

两个并发 Start 都可能查不到 Session,分别创建 Conversation,然后在唯一索引竞争。当前没有 IdempotencyKey、唯一冲突重读、分布式锁或孤儿回收证据。

9. InitialQuestion 部分成功

Session 成功创建后才发送 InitialQuestion。若 AI 消息失败,Start Command 返回 Failure,但 Session 与 Conversation 已保留。客户端重试会复用它,可能可恢复,但响应没有 SessionCreatedButMessageFailed 状态或 SessionId。

GA 契约应返回清晰的阶段状态,或把首问作为带 ClientTurnId 的可重放子操作。不能用普通失败隐藏已经发生的持久化副作用。

10. 直接调用 AIManage Handler

Adapter 注入 ICommandHandler<SendMessage.Command,...> 与 IQueryHandler<StreamMessage.Command,...> 并直接调用 Handle,不是通过 Mediator Pipeline。这可能绕过 AIManage 请求级 Authorization、Feature、Validation、Audit 或其他 Pipeline 行为,具体取决于 Handler 内部自校验。

更稳健的设计是 AIManage owner 提供窄 IAiConversationSessionPort,内部统一执行 Workspace owner、Model allowlist、Usage、权限和幂等,而不是让消费模块选择具体 Store/Handler。

11. 消息与模型输入

Guidance 只检查 Content 非空,不限制长度、格式或敏感信息。ModelId 由客户端传入并原样交给 AIManage Handler;Guidance 没有租户允许模型、成本等级或数据区域校验。

助手独立 Feature/Permission/Quota 缺失。所有 Start/Send/Stream 仍使用 content Resource,UserId 缺失时写 "0",多个非用户调用者可能碰撞。

12. 会话目标合同

Session 建议保存 TenantId、UserId、Route、Component、Language、GuideId/Revision、PromptHash/PolicyVersion、Workspace/Model policy、Created/LastUsed/ExpiresAt、Status。每次消息验证所有权、Feature、角色/权限、revision 与过期状态。

指南发布/撤回、角色或 Permission 变化、Workspace 秘钥/策略轮换应发事件或执行在线重验,关闭/刷新受影响 Session。

13. 测试矩阵

场景必须证明
助手关闭/缺 Workspace无 Conversation/Session
相同 Start 重放一个 Conversation 与 Session
并发 Start唯一结果,无孤儿
Session 保存失败Conversation 补偿/可恢复
首问失败可见阶段状态,可安全重放
角色撤销旧 Prompt 不可继续泄漏
指南发布新版本刷新或新 Session
跨租户/跨用户 SessionIdNotFound
超长/敏感消息写前拒绝/脱敏
未允许 ModelIdPolicy denied

14. 检查命令

Terminal window
# 当前 Prompt、会话唯一键和直接 AIManage 调用。
rg -n "MaxGuideCharacters|TenantId:|UX_GuidanceAiSession|CreateConversationAsync|_sendMessageHandler.Handle" \
src/Platform/Guidance -g '*.cs'
# Prompt 版本、过期、关闭与助手权限当前预期无命中。
rg -n "PromptHash|GuideVersion|ExpiresAt|CloseSession|guidance.assistant" \
src/Platform/Guidance -g '*.cs'

Guidance 总览 · 上下文授权 · 流式与 GA

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%