在线链路做什么
在线链路处理用户的每一次提问:改写问题、向量化、按召回策略取回候选片段、重排、按 token 预算组装上下文,最后交给大模型生成带引用的答案。它是一条延迟敏感的同步链路,每一步都要分配好时间与 token 预算,并且要能单独观测与单测。
基本信息
| 输入 | 当前问题 + 最近几轮对话历史 |
|---|---|
| 输出 | 答案文本 + 引用片段列表 |
| 关键约束 | 端到端延迟、上下文窗口、单次调用成本 |
| 强一致要求 | 查询侧与索引侧必须同一 embedding 模型与版本 |
| 可观测项 | 各环节耗时、召回条数、重排分数分布、拒答率 |
在线链路环节
| 环节 | 作用 | 常见实现 |
|---|---|---|
| 问题改写 | 补全指代、扩展同义说法 | LLM 改写提示词 / Multi-Query |
| 向量化 | 把问题编码为向量 | 与索引使用同一 embedding 模型 |
| 召回 | 取回 top-k 候选 | 向量检索 + BM25 混合 |
| 重排 | 对候选精排 | Cross-Encoder 重排模型 / 重排 API |
| 生成 | 带上下文作答 | LLM + 引用标注提示词 |
请求处理骨架
请求处理骨架
def answer(question, history):
q = rewrite(question, history) # 指代消解与改写
hits = hybrid_search(q, top_k=20) # 混合召回
hits = rerank(q, hits, top_n=5) # 重排
ctx = build_context(hits, max_tokens=3000)
return llm_answer(q, ctx, cite=hits) # 生成 + 引用延迟预算参考
- 问题改写:一次小的 LLM 调用,几十到几百毫秒,通常可缓存同一会话的改写结果
- 向量化:单条查询一次 encode,本地模型通常几十毫秒
- 召回:向量与关键词各一次查询,可并行发起取较慢的一路
- 重排:对几十条候选逐对打分,是本地管线里最容易超时的一环
- 生成:耗时与输出长度正相关,是整条链路的主要成本项
常见降级手段
| 异常 | 降级动作 | 影响 |
|---|---|---|
| 改写服务超时 | 直接用原始问题检索 | 多轮指代类问题命中变差 |
| 重排超时 | 按召回顺序截断返回 | 排序质量下降但可用 |
| 向量库不可用 | 退化为关键词检索 | 语义近似类问题召回下降 |
| 上下文超预算 | 按分数从低到高丢弃片段 | 答案要点可能缺失,需在回答中说明 |
在线链路要能逐段单测:先测检索命中,再测重排增益,最后测生成忠实度。把每步输入输出留档,出问题时才可复现。
在线与离线使用不同 embedding 模型或版本,向量空间不一致,检索会明显变差且不会报错;模型升级必须与索引重建成对上线。