单次问答背后的全链路
上一篇讲了初始化——用三个 Python 脚本把 Ragent 从空白搭到了可评测状态:4 个知识库、115 篇已分块的文档、30 个意图节点。评估集也准备好了,20 条 query 等着跑。
接下来的问题是:怎么把这 20 条 query 逐条喂进 Ragent,把检索结果、生成答案、性能数据一次性收齐?
拿评估集里的一条样本来说——“预算 3000 左右,有没有拍照比较好的手机推荐?”。跑完之后,我需要知道四件事:召回了哪几篇文档(算 Hit@K)、命中了哪个意图叶子(算意图准确率)、模型回了什么(算 faithfulness、answer_correctness 等)、用户等了多久才看到第一个字(算 TTFT P95)。
问题在于,Ragent 的生产接口 /rag/v3/chat 是 SSE 流式输出,一个字一个字蹦出来——拿得到答案和首字耗时,但拿不到中间产物。召回了哪些 chunk、分到了哪个意图,SSE 流里没有这些数据。
一个接口不够用,runner 的核心设计就是一条 query 跑两个接口。
为什么一个接口不够用
先看评测需要哪些数据,以及生产 SSE 接口能不能给:
| 评测需要的数据 | 用来算什么指标 | 生产 SSE 能给吗 |
|---|---|---|
| 召回了哪些 docId / chunkId | Hit@K / Recall@K / MRR | ❌ 不暴露中间产物 |
| 意图分类结果 | 意图 Top-1 准确率 | ❌ |
| chunk 文本内容 | RAGAS faithfulness / context_recall | ❌ |
| 模型完整回复 | faithfulness / answer_correctness | ✅ 拼接 delta 即可 |
| 首字到达时间 | TTFT P95 | ✅ 需要自己打点 |
| 总耗时 | 性能基线 | ✅ |
六项里有三项拿不到。所以需要一个旁路接口来补齐检索证据,跟 SSE 接口配合,一次性收齐所有数据。