目录
- [1. 引言](#1. 引言)
- [2. 为什么 AI 时代的数据权限更难管控](#2. 为什么 AI 时代的数据权限更难管控)
- [3. 治理框架总览:三层边界](#3. 治理框架总览:三层边界)
- [3.1 数据层:先定权限,再谈智能](#3.1 数据层:先定权限,再谈智能)
- [3.2 访问层:让每一次检索都"带着身份"](#3.2 访问层:让每一次检索都“带着身份”)
- [3.3 模型层:能力越大,约束要越细](#3.3 模型层:能力越大,约束要越细)
- [3.4 审计层:权限边界必须可追溯](#3.4 审计层:权限边界必须可追溯)
- [4. 模型能力与数据权限的三个典型边界场景](#4. 模型能力与数据权限的三个典型边界场景)
- [4.1 场景一:RAG 检索越过文档目录权限](#4.1 场景一:RAG 检索越过文档目录权限)
- [4.2 场景二:模型工具调用越权执行](#4.2 场景二:模型工具调用越权执行)
- [4.3 场景三:生成内容泄露跨租户数据](#4.3 场景三:生成内容泄露跨租户数据)
- [5. 落地实践:把边界变成可执行的策略](#5. 落地实践:把边界变成可执行的策略)
- [5.1 权限不依赖模型的"自觉"](#5.1 权限不依赖模型的“自觉”)
- [5.2 权限随切片流动](#5.2 权限随切片流动)
- [5.3 生成前、中、后三重校验](#5.3 生成前、中、后三重校验)
- [5.4 建立权限最小化的数据访问链路](#5.4 建立权限最小化的数据访问链路)
- [6. 一个简化的权限过滤示例](#6. 一个简化的权限过滤示例)
- [7. 常见误区](#7. 常见误区)
- [8. 结语](#8. 结语)
1. 引言
当大模型的能力越来越强,一个核心矛盾也随之浮出水面:模型既能回答问题,却不一定有资格访问答案背后的数据。在 AI 应用中,模型能力越强,越容易在无意间突破权限边界。比如,一个检索增强生成(RAG)系统明明接入了企业知识库,却可能因为向量检索的相似度匹配,把本该保密的项目文档"喂"给了普通员工。
因此,AI 数据安全治理的关键,不只是"限制模型能做什么",而是建立一套模型能力与数据权限之间的边界体系------既要让模型充分利用数据提供价值,又要确保每一次数据访问都发生在授权范围内。
本文从治理框架的视角,梳理 AI 系统中数据权限的组成、模型能力如何放大风险,以及如何在落地时划清这条边界。
2. 为什么 AI 时代的数据权限更难管控
传统数据权限管控大多依赖明确的访问控制列表(ACL)、角色权限(RBAC)和数据分级。它们的前提是:用户直接访问数据,系统可以在入口处拦截。
但 AI 应用改变了这个前提:
- 访问路径发生变化:用户不再直接查询数据库,而是向模型提问,模型再间接检索或生成数据。
- 权限上下文更容易丢失:文档被切块、向量化后,原始的目录权限、密级标签很难完整跟随每一段文本。
- 生成结果具有"融合性":模型可能把多份来源的数据融合成一段回答,回答里既有公开信息,也有敏感信息。
- 模型自身存在不确定性:幻觉、过拟合、提示词注入等都可能让模型输出本不该输出的内容。
因此,AI 数据安全治理不能只靠"数据不动、权限卡住",而要同时约束数据、模型、应用三个层面的行为。
3. 治理框架总览:三层边界
一个可落地的 AI 数据安全治理框架,可以从三层边界来理解:
#mermaid-svg-xGSQvjKQtfL96DO7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xGSQvjKQtfL96DO7 .error-icon{fill:#552222;}#mermaid-svg-xGSQvjKQtfL96DO7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xGSQvjKQtfL96DO7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xGSQvjKQtfL96DO7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xGSQvjKQtfL96DO7 .marker.cross{stroke:#333333;}#mermaid-svg-xGSQvjKQtfL96DO7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xGSQvjKQtfL96DO7 p{margin:0;}#mermaid-svg-xGSQvjKQtfL96DO7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xGSQvjKQtfL96DO7 .cluster-label text{fill:#333;}#mermaid-svg-xGSQvjKQtfL96DO7 .cluster-label span{color:#333;}#mermaid-svg-xGSQvjKQtfL96DO7 .cluster-label span p{background-color:transparent;}#mermaid-svg-xGSQvjKQtfL96DO7 .label text,#mermaid-svg-xGSQvjKQtfL96DO7 span{fill:#333;color:#333;}#mermaid-svg-xGSQvjKQtfL96DO7 .node rect,#mermaid-svg-xGSQvjKQtfL96DO7 .node circle,#mermaid-svg-xGSQvjKQtfL96DO7 .node ellipse,#mermaid-svg-xGSQvjKQtfL96DO7 .node polygon,#mermaid-svg-xGSQvjKQtfL96DO7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xGSQvjKQtfL96DO7 .rough-node .label text,#mermaid-svg-xGSQvjKQtfL96DO7 .node .label text,#mermaid-svg-xGSQvjKQtfL96DO7 .image-shape .label,#mermaid-svg-xGSQvjKQtfL96DO7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-xGSQvjKQtfL96DO7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xGSQvjKQtfL96DO7 .rough-node .label,#mermaid-svg-xGSQvjKQtfL96DO7 .node .label,#mermaid-svg-xGSQvjKQtfL96DO7 .image-shape .label,#mermaid-svg-xGSQvjKQtfL96DO7 .icon-shape .label{text-align:center;}#mermaid-svg-xGSQvjKQtfL96DO7 .node.clickable{cursor:pointer;}#mermaid-svg-xGSQvjKQtfL96DO7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xGSQvjKQtfL96DO7 .arrowheadPath{fill:#333333;}#mermaid-svg-xGSQvjKQtfL96DO7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xGSQvjKQtfL96DO7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xGSQvjKQtfL96DO7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xGSQvjKQtfL96DO7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xGSQvjKQtfL96DO7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xGSQvjKQtfL96DO7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xGSQvjKQtfL96DO7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xGSQvjKQtfL96DO7 .cluster text{fill:#333;}#mermaid-svg-xGSQvjKQtfL96DO7 .cluster span{color:#333;}#mermaid-svg-xGSQvjKQtfL96DO7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xGSQvjKQtfL96DO7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xGSQvjKQtfL96DO7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-xGSQvjKQtfL96DO7 .icon-shape,#mermaid-svg-xGSQvjKQtfL96DO7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xGSQvjKQtfL96DO7 .icon-shape p,#mermaid-svg-xGSQvjKQtfL96DO7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xGSQvjKQtfL96DO7 .icon-shape .label rect,#mermaid-svg-xGSQvjKQtfL96DO7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xGSQvjKQtfL96DO7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xGSQvjKQtfL96DO7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xGSQvjKQtfL96DO7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据层:分级与授权
访问层:检索与过滤
模型层:生成与服务
审计层:监控与追溯
3.1 数据层:先定权限,再谈智能
数据层的目标是明确"谁的数据、什么级别、谁能用"。具体包括:
- 数据分类分级:公开、内部、机密、绝密。
- 数据归属:按部门、项目、租户划分。
- 授权模型:RBAC、ABAC、ReBAC。
- 数据脱敏与加密:对敏感字段做静态脱敏、传输加密、存储加密。
3.2 访问层:让每一次检索都"带着身份"
AI 应用中,数据访问通常发生在向量检索、数据库查询、工具调用等环节。访问层的核心是把用户的身份和权限,注入到每一次数据访问请求中:
- 向量检索时先做权限过滤,再返回候选文档。
- 数据库查询时统一走权限中间件,避免模型拼接越权的 SQL。
- 工具调用时对工具做最小授权,只允许访问与当前用户相关的资源。
3.3 模型层:能力越大,约束要越细
模型层关注的是模型本身的行为边界:
- 提示词工程与系统指令,明确模型可以做什么、不能做什么。
- RAG 生成时,强制模型只依据已授权文档回答,不凭空补充。
- 对高风险场景引入拒绝机制,识别到越权意图时停止生成并提示。
- 对模型输出做敏感信息扫描,动态屏蔽未授权字段。
3.4 审计层:权限边界必须可追溯
没有审计的权限边界是脆弱的。审计层需要记录:
- 谁在什么时间问了什么问题。
- 系统检索了哪些文档、哪些字段。
- 模型最终生成了什么内容。
- 哪些访问被拦截、哪些策略被触发。
审计数据不仅用于事后追责,也应反哺策略优化,形成闭环。
4. 模型能力与数据权限的三个典型边界场景
4.1 场景一:RAG 检索越过文档目录权限
企业知识库常常按部门设置目录权限,例如财务部的文档只能财务人员访问。但文档被切块、向量化后,如果检索不携带权限信息,普通员工询问"公司上季度利润多少",系统可能从财务文档中检索到答案。
边界设计:在向量库的元数据中保留文档的权限标签,检索时以当前用户身份做预过滤(pre-filter),再让模型基于过滤后的文档生成回答。
4.2 场景二:模型工具调用越权执行
Agent 类应用会调用数据库、邮件、内部系统等工具。如果模型可以自由调用"查询所有员工薪资"的接口,安全风险会非常大。
边界设计:对每个工具按用户角色做最小授权。用户身份通过上下文传入工具层,由工具层而非模型层做权限校验。模型只能调用"自己有权限"的工具。
4.3 场景三:生成内容泄露跨租户数据
多租户 SaaS 场景中,模型可能从不同租户的数据中归纳总结。如果训练语料或检索池没有严格隔离,A 租户的数据可能出现在 B 租户的回答里。
边界设计:租户级数据物理或逻辑隔离,检索只在当前租户的数据空间内进行;模型不得在租户间共享上下文。
5. 落地实践:把边界变成可执行的策略
5.1 权限不依赖模型的"自觉"
不要把安全寄托在提示词"请你不要输出敏感信息"上。模型可能被绕过,因此权限校验必须放在模型之前的确定性系统层。模型可以辅助判断,但不能成为唯一的安全闸门。
5.2 权限随切片流动
文档切块后,每一块都要继承原始文档的权限属性,例如:
json
{
"chunk_id": "c_000123",
"doc_id": "finance_q3_report.pdf",
"department": "finance",
"sensitivity": "confidential",
"allowed_roles": ["finance_analyst", "cfo"]
}
前端请求时带上用户身份与角色,检索层按 allowed_roles 过滤,只有命中的切片才能进入模型的上下文。
5.3 生成前、中、后三重校验
- 生成前:对输入做越权意图识别和提示词注入检测。
- 生成中:限制上下文只包含授权数据,减少模型"自由发挥"的空间。
- 生成后:对输出做敏感信息检测、脱敏或打码,必要时做人工审核。
5.4 建立权限最小化的数据访问链路
一条推荐的链路如下:
审计层 模型层 检索层 网关/身份层 用户 审计层 模型层 检索层 网关/身份层 用户 #mermaid-svg-JtQ6zP8fN3Q6p5ad{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .error-icon{fill:#552222;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .marker.cross{stroke:#333333;}#mermaid-svg-JtQ6zP8fN3Q6p5ad svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JtQ6zP8fN3Q6p5ad p{margin:0;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JtQ6zP8fN3Q6p5ad text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-JtQ6zP8fN3Q6p5ad .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-JtQ6zP8fN3Q6p5ad #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .sequenceNumber{fill:white;}#mermaid-svg-JtQ6zP8fN3Q6p5ad #sequencenumber{fill:#333;}#mermaid-svg-JtQ6zP8fN3Q6p5ad #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .messageText{fill:#333;stroke:none;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .labelText,#mermaid-svg-JtQ6zP8fN3Q6p5ad .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .loopText,#mermaid-svg-JtQ6zP8fN3Q6p5ad .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-JtQ6zP8fN3Q6p5ad .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .noteText,#mermaid-svg-JtQ6zP8fN3Q6p5ad .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .actorPopupMenu{position:absolute;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-JtQ6zP8fN3Q6p5ad .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JtQ6zP8fN3Q6p5ad .actor-man circle,#mermaid-svg-JtQ6zP8fN3Q6p5ad line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-JtQ6zP8fN3Q6p5ad :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 提问 身份认证、权限注入 携带权限查询授权切片 仅返回授权数据 生成回答 记录检索与生成日志
在这条链路中,数据权限的判定始终发生在模型生成之前,模型只负责基于授权数据生成内容。
6. 一个简化的权限过滤示例
下面以 RAG 检索为例,说明如何在向量检索时附带权限过滤。这里假设后端使用角色数组来判断当前用户可见的文档。
python
def retrieve_with_permissions(query: str, user_roles: list[str]):
# 按用户角色构建可见文档的过滤条件
role_filters = [
{"term": {"allowed_roles": role}}
for role in user_roles
]
# 检索时,同时把相似度查询和权限过滤一起执行
search_body = {
"query": {
"bool": {
"must": [
{
"match": {
"content": {
"query": query,
}
}
}
],
"filter": [
{"bool": {"should": role_filters, "minimum_should_match": 1}}
],
}
}
}
results = vector_store.search(search_body)
return results
def answer_with_rag(query: str, user_roles: list[str]):
authorized_chunks = retrieve_with_permissions(query, user_roles)
context = "\n\n".join(chunk["content"] for chunk in authorized_chunks)
prompt = (
"你是企业知识助手。请仅依据以下上下文回答用户问题,"
"不要使用上下文之外的知识。\n\n"
f"上下文:\n{context}\n\n"
f"问题:{query}"
)
return call_llm(prompt)
要点在于:权限过滤发生在检索阶段,而不是把全部文档都塞给模型后再让模型"看着办"。这样即使模型被诱导,也无法接触到未授权数据。
7. 常见误区
- 误区一:数据加密了就安全。加密解决的是传输和存储安全,解决不了"有权访问的人把数据喂给无权使用的人"的问题。
- 误区二:给模型一段系统提示词就够了。提示词既不是访问控制,也不具备强制力,只能作为辅助策略。
- 误区三:只管控入口,不审计出口。很多泄露发生在生成结果里,输出侧同样需要敏感信息检测。
- 误区四:权限粒度越细越好。过细的权限会导致维护成本爆炸,应在"安全"与"可用"之间找到平衡,按数据价值和风险分级投入。
8. 结语
AI 数据安全治理的本质,是在模型能力持续增强的前提下,仍然让数据按照既定规则流动。模型能力决定了它能做多少事,数据权限决定了它当前这件事能不能做。
边界不是一条静态的线,而是一套随身份、上下文、数据敏感度动态变化的策略体系。一个稳健的治理框架,应当让数据权限在检索前生效、在生成中约束、在输出后校验、在运行后审计,形成完整闭环。
对团队而言,与其追逐"绝对安全的模型",不如先把数据分级、身份注入、检索过滤、输出审计这四件事做扎实。边界清晰了,模型的能力才有更大的发挥空间。