RAG 越权检索
用户只能看 A 部门文档,但向量库先召回全公司文档,再把不该看的片段放进上下文,最终模型摘要泄露。
租户串数据
tenant_id 没有进入索引、缓存、会话、记忆和日志链路,A 客户的问题命中了 B 客户的知识或历史状态。
工具权限过宽
Agent 拿到系统级 token,可以查所有客户、改所有记录或调用生产写接口,模型错误就变成真实业务事故。
记忆污染
长期记忆没有按用户、租户、角色和数据级别隔离,历史敏感信息在后续对话里被错误带出。
缓存越界复用
语义缓存或答案缓存只按问题文本命中,没有包含租户、权限、知识版本和策略版本,导致低权限用户拿到高权限答案。
审计证据缺失
事故发生后只看到最终回答,看不到当时的身份、策略决策、检索文档、工具参数和审批记录。
| 环节 | 正确做法 | 高风险做法 | 需要留证据 |
| 文档入库 | 写入 tenant、owner、ACL、classification、valid_from / valid_to、source | 只写文本和 embedding,不写权限元数据 | doc_id、source_id、acl_version、index_version |
| 查询改写 | 保留用户意图,但权限条件来自系统策略,不来自用户文本 | 用户说“我是管理员”就扩大检索范围 | query、user_context、policy_context |
| 召回过滤 | 在向量检索、关键词检索和 rerank 前后都应用权限过滤 | 先召回全量,再让模型忽略不该看的片段 | candidate_count、filtered_count、filter_reason |
| 上下文拼装 | 只把授权片段放入 Prompt,并保留引用来源 | 把未授权片段放进 hidden context | retrieved_doc_ids、chunk_ids、citation_ids |
| 答案生成 | 要求引用授权材料,缺证据时说明不可回答或请求授权 | 模型用常识补出内部数据 | citation_coverage、refusal_reason、risk_flag |
| 反馈回流 | 坏例进入带权限标签的回归集 | 把敏感坏例直接放进通用训练集 | eval_case_id、redaction_status、owner |
RBAC:角色能做什么
适合客服、销售、管理员、审计员等稳定角色。问题是角色太粗时容易过度授权。
ABAC:属性决定边界
按部门、地区、客户归属、数据分类、合同状态、时间窗口等属性裁决,更适合复杂企业数据。
Purpose-based Access:用途约束
同一份数据用于客服答疑、风控审核、模型训练、产品分析时权限不同,不能只看身份。
Runtime Policy:请求时裁决
AI 请求经常组合 RAG、工具和外部动作,最好每次调用都生成 policy decision,而不是只在登录时判断。
| 字段组 | 最小字段 | 用途 |
| 身份 | request_id、tenant_id、user_id、role、session_id、actor_type | 证明这次请求代表谁 |
| 策略 | policy_version、decision_id、allow / deny、reason、risk_tier | 证明为什么允许或拒绝 |
| 数据 | rag_index_version、retrieved_doc_ids、chunk_ids、acl_version、filtered_count、context_snapshot_id | 证明看到了哪些材料、过滤了哪些材料,以及最终进入上下文窗口的授权快照 |
| 缓存 / 路由 | cache_key_hash、permission_hash、route_id、fallback_to、allowed_provider、region | 证明答案缓存、语义缓存、模型路由和 fallback 没有绕过租户、权限和地域边界 |
| 工具 | tool_name、tool_scope、args_hash、approval_id、idempotency_key、result_status | 证明做了什么动作、谁批准、是否可重放 |
| 输出 | answer_id、citations、redaction_status、refusal_reason、risk_flags | 证明最终输出和风险处理 |
| 闭环 | incident_id、eval_case_id、regression_slice、release_gate_id、owner、resolved_version、retention_until | 证明坏例、事故、修复版本和发布门禁是否进入闭环 |
| 事故现象 | 先锁定的证据 | 判断重点 | 沉淀产物 |
| 低权限用户看到了高权限文档内容 | request_id、tenant_id、user_role、retrieved_doc_ids、acl_version、filtered_count、context_pack_id | 是检索前过滤缺失、rerank 后混入、上下文拼装错误,还是缓存复用了高权限答案? | rag_acl_failure_case、eval_case_id、fixed_index_version |
| A 租户命中了 B 租户知识或记忆 | tenant_id、session_id、memory_id、cache_key_hash、index_version、permission_hash | 租户键是否进入会话、索引、缓存、记忆、日志和评测集;切换组织时上下文是否重算? | tenant_boundary_incident、cache_key_rule_update |
| Agent 调用了不该调用的工具 | tool_call_id、tool_scope、actor_id、policy_version、decision_id、approval_id、args_hash | 模型只是提出意图,运行时为什么允许;工具 registry、策略引擎和确认门是否缺失? | tool_permission_case、policy_test_case、runbook_update |
| Fallback 后突破了地域或供应商边界 | route_id、fallback_from、fallback_to、allowed_provider、region、policy_reason、risk_tier | 路由策略是否继承数据地域、供应商、租户隔离和日志脱敏要求? | routing_policy_fix、release_gate_change |
| 排障人员在日志里看到了敏感原文 | trace_id、redaction_status、debug_access_actor、retention_until、log_scope、break_glass_reason | 日志和 Trace 是否分级脱敏;排障访问是否有审批、用途、过期和审计? | debug_access_review、retention_policy_update |
| 安全误拒或漏拦来自权限口径不清 | policy_version、decision_reason、risk_label、human_review_label、user_feedback、eval_case_id | 是策略规则错、风险标签错、业务用途不清,还是高风险样本没有进入回归? | safety_permission_regression、fixed_policy_version |