抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

知识摄取任务变绿,用户仍搜不到文档,通常不是“向量库偶尔没命中”这么简单。任务成功只说明代码走到了结束,没有证明源内容枚举完整、解析结果没截断、每个 chunk 都生成向量、索引切到了新版本,也没证明查询链路使用了这版索引。

我会沿六层做证据对账:枚举、抓取、解析、切块/embedding、发布、查询。每层都有输入输出不变量和 manifest。定位从第一个数量或版本不一致的层开始,不先调 top-k。

知识摄取失败的分层定位

AI 写 SQL 已经不难,难的是决定哪条 SQL 可以进入生产查询链路。只做语法检查,会放过越权与全表扫描;只做权限,会放过指标口径错误;让用户自己审核,又很难在一键分析和 Agent 自动执行中保持一致。

我会设置四道独立闸门:语句、数据、资源、语义。它们分别回答“能不能解析”“能不能看这些数据”“能不能以这个代价运行”“是否真的回答了问题”。四层结论和证据一起返回,不用一个笼统的 safe/unsafe 盖掉差异。

AI SQL 的四道闸门

Prompt Injection 不是在 system prompt 后面多写一句“不要听用户的”就能解决。Agent 会读取网页、文档、邮件和工具输出,这些内容都可能包含类似指令的文本。模型很难只凭自然语言可靠区分“这是数据”还是“这是更高优先级命令”。

我的防线不建立在模型永远识别攻击上,而是建立在权限与执行分层:不可信内容可以影响候选答案,不能自行提升为控制指令;任何工具动作仍需通过确定性的对象、权限、状态和确认检查。

不可信内容不能直接变成工具指令

知识库页面显示“今天更新”,不代表用户现在问问题能检索到今天的内容。源文档变更后,要经过事件发现、抓取、解析、embedding、索引发布、复制与缓存失效。任何一段积压,答案都可能继续引用旧版本。

我把新鲜度定义为 query-visible time - source event time,再拆成各阶段延迟预算。没有源事件时间时,只能报告“平台最近一次成功观测”,不能把抓取时间冒充内容真实更新时间。

知识新鲜度预算拆解

很多知识库上线时只做了导入:抓文档、切块、算向量。过几个月后,同一制度的新旧版本一起命中,已离职人员的私有文档仍能被检索,源文件删除了,向量库里还留着片段。问题不在 RAG 算法,而在内容从来没有生命周期。

我把摄取当成一条可发布的数据管道。源系统的 create、update、delete、ACL change 都变成有版本的事件;新索引先在 staging 校验,再切换 current alias;删除和撤权先用 tombstone 立即阻断查询,物理清理由后台完成。

RAG 内容从源版本到索引发布

传统 API 监控里,一条 HTTP 请求通常对应一个服务操作。LLM 应用不一样:用户问一句话,内部可能先检索两次、调用主模型、执行工具、再调用模型总结;上游断流后还可能换模型重试。只记录入口 latency 和 status=200,看不出回答为何错,也算不清真实成本。

我把 run 定义成一次用户意图的完整处理,下面挂 retrieval、model attempt、tool call、policy decision 和 finalization。HTTP request 是承载方式之一,不是业务身份。所有事件通过 run_id 串起来,最终状态由证据归并得出。

一次 LLM Run 的证据树

RAG 产品加上“参考资料”区域后,答案看起来会可信很多。实际抽查时经常发现:链接确实相关,却没有支持模型写出的数字;文档说的是测试环境,答案扩展到了生产;三条引用里两条互相冲突,模型选了表达最顺的一条。

引用是展示形式,证据关系才是可验证结构。我会在最终答案前增加 Evidence 层:先拆出可核查 claim,再把每个 claim 与具体 source/version/span 对齐,标注支持、冲突或不足,最后由发布策略决定保留、降级措辞或拒答。

答案层之外增加 Claim-Evidence 层

多接几家模型后,网关很容易加一条“失败就切下一个”的逻辑。它能缓解单供应商不可用,却不是完整路由:备用模型可能不支持 function calling、上下文不够、数据地域不合规,或者虽然 HTTP 成功,业务输出已经无法使用。

我把路由分成两步。先用硬约束过滤出“有资格执行”的模型,再在候选中按具体任务的成功率、延迟和成本选择。fallback 也必须重新通过硬约束,不能为了可用性把安全与能力要求降掉。

多模型路由从请求约束出发

给 Agent 配一份“可用工具列表”,只能说明模型可以看到哪些函数,不能说明用户有权对哪些对象做什么。一个用户能调用 rerun_job,不代表他能重跑所有项目、所有环境的任务;能调用 query_table,也不代表能读每张表的每个字段。

我把工具权限表达为 subject × action × resource × context。主体来自可信会话,动作来自已注册工具,对象必须解析为稳定 ID,上下文包含租户、环境、时间和资源当前状态。模型只提出参数,不参与最终授权结论。

Agent 工具权限落到动作与对象

RAG 团队常用一张端到端准确率报表:问题发进去,答案对就记 1,错就记 0。这个数适合看整体趋势,却不能告诉我们该改 embedding、chunking、reranker、Prompt 还是知识源。

我会把评测拆成三层。第一层只测检索是否拿到充分证据;第二层固定正确证据,只测模型能否组织出正确、受引用支持的答案;第三层才跑真实端到端链路,验证两者组合后的延迟、成本和失败分布。

检索与回答分开评测,失败才能归因

Prompt 从十几行增长到几百行后,很容易变成一份“谁都能改、没人敢删”的线上配置。有人为了修一个格式问题加两句指令,第二天工具选择率下降;回滚时只把文本改回去,结果仍和上周不同,因为模型别名、工具 schema 或检索模板已经变了。

我不把 Prompt 单独视为版本单位。真正决定一次模型行为的是完整运行组合:system prompt、消息模板、模型 snapshot、sampling 参数、工具定义、检索/上下文策略和输出 parser。它们一起形成不可变 Bundle,发布与回滚都指向 Bundle ID。

Prompt 变更按软件版本发布

SQL Copilot 最容易做成“代码补全器”:模型返回 SQL,编辑器高亮一下,用户自己运行。到了需要自动修复、自动解释或一键执行的场景,这个边界就不够了。模型写出的 SQL 往往像标准 SQL,真正交给 Flink、Spark、Hive 或 PostgreSQL 时,方言、Catalog 和执行计划都会给出不同结论。

我把验证分成三段:目标引擎 Parser 证明语句属于这个方言,Catalog/Analyzer 证明对象和类型能解析,Planner/受控执行证明计划风险和结果语义可接受。任何一段失败,都返回具体证据,而不是笼统说“SQL 可能有问题”。

SQL Copilot 的三段验证