检索命中了订单和品牌,却没有 SKU 中间表,模型就可能发明一个不存在的直接连接。Schema 剪枝要解决的不是“尽量短”,而是“在可用预算内留下够用的关系”。
10 月 20 日的分析 Agent 基准把多跳数据层的使用与计划错误分开观察。它不能证明某种剪枝器对所有企业都有效,但能帮助我们提出一个更具体的测试问题:相关表找到了,连接路径是否也保住了?Agentic Analytics Benchmark 第二轮
保留顺序,补齐必需路径
候选列表有排名,不能先转集合再取前三。外键补全也不是随便拉进所有邻居:应从确认的核心表出发,在可信关系图中寻找路径,保留桥接节点。预算装不下必要路径时应失败或反问,而不是悄悄把桥表截掉。
from collections import deque graph = {'orders': ['items'], 'items': ['orders', 'brands'], 'brands': ['items']} def path_between(start, goal): queue = deque([(start, [start])]) seen = {start} while queue: node, path = queue.popleft() if node == goal: return path for neighbor in graph.get(node, []): if neighbor not in seen: seen.add(neighbor) queue.append((neighbor, path + [neighbor])) raise ValueError('no approved join path') def prune(ranked_hits, max_tables=4): selected = list(dict.fromkeys(ranked_hits)) if not selected: return [] anchor = selected[0] for target in selected[1:]: for table in path_between(anchor, target): if table not in selected: selected.append(table) if len(selected) > max_tables: raise ValueError('required join graph exceeds budget') return selected answer = prune(['orders', 'brands', 'orders']) assert set(answer) == {'orders', 'items', 'brands'} assert answer[:2] == ['orders', 'brands'] print(answer)这是无权图上的教学 BFS,不是向量检索或跨编码器实现。图中的边应来自经过核对的关系元数据,并包含主键、外键、基数与有效时间等信息;最短的图路径也不一定具有正确业务粒度。
该保留的不只是列名
订单表可能是订单粒度,明细表是一单多行,品牌表还可能有缓慢变化版本。即便三表连通,若 JOIN 后重复累计订单实付额,结果仍会错。剪枝上下文需要附上粒度、去重规则与应使用的金额字段。
评估时至少记录表召回、桥表遗漏、最终结果正确率、上下文长度和延迟。只看 token 减少,容易奖励一个把正确答案也剪掉的算法。重排用真实打分器还是规则排序,要在方案里说清楚,不能把candidates[:k]标成已经完成了神经重排。
本文没有接入 embedding 服务、向量数据库或真实模型,也不提供“从 500KB 到 3KB”“准确率提升到 93.5%”的实测结论。先用一张小图把连接关系解释清楚,再决定是否值得引入更复杂的检索组件。
延伸阅读
- Agentic Analytics Benchmark 第二轮
- DuckDB 2.0.0 LTS 发布说明