这个坑值得记一笔。测试环境复现:A 公司的账号检索时命中 B 公司的工单内容,检索请求里 tenant 字段有值,但生成的 filter 语句里没带这个条件。

刚开始盯着「索引里 tenant 是普通字段而不是分区键」,折腾了半个多小时,排掉了。

排查方向其实有限,先把可能性排一排。过滤条件写在业务层,检索层没强制拼 tenant;旧数据写入时没写 tenant 字段,过滤被跳过;缓存键没带租户,跨租户共用同一份结果。

第一件事是抽查索引里 tenant 字段的空值比例

python -c "import json;cs=[json.loads(l) for l in open('chunks.jsonl')];print(sum(1 for c in cs if not c.get('tenant')),len(cs))"

随后在检索封装层强制拼接租户条件

python -c "print({'filter':'tenant == \"%s\"' % 'a1'})"

接着把缓存键加上租户前缀后重放测试

python retrieve.py --tenant a1 --no-cache --q '退款工单'

末了用两个租户交叉查询验证不串数据

python cross_tenant_test.py --t1 a1 --t2 b1

改完先别撤,确认这几项。两个租户交叉查询各只返回自己的条目,缓存键里带租户前缀,审计日志能查到每次检索的租户。

补一句。权限过滤不能依赖调用方传参,要在统一的检索入口强制注入,写入时也要校验租户字段非空。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189