跳转到内容

第 20 周:接通 Capstone 数据与访问边界

直接答案: 第 20 周只做 Capstone M1:把 M0 批准的数据和角色边界落实到摄取、索引、检索与缓存,并证明未授权分块没有进入声明测试矩阵的候选集。本周不生成最终回答、不接写工具,也不毕业;第 21–24 周的 RAG、MCP、综合安全、试点和交接仍然保留。

为什么权限必须在生成之前成立

标题“为什么权限必须在生成之前成立”

如果系统先取回所有文档,再让模型“不要引用无权内容”,敏感内容已经进入了不该进入的上下文。安全边界应更早生效:

已认证身份与角色
+ M0 数据范围
+ 语料版本、有效期与撤销状态
→ 存储或检索查询层 ACL
→ 只产生允许的候选分块
→ 按权限摘要与版本隔离的缓存
→ 第 21 周才允许进入回答生成

本周验收对象是原始候选集,不是最终回答文字。一个最终回答看似没有泄密,不能证明受限分块从未进入模型或缓存。

先看完成品:北辰双业务单元矩阵

标题“先看完成品:北辰双业务单元矩阵”

以下文档、身份、租户和测试结果都是课程固定合成材料。北辰 M0 已明确要求 A、B 两个业务单元隔离,所以这个完成示例使用租户边界;你的 M0 没有该需求时,只实现已批准的角色或业务单元边界,不要为了展示技术强行增加多租户。

文档 ID 业务单元 角色 状态 内容用途
A-POLICY-01-v3 A 普通客服 当前有效 A 的普通退款政策
A-EXCEPTION-02-v2 A 主管 当前有效 A 的主管例外
B-POLICY-01-v5 B 普通客服 当前有效 B 的同名政策
A-NOTICE-OLD-v1 A 普通客服 已过期 旧通知负向夹具
A-UNKNOWN-ACL-v1 A 缺失 隔离 缺 ACL 负向夹具
身份摘要 业务单元 角色
id-a-agent A 普通客服
id-a-lead A 主管
id-b-agent B 普通客服

原始候选的预期结果

标题“原始候选的预期结果”
查询身份与状态 允许进入候选 必须为 0 的候选
A 普通客服 A-POLICY-01-v3 A 主管、B、过期、缺 ACL
A 主管 A 普通 + A 主管当前资料 B、过期、缺 ACL
B 普通客服 B-POLICY-01-v5 A、过期、缺 ACL
A 主管降权为普通客服 仅 A 普通资料 之前缓存的 A 主管资料
撤销 A-POLICY-01-v3 无该文档 已撤销版本

一条可检查的测试记录应同时包含输入、版本、预期候选和实际候选:

{
"case_id": "m1-a-agent-cross-unit",
"identity_fixture": "id-a-agent",
"corpus_version": "northstar-capstone-corpus-v1",
"retrieval_version": "retriever-v1",
"query_fixture": "refund-policy",
"expected_candidate_ids": ["A-POLICY-01-v3"],
"forbidden_candidate_ids": [
"A-EXCEPTION-02-v2",
"B-POLICY-01-v5",
"A-NOTICE-OLD-v1",
"A-UNKNOWN-ACL-v1"
],
"result_scope": "synthetic_fixed_matrix"
}

这是测试输入契约,不是假装已经运行过的结果。你必须用自己的实现保存实际候选并逐项比较。

第一步:从 M0 写出数据与访问合同

标题“第一步:从 M0 写出数据与访问合同”

不要直接打开向量库。先把业务语言映射成系统可执行的边界:

# Capstone M1 数据与访问合同 v1
## 获准范围
- 业务决定与任务:
- 身份来源:
- 角色 / 业务单元 / 租户:
- 允许的数据分类:
- 明确禁止的数据:
## 文档进入条件
| 字段 | 必填? | 缺失动作 | 负责人 |
| --- | --- | --- | --- |
| source_id | 是 | 隔离 | 数据所有者 |
| owner | 是 | 隔离 | 知识负责人 |
| acl | 是 | 默认拒绝并隔离 | 安全/数据负责人 |
| effective_from / expires_at | 是 | 不进入可靠候选 | 知识负责人 |
| version | 是 | 拒绝构建 | 工程负责人 |
## 查询与缓存规则
- ACL 在哪一层执行:
- 身份和权限摘要怎样形成:
- 缓存键包含哪些版本与权限字段:
- 权限改变、文档撤销或语料更新怎样失效:
- 原始候选怎样进入受限审计证据:
## M1 负向矩阵
- 跨角色或跨业务单元;
- 降权后复用缓存;
- 缺 ACL;
- 过期与撤销;
- 旧语料版本或旧索引。

如果 M0 没有租户概念,合同就不要出现租户字段。权限模型要来自问题证据,不来自作品集想展示的复杂度。

第二步:建立可重建、默认拒绝的语料入口

标题“第二步:建立可重建、默认拒绝的语料入口”

摄取和索引必须满足:

  1. 每个文档和分块保留来源、所有者、版本、有效期、分类与 ACL;
  2. 分块不能丢失或放宽父文档权限;
  3. 缺 ACL、所有者或有效期的材料进入隔离区,不按公开处理;
  4. 同一事实来源、解析规则和分块版本可以重建相同语料快照;
  5. 索引不是唯一事实来源,能够从版本化原始源重建;
  6. 撤销、来源下线或有效期变化有刷新时限和硬停止规则。

语料 manifest 最小字段

标题“语料 manifest 最小字段”
corpus_version: northstar-capstone-corpus-v1
source_snapshot: synthetic-policy-fixture-v1
parser_version: parser-v1
chunking_version: chunker-v1
access_policy_version: access-policy-v1
document_count: 5
quarantined_document_ids:
- A-UNKNOWN-ACL-v1
scope: synthetic_training_only

这些字段是完成示例。你的报告记录自己的实际版本与计数,不要复制示例数字当运行证据。

第三步:把 ACL 下推到查询层

标题“第三步:把 ACL 下推到查询层”

一次检索至少需要:

  • 已验证的身份与角色;
  • 若 M0 要求,则包含业务单元或租户;
  • 权限策略版本;
  • 语料与索引版本;
  • 文档状态过滤:当前有效、未撤销、来源仍在线;
  • 一个可追踪的 run_id

实现可以是带过滤条件的数据库查询、搜索引擎过滤、向量检索 metadata filter,或先构建物理隔离索引。无论选哪一种,都必须能检查过滤后的原始候选 ID,并证明受限分块未进入后续上下文。

第四步:运行声明清楚的负向矩阵

标题“第四步:运行声明清楚的负向矩阵”

至少覆盖:

测试 先做什么 必须观察什么
允许身份 查询当前普通政策 只返回允许且当前的候选
跨角色 普通角色查询主管资料 受限候选数为 0
跨范围 若 M0 有业务单元/租户边界,查询同名资料 其他范围候选数为 0
降权缓存 先以高权限查询,再降权复用同一问题 高权限候选不从缓存出现
缺 ACL 摄取缺权限字段文档 文档被隔离,候选数为 0
过期 查询过期政策 不进入可靠候选,并返回可解释状态
撤销 查询后撤销,再在声明传播窗口后查询 已撤销版本不再命中
旧版本 切换语料或策略版本 缓存与 trace 不混用版本

一次泄漏就阻断第 21 周。不能说“生成阶段会过滤”,也不能把它留到第 23 周综合安全测试再修。

第五步:写一份不夸大的 M1 报告

标题“第五步:写一份不夸大的 M1 报告”

报告至少分成四段:

  1. 测试范围: 固定语料、索引、身份、版本、负向矩阵与运行日期;
  2. 逐例结果: 预期与实际候选 ID、权限摘要、缓存状态和 run_id
  3. 失败与恢复: 泄漏、过期或缓存污染如何修复,修复后重跑哪些回归;
  4. 证据边界: 未覆盖角色、罕见缓存状态、并发权限变化和真实生产环境仍未知。

合格结论示例:

northstar-capstone-corpus-v1、三种固定身份与本报告声明的 8 类合成测试中,未授权分块进入检索候选的数量为 0。该结果只覆盖当前版本和矩阵,不证明未测试身份、并发权限变化或真实生产环境永不泄漏。

学习日 建议时间 当天动作 离开前必须有的结果
第 1 天 1–2 小时 固定语料、身份、权限与预期候选矩阵 数据/访问合同与负向用例
第 2 天 2 小时 复用并调整摄取、隔离和可重建索引 语料卡、manifest 与隔离证据
第 3 天 2 小时 在存储或查询层实施 ACL 与缓存隔离 可检查原始候选的检索基线
第 4 天 1–2 小时 跑跨角色/范围、降权、过期、撤销和缺 ACL 测试 逐例实际结果与失败修复
第 5 天 1–2 小时 核对来源、版本和 run_id,完成三层演示 M1 报告与第 21 周入口清单
  • 在固定语料、身份、版本和声明矩阵中,未授权分块进入候选集的数量为 0;
  • 缺失 ACL 默认拒绝并隔离;
  • 文档分块没有丢失或放宽父文档权限;
  • ACL 在存储或检索查询层生效,而不是生成后过滤;
  • 缓存键包含权限摘要、语料版本和检索版本;M0 有租户边界时还包含租户;
  • 降权、撤销和版本变化能使不再适用的缓存失效;
  • 索引可从版本化事实来源重建,并记录解析与分块版本;
  • 过期、撤销和来源下线有刷新或硬停止规则;
  • 每次检索保存 run_id、身份摘要、策略与语料版本;
  • 任何泄漏都会阻断第 21 周;
  • 结论明确限定于合成或授权数据、固定版本和已声明测试矩阵。
失败 诊断信号 修复动作
检索后才过滤权限 原始候选含受限分块 把 ACL 下推到存储或查询层并重跑原始候选测试
缺 ACL 被当成公开 未知文档进入索引 默认拒绝、隔离并修复数据所有权
主管查询污染普通缓存 降权后仍命中主管内容 权限摘要进入缓存键,清旧缓存并加降权回归
索引成为唯一事实来源 无法说明来源或重建 从版本化原始源重建并对账摘要
撤销文档仍能命中 传播窗口后候选仍含旧版本 增加失效传播、陈旧上限和硬停止
只测试允许身份 报告没有负向候选 增加跨角色/范围、降权、撤销与缓存复用
为展示而增加多租户 M0 没有租户证据 删除无依据边界,回到已批准角色模型

独立迁移:增加外包客服角色

标题“独立迁移:增加外包客服角色”

在不改变北辰完成示例的前提下,独立增加一个“外包客服”角色。先写预期,再改数据:

  1. 它能看到哪些当前政策?
  2. 哪些 A 普通客服资料也必须拒绝?
  3. 角色切换和降权时缓存键怎样变化?
  4. 缺少外包范围标记的文档是公开还是隔离?
  5. 哪些测试失败会要求重开 M0,而不是继续补 if/else?

如果这个角色没有业务证据,只把它作为明确标注的权限练习,不要声称来自真实客户需求。

用同一份证据向三类人解释

标题“用同一份证据向三类人解释”
  • 老板版: 当前降低的是哪一类数据访问风险,哪项失败会立即停止项目,尚未证明什么业务价值。
  • 一线版: 为什么某些资料不可见、过期或撤销时系统怎样说明、由谁负责更新或升级。
  • 工程版: ACL 如何贯穿摄取、分块、索引、查询、缓存、撤销、版本和审计。

下一步:课程仍未结束

标题“下一步:课程仍未结束”

第 20 周通过只建立了 M1 数据与检索候选基线。第 21 周只能消费固定版本的语料、ACL 检索接口和负向测试;语料或权限变化必须新建版本并重跑 M1。完整的第 21–24 周仍保留在24 周标准路线中:

  • 第 21 周:Capstone 有引用问答、拒答、冲突/过期处理和失败分类;
  • 第 22 周:MCP 预览、逐次审批、写入、幂等、对账与审计;
  • 第 23 周:冻结盲测、威胁测试、负载/成本、故障演练与上线决定;
  • 第 24 周:受控试点或明确模拟走查、最终交接、复盘和三听众答辩。

核验日期:2026-08-25。 北辰文档、身份、租户、矩阵和版本均为合成材料;示例 JSON 是输入契约,不是伪造运行结果。本周门槛是课程设计,不证明真实生产安全、合规、无泄漏、采用率、效率或 ROI,也不代表完成第 24 周毕业要求。