快速开始
整个演示不需要 API key,也不需要 GPU。首次构建会下载 Maven 依赖与一个约 70 MB 的 embedding 模型,通常需要几分钟;之后启动只要十几秒。
环境要求:Docker、uv。本地开发另需 JDK 21+ 与 Maven 3.9+。
一、三条命令跑起来
git clone https://github.com/poppycoderr/grounded-access.git
cd grounded-access
docker compose up -d --build --wait # PostgreSQL + pgvector、控制面、CPU 模型服务
./scripts/load-demo # 导入 Northstar 与 Orbit Labs 两套虚构语料
./scripts/demo-queries # 同一个问题,不同身份--wait 会等到三个容器都健康。控制面的健康检查直接探测 8080 端口,Tomcat 只有在应用上下文就绪后才开放端口,因此健康即可用。
二、看同一个问题的两种结果
./scripts/demo-queries 的第一组输出:
alice-engineer (tenant northstar) · dense-only · policy tenant-only/1
1. hr-volunteer-policy › Volunteer Time Off Policy > European Union
Employees based in the EU receive two paid volunteer days per calendar year.
2. hr-volunteer-policy › Volunteer Time Off Policy > United States
Employees based in the US receive one paid volunteer day per calendar year.
mallory-outsider (tenant external) · dense-only · policy tenant-only/1
1. volunteer-handbook › Community Volunteering Handbook > Volunteer days
Orbit Labs employees receive three volunteer days per year, which can be taken as half days.两次请求除了 token 完全相同。外部身份得到的不是「权限不足」,没有命中数量,也看不到任何 Northstar 文档的标题——租户条件是筛选候选那条 SQL 的一部分,Northstar 的政策从来没有成为他结果集里的一行。
第二组输出对比 sparse 与 dense 在同一个改写提问上的差异:问「去德国出差每天的餐费预算是多少」,原文写的是 "meal allowance … inside the EU",没有共同词元,FTS 找不到,向量检索能找到。
三、以任意身份检索
demo 身份定义在 data/principals.yaml,包括 alice-engineer、bob-support、carol-manager(Northstar 租户)与 mallory-outsider(外部租户),以及两个租户的管理员。
uv run --project packages/evaluation ga-eval search alice-engineer "How many paid volunteer days do EU employees receive?"
uv run --project packages/evaluation ga-eval search bob-support "When does a locked account unlock?" --strategy sparse-only自己签发 token 调用 API:
TOKEN=$(uv run scripts/mint-token.py alice-engineer --scope "query debug")
curl -s localhost:8080/api/v1/retrieval/search \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"query":"paid volunteer days","strategy":"dense-only","k":3}'作用域决定能做什么:admin 可入库,query 可检索,只有带 debug 的 token 才能看到原始分数。缺少 sub 或 tenant_id 的 token 在验签阶段就被拒绝。
data/demo-keys/里的签名密钥是公开的,任何人都能签出任意身份的 token。它只用于本地演示,真实部署要换成自己的验证密钥或接入 OIDC。
四、跑一次评测
./scripts/benchmark # 结果写入 results/<时间戳>/
./scripts/benchmark --out benchmarks/reports/my-run评测会以每条用例指定的身份调用公开 API,计算 Recall@5/@10、MRR@10,并执行安全门禁:只要返回的文档不在人工标注的可见集合里,命令以退出码 2 结束。当前提交在仓库中的运行结果:
| 策略 | Recall@10 | MRR@10 | nDCG@10 | 越权结果 |
|---|---|---|---|---|
sparse-only(PostgreSQL FTS) | 0.930 [0.86, 0.98] | 0.640 [0.54, 0.74] | 0.711 [0.63, 0.79] | 0 |
dense-only(pgvector 精确检索) | 0.965 [0.91, 1.00] | 0.856 [0.78, 0.93] | 0.884 [0.81, 0.94] | 0 |
hybrid-rrf(两者的 RRF 融合) | 0.965 [0.91, 1.00] | 0.797 [0.71, 0.88] | 0.837 [0.77, 0.90] | 0 |
bm25-reference(离线,同一批已授权 chunk) | 0.921 [0.84, 0.98] | 0.689 [0.59, 0.78] | 0.744 [0.66, 0.82] | 0 |
以上为数据集 v2 的 test 划分、57 条可回答用例、95% bootstrap 区间,由 CI runner 生成。dense 在 MRR 上明显优于 FTS 和 BM25;hybrid 与 dense 之间没有可检测的差异;108 条用例(其中 30 条授权负例)的越权结果为 0。详见评测方法。
五、自己导入文档
入库接口接收内联内容,服务端不会去读客户端给出的文件路径:
ADMIN=$(uv run scripts/mint-token.py northstar-admin)
curl -s localhost:8080/api/v1/ingestion-jobs \
-H "Authorization: Bearer $ADMIN" -H 'content-type: application/json' \
-D - -d '{"documents":[{"key":"team-handbook","title":"Team Handbook","content":"# Handbook\n\n## On-call\n\nThe on-call engineer acknowledges a page within five minutes.\n"}]}'入库是异步的:接口立即返回 202 Accepted,Location 头指向任务,body 中 status 为 queued。轮询这个地址,直到状态变为 succeeded 或 failed:
curl -s localhost:8080/api/v1/ingestion-jobs/<jobId> -H "Authorization: Bearer $ADMIN"
# {"status":"succeeded","documents":1,"processed":1,"created":1,"updated":0,"unchanged":0,"chunks":1,"attempts":1,"errorCode":null,...}再次提交相同内容会得到 unchanged: 1——幂等键是规范化文本的 SHA-256;内容变化则写入新版本并原子切换指针。ga-eval load(即 scripts/load-demo)内部就是提交任务再轮询。
六、本地开发
mvn -B -ntp clean verify # Java:单测、Testcontainers 集成测试、架构测试、格式检查
uv run --directory apps/model-service pytest # 模型服务
uv run --directory packages/evaluation pytest # 评测 CLI
uv run --project packages/evaluation ga-eval validate # 数据集一致性几个容易踩的点:
- 用
clean verify。NullAway 只检查被重新编译的类,增量构建可能漏掉空安全错误,而 CI 与镜像构建会抓到。 - 集成测试需要 Docker,Testcontainers 会拉起真实的 pgvector。
- 不要绕过失败的检查。架构测试、安全门禁与格式检查都是有意设置的硬门槛。
常见问题
能接入自己的文档吗? 可以,但当前只支持 Markdown 与纯文本,并且只做租户级隔离。完整的部门 / 项目 / 密级控制要等 M2。
没有生成模型也能用吗? 当前版本只有检索接口,返回排序后的证据片段。带引用与拒答的 /api/v1/query 在 M3。
为什么向量检索不建索引? 约 80 个 chunk 的 demo 规模下精确检索足够快,而且精确检索保证「加了授权过滤不会损失召回」这条不变量成立。建 ANN 索引之后需要专门测量高选择性过滤下的召回,见检索通道。