Harness Times
HARNESS 与 AGENT 工程学习站
原理 ◆ 工程 ◆ 评测 ◆ 知识
这里是全站 72 道面试问题的总入口。它们不是「常见题汇总」,而是按 面试官的真实提问顺序反推出来的:先问机制,再问代价,最后问你有没有在真实场景里撞过墙。 每道题都配了参考答案、追问链(答对之后会往哪追)和加分点(哪句话能证明你真做过)。
建议用法:先只看问题,心里答一遍,再展开对照。凡是答不出「代价和边界」的,就是还没掌握。 自评「已能答出」的记录只存在你这台机器的浏览器里,不会上传。
72问题总数
30高频标记
22覆盖章节
4知识领域
I · 大模型原理 Model Foundations
01 Transformer 与自注意力 3 问
为什么注意力复杂度是 O(n²)?这对做 Agent 意味着什么? 高频
注意力要让每个位置对其他所有位置算一个权重,得到的是
对 Agent 的直接含义有三层:第一,上下文越长,成本不是线性上涨而是平方级上涨,这是"长上下文很贵"的物理原因;第二,往上下文里多塞一倍内容,代价远不止翻一倍;第三,裁剪、压缩、状态外置不是优化技巧,而是必须做的基本功。
seq × seq 的注意力矩阵,所以算力随序列长度呈平方增长。对 Agent 的直接含义有三层:第一,上下文越长,成本不是线性上涨而是平方级上涨,这是"长上下文很贵"的物理原因;第二,往上下文里多塞一倍内容,代价远不止翻一倍;第三,裁剪、压缩、状态外置不是优化技巧,而是必须做的基本功。
追问链
- 那 KV Cache 的显存占用怎么估算?它和 n² 是同一个量级吗?
- 如果只关心首 token 延迟,哪个成本占主导?
多头注意力比单头好在哪?
单头只有一组 Q/K/V 投影,只能学到一种关注方式。多头把表示空间切成若干子空间并行做注意力,不同的头可以各自关注不同类型的关联——位置邻近、指代关系、句式结构等,最后拼接再投影。
工程意义在于:模型能同时维持多种关系,这是长链路任务里"既记住目标又盯住细节"的基础。注意头的数量与 head_dim 的乘积大致等于隐藏维度,所以加头并不等比例增加算力,但头太多也会稀释每个头的表达空间。
加分点:主动补一句"不是越多越好",显示你有工程判断而不是背书。 工程意义在于:模型能同时维持多种关系,这是长链路任务里"既记住目标又盯住细节"的基础。注意头的数量与 head_dim 的乘积大致等于隐藏维度,所以加头并不等比例增加算力,但头太多也会稀释每个头的表达空间。
位置编码解决什么问题?没有会怎样?
注意力本身是置换等变的——把输入顺序打乱,输出只会跟着打乱,模型无法区分"猫追狗"和"狗追猫"。位置编码把顺序信息注入表示。演化路径大致是可学习绝对位置嵌入 → 正弦编码 → 现在主流的 RoPE 这类相对位置方案。
对工程的启示:相对位置方案让模型对超出训练长度的位置有一定外推能力,但外推能力有限。"把窗口调大"不等于"模型真的能用好长窗口",这就是长上下文需要专门训练和评测的原因。
加分点:把位置编码与"有效上下文长度"联系起来,是一个很自然的加分项。 对工程的启示:相对位置方案让模型对超出训练长度的位置有一定外推能力,但外推能力有限。"把窗口调大"不等于"模型真的能用好长窗口",这就是长上下文需要专门训练和评测的原因。
02 KV Cache:多轮对话的隐性账单 4 问
KV Cache 是什么?为什么多轮对话能省下来钱? 高频
自回归解码时,每生成一个 token 都要重新做一遍注意力计算,而每一层的 K(键)和 V(值)只依赖已经出现过的前缀。既然前缀没变,重算出来的 K/V 就是一样的——于是把它们缓存起来,下一步直接复用,只计算新 token 的那一份。
多轮对话之所以能省,是因为第二轮的 prompt 里,绝大部分是第一轮已经算过的内容。前缀完全一致时,这段直接命中缓存,不重复计算,在按 token 计价的 API 上直接体现为折扣。
多轮对话之所以能省,是因为第二轮的 prompt 里,绝大部分是第一轮已经算过的内容。前缀完全一致时,这段直接命中缓存,不重复计算,在按 token 计价的 API 上直接体现为折扣。
追问链
- 那缓存命中率取决于什么?
- 显存占用怎么估?和 batch size 是什么关系?
缓存命中率取决于什么?—— 这道题几乎决定你懂不懂成本。 高频
取决于前缀稳定性。缓存的匹配方式是"从头开始逐 token 比对,直到第一个不同点",也就是说:前缀里任何一处变化,都会让从该点之后的所有缓存全部失效。
常见破坏点包括:system prompt 里塞了当前时间戳或随机 ID、把工具列表按使用频率每次重排、把检索结果按时间排序每次都变、few-shot 示例顺序随机、会话 ID 注入到 prompt 开头。这些写法看起来无害,实际每一轮都在让缓存重置。
常见破坏点包括:system prompt 里塞了当前时间戳或随机 ID、把工具列表按使用频率每次重排、把检索结果按时间排序每次都变、few-shot 示例顺序随机、会话 ID 注入到 prompt 开头。这些写法看起来无害,实际每一轮都在让缓存重置。
追问链
- 那你系统里具体哪些地方在破坏缓存?你怎么改的?
- 改成稳定前缀之后,命中率大概提升了多少?
Agent 场景下,token 成本的大头在哪? 高频
不在单次输入,而在多轮累积的历史。一个十轮的 Agent 任务,第 n 轮要把前面 n−1 轮的全部消息重新送进去,输入 token 的总量大致是平方级累积的——这和注意力复杂度是两个独立但叠加的成本问题。
所以成本杠杆的优先级通常是:① 前缀缓存友好(提升命中率,直接对应 API 折扣);② 工具结果裁剪(只回关键字段,不要把整页 JSON 塞进去);③ 历史摘要化(保留决策与结论,丢掉过程);④ 状态外置(大块数据落盘,按需回读);⑤ 模型分级路由(简单环节用便宜档位)。
加分点:把成本按"输入 / 输出 / 命中缓存"三段分别报价再谈优化,能立刻显出你算过账。 所以成本杠杆的优先级通常是:① 前缀缓存友好(提升命中率,直接对应 API 折扣);② 工具结果裁剪(只回关键字段,不要把整页 JSON 塞进去);③ 历史摘要化(保留决策与结论,丢掉过程);④ 状态外置(大块数据落盘,按需回读);⑤ 模型分级路由(简单环节用便宜档位)。
长上下文和 RAG 该怎么选?
判据是召回精度需求与成本结构,不是"哪个更先进"。
适合长上下文:全集较小且必须整体把握(例如一次代码评审要把整个文件读完)、需要跨段落的推理与全局一致性。
适合 RAG:库很大、每次只需要极少相关片段、需要精确引用来源。
真实系统几乎都是混合:用检索把候选收窄到可控范围,再把候选完整放进上下文,这样既控制了 token 又保住了精度。反过来做——把整个库塞进长上下文——成本和延迟都不可接受,而且要面对"中间内容被忽略"的注意力衰减问题。
适合长上下文:全集较小且必须整体把握(例如一次代码评审要把整个文件读完)、需要跨段落的推理与全局一致性。
适合 RAG:库很大、每次只需要极少相关片段、需要精确引用来源。
真实系统几乎都是混合:用检索把候选收窄到可控范围,再把候选完整放进上下文,这样既控制了 token 又保住了精度。反过来做——把整个库塞进长上下文——成本和延迟都不可接受,而且要面对"中间内容被忽略"的注意力衰减问题。
03 MoE 与稀疏激活 3 问
为什么 MoE 的总参数量和激活参数量不是一回事? 高频
MoE 把前馈层(FFN)拆成很多个专家,每个 token 只被路由到其中 Top-K 个专家参与计算。于是:
总参数量是所有专家参数之和——决定模型需要
要多少显存/内存装下它;
激活参数量是单个 token 实际参与运算的那部分参数——决定算力开销。
所以一个总参数 671B 的模型,单 token 激活可能只有 37B 量级,算力像小模型,容量像大模型,这就是它便宜的原因。
总参数量是所有专家参数之和——决定模型需要
要多少显存/内存装下它;
激活参数量是单个 token 实际参与运算的那部分参数——决定算力开销。
所以一个总参数 671B 的模型,单 token 激活可能只有 37B 量级,算力像小模型,容量像大模型,这就是它便宜的原因。
追问链
- 那显存能不能按激活参数量来估?
- 路由不均(专家负载倾斜)会带来什么工程问题?
MoE 和稠密模型分别适合什么场景?
这道题答错会直接扣分,因为它考察的是工程选型直觉。
MoE 适合:预算充足、追求单位算力下的质量、有大规模并发可以摊薄通信与调度开销、以及显存资源相对宽裕的服务端部署。
稠密模型适合:显存受限(端侧、单机小卡)、并发低且延迟敏感(MoE 的专家并行会引入额外通信延迟)、需要极简部署与稳定吞吐的场景。
换句话说:MoE 换来的是"用容量换质量",代价是显存占用、通信开销与调度复杂度。
加分点:主动提 MoE 的代价(通信、负载均衡、显存),而不是只夸它便宜。 MoE 适合:预算充足、追求单位算力下的质量、有大规模并发可以摊薄通信与调度开销、以及显存资源相对宽裕的服务端部署。
稠密模型适合:显存受限(端侧、单机小卡)、并发低且延迟敏感(MoE 的专家并行会引入额外通信延迟)、需要极简部署与稳定吞吐的场景。
换句话说:MoE 换来的是"用容量换质量",代价是显存占用、通信开销与调度复杂度。
MoE 的负载不均衡是什么问题?会怎么表现?
门控网络倾向于把 token 集中路由到少数"表现好"的专家,导致部分专家过载、部分闲置。表现是:训练时出现"专家坍缩"(大部分专家学不到东西),推理时吞吐被少数热专家的算力上限卡住,整体并行效率下降。
常规处理是加负载均衡损失(鼓励路由分布均匀)、设置专家容量上限与溢出丢弃策略、以及在工程侧做专家并行的重排布。对使用方的启示:同一个模型在不同任务分布下的实际吞吐可能差异很大,压测要用真实流量而不是随机文本。
常规处理是加负载均衡损失(鼓励路由分布均匀)、设置专家容量上限与溢出丢弃策略、以及在工程侧做专家并行的重排布。对使用方的启示:同一个模型在不同任务分布下的实际吞吐可能差异很大,压测要用真实流量而不是随机文本。
04 采样、温度与确定性 3 问
Temperature 和 top_p 分别在调什么?Agent 场景你会怎么设?
两者都作用于下一个 token 的概率分布,但手法不同:temperature 在 softmax 前对 logits 做缩放,调的是分布的"陡峭程度"——温度越低分布越尖,越倾向于选最高概率的词;top_p(核采样)先按概率从高到低累加,只保留累计概率达到 p 的那一截候选,把长尾直接砍掉。
Agent 场景的经验是一条原则:凡是输出要被程序解析的地方(工具调用、结构化参数、JSON),尽量低温甚至贪婪解码;需要发散的地方(头脑风暴、候选方案生成)才提高温度。
要注意:即使 temperature = 0,由于并行归约的浮点非确定性、批处理组合变化等原因,输出也不保证逐字一致——所以兜底必须是校验和重试,而不是"假设它稳定"。
Agent 场景的经验是一条原则:凡是输出要被程序解析的地方(工具调用、结构化参数、JSON),尽量低温甚至贪婪解码;需要发散的地方(头脑风暴、候选方案生成)才提高温度。
要注意:即使 temperature = 0,由于并行归约的浮点非确定性、批处理组合变化等原因,输出也不保证逐字一致——所以兜底必须是校验和重试,而不是"假设它稳定"。
追问链
- 那参数校验失败了你怎么办?
- 为什么 temperature=0 仍然可能两次结果不同?
同一个问题问两次答案不同,这在 Agent 里会变成什么问题?
在聊天场景里这只是"有创造力",在 Agent 里它会直接变成三类故障:① 工具参数漂移(同一次意图生成出不同的参数,导致查询结果不一致);② 流程分支抖动(该调工具时直接凭记忆回答,或者反过来);③ 评测不可复现(你无法判断指标变化是改动带来的还是采样噪声)。
对应的工程手段是:结构化输出 + Schema 校验、解码参数按环节分级设置、把关键决策点做成确定性代码而不是交给模型自由发挥、评测时固定随机种子并多次重复取分布。
加分点:把"采样不确定性"翻译成具体的故障清单,比讨论参数含义更能体现工程视角。 对应的工程手段是:结构化输出 + Schema 校验、解码参数按环节分级设置、把关键决策点做成确定性代码而不是交给模型自由发挥、评测时固定随机种子并多次重复取分布。
top_k 和 top_p 能同时用吗?会有什么问题?
可以同时用,但一般是"有一个主约束"更清晰。两者叠加的实际效果是取交集性质——先按 top_k 砍掉长尾,再按 top_p 收敛,最终候选集会比单独用任何一个都小,可能过度限制多样性。
更实用的建议是:固定一个主参数(OpenAI 系通常调 top_p,部分开源模型偏 top_k),另一个设为默认值,避免两个旋钮互相干扰导致调参不可解释。另外,把"温度"和"惩罚项"(presence / frequency penalty)混着调最容易出现"越调越怪"的情况。
更实用的建议是:固定一个主参数(OpenAI 系通常调 top_p,部分开源模型偏 top_k),另一个设为默认值,避免两个旋钮互相干扰导致调参不可解释。另外,把"温度"和"惩罚项"(presence / frequency penalty)混着调最容易出现"越调越怪"的情况。
05 推理优化与成本杠杆 3 问
如果让你把推理成本砍一半,你会动哪几个杠杆? 高频
按"先看瓶颈、再选手段"的顺序来,不要一上来就报技术名词。
① 先量瓶颈:是显存不够(并发上不去)、还是首 token 延迟高、还是吞吐被批处理限制?三个瓶颈对应完全不同的杠杆。
② 缓存与上下文侧(几乎无质量损失,优先级最高):提升前缀缓存命中率、裁剪工具结果、压缩历史。
③ 调度侧:连续批处理提高批内利用率、分页管理 KV Cache 降低碎片。
④ 模型侧:量化(FP8/INT8)、分级路由(简单任务走小模型)。
⑤ 采样侧:投机解码用小模型起草、大模型验证。
顺序很关键:能在上下文层解决的问题,不要动到模型精度。
① 先量瓶颈:是显存不够(并发上不去)、还是首 token 延迟高、还是吞吐被批处理限制?三个瓶颈对应完全不同的杠杆。
② 缓存与上下文侧(几乎无质量损失,优先级最高):提升前缀缓存命中率、裁剪工具结果、压缩历史。
③ 调度侧:连续批处理提高批内利用率、分页管理 KV Cache 降低碎片。
④ 模型侧:量化(FP8/INT8)、分级路由(简单任务走小模型)。
⑤ 采样侧:投机解码用小模型起草、大模型验证。
顺序很关键:能在上下文层解决的问题,不要动到模型精度。
追问链
- 每一档的代价是什么?
- 怎么验证优化没有伤害质量?
量化的代价到底是什么?
量化把权重(以及激活)从高精度浮点压到更低比特,换到的收益是显存占用下降、带宽压力下降、吞吐上升。代价有三个方面:
① 精度损失,且不是均匀的——对数值敏感的环节(长链推理、精确算术、结构化输出)更容易先崩;
② 长尾能力退化,平均分可能只掉一点,但某些能力会明显下滑,所以必须看分项而不是看总分;
③ 工程复杂度,不同量化格式对推理引擎、算子支持、硬件的要求不同,实际部署时"能不能跑"和"跑得快不快"是两回事。
结论:量化必须配评测,用平均分判断量化是否可行是危险的。
① 精度损失,且不是均匀的——对数值敏感的环节(长链推理、精确算术、结构化输出)更容易先崩;
② 长尾能力退化,平均分可能只掉一点,但某些能力会明显下滑,所以必须看分项而不是看总分;
③ 工程复杂度,不同量化格式对推理引擎、算子支持、硬件的要求不同,实际部署时"能不能跑"和"跑得快不快"是两回事。
结论:量化必须配评测,用平均分判断量化是否可行是危险的。
投机解码(speculative decoding)为什么能加速?
核心是利用"验证比生成便宜"这个不对称性:用一个小而快的草稿模型一次并行猜出 k 个 token,再让大模型一次前向并行验证这 k 个 token,接受其中连续正确的部分,遇到第一个不被接受的就从那之后重来。
因为大模型的一次前向是并行的,验证 k 个 token 的成本接近验证 1 个,所以只要草稿的接受率够高,就能在一次前向上推进多个 token,端到端提速。
前提条件:草稿模型的分布要与目标模型足够接近(否则接受率低、反而更慢),且任务可预测性较强(代码补全、格式化输出这类收益最明显,自由创作收益有限)。
加分点:说清"接受率决定收益、分布不匹配会反噬"这个前提,说明你理解适用边界。 因为大模型的一次前向是并行的,验证 k 个 token 的成本接近验证 1 个,所以只要草稿的接受率够高,就能在一次前向上推进多个 token,端到端提速。
前提条件:草稿模型的分布要与目标模型足够接近(否则接受率低、反而更慢),且任务可预测性较强(代码补全、格式化输出这类收益最明显,自由创作收益有限)。
II · Harness 工程 Harness Engineering
01 Harness 是什么 3 问
Harness 的定义是什么?边界在哪? 高频
一句话:Agent = Model + Harness,Harness 是"除模型本身以外的所有工作"。
具体可以拆成七层:① 执行层(Agent Loop、终止条件、状态机);② 能力层(工具注册与契约、MCP 接入、工具执行与沙箱);③ 上下文层(预算分配、压缩、缓存友好组装、记忆);④ 编排层(规划、Subagent、多 Agent 通信);⑤ 治理层(权限、审计、提示注入防御、配额);⑥ 质量层(评测集、指标、trace、回归门禁);⑦ 适配层(多模型网关、参数 профиль、与训练团队的反馈回流)。
边界判断有个简单标准:如果是"让模型自己变强"的事,属于模型侧;如果是"让变强的模型能可靠地完成任务"的事,属于 Harness。
具体可以拆成七层:① 执行层(Agent Loop、终止条件、状态机);② 能力层(工具注册与契约、MCP 接入、工具执行与沙箱);③ 上下文层(预算分配、压缩、缓存友好组装、记忆);④ 编排层(规划、Subagent、多 Agent 通信);⑤ 治理层(权限、审计、提示注入防御、配额);⑥ 质量层(评测集、指标、trace、回归门禁);⑦ 适配层(多模型网关、参数 профиль、与训练团队的反馈回流)。
边界判断有个简单标准:如果是"让模型自己变强"的事,属于模型侧;如果是"让变强的模型能可靠地完成任务"的事,属于 Harness。
追问链
- 模型越来越强之后,Harness 会不会被吃掉?
- 这七层里你认为哪一层最难做?
为什么说 Harness 的难点不在"让它跑起来",而在"让它可评测、可回滚"?
因为"跑起来"是一次性的,"可评测、可回滚"是可持续的。
一个只在开发机上跑通过的 Agent,缺三样东西就无法成为产品:① 可观测——出了问题你拿不到完整链路(每轮的 prompt、工具调用、耗时、token),只能靠猜;② 可复现——没有 trace 就没有 replay,同一个 bug 你复现不出来,也就无法验证修好了没;③ 可安全变更——prompt 和工具描述本质上就是代码,没有版本化、灰度和一键回滚,每次改动都是在赌。
所以成熟的 Harness 有个特征:prompt 变更有版本号、有对照评测、有灰度门禁,而不是直接改线上。
一个只在开发机上跑通过的 Agent,缺三样东西就无法成为产品:① 可观测——出了问题你拿不到完整链路(每轮的 prompt、工具调用、耗时、token),只能靠猜;② 可复现——没有 trace 就没有 replay,同一个 bug 你复现不出来,也就无法验证修好了没;③ 可安全变更——prompt 和工具描述本质上就是代码,没有版本化、灰度和一键回滚,每次改动都是在赌。
所以成熟的 Harness 有个特征:prompt 变更有版本号、有对照评测、有灰度门禁,而不是直接改线上。
你怎么判断一个 Agent 产品做得好不好?
我会看四个指标,而不是看 demo 有多惊艳:
① 真实任务成功率——在用户的真实任务分布上,能独立完成的比例是多少;
② 人工介入成本——需要用户接管、确认、纠正的次数,这直接决定它是不是负担;
③ 可恢复性——跑偏之后能不能回退、能不能断点续跑、会不会把副作用做重;
④ 单位任务成本——token 与时间的消耗。
一个重要的判断信号是:好的 Agent 产品会把"不确定性"显式暴露给用户(比如告诉你它删除了哪些文件、改了哪些内容、依据是什么),而不是假装自己一直很确定。
加分点:最后那句"把不确定性显式暴露"是品味题的高分表达。 ① 真实任务成功率——在用户的真实任务分布上,能独立完成的比例是多少;
② 人工介入成本——需要用户接管、确认、纠正的次数,这直接决定它是不是负担;
③ 可恢复性——跑偏之后能不能回退、能不能断点续跑、会不会把副作用做重;
④ 单位任务成本——token 与时间的消耗。
一个重要的判断信号是:好的 Agent 产品会把"不确定性"显式暴露给用户(比如告诉你它删除了哪些文件、改了哪些内容、依据是什么),而不是假装自己一直很确定。
02 Agent Loop 与终止条件 4 问
Agent Loop 的终止条件你会设计哪几类? 高频
五类缺一不可:
① 显式完成——模型明确表示任务达成(要做好格式约束,不要靠正则猜自然语言);
② 资源用尽——最大轮数、token 预算上限、时间上限,三者都要有,因为不同任务会先撞到不同的墙;
③ 无进展检测——连续 N 轮动作或工具调用高度相似、或者没有产生新的有效信息,判定为原地打转并中断;
④ 循环检测——A→B→A 这类振荡模式;
⑤ 主动挂起——需要人工确认、缺少必要信息、或者触及高风险操作时,转 Human-in-the-loop 而不是硬着头皮往下走。
还要有一个兜底:异常终止也必须产出可读的中间结果,而不是把已经完成的工作丢掉。
① 显式完成——模型明确表示任务达成(要做好格式约束,不要靠正则猜自然语言);
② 资源用尽——最大轮数、token 预算上限、时间上限,三者都要有,因为不同任务会先撞到不同的墙;
③ 无进展检测——连续 N 轮动作或工具调用高度相似、或者没有产生新的有效信息,判定为原地打转并中断;
④ 循环检测——A→B→A 这类振荡模式;
⑤ 主动挂起——需要人工确认、缺少必要信息、或者触及高风险操作时,转 Human-in-the-loop 而不是硬着头皮往下走。
还要有一个兜底:异常终止也必须产出可读的中间结果,而不是把已经完成的工作丢掉。
追问链
- 如果只允许你保留一个条件,你留哪个?为什么?
- 无进展检测具体怎么实现?
模型开始重复同一个动作不收敛,你系统层面怎么发现? 高频
不指望模型自己发现,要在 Harness 层做判定。可用的信号有四种:
① 动作指纹去重——把每轮的工具名 + 规范化参数(排序后哈希)作为指纹,连续重复即判定打转;
② 结果熵检测——工具返回内容高度相似甚至完全一致,说明再调也拿不到新信息;
③ 目标相似度——对比相邻几轮的思考文本相似度,超过阈值说明在原地复述;
④ 进度信号——为任务维护"已完成子目标集合",若连续多轮集合不增长,即无进展。
检出之后的处理分三级:先注入提示纠偏(告诉它已经做过什么)→ 再强制换策略(禁用刚才那个工具)→ 最后中断并交出中间结果并说明卡在哪。
加分点:给出"三级处理"而不是直接中断,说明你考虑过误判成本——这是判断力的体现。 ① 动作指纹去重——把每轮的工具名 + 规范化参数(排序后哈希)作为指纹,连续重复即判定打转;
② 结果熵检测——工具返回内容高度相似甚至完全一致,说明再调也拿不到新信息;
③ 目标相似度——对比相邻几轮的思考文本相似度,超过阈值说明在原地复述;
④ 进度信号——为任务维护"已完成子目标集合",若连续多轮集合不增长,即无进展。
检出之后的处理分三级:先注入提示纠偏(告诉它已经做过什么)→ 再强制换策略(禁用刚才那个工具)→ 最后中断并交出中间结果并说明卡在哪。
一次 loop 最多几轮?这个数怎么定?
不该拍一个固定值,应该按任务类型分层:
简单查询型 3–5 轮(一次检索加一次总结足够);常规办事型 10–20 轮;代码修复类长任务可以放到 30–50 轮,但必须配预算上限兜底。
定这个数的依据是"分布 + 成本":看线上真实任务的轮数分布,取 P95 再留一点余量;同时算一下撞到上限时的最坏成本,确保可接受。
另外要区分软上限与硬上限:软上限触发时提示模型"轮数不多了,请收尾并给出当前结论",硬上限触发时直接中断。只设硬上限会让模型在最后一轮还去开一个新工具,交出一个半成品。
简单查询型 3–5 轮(一次检索加一次总结足够);常规办事型 10–20 轮;代码修复类长任务可以放到 30–50 轮,但必须配预算上限兜底。
定这个数的依据是"分布 + 成本":看线上真实任务的轮数分布,取 P95 再留一点余量;同时算一下撞到上限时的最坏成本,确保可接受。
另外要区分软上限与硬上限:软上限触发时提示模型"轮数不多了,请收尾并给出当前结论",硬上限触发时直接中断。只设硬上限会让模型在最后一轮还去开一个新工具,交出一个半成品。
ReAct 和 Plan-and-Execute 该怎么选?
取决于任务的可预规划程度与失败代价。
ReAct(边想边做)每轮根据最新观察决定下一步,适应性强、对信息不确定的任务友好,缺点是容易短视、可能反复试探、总轮数偏高。
Plan-and-Execute(先规划再执行)先生成步骤清单再逐步执行,优点是全局感强、可审计、可并行;缺点是计划一旦错误会一路错下去,且环境变化后计划失效。
实践中常见的组合是两层:外层用规划定大方向(3–6 步),内层用 ReAct 处理每一步的具体不确定性,并在关键节点重新规划。选择标准是:信息在开始时就基本齐备 → 偏规划;信息要边做边获得 → 偏 ReAct。
ReAct(边想边做)每轮根据最新观察决定下一步,适应性强、对信息不确定的任务友好,缺点是容易短视、可能反复试探、总轮数偏高。
Plan-and-Execute(先规划再执行)先生成步骤清单再逐步执行,优点是全局感强、可审计、可并行;缺点是计划一旦错误会一路错下去,且环境变化后计划失效。
实践中常见的组合是两层:外层用规划定大方向(3–6 步),内层用 ReAct 处理每一步的具体不确定性,并在关键节点重新规划。选择标准是:信息在开始时就基本齐备 → 偏规划;信息要边做边获得 → 偏 ReAct。
03 Tool Use 与工具契约 4 问
工具描述怎么写才算好? 高频
把工具描述当成给一个新同事的操作手册,而不是给人看的 API 文档。至少要包含五件事:
① 什么时候该用、什么时候不该用(最重要的,能显著减少误调用);
② 每个参数的业务含义与取值约束(枚举值、格式、范围,以及默认行为);
③ 典型调用示例(一到两个真实例子,最好包含常见错误写法);
④ 返回值结构(模型要能判断调用是否成功、结果里哪个字段才是它要的);
⑤ 失败与边界情况(什么输入会报错、报错长什么样、能不能重试)。
经验数据是:描述质量对调用准确率的影响,往往比换模型更大。所以我们把工具描述当一等公民维护,有版本、有评测。
① 什么时候该用、什么时候不该用(最重要的,能显著减少误调用);
② 每个参数的业务含义与取值约束(枚举值、格式、范围,以及默认行为);
③ 典型调用示例(一到两个真实例子,最好包含常见错误写法);
④ 返回值结构(模型要能判断调用是否成功、结果里哪个字段才是它要的);
⑤ 失败与边界情况(什么输入会报错、报错长什么样、能不能重试)。
经验数据是:描述质量对调用准确率的影响,往往比换模型更大。所以我们把工具描述当一等公民维护,有版本、有评测。
追问链
- 那工具描述和 CLI 的 --help 是同一份吗?
- 怎么验证描述改好了?
模型调用工具失败了,你怎么处理?
先分类,不要统一 try-catch:
① 参数错误(缺必填、类型不对、枚举越界)——可修复,把结构化错误回喂(哪个字段、错在哪里、合法取值集合是什么),允许重试 1–2 轮;
② 权限拒绝——不可自动修复,需要用户授权或换路径,应中断并说明;
③ 超时/限流——可重试,但要指数退避 + 上限,并考虑换通道;
④ 业务性错误(查无此人、条件不满足)——不该重试,这是有效信息,应该把"这个事实"告诉模型让它改变策略;
⑤ 工具自身 bug——不该让模型兜底,要告警并降级。
最容易犯的错是把"业务性错误"当异常重试,结果白白烧掉好几轮预算。
加分点:"业务性错误不该重试"这一条能把有实战经验的人区分出来。 ① 参数错误(缺必填、类型不对、枚举越界)——可修复,把结构化错误回喂(哪个字段、错在哪里、合法取值集合是什么),允许重试 1–2 轮;
② 权限拒绝——不可自动修复,需要用户授权或换路径,应中断并说明;
③ 超时/限流——可重试,但要指数退避 + 上限,并考虑换通道;
④ 业务性错误(查无此人、条件不满足)——不该重试,这是有效信息,应该把"这个事实"告诉模型让它改变策略;
⑤ 工具自身 bug——不该让模型兜底,要告警并降级。
最容易犯的错是把"业务性错误"当异常重试,结果白白烧掉好几轮预算。
MCP 和直接写 Tools 有什么区别?什么时候用哪个? 高频
本质区别是解耦层次:直接写 Tools 是把能力硬编码进 Harness,调用方式、鉴权、协议都是平台自己的;MCP 把"能力暴露与调用"标准化成协议,新增一个上游只需要提供一个 MCP server,平台侧不用改代码。
选型建议:
用 MCP——能力来自外部或第三方、需要生态复用、团队分工上由能力方自己维护、长尾能力多;
用内部 Tools——高频核心链路、需要强管控与极致性能、需要平台级统一配额与审计、参数要深度校验。
真实系统通常是两者并存:核心高频能力走内部工具,长尾与外部能力走 MCP,在模型看来它们是同一套工具抽象。
选型建议:
用 MCP——能力来自外部或第三方、需要生态复用、团队分工上由能力方自己维护、长尾能力多;
用内部 Tools——高频核心链路、需要强管控与极致性能、需要平台级统一配额与审计、参数要深度校验。
真实系统通常是两者并存:核心高频能力走内部工具,长尾与外部能力走 MCP,在模型看来它们是同一套工具抽象。
追问链
- MCP 的安全边界怎么处理?
- 两种工具在权限模型上要区别对待吗?
工具重试导致重复写库、重复发消息,怎么办?
根子上要先给工具分级,再定重试策略:
① 只读查询——随便重试,无副作用;
② 幂等写——可以重试,依赖幂等键去重;
③ 非幂等副作用(发消息、转账、提交表单)——默认不自动重试,改由人工确认或状态查询后决定。
幂等键的做法是:在真正执行前,用「任务 ID + 工具名 + 参数规范化哈希」生成键,写入去重表(带 TTL),执行前先查、执行后标记。这样即便重试也只落地一次。
还要注意一个隐蔽问题:超时不代表没执行。超时后应该先查询执行状态,再决定重试,而不是直接重发。
加分点:"超时不代表没执行"是这一题的分水岭,很多人会漏掉。 ① 只读查询——随便重试,无副作用;
② 幂等写——可以重试,依赖幂等键去重;
③ 非幂等副作用(发消息、转账、提交表单)——默认不自动重试,改由人工确认或状态查询后决定。
幂等键的做法是:在真正执行前,用「任务 ID + 工具名 + 参数规范化哈希」生成键,写入去重表(带 TTL),执行前先查、执行后标记。这样即便重试也只落地一次。
还要注意一个隐蔽问题:超时不代表没执行。超时后应该先查询执行状态,再决定重试,而不是直接重发。
04 Context Engineering 4 问
Prompt Engineering 和 Context Engineering 的区别是什么? 高频
一个很实用的划分:Prompt Engineering 解决"怎么说",Context Engineering 解决"给它看什么"。
前者是措辞、格式、few-shot 的组织、角色与约束的表达;后者是决定模型的可见信息集合——召回哪些内容、裁剪掉哪些、什么时候注入记忆、历史压缩到什么粒度、静态与动态部分怎么排列。
工程上后者的权重更大,因为它决定了效果上限:提示词写得再好,如果关键信息根本没进上下文,模型只能猜。而且 Context Engineering 直接决定成本(token 量、缓存命中率)与延迟,是可量化、可优化的部分。
前者是措辞、格式、few-shot 的组织、角色与约束的表达;后者是决定模型的可见信息集合——召回哪些内容、裁剪掉哪些、什么时候注入记忆、历史压缩到什么粒度、静态与动态部分怎么排列。
工程上后者的权重更大,因为它决定了效果上限:提示词写得再好,如果关键信息根本没进上下文,模型只能猜。而且 Context Engineering 直接决定成本(token 量、缓存命中率)与延迟,是可量化、可优化的部分。
Schema 有几百个字段,你会全塞进 prompt 吗? 高频
不会。全塞进去有三个问题:token 成本高、字段之间互相干扰导致选错、以及破坏前缀稳定性(每次召回的字段集不同,缓存全废)。
分层做法:
① 常驻层——工具名、少量最高频字段、以及"如何获取字段清单"的元工具(让模型能主动查);
② 按需召回层——先用一次轻量检索(关键词或向量)从字段库里召回候选字段子集,再放进上下文;
③ 外置层——完整 schema 放在可查询的资源里,模型需要时通过工具查全量定义。
更稳的做法是两阶段:先让模型输出"我要用到哪些字段",程序校验后把对应 schema 注入,再让它生成最终条件。这样既省 token,也让每一步的生成空间可控、可校验。
分层做法:
① 常驻层——工具名、少量最高频字段、以及"如何获取字段清单"的元工具(让模型能主动查);
② 按需召回层——先用一次轻量检索(关键词或向量)从字段库里召回候选字段子集,再放进上下文;
③ 外置层——完整 schema 放在可查询的资源里,模型需要时通过工具查全量定义。
更稳的做法是两阶段:先让模型输出"我要用到哪些字段",程序校验后把对应 schema 注入,再让它生成最终条件。这样既省 token,也让每一步的生成空间可控、可校验。
追问链
- 那召回错了怎么办?
- 这个两阶段设计会多花一轮,成本上划算吗?
上下文快满了,你怎么知道?压缩策略是什么? 高频
第一件事是主动计量,而不是等 API 报错。每次组装上下文前精确算 token(含工具 schema 与预留的输出预算),维护一个"预算水位"。触发阈值通常设在 70%–80%,给自己留出压缩和重试的余量。
压缩按"损伤从小到大"分三级:
① 裁剪——工具结果只保留关键字段,丢弃冗长的原始响应、日志、重复内容。这一级几乎无损,应该常态化执行;
② 摘要化——把早期历史替换成摘要,只保留决策与结论,丢掉推理过程;
③ 外置——把大块内容(长文档、大 JSON、已完成产物)落盘,上下文里只留指针(路径、ID、摘要),需要时通过工具回读。
关键设计是摘要里必须保留指针,否则信息真丢了。压缩要记日志、最好对用户可见,并且可回滚。
加分点:强调"摘要保留指针 + 压缩可回滚",是从"能跑"到"能上生产"的差别。 压缩按"损伤从小到大"分三级:
① 裁剪——工具结果只保留关键字段,丢弃冗长的原始响应、日志、重复内容。这一级几乎无损,应该常态化执行;
② 摘要化——把早期历史替换成摘要,只保留决策与结论,丢掉推理过程;
③ 外置——把大块内容(长文档、大 JSON、已完成产物)落盘,上下文里只留指针(路径、ID、摘要),需要时通过工具回读。
关键设计是摘要里必须保留指针,否则信息真丢了。压缩要记日志、最好对用户可见,并且可回滚。
为什么上下文的排列顺序会影响成本?
因为缓存是前缀匹配的。缓存从第一个 token 开始比对,遇到第一个不同点,之后的全部失效。所以排列顺序直接决定命中率:
稳定内容放前面(静态 system prompt、工具列表按固定顺序、few-shot 固定不变),动态内容放后面(当前时间、用户信息、本轮检索结果、新增历史)。
常见的反面写法很隐蔽:把当前时间戳放在 system prompt 开头、每次按使用频率重排工具列表、把召回片段按相关度排序(顺序每次不同)、在开头注入会话 ID。这些都会让整段缓存作废,成本可能差好几倍,而日志上完全看不出来——只能靠监控命中率发现。
稳定内容放前面(静态 system prompt、工具列表按固定顺序、few-shot 固定不变),动态内容放后面(当前时间、用户信息、本轮检索结果、新增历史)。
常见的反面写法很隐蔽:把当前时间戳放在 system prompt 开头、每次按使用频率重排工具列表、把召回片段按相关度排序(顺序每次不同)、在开头注入会话 ID。这些都会让整段缓存作废,成本可能差好几倍,而日志上完全看不出来——只能靠监控命中率发现。
05 Memory 记忆系统 3 问
长期记忆你会存什么?什么时候写? 高频
存的内容分三类:偏好记忆(用户的表达风格、格式要求、反感什么)、事实记忆(用户的身份、所在团队、长期目标等稳定信息)、场景记忆(某类任务上一次是怎么做成的、踩过什么坑)。
写入时机是这道题的关键:只在信号足够强的时候写——用户显式纠正("以后别用表格")、用户显式声明("我在做招聘")、或者同一偏好被重复观察到多次。绝不能把每一次会话里的临时要求都写进去,否则记忆区会变成噪声区,注入后反而干扰判断。
配套要求:写入带时间戳与来源,支持用户查看与删除,并设置 TTL 或衰减机制。
写入时机是这道题的关键:只在信号足够强的时候写——用户显式纠正("以后别用表格")、用户显式声明("我在做招聘")、或者同一偏好被重复观察到多次。绝不能把每一次会话里的临时要求都写进去,否则记忆区会变成噪声区,注入后反而干扰判断。
配套要求:写入带时间戳与来源,支持用户查看与删除,并设置 TTL 或衰减机制。
追问链
- 怎么防止把一次性偏好写进去?
- 记忆检索是走向量还是规则?
记忆和新事实冲突了怎么办?
不能简单地"新的覆盖旧的",因为新的未必更对。我的处理是分层消解:
① 先分类——是"偏好变化"还是"事实变化"?偏好变化(从喜欢表格改成喜欢列表)通常是覆盖;事实变化(换团队了)也是覆盖,但要保留历史区间。
② 带时间与置信度——每条记忆都有生效时间与置信度,冲突时高置信度优先;同等置信度则新的优先,但把旧的标记为 superseded 而不是删除。
③ 不可消解就暴露给用户——如果两条记忆指向矛盾结论(用户说"汇报要简洁",但历史反馈显示他常要求补充细节),不要自己赌,应该在输出时给出选择或直接询问。
核心原则是:记忆系统要能解释自己为什么这么判断,否则出错时无法排查。
① 先分类——是"偏好变化"还是"事实变化"?偏好变化(从喜欢表格改成喜欢列表)通常是覆盖;事实变化(换团队了)也是覆盖,但要保留历史区间。
② 带时间与置信度——每条记忆都有生效时间与置信度,冲突时高置信度优先;同等置信度则新的优先,但把旧的标记为 superseded 而不是删除。
③ 不可消解就暴露给用户——如果两条记忆指向矛盾结论(用户说"汇报要简洁",但历史反馈显示他常要求补充细节),不要自己赌,应该在输出时给出选择或直接询问。
核心原则是:记忆系统要能解释自己为什么这么判断,否则出错时无法排查。
怎么证明记忆让效果变好了,而不是让输出变得飘忽?
把记忆当成一个可评测的改动,而不是默认有益的机制。
做法是 A/B:同一批任务分别跑「注入记忆」与「不注入记忆」两条链路,对比任务完成率、人工介入次数、以及目标风格的一致率。要特别关注负向信号:注入记忆后,模型是否开始在不相关场景里生搬硬套旧偏好(过拟合);是否出现"忘了任务本身要求,只记得风格要求"(注意力争夺)。
工程上还有两个必要设计:记忆可关闭(某个任务可以临时不使用历史偏好)和记忆可追溯(输出里能看出用了哪条记忆)。没有这两样,记忆出问题时你会连原因都定位不到。
加分点:把"记忆可能有害"当成前提来设计,是这道题最容易被忽略的深度。 做法是 A/B:同一批任务分别跑「注入记忆」与「不注入记忆」两条链路,对比任务完成率、人工介入次数、以及目标风格的一致率。要特别关注负向信号:注入记忆后,模型是否开始在不相关场景里生搬硬套旧偏好(过拟合);是否出现"忘了任务本身要求,只记得风格要求"(注意力争夺)。
工程上还有两个必要设计:记忆可关闭(某个任务可以临时不使用历史偏好)和记忆可追溯(输出里能看出用了哪条记忆)。没有这两样,记忆出问题时你会连原因都定位不到。
06 Subagent 与多智能体编排 3 问
为什么要用 Subagent,而不是一个长上下文 Agent 一直做下去? 高频
三个理由,按重要性排序:
① 上下文隔离——如果所有子任务都塞进同一个上下文,会互相污染(无关信息干扰判断),而且上下文会迅速膨胀到需要频繁压缩,压缩就会丢信息。Subagent 各自持有干净上下文,只装载与自己任务相关的信息。
② 并行提速——互相独立的子任务可以并发执行,端到端时间从求和变成取最大值。
③ 权限与提示隔离——不同子任务需要的工具权限不同(读数据的和写数据库的不该有同样的能力),分 Agent 天然形成权限边界;同时每个 Subagent 可以有专门化的提示词,比一个"什么都会"的通用提示更稳。
但要多说一句:跨 Agent 传递只走结构化产物(文件、JSON 结果),不要用自然语言转述,否则会引入"传话失真",这是多 Agent 系统最常见的翻车方式。
① 上下文隔离——如果所有子任务都塞进同一个上下文,会互相污染(无关信息干扰判断),而且上下文会迅速膨胀到需要频繁压缩,压缩就会丢信息。Subagent 各自持有干净上下文,只装载与自己任务相关的信息。
② 并行提速——互相独立的子任务可以并发执行,端到端时间从求和变成取最大值。
③ 权限与提示隔离——不同子任务需要的工具权限不同(读数据的和写数据库的不该有同样的能力),分 Agent 天然形成权限边界;同时每个 Subagent 可以有专门化的提示词,比一个"什么都会"的通用提示更稳。
但要多说一句:跨 Agent 传递只走结构化产物(文件、JSON 结果),不要用自然语言转述,否则会引入"传话失真",这是多 Agent 系统最常见的翻车方式。
追问链
- 部分子任务失败了怎么办?
- 结果汇总阶段会不会又变成一个长上下文问题?
多 Agent 怎么协作?有哪些组件?
一个可用的最小架构包含六部分:
① Orchestrator(调度与规划,负责拆任务、下发、汇总);
② Subagent Pool(执行单元,各自独立上下文与能力集);
③ 通信层(结构化消息:任务目标 + 约束 + 输入产物指针 + 期望输出 schema);
④ 结果汇总层(按 schema 校验、去重、冲突标注);
⑤ 失败隔离层(单个子任务失败不阻塞其他,可重试或降级,明确"部分成功"语义);
⑥ 可观测层(每个 Subagent 的 trace 挂到同一个任务链路下)。
模式上主要三种:Supervisor(集中调度,适合任务可明确分解)、Pipeline(固定阶段流水线,适合稳定流程)、去中心化(适合探索型、无明确分解方案)。
选型标准是任务可分解性 + 失败隔离需求——不是 Agent 越多越好。
加分点:主动说"不是越多越好,多 Agent 的协调成本会吃掉收益",是成熟的信号。 ① Orchestrator(调度与规划,负责拆任务、下发、汇总);
② Subagent Pool(执行单元,各自独立上下文与能力集);
③ 通信层(结构化消息:任务目标 + 约束 + 输入产物指针 + 期望输出 schema);
④ 结果汇总层(按 schema 校验、去重、冲突标注);
⑤ 失败隔离层(单个子任务失败不阻塞其他,可重试或降级,明确"部分成功"语义);
⑥ 可观测层(每个 Subagent 的 trace 挂到同一个任务链路下)。
模式上主要三种:Supervisor(集中调度,适合任务可明确分解)、Pipeline(固定阶段流水线,适合稳定流程)、去中心化(适合探索型、无明确分解方案)。
选型标准是任务可分解性 + 失败隔离需求——不是 Agent 越多越好。
多 Agent 系统的常见踩坑有哪些?
四类高频问题:
① 传话失真——用自然语言在 Agent 之间转述需求,每转一手丢一点信息。解法是只传结构化产物,且用 schema 强制约束。
② 上下文重复膨胀——为了"让子 Agent 有足够信息",把主上下文整个复制下去,结果每个子 Agent 都背着几十 K token,成本和延迟全部失控。解法是只下发该子任务的最小必要上下文,其余通过工具按需拉取。
③ 汇总变成新的长上下文——Oracle 把所有子结果原文拼起来再决策,又回到长上下文问题。解法是要求子 Agent 输出结构化摘要 + 产物指针,汇总层只读摘要,需要细节时回读产物。
④ 死锁与循环等待——A 等 B 的结论、B 等 A 的输入。解法是显式依赖图 + 超时 + 单向数据流。
① 传话失真——用自然语言在 Agent 之间转述需求,每转一手丢一点信息。解法是只传结构化产物,且用 schema 强制约束。
② 上下文重复膨胀——为了"让子 Agent 有足够信息",把主上下文整个复制下去,结果每个子 Agent 都背着几十 K token,成本和延迟全部失控。解法是只下发该子任务的最小必要上下文,其余通过工具按需拉取。
③ 汇总变成新的长上下文——Oracle 把所有子结果原文拼起来再决策,又回到长上下文问题。解法是要求子 Agent 输出结构化摘要 + 产物指针,汇总层只读摘要,需要细节时回读产物。
④ 死锁与循环等待——A 等 B 的结论、B 等 A 的输入。解法是显式依赖图 + 超时 + 单向数据流。
07 沙箱、权限与提示注入 3 问
工具要不要跑在沙箱里?桌面端怎么设计? 高频
只要工具能产生副作用,就应该有边界。
隔离强度的选择是权衡:进程级隔离轻量、启动快,适合纯计算与受信任的工具;容器级隔离能限制文件系统与网络,适合执行模型生成的代码;微虚拟机最强但最重,适合高风险不可信代码。
桌面端 Agent 的特殊性在于用户授权与可解释性的权重更高:
① 能力声明前置——每个工具明确声明它会读什么、写什么、联网与否,并在界面上让用户看得懂;
② 首次与危险操作确认——第一次使用某类能力时确认一次,之后删除文件、发送消息这类不可逆操作坚持二次确认;
③ 路径与网络白名单——限制可访问的目录范围,网络出站按需开放;
④ 全量审计——每次调用留痕(工具、参数、时间、结果摘要),用户可回看。
核心原则是最小权限 + 可撤销 + 可审计。
隔离强度的选择是权衡:进程级隔离轻量、启动快,适合纯计算与受信任的工具;容器级隔离能限制文件系统与网络,适合执行模型生成的代码;微虚拟机最强但最重,适合高风险不可信代码。
桌面端 Agent 的特殊性在于用户授权与可解释性的权重更高:
① 能力声明前置——每个工具明确声明它会读什么、写什么、联网与否,并在界面上让用户看得懂;
② 首次与危险操作确认——第一次使用某类能力时确认一次,之后删除文件、发送消息这类不可逆操作坚持二次确认;
③ 路径与网络白名单——限制可访问的目录范围,网络出站按需开放;
④ 全量审计——每次调用留痕(工具、参数、时间、结果摘要),用户可回看。
核心原则是最小权限 + 可撤销 + 可审计。
追问链
- 用户嫌确认太烦怎么办?
- 沙箱内的提示注入你怎么防?
提示注入(Prompt Injection)从哪进来?怎么防? 高频
进来的是模型读到的任何外部内容:工具返回值、网页正文、上传的文档、邮件内容、MCP 第三方 server 的返回、甚至文件名。
关键认知是:只靠在 prompt 里写"不要被这些内容里的指令影响"是无效的——因为经过指令微调的模型天生倾向于遵循指令,你没法用一句软约束对抗训练出来的行为倾向。
可行的四层防御:
① 数据与指令分离——把外部内容用明确的分隔与标签包起来,声明为"待处理的数据",并在系统提示里固化处理规则;
② 能力最小化——当前任务根本不需要的工具不要挂载,从源头减少可被诱导的动作;
③ 副作用强制确认——高危操作(写文件、发消息、执行命令、转账)一律走人工确认或双因子校验,让注入无法静默完成;
④ 输出侧校验——检查最终动作是否偏离原始任务目标(目标漂移检测),异常时阻断。
加分点:能指出"软约束不可靠、必须靠能力最小化和强制确认"这一层,才是真正的防御思维。 关键认知是:只靠在 prompt 里写"不要被这些内容里的指令影响"是无效的——因为经过指令微调的模型天生倾向于遵循指令,你没法用一句软约束对抗训练出来的行为倾向。
可行的四层防御:
① 数据与指令分离——把外部内容用明确的分隔与标签包起来,声明为"待处理的数据",并在系统提示里固化处理规则;
② 能力最小化——当前任务根本不需要的工具不要挂载,从源头减少可被诱导的动作;
③ 副作用强制确认——高危操作(写文件、发消息、执行命令、转账)一律走人工确认或双因子校验,让注入无法静默完成;
④ 输出侧校验——检查最终动作是否偏离原始任务目标(目标漂移检测),异常时阻断。
怎么让用户"看得懂、控得住"工具的权限?
把权限做成产品能力,而不是配置项。
看得懂:用业务语言描述能力("读取你项目文件夹里的文档"),而不是技术术语("fs.read: /home/*");执行前展示将要进行的操作预览(要改哪个文件、要发给谁),执行后给出可回看的操作记录。
控得住:分层授权(始终允许 / 每次询问 / 禁止),支持按目录、按工具、按任务临时授权;提供一键撤销与会话级回收;对不可逆操作强制二次确认。
兜底:所有副作用操作留痕可审计,且尽量设计成可回滚(写文件先备份、批量操作先给 diff)。
一个判断标准:如果用户无法回答"它刚才到底做了什么",那就是权限设计失败了。
看得懂:用业务语言描述能力("读取你项目文件夹里的文档"),而不是技术术语("fs.read: /home/*");执行前展示将要进行的操作预览(要改哪个文件、要发给谁),执行后给出可回看的操作记录。
控得住:分层授权(始终允许 / 每次询问 / 禁止),支持按目录、按工具、按任务临时授权;提供一键撤销与会话级回收;对不可逆操作强制二次确认。
兜底:所有副作用操作留痕可审计,且尽量设计成可回滚(写文件先备份、批量操作先给 diff)。
一个判断标准:如果用户无法回答"它刚才到底做了什么",那就是权限设计失败了。
08 长任务与失败恢复 4 问
你做 Agent 的时候遇到过哪些工程挑战? 高频
这道题是分水岭:回答"减少幻觉、提升长程推理能力"是研究问题,会被判定站位不对。要答工程问题,例如:
① provider 侧不稳定——限流、超时、通道抖动,需要多通道抽象 + 健康探测 + 自动切换 + 切换后的结果一致性校验;
② 流式输出卡死——连接还在但不出 token,需要首 token 超时 + 空闲心跳超时 + 强制中断与重试;
③ 上下文溢出——主动计量、分级压缩、状态外置,并在触发时给用户可见提示;
④ 长任务中断恢复——进程被杀、机器重启,需要任务状态机 + 检查点 + 断点续跑;
⑤ 副作用重复——重试导致重复写库,需要幂等键与去重表;
⑥ 成本失控——预算上限、轮数上限、缓存友好前缀;
⑦ 变更风险——prompt 一改就翻车,需要版本化、灰度、自动回滚。
答完再补一句:这些问题的共同点是"模型没坏,是系统没兜住",这正是 Harness 存在的价值。
① provider 侧不稳定——限流、超时、通道抖动,需要多通道抽象 + 健康探测 + 自动切换 + 切换后的结果一致性校验;
② 流式输出卡死——连接还在但不出 token,需要首 token 超时 + 空闲心跳超时 + 强制中断与重试;
③ 上下文溢出——主动计量、分级压缩、状态外置,并在触发时给用户可见提示;
④ 长任务中断恢复——进程被杀、机器重启,需要任务状态机 + 检查点 + 断点续跑;
⑤ 副作用重复——重试导致重复写库,需要幂等键与去重表;
⑥ 成本失控——预算上限、轮数上限、缓存友好前缀;
⑦ 变更风险——prompt 一改就翻车,需要版本化、灰度、自动回滚。
答完再补一句:这些问题的共同点是"模型没坏,是系统没兜住",这正是 Harness 存在的价值。
追问链
- 流式卡死具体怎么检测?阈值怎么定?
- 上下文自动压缩在架构上放在哪一层?
模型输出卡死(连接还在但不出 token)怎么发现、怎么恢复? 高频
三级超时 + 一次中断:
① 首 token 超时——从发起请求到收到第一个 token 的时间上限。这能抓住"请求已受理但模型排队/卡住"的情况,阈值取实测 P99 再放宽,比如 30–60 秒。
② 空闲心跳超时——两个相邻 token 之间的最大间隔。这能抓住"已经开始输出但中途挂住"的情况,阈值可以比首 token 短得多,比如 10–20 秒。
③ 总时长上限——整个响应的时间上限,防止"一直缓慢吐字"把任务无限拖下去。
任一触发就主动中断连接(不要等对端),记录现场(已收到的部分内容、耗时、阶段),然后按策略恢复:同一通道重试 → 换通道重试 → 降级到非流式 → 报错并把中间结果交出。
判断"慢"还是"死"的关键是心跳:只要还在稳定吐字就不算卡死,所以不能只看总时长。
加分点:说清"总时长上限和心跳超时抓的是不同故障",并强调不能只看总时长,这是关键细节。 ① 首 token 超时——从发起请求到收到第一个 token 的时间上限。这能抓住"请求已受理但模型排队/卡住"的情况,阈值取实测 P99 再放宽,比如 30–60 秒。
② 空闲心跳超时——两个相邻 token 之间的最大间隔。这能抓住"已经开始输出但中途挂住"的情况,阈值可以比首 token 短得多,比如 10–20 秒。
③ 总时长上限——整个响应的时间上限,防止"一直缓慢吐字"把任务无限拖下去。
任一触发就主动中断连接(不要等对端),记录现场(已收到的部分内容、耗时、阶段),然后按策略恢复:同一通道重试 → 换通道重试 → 降级到非流式 → 报错并把中间结果交出。
判断"慢"还是"死"的关键是心跳:只要还在稳定吐字就不算卡死,所以不能只看总时长。
长任务跑到一半崩了怎么办?
靠任务状态机 + 检查点,而不是靠重跑。
状态机至少要覆盖:排队、运行、等待人工确认、暂停、成功、失败、重试中、已取消——每个状态有明确的进入/退出条件与持久化内容。
检查点要落盘四样东西:任务目标与约束、已完成步骤清单、每步的产物指针、下一步计划。落盘时机选在"每个子目标完成之后"而不是固定时间间隔,因为子目标边界才是真正的可恢复点。
恢复流程是:读出检查点 → 校验产物是否已存在(避免重复执行)→ 从下一个未完成步骤继续,并把"之前发生过什么"用摘要注入上下文。
还有一个容易被忽略的点:重试不能重复副作用,所以恢复时必须先查状态再决定是否执行,而不是无条件重放。
状态机至少要覆盖:排队、运行、等待人工确认、暂停、成功、失败、重试中、已取消——每个状态有明确的进入/退出条件与持久化内容。
检查点要落盘四样东西:任务目标与约束、已完成步骤清单、每步的产物指针、下一步计划。落盘时机选在"每个子目标完成之后"而不是固定时间间隔,因为子目标边界才是真正的可恢复点。
恢复流程是:读出检查点 → 校验产物是否已存在(避免重复执行)→ 从下一个未完成步骤继续,并把"之前发生过什么"用摘要注入上下文。
还有一个容易被忽略的点:重试不能重复副作用,所以恢复时必须先查状态再决定是否执行,而不是无条件重放。
你的系统怎么区分"工具超时了"和"工具执行失败了"?
这个区分很重要,因为处理方式完全不同:
执行失败意味着服务明确返回了错误(4xx/5xx、业务异常),说明请求已被处理且结果是失败——通常不该原样重试,要么修参数,要么换方案。
超时意味着我们只是没等到回应,请求可能成功了、可能失败了、也可能还在执行中——这叫"结果未知",比失败更危险,直接重试可能造成重复副作用。
所以正确做法是:对可能产生副作用的工具,超时后先走状态查询(用幂等键或业务 ID 查这次调用到底有没有生效),确认未生效才重试;如果工具没有查询接口,就不该给它自动重试的权限,只能上报人工处理。
这也解释了为什么设计工具时就要把幂等键和查询能力作为契约的一部分,而不是事后补。
加分点:把"结果未知比失败更危险"讲出来,是很有经验感的表达。 执行失败意味着服务明确返回了错误(4xx/5xx、业务异常),说明请求已被处理且结果是失败——通常不该原样重试,要么修参数,要么换方案。
超时意味着我们只是没等到回应,请求可能成功了、可能失败了、也可能还在执行中——这叫"结果未知",比失败更危险,直接重试可能造成重复副作用。
所以正确做法是:对可能产生副作用的工具,超时后先走状态查询(用幂等键或业务 ID 查这次调用到底有没有生效),确认未生效才重试;如果工具没有查询接口,就不该给它自动重试的权限,只能上报人工处理。
这也解释了为什么设计工具时就要把幂等键和查询能力作为契约的一部分,而不是事后补。
III · 评测工程 Evaluation Engineering
01 评测的第一性问题 3 问
你怎么知道一版改动真的让 Agent 变好了? 高频
需要三样东西同时具备,缺一个结论就不成立:
① 固定的评测集——改动前后跑的是同一批题,否则数字不可比;
② 明确的基线——上一版的数据是什么,没有基线就没有"变好"这个概念;
③ 噪声估计——同一版本重复跑多次,看指标的波动区间。如果提升幅度落在波动区间内,那不能算改进。
实践上还要注意两点:看分布而不只看均值(平均分涨了但某些关键场景崩塌,这是净损失);区分"变好"和"变长"(轮数变多、token 变多往往能刷高完成率,但用户体验和成本都变差了,所以指标必须成组看)。
① 固定的评测集——改动前后跑的是同一批题,否则数字不可比;
② 明确的基线——上一版的数据是什么,没有基线就没有"变好"这个概念;
③ 噪声估计——同一版本重复跑多次,看指标的波动区间。如果提升幅度落在波动区间内,那不能算改进。
实践上还要注意两点:看分布而不只看均值(平均分涨了但某些关键场景崩塌,这是净损失);区分"变好"和"变长"(轮数变多、token 变多往往能刷高完成率,但用户体验和成本都变差了,所以指标必须成组看)。
追问链
- 怎么估计噪声?
- 如果提升只有 2 个百分点,你上线吗?
为什么说"感觉这次好多了"不能作为工程结论?
因为人的主观判断有三个系统性偏差:
① 样本偏差——你试的往往是自己熟悉的几个 case,而线上失败集中在长尾;
② 确认偏差——你刚改完,倾向于把符合预期的表现看成改进,把不符合的看成偶然;
③ 无基线——没有同时跑旧版本,等于没有对照,无法排除"这次任务本来就简单"。
不是说主观判断没价值,它的正确用途是发现"哪里不对"(产生假设),而不是判断"是否变好"(验证假设)。前者靠人,后者靠评测。
① 样本偏差——你试的往往是自己熟悉的几个 case,而线上失败集中在长尾;
② 确认偏差——你刚改完,倾向于把符合预期的表现看成改进,把不符合的看成偶然;
③ 无基线——没有同时跑旧版本,等于没有对照,无法排除"这次任务本来就简单"。
不是说主观判断没价值,它的正确用途是发现"哪里不对"(产生假设),而不是判断"是否变好"(验证假设)。前者靠人,后者靠评测。
离线评测和线上指标的关系是什么?
两者回答不同的问题,不能互相替代:
离线评测回答"在受控条件下,这一版的正确性有没有退化"——可复现、可归因、能拦住回归,但它的任务分布是过去的,未必代表未来。
线上指标回答"在真实流量下,用户是否真的受益"——分布真实,但噪声大、混杂因素多(用户群变化、流量结构变化),归因困难。
正确的用法是用离线守回归底线,用线上看真实收益:离线不通过不上线;离线通过后灰度上线,用线上数据验证;线上出现新的 badcase,回流进离线评测集。离线评测集就是由线上 badcase 长出来的,这样两者才形成一个闭环而不是两套体系。
离线评测回答"在受控条件下,这一版的正确性有没有退化"——可复现、可归因、能拦住回归,但它的任务分布是过去的,未必代表未来。
线上指标回答"在真实流量下,用户是否真的受益"——分布真实,但噪声大、混杂因素多(用户群变化、流量结构变化),归因困难。
正确的用法是用离线守回归底线,用线上看真实收益:离线不通过不上线;离线通过后灰度上线,用线上数据验证;线上出现新的 badcase,回流进离线评测集。离线评测集就是由线上 badcase 长出来的,这样两者才形成一个闭环而不是两套体系。
02 评测集建设与防过拟合 3 问
你的评测集是怎么建起来的? 高频
主要来源是线上真实使用,而不是拍脑袋造题。具体三步:
① 采集——从线上失败案例(用户重试、纠错、放弃、人工介入的会话)中捞取原始输入与完整链路,这些是最有信息量的样本;
② 归因分类——把失败按原因打标(理解错意图 / 参数生成错 / 工具选择错 / 上下文缺失 / 表达问题),保证每个类别的样本数够,否则指标会被大类淹没;
③ 固化——整理成带期望输出的测试用例,人工确认标注正确后入库,并保留原始链路便于 replay。
另外要主动构造一部分边界与对抗样本:模糊表述、自相矛盾的输入、超长输入、以及"工具返回了恶意内容"的注入场景——这些线上出现频次低但破坏力大,靠等线上出现太被动。
① 采集——从线上失败案例(用户重试、纠错、放弃、人工介入的会话)中捞取原始输入与完整链路,这些是最有信息量的样本;
② 归因分类——把失败按原因打标(理解错意图 / 参数生成错 / 工具选择错 / 上下文缺失 / 表达问题),保证每个类别的样本数够,否则指标会被大类淹没;
③ 固化——整理成带期望输出的测试用例,人工确认标注正确后入库,并保留原始链路便于 replay。
另外要主动构造一部分边界与对抗样本:模糊表述、自相矛盾的输入、超长输入、以及"工具返回了恶意内容"的注入场景——这些线上出现频次低但破坏力大,靠等线上出现太被动。
追问链
- 多少条算够?
- 怎么保证评测集不过期?
评测集多少条才够用?
没有绝对数字,取决于你要检测多大的差异。经验规律是:样本量越小,能分辨的最小差异越大。
几十条的评测集只能发现"明显崩了"(掉了十几个百分点),无法判断"提升 2% 是不是真的";要稳定分辨几个百分点级别的差异,通常需要几百条量级,而且每个关键类别(而不是总数)都要有足够样本——因为指标是按类别看的。
更实用的建议是先建小而纯,再逐步扩充:30–50 条覆盖核心场景的"冒烟集",用来快速拦住大回归;300 条以上的"回归集",用来判断小改动是否有效。不要一开始就追求几千条,那会因为标注质量参差而变得不可信。
加分点:强调"按类别保证样本量"而不是只看总数,说明你真的用过评测集。 几十条的评测集只能发现"明显崩了"(掉了十几个百分点),无法判断"提升 2% 是不是真的";要稳定分辨几个百分点级别的差异,通常需要几百条量级,而且每个关键类别(而不是总数)都要有足够样本——因为指标是按类别看的。
更实用的建议是先建小而纯,再逐步扩充:30–50 条覆盖核心场景的"冒烟集",用来快速拦住大回归;300 条以上的"回归集",用来判断小改动是否有效。不要一开始就追求几千条,那会因为标注质量参差而变得不可信。
怎么防止系统把评测集"背下来"?
三个机制:
① 保留集(hold-out)——把评测集切成可见/不可见两部分。调优时只能看可见部分,最终验收用不可见部分。如果两者差距很大,说明过拟合了。
② 持续注入新样本——评测集不是一次建完的静态资产,线上新 badcase 要持续回流,让评测集不断变难。一个长期不更新的评测集,指标会逐渐失去区分度。
③ 生成式与参数化样本——对于可枚举的任务(查询条件生成、参数填充),用模板 + 参数组合自动生成大批样本,让"记住答案"在成本上不可行。
判断是否过拟合的信号很直接:评测集上稳步提升,但线上指标不动甚至下降。出现这个现象就要立刻检查评测集是否已经泄漏。
① 保留集(hold-out)——把评测集切成可见/不可见两部分。调优时只能看可见部分,最终验收用不可见部分。如果两者差距很大,说明过拟合了。
② 持续注入新样本——评测集不是一次建完的静态资产,线上新 badcase 要持续回流,让评测集不断变难。一个长期不更新的评测集,指标会逐渐失去区分度。
③ 生成式与参数化样本——对于可枚举的任务(查询条件生成、参数填充),用模板 + 参数组合自动生成大批样本,让"记住答案"在成本上不可行。
判断是否过拟合的信号很直接:评测集上稳步提升,但线上指标不动甚至下降。出现这个现象就要立刻检查评测集是否已经泄漏。
03 办事型 Agent 的硬指标 3 问
"参数生成准确性"具体怎么算? 高频
不能一句话"用 LLM 打分"糊过去,要分类型定义口径:
① 枚举类参数(状态、类型、操作符)——精确匹配。生成值必须在合法枚举集合内且与期望一致,错一个就是错。
② 数值类参数(阈值、数量、日期区间)——精确匹配或带明确容差的近似匹配,容差要事前写清楚(例如日期允许 ±0,金额允许 ±0.01)。
③ 自由文本参数(检索关键词、描述字段)——结构化逐项比对:先把期望拆成必含要素集合,再检查生成结果覆盖了哪些要素,得分是覆盖率;若有明确禁止项,命中即扣分。
④ 集合类参数(多选标签、字段列表)——用精确率/召回率或 Jaccard 相似度,而不是"差不多就行"。
还有两个必须明确的口径问题:分母是什么(所有调用,还是只统计"模型认为该调用工具"的那些);部分正确怎么算(4 个参数对 3 个,是算 0 还是 0.75——不同选择会得出完全不同的结论)。
① 枚举类参数(状态、类型、操作符)——精确匹配。生成值必须在合法枚举集合内且与期望一致,错一个就是错。
② 数值类参数(阈值、数量、日期区间)——精确匹配或带明确容差的近似匹配,容差要事前写清楚(例如日期允许 ±0,金额允许 ±0.01)。
③ 自由文本参数(检索关键词、描述字段)——结构化逐项比对:先把期望拆成必含要素集合,再检查生成结果覆盖了哪些要素,得分是覆盖率;若有明确禁止项,命中即扣分。
④ 集合类参数(多选标签、字段列表)——用精确率/召回率或 Jaccard 相似度,而不是"差不多就行"。
还有两个必须明确的口径问题:分母是什么(所有调用,还是只统计"模型认为该调用工具"的那些);部分正确怎么算(4 个参数对 3 个,是算 0 还是 0.75——不同选择会得出完全不同的结论)。
追问链
- 分母你选哪个?为什么?
- 部分正确你怎么处理?
工具调用成功率这个指标有什么陷阱?
至少四个陷阱:
① 分母陷阱——如果把"模型压根没调工具"的情况排除在分母外,成功率会虚高,掩盖"该调不调"的问题。分母应该是所有本应调用工具的场景。
② 成功定义陷阱——HTTP 200 不等于任务成功。要区分"调用发出成功""参数正确""业务结果符合预期"三层,混在一起会看不出问题在哪。
③ 难度混同陷阱——把简单查询和复杂多步任务混在一个数字里,任何改动都会被大类淹没。应该按任务类型分层看。
④ 重试归因陷阱——经过重试才成功的算不算成功?我倾向于分开统计:一次成功率(反映模型质量)与最终成功率(反映系统兜底能力),两者同时看。只看最终成功率,会让"重试兜住一切"掩盖模型本身的问题。
加分点:"一次成功率 vs 最终成功率"分开看,是很能体现工程思维的细节。 ① 分母陷阱——如果把"模型压根没调工具"的情况排除在分母外,成功率会虚高,掩盖"该调不调"的问题。分母应该是所有本应调用工具的场景。
② 成功定义陷阱——HTTP 200 不等于任务成功。要区分"调用发出成功""参数正确""业务结果符合预期"三层,混在一起会看不出问题在哪。
③ 难度混同陷阱——把简单查询和复杂多步任务混在一个数字里,任何改动都会被大类淹没。应该按任务类型分层看。
④ 重试归因陷阱——经过重试才成功的算不算成功?我倾向于分开统计:一次成功率(反映模型质量)与最终成功率(反映系统兜底能力),两者同时看。只看最终成功率,会让"重试兜住一切"掩盖模型本身的问题。
任务完成率怎么定义?由谁判定?
定义上要区分三种口径,并明确说明用的是哪种:
① 自动化判定——任务有明确的可验证结果(生成了符合条件的文件、查询返回了非空结果、代码通过了测试),这是最可靠的,应当优先把任务设计成可自动验证的。
② 模型判定——用 LLM 对照 rubric 打分,适用于结果无法程序化验证的场景,必须配人工抽检校准。
③ 人工判定——最准但成本最高,用于校准前两者、以及构建金标准集。
工程上的目标是把尽可能多的任务转化为第 ① 类:给任务设计机器可验证的产出(结构化结果、断言、测试),这比提高打分模型的准确率更根本。
① 自动化判定——任务有明确的可验证结果(生成了符合条件的文件、查询返回了非空结果、代码通过了测试),这是最可靠的,应当优先把任务设计成可自动验证的。
② 模型判定——用 LLM 对照 rubric 打分,适用于结果无法程序化验证的场景,必须配人工抽检校准。
③ 人工判定——最准但成本最高,用于校准前两者、以及构建金标准集。
工程上的目标是把尽可能多的任务转化为第 ① 类:给任务设计机器可验证的产出(结构化结果、断言、测试),这比提高打分模型的准确率更根本。
04 洞察型评分与 LLM-as-Judge 3 问
洞察型 Agent 的"内容质量"怎么评? 高频
先把"好不好"拆成可独立判断的维度,每个维度给可操作的 rubric:
① 方向相关性——产出的分析是否落在问题上,有没有跑偏到无关角度;
② 证据充分性——结论是否有可溯源的数据支撑,还是只是合理推测;
③ 可操作性——是否给出了能落地的判断或建议,而不是正确的废话;
④ 表达清晰度——结构是否清楚、重点是否突出、有没有冗余。
每个维度用 3–5 级量表并写清每级的判定标准(rubric 的关键是让不同评分者得出接近的结果)。
最重要的设计是:维度分不是用来算总分的,而是用来做归因的——低分出现在"证据充分性",说明是检索没召回;出现在"表达清晰度",说明是提示或组织问题。只有能定位到环节,评分才有迭代价值。
① 方向相关性——产出的分析是否落在问题上,有没有跑偏到无关角度;
② 证据充分性——结论是否有可溯源的数据支撑,还是只是合理推测;
③ 可操作性——是否给出了能落地的判断或建议,而不是正确的废话;
④ 表达清晰度——结构是否清楚、重点是否突出、有没有冗余。
每个维度用 3–5 级量表并写清每级的判定标准(rubric 的关键是让不同评分者得出接近的结果)。
最重要的设计是:维度分不是用来算总分的,而是用来做归因的——低分出现在"证据充分性",说明是检索没召回;出现在"表达清晰度",说明是提示或组织问题。只有能定位到环节,评分才有迭代价值。
追问链
- 维度之间高度相关怎么办?
- 怎么知道评分标准本身是合理的?
LLM-as-Judge 有哪些偏差?怎么控制? 高频
四类主要偏差与对策:
① 位置偏差——倾向给排在前面的答案更高分。对策:交换顺序各评一次,取一致结论;不一致就判为平局或人工介入。
② 长度偏差——倾向给更长、更"全面"的回答高分。对策:rubric 里显式区分"信息量"与"篇幅",加一条"冗余扣分";或对长度做归一化后再比较。
③ 自我偏好——偏爱自己(同族模型)生成的文本。对策:用不同模型评判,或至少做交叉验证;关键评测用人工校准。
④ 格式/表述偏差——被排版、markdown 结构、自信的语气影响。对策:rubric 明确只看内容不看形式,或统一后处理格式再评。
此外必须有人工抽检校准:定期抽一批让真人评,与机器评分比对,一致率下降就说明评判标准漂了,要回去修 rubric。
加分点:"把机器评分与人工抽检的一致率作为监控指标"——这个做法能让面试官确认你不是在空谈。 ① 位置偏差——倾向给排在前面的答案更高分。对策:交换顺序各评一次,取一致结论;不一致就判为平局或人工介入。
② 长度偏差——倾向给更长、更"全面"的回答高分。对策:rubric 里显式区分"信息量"与"篇幅",加一条"冗余扣分";或对长度做归一化后再比较。
③ 自我偏好——偏爱自己(同族模型)生成的文本。对策:用不同模型评判,或至少做交叉验证;关键评测用人工校准。
④ 格式/表述偏差——被排版、markdown 结构、自信的语气影响。对策:rubric 明确只看内容不看形式,或统一后处理格式再评。
此外必须有人工抽检校准:定期抽一批让真人评,与机器评分比对,一致率下降就说明评判标准漂了,要回去修 rubric。
为什么不能只看平均分?
因为平均分掩盖分布,而工程风险几乎全在尾部。
三种典型情况:① 平均分涨了但关键场景崩了(比如回答变得很长,平均分因信息量提升而上涨,但简短咨询类场景全部变糟);② 平均分不动但方差变大(一端显著变好、另一端显著变差,稳定性实际下降);
③ 高分样本挤占(某些原本满分的场景现在稳定扣一点分,被其他场景的涨幅掩盖)。
所以指标要成组看:均值 + 分位数(P5/P95)+ 关键场景单独看 + 最差类别。我在实践中会额外维护一份"绝不能退化的场景清单",无论平均分怎么涨,这些场景退化就是不能上线。
三种典型情况:① 平均分涨了但关键场景崩了(比如回答变得很长,平均分因信息量提升而上涨,但简短咨询类场景全部变糟);② 平均分不动但方差变大(一端显著变好、另一端显著变差,稳定性实际下降);
③ 高分样本挤占(某些原本满分的场景现在稳定扣一点分,被其他场景的涨幅掩盖)。
所以指标要成组看:均值 + 分位数(P5/P95)+ 关键场景单独看 + 最差类别。我在实践中会额外维护一份"绝不能退化的场景清单",无论平均分怎么涨,这些场景退化就是不能上线。
05 Trace、Replay 与线上闭环 3 问
Trace 你会记录哪些字段? 高频
目标是让任何一次失败都能被完整复现,所以按"能 replay"的标准来设计:
任务级——任务 ID、用户、入口、目标与约束、开始/结束时间、最终状态、总 token 与成本。
轮次级——轮次编号、模型与参数、完整的 prompt 组成(含系统提示版本号、注入的上下文片段及其来源、裁剪了什么)、模型原始输出、解析后的工具调用、耗时、输入/输出 token、缓存命中情况。
工具级——工具名与版本、参数、执行耗时、返回结果摘要与原始结果指针、错误分类、是否重试。
变更级——本次运行使用的 prompt / 工具 / 模型配置版本号。
两个容易被漏掉但很关键的字段:prompt 的各段来源与版本(否则改了提示词就再也复现不了旧结果)、以及裁剪/压缩的日志(否则你不知道模型当时"没看到"什么)。
任务级——任务 ID、用户、入口、目标与约束、开始/结束时间、最终状态、总 token 与成本。
轮次级——轮次编号、模型与参数、完整的 prompt 组成(含系统提示版本号、注入的上下文片段及其来源、裁剪了什么)、模型原始输出、解析后的工具调用、耗时、输入/输出 token、缓存命中情况。
工具级——工具名与版本、参数、执行耗时、返回结果摘要与原始结果指针、错误分类、是否重试。
变更级——本次运行使用的 prompt / 工具 / 模型配置版本号。
两个容易被漏掉但很关键的字段:prompt 的各段来源与版本(否则改了提示词就再也复现不了旧结果)、以及裁剪/压缩的日志(否则你不知道模型当时"没看到"什么)。
追问链
- 存原始 prompt 全文会不会太大?
- 怎么按任务链路把多 Agent 的 trace 串起来?
Replay 有什么用?
Replay 是"把一次线上运行在本地原样重放"的能力,它解决三个具体问题:
① 复现——线上失败很难在开发环境重现(输入随机、上下文巨大、依赖外部状态),replay 让你用当时的完整输入重跑,把不可复现变成可调试。
② 对比——在同一个测试用例上跑旧版本与新版本(A/B replay),直接看出行为差异,这是判断改动是否有效的核心手段。
③ 回归——把有代表性的 trace 固化成回归用例,每次改动自动重放这批用例,形成门禁。
实现要点是把"可重放"作为架构约束而不是事后补的功能:所有外部依赖(模型、工具、检索)都要能在 replay 模式下用录制结果替换(mock/replay 层),否则外部状态一变,重放就不成立。
加分点:"把可重放做成架构约束而非事后补功能",是有系统设计经验的人才会说的。 ① 复现——线上失败很难在开发环境重现(输入随机、上下文巨大、依赖外部状态),replay 让你用当时的完整输入重跑,把不可复现变成可调试。
② 对比——在同一个测试用例上跑旧版本与新版本(A/B replay),直接看出行为差异,这是判断改动是否有效的核心手段。
③ 回归——把有代表性的 trace 固化成回归用例,每次改动自动重放这批用例,形成门禁。
实现要点是把"可重放"作为架构约束而不是事后补的功能:所有外部依赖(模型、工具、检索)都要能在 replay 模式下用录制结果替换(mock/replay 层),否则外部状态一变,重放就不成立。
从线上 badcase 到回归门禁,完整闭环怎么建?
六步闭环:
① 发现——通过用户反馈信号(重试、纠错、放弃、点踩)与系统指标异常(成功率下降、超时率上升)自动捞取候选 badcase。
② 归因——按失败原因打标分类(意图理解 / 参数生成 / 工具选择 / 上下文缺失 / 表达 / 系统故障),并区分"模型问题"与"系统问题"。
③ 固化——把可复现的案例整理成评测用例入库,保留原始 trace。
④ 修复——针对原因改对应的层(提示 / 工具描述 / 上下文策略 / 代码逻辑),而不是一律改提示词。
⑤ 回归——在固定评测集上跑,既有全量指标也要看新用例;不能有回归才允许进入下一步。
⑥ 灰度与回滚——按用户或租户灰度,监控线上指标与失败率,劣化自动回滚,正常后放量。
这个闭环能持续运转的前提是第 ③ 步要自动化一部分,否则人工整理会成为瓶颈,闭环很快就断了。
加分点:指出"闭环的瓶颈通常在人工整理用例这一步,所以必须部分自动化",非常贴近真实工程。 ① 发现——通过用户反馈信号(重试、纠错、放弃、点踩)与系统指标异常(成功率下降、超时率上升)自动捞取候选 badcase。
② 归因——按失败原因打标分类(意图理解 / 参数生成 / 工具选择 / 上下文缺失 / 表达 / 系统故障),并区分"模型问题"与"系统问题"。
③ 固化——把可复现的案例整理成评测用例入库,保留原始 trace。
④ 修复——针对原因改对应的层(提示 / 工具描述 / 上下文策略 / 代码逻辑),而不是一律改提示词。
⑤ 回归——在固定评测集上跑,既有全量指标也要看新用例;不能有回归才允许进入下一步。
⑥ 灰度与回滚——按用户或租户灰度,监控线上指标与失败率,劣化自动回滚,正常后放量。
这个闭环能持续运转的前提是第 ③ 步要自动化一部分,否则人工整理会成为瓶颈,闭环很快就断了。
IV · 知识引擎 Knowledge Engine
01 知识建模:实体、事实、推断 3 问
为什么要把知识拆成实体、事实、推断三层? 高频
因为三层的可信度与生命周期完全不同,混在一起就无法治理:
实体层(人、项目、组织、产品)——可锚定的对象,有唯一标识,相对稳定,来自主数据,可信度最高。
事实层(参与了某项目、在某时间发生了某事)——可溯源的关系与事件,来自业务系统记录或结构化抽取,每条都能回指来源,可校验。
推断层(基于实体与事实得出的结论,如"该成员适配某类岗位")——由模型生成,必然带不确定性,必须标注依据链与置信度,且可被新事实推翻后重算。
分开的核心价值是:事实层可溯源,所以敢拿去支撑结论;推断层带依据,所以敢展示但知道要谨慎。如果把三者混成一个"知识库",你无法回答"这条结论到底站不站得住"。
实体层(人、项目、组织、产品)——可锚定的对象,有唯一标识,相对稳定,来自主数据,可信度最高。
事实层(参与了某项目、在某时间发生了某事)——可溯源的关系与事件,来自业务系统记录或结构化抽取,每条都能回指来源,可校验。
推断层(基于实体与事实得出的结论,如"该成员适配某类岗位")——由模型生成,必然带不确定性,必须标注依据链与置信度,且可被新事实推翻后重算。
分开的核心价值是:事实层可溯源,所以敢拿去支撑结论;推断层带依据,所以敢展示但知道要谨慎。如果把三者混成一个"知识库",你无法回答"这条结论到底站不站得住"。
追问链
- 推断层怎么保证质量?
- 实体对齐怎么做?
推断的质量怎么保证?
三道闸,缺一不可:
① 生成时强制给依据——要求推断必须附带它引用了哪些事实(事实 ID 列表),没有依据的推断直接丢弃。这既是质量控制,也是可解释性。
② 置信度与呈现策略——按依据数量、事实新鲜度、以及是否有冲突事实计算置信度;低置信度的推断不以结论性语气呈现,而是作为"可能的观察"提示,避免误导用户做出重要决策。
③ 抽样人审 + 回流——定期抽样人工核验,把误判案例回流入评测集与规则库。审的结果要反哺到生成策略(比如某类推断总是错,就要收紧触发条件)。
还要有失效机制:推断所依赖的事实发生变化时(人员转岗、项目结束),相关推断必须被标记为待重算而不是继续留着——"过期但看起来很确定"的推断比没有推断更危险。
加分点:"过期推断比没有推断更危险"是一句很有分量的话,能体现对知识时效性的理解。 ① 生成时强制给依据——要求推断必须附带它引用了哪些事实(事实 ID 列表),没有依据的推断直接丢弃。这既是质量控制,也是可解释性。
② 置信度与呈现策略——按依据数量、事实新鲜度、以及是否有冲突事实计算置信度;低置信度的推断不以结论性语气呈现,而是作为"可能的观察"提示,避免误导用户做出重要决策。
③ 抽样人审 + 回流——定期抽样人工核验,把误判案例回流入评测集与规则库。审的结果要反哺到生成策略(比如某类推断总是错,就要收紧触发条件)。
还要有失效机制:推断所依赖的事实发生变化时(人员转岗、项目结束),相关推断必须被标记为待重算而不是继续留着——"过期但看起来很确定"的推断比没有推断更危险。
实体对齐是什么?不做会怎样?
实体对齐是把来自不同数据源的"同一个对象"识别并合并成唯一实体——比如 HR 系统里的"张三(工号 001)"、项目系统里的"zhangsan"、邮件签名里的"三哥",需要判定为同一个人。
不做对齐有三类后果:
① 信息碎片化——同一个人被拆成多个实体,各自的记录都不完整,检索时召回不全,看起来像"知识缺失",实际是对齐没做。
② 事实冲突——同一个实体的属性在不同来源里被存成两份,取值不同且无法判断谁新谁旧。
③ 统计口径失真——"参与过几个项目"这类聚合会失真。
常用手段是用强标识优先(工号、唯一 ID)→ 弱标识兜底(姓名 + 部门 + 时间窗)→ 冲突时人工裁决,并且对齐结果要可回溯(记录合并了哪些来源),否则出错了无法拆开。
不做对齐有三类后果:
① 信息碎片化——同一个人被拆成多个实体,各自的记录都不完整,检索时召回不全,看起来像"知识缺失",实际是对齐没做。
② 事实冲突——同一个实体的属性在不同来源里被存成两份,取值不同且无法判断谁新谁旧。
③ 统计口径失真——"参与过几个项目"这类聚合会失真。
常用手段是用强标识优先(工号、唯一 ID)→ 弱标识兜底(姓名 + 部门 + 时间窗)→ 冲突时人工裁决,并且对齐结果要可回溯(记录合并了哪些来源),否则出错了无法拆开。
02 RAG 的链路与失效模式 3 问
RAG 的完整链路有哪几步? 高频
六个环节,每一步都能单独把结果做错:
① 采集与清洗——把文档、表格、日志接进来,去重、去噪、处理编码与格式。
② 切分(Chunking)——决定检索的最小单位。切得太大召回不准且占 token,切得太小语义不完整。
③ 索引——为每个 chunk 建关键词索引与向量索引,并保留元数据(来源、时间、权限、层级结构)。
④ 召回——根据查询取回候选集(关键词 + 向量混合)。
⑤ 排序(Rerank)——对候选做精排,选出真正该进上下文的那几条。
⑥ 生成——把选中片段与问题一起交给模型,要求带引用作答。
最常见的误区是把 RAG 理解成"④ + ⑥",然后所有问题都往提示词上改。实际上大部分 RAG 故障发生在 ②③⑤,而这三步都在模型之外。
① 采集与清洗——把文档、表格、日志接进来,去重、去噪、处理编码与格式。
② 切分(Chunking)——决定检索的最小单位。切得太大召回不准且占 token,切得太小语义不完整。
③ 索引——为每个 chunk 建关键词索引与向量索引,并保留元数据(来源、时间、权限、层级结构)。
④ 召回——根据查询取回候选集(关键词 + 向量混合)。
⑤ 排序(Rerank)——对候选做精排,选出真正该进上下文的那几条。
⑥ 生成——把选中片段与问题一起交给模型,要求带引用作答。
最常见的误区是把 RAG 理解成"④ + ⑥",然后所有问题都往提示词上改。实际上大部分 RAG 故障发生在 ②③⑤,而这三步都在模型之外。
追问链
- 每一环的典型失效表现是什么?
- 怎么定位故障出在哪一环?
RAG 的典型失效模式有哪些?怎么定位?
按链路顺序列四类最常见的:
① 切分破坏语义——把一张表格从中间切断、把一个流程分成两半,导致召回片段残缺。表现为"答案缺一半"或"细节对不上"。定位:直接看召回片段的原文。
② 召回失败——正确片段根本没进候选集。这是最隐蔽的,因为模型会基于错误材料自信作答。定位:把"正确片段是否在候选集里"单独作为指标统计(召回率),而不是只看最终答案正确率。
③ 排序失败——正确片段在候选集里但被挤到后面,最终没进上下文。定位:看 rerank 前后的排名变化。
④ 生成忽略——材料都在上下文里,模型却没用,或者用了却编造了细节。定位:要求输出引用并在评测里检查引用是否真实存在。
关键方法论是把链路分层评测:先保证召回,再保证排序,最后才谈生成——否则你会一直在错误的环节上优化。
加分点:强调"召回率要单独统计",因为最终答案正确率会把召回失败和生成失败混在一起。 ① 切分破坏语义——把一张表格从中间切断、把一个流程分成两半,导致召回片段残缺。表现为"答案缺一半"或"细节对不上"。定位:直接看召回片段的原文。
② 召回失败——正确片段根本没进候选集。这是最隐蔽的,因为模型会基于错误材料自信作答。定位:把"正确片段是否在候选集里"单独作为指标统计(召回率),而不是只看最终答案正确率。
③ 排序失败——正确片段在候选集里但被挤到后面,最终没进上下文。定位:看 rerank 前后的排名变化。
④ 生成忽略——材料都在上下文里,模型却没用,或者用了却编造了细节。定位:要求输出引用并在评测里检查引用是否真实存在。
关键方法论是把链路分层评测:先保证召回,再保证排序,最后才谈生成——否则你会一直在错误的环节上优化。
切分(chunking)你会怎么定?
按内容结构切,不要按固定字数机械切。
原则:① 尊重结构边界——按章节、段落、表格、列表项切,别把标题和它的正文分开;② 保留上下文——每个 chunk 带上标题路径(文档 > 章节 > 小节),让它在脱离原文时仍可被理解;③ 允许重叠——相邻 chunk 之间留 10%–20% 重叠,缓解边界信息丢失;④ 长度适配——大小要兼顾语义完整与检索粒度,通常几百 token;表格和代码这类结构化内容要整体保留,宁可超长。
还有一个常被忽略的点:要为不同类型的资料用不同的切分策略(政策文档按条款、会议记录按发言段落、指标字典按字典项),一刀切是精度损失的常见来源。
判断切分好坏的实用方法:随机抽 20 个 chunk 单独读,能不能看懂它在说什么——看不懂就是切坏了。
原则:① 尊重结构边界——按章节、段落、表格、列表项切,别把标题和它的正文分开;② 保留上下文——每个 chunk 带上标题路径(文档 > 章节 > 小节),让它在脱离原文时仍可被理解;③ 允许重叠——相邻 chunk 之间留 10%–20% 重叠,缓解边界信息丢失;④ 长度适配——大小要兼顾语义完整与检索粒度,通常几百 token;表格和代码这类结构化内容要整体保留,宁可超长。
还有一个常被忽略的点:要为不同类型的资料用不同的切分策略(政策文档按条款、会议记录按发言段落、指标字典按字典项),一刀切是精度损失的常见来源。
判断切分好坏的实用方法:随机抽 20 个 chunk 单独读,能不能看懂它在说什么——看不懂就是切坏了。
03 Embedding 与向量检索 3 问
语义检索为什么会找错? 高频
根本原因是:"语义相近"和"对回答问题有用"是两件不同的事。
四类具体错法:
① 语义相似但答案无关——查询"如何申请年假"召回《请假制度总则》的相似段落,但真正有用的是《年假实施细则》,两者语义高度接近。
② 精确标识失效——向量对数字、工号、型号、专有名词不敏感,"型号 A123" 和 "型号 A132" 在向量空间里几乎没区别,但答案完全不同。
③ 否定与条件丢失——"不含"、"除……之外"这类逻辑关系在稠密向量里表达很弱。
④ 频次与时效被稀释——出现 20 次的关键条款,可能比只出现 1 次的临时通知排在更前,但后者才是当前有效的版本。
所以纯向量检索在真实系统里几乎总是配合关键词检索(补精确匹配)+ 元数据过滤(补时效与权限)+ Rerank(补真实相关性)使用。
四类具体错法:
① 语义相似但答案无关——查询"如何申请年假"召回《请假制度总则》的相似段落,但真正有用的是《年假实施细则》,两者语义高度接近。
② 精确标识失效——向量对数字、工号、型号、专有名词不敏感,"型号 A123" 和 "型号 A132" 在向量空间里几乎没区别,但答案完全不同。
③ 否定与条件丢失——"不含"、"除……之外"这类逻辑关系在稠密向量里表达很弱。
④ 频次与时效被稀释——出现 20 次的关键条款,可能比只出现 1 次的临时通知排在更前,但后者才是当前有效的版本。
所以纯向量检索在真实系统里几乎总是配合关键词检索(补精确匹配)+ 元数据过滤(补时效与权限)+ Rerank(补真实相关性)使用。
余弦相似度、点积、欧氏距离该怎么选?
取决于向量是否归一化:
向量已归一化(模长为 1)——余弦相似度与点积完全等价,此时用点积更快(省掉除法)。大多数现代 embedding 模型输出的向量本身就是归一化的,所以实践中常见"用点积近似余弦"。
向量未归一化——点积会把模长也计入相似度,如果向量模长本身有含义(例如代表置信度或频次),这可能是特性;如果没有含义,那就是噪声,应该先归一化。
欧氏距离——在归一化向量上,欧氏距离与余弦相似度是单调等价的(
工程上的建议是:跟你的向量库与索引实现保持一致——很多 ANN 库针对特定度量做了优化(比如内积),混用不同度量的预计算会导致结果与暴力检索不一致,这种 bug 很难发现。
向量已归一化(模长为 1)——余弦相似度与点积完全等价,此时用点积更快(省掉除法)。大多数现代 embedding 模型输出的向量本身就是归一化的,所以实践中常见"用点积近似余弦"。
向量未归一化——点积会把模长也计入相似度,如果向量模长本身有含义(例如代表置信度或频次),这可能是特性;如果没有含义,那就是噪声,应该先归一化。
欧氏距离——在归一化向量上,欧氏距离与余弦相似度是单调等价的(
d² = 2 − 2·cos),所以排序结果相同。它的好处是直觉上更好解释,坏处是对模长变化更敏感。工程上的建议是:跟你的向量库与索引实现保持一致——很多 ANN 库针对特定度量做了优化(比如内积),混用不同度量的预计算会导致结果与暴力检索不一致,这种 bug 很难发现。
向量检索的能力边界在哪?什么场景不该用它?
不该用(或必须配合其他手段)的场景有四类:
① 需要精确匹配——编号、单号、金额、日期范围、代码符号。这些必须走结构化查询或关键词精确匹配。
② 需要聚合与统计——"上个月有多少人入职"。向量检索只能找相似文本,不能做聚合,这本质上是数据库问题。
③ 需要严格权限与合规——向量检索没有天然的权限语义,必须在检索前做元数据过滤(pre-filter),而不是检索后再筛(否则会泄漏被过滤内容的存在性,也浪费召回额度)。
④ 需要多跳推理——"和 A 合作过项目的人,他们的共同上级是谁"。这是图查询擅长的事,向量检索只能拿到与 A 相关的文本片段。
一句话总结:向量检索擅长"找相似的说法",不擅长"精确匹配、聚合、关系推理、权限控制"——所以真实系统里它只是检索层的一个组件,而不是全部。
加分点:把"pre-filter 而非 post-filter"这一点讲出来,会显得你真做过带权限的检索系统。 ① 需要精确匹配——编号、单号、金额、日期范围、代码符号。这些必须走结构化查询或关键词精确匹配。
② 需要聚合与统计——"上个月有多少人入职"。向量检索只能找相似文本,不能做聚合,这本质上是数据库问题。
③ 需要严格权限与合规——向量检索没有天然的权限语义,必须在检索前做元数据过滤(pre-filter),而不是检索后再筛(否则会泄漏被过滤内容的存在性,也浪费召回额度)。
④ 需要多跳推理——"和 A 合作过项目的人,他们的共同上级是谁"。这是图查询擅长的事,向量检索只能拿到与 A 相关的文本片段。
一句话总结:向量检索擅长"找相似的说法",不擅长"精确匹配、聚合、关系推理、权限控制"——所以真实系统里它只是检索层的一个组件,而不是全部。
04 混合检索、Rerank 与知识可信 4 问
混合检索怎么设计?关键词和向量怎么融合? 高频
目标是用关键词补精确性、用向量补语义泛化,两者召回后再融合排序。
① 并行召回——一路 BM25/倒排做关键词检索(擅长精确命中、专有名词、数字),一路向量检索(擅长同义改写、语义近似),各取 Top-K(比如各 50 条)。
② 分数融合——两种分数不可直接比较(量纲不同),常见做法是RRF(倒数排名融合):只用排名不用分数,
③ 元数据过滤——在召回阶段就加权限、时效、类型过滤,而不是事后筛。
④ 精排——把融合后的前 50–100 条交给 Rerank 模型(cross-encoder),选出最终进上下文的 5–10 条。
这套结构的分工是:召回要宽(宁可多召回)→ 排序要准(决定最终质量)→ 上下文要省(只放最相关的几条)。
① 并行召回——一路 BM25/倒排做关键词检索(擅长精确命中、专有名词、数字),一路向量检索(擅长同义改写、语义近似),各取 Top-K(比如各 50 条)。
② 分数融合——两种分数不可直接比较(量纲不同),常见做法是RRF(倒数排名融合):只用排名不用分数,
score = Σ 1/(k + rank),简单、鲁棒、不需要调权重;或者做分数归一化后加权求和,但要为不同数据源分别标定。③ 元数据过滤——在召回阶段就加权限、时效、类型过滤,而不是事后筛。
④ 精排——把融合后的前 50–100 条交给 Rerank 模型(cross-encoder),选出最终进上下文的 5–10 条。
这套结构的分工是:召回要宽(宁可多召回)→ 排序要准(决定最终质量)→ 上下文要省(只放最相关的几条)。
追问链
- RRF 的 k 一般取多少?
- Rerank 模型和 embedding 模型的区别是什么?
Rerank 为什么比向量检索准?代价是什么?
区别在于是否让查询和文档相互作用:
向量检索(bi-encoder)先把查询和文档各自独立编码成向量,再算相似度。好处是可以离线建索引、检索快(毫秒级),代价是查询和文档之间没有交互,细粒度的匹配关系表达不出来。
Rerank(cross-encoder)把查询和文档拼接后一起送进模型,让每个词之间都能相互作用,因此精度显著更高。代价是无法预计算——每个(查询,文档)对都要跑一次前向,成本随候选数线性增长,所以只能用在精排阶段、候选只有几十到上百条的时候。
这就是"粗排用双塔求快,精排用交叉编码器求准"的两阶段架构的根本原因。
补充一句工程考量:Rerank 的延迟通常几十到几百毫秒,如果对首字延迟极敏感,可以考虑异步 rerank + 先返回粗排结果再更新,或者只对 Top-N 做 rerank。
加分点:能说出"两阶段架构的根本原因是可预计算性",说明你理解的是原理而不是套件。 向量检索(bi-encoder)先把查询和文档各自独立编码成向量,再算相似度。好处是可以离线建索引、检索快(毫秒级),代价是查询和文档之间没有交互,细粒度的匹配关系表达不出来。
Rerank(cross-encoder)把查询和文档拼接后一起送进模型,让每个词之间都能相互作用,因此精度显著更高。代价是无法预计算——每个(查询,文档)对都要跑一次前向,成本随候选数线性增长,所以只能用在精排阶段、候选只有几十到上百条的时候。
这就是"粗排用双塔求快,精排用交叉编码器求准"的两阶段架构的根本原因。
补充一句工程考量:Rerank 的延迟通常几十到几百毫秒,如果对首字延迟极敏感,可以考虑异步 rerank + 先返回粗排结果再更新,或者只对 Top-N 做 rerank。
怎么让回答"有据可查"?
关键是把引用做成可验证的数据,而不是装饰性的角标。
① 要求结构化引用——模型输出时对每个结论都要给出来源标识(chunk ID、文档 ID),而不是在正文里写一句"[1]"。
② 引用必须真实存在——后处理阶段校验:引用的 ID 是否真的在本次上下文中、引用的段落是否真的支持该结论。这一步能拦掉相当比例的"编造引用"。
③ 溯源到原文位置——chunk 要保留原文定位信息(文档链接 + 页码/段落),用户点开能看到原始上下文,而不是只看到片段。
④ 无据要能拒答——明确允许并鼓励"根据现有资料无法回答",并对这种情况监控比例。一个从不拒答的系统,其引用可信度必然很低。
⑤ 评测引用质量——把"引用支持率"(引用是否真的支撑结论)作为独立指标,而不是只看答案看起来对不对。
加分点:把"引用支持率"作为独立指标、并强调"要允许拒答",是这一步最核心的两个设计。 ① 要求结构化引用——模型输出时对每个结论都要给出来源标识(chunk ID、文档 ID),而不是在正文里写一句"[1]"。
② 引用必须真实存在——后处理阶段校验:引用的 ID 是否真的在本次上下文中、引用的段落是否真的支持该结论。这一步能拦掉相当比例的"编造引用"。
③ 溯源到原文位置——chunk 要保留原文定位信息(文档链接 + 页码/段落),用户点开能看到原始上下文,而不是只看到片段。
④ 无据要能拒答——明确允许并鼓励"根据现有资料无法回答",并对这种情况监控比例。一个从不拒答的系统,其引用可信度必然很低。
⑤ 评测引用质量——把"引用支持率"(引用是否真的支撑结论)作为独立指标,而不是只看答案看起来对不对。
知识冲突(同一事实有多个版本的记录)怎么处理?
先判断冲突类型,再决定策略:
① 时效性冲突(旧版制度 vs 新版制度)——按生效时间处理:检索时优先返回当前生效版本,但保留历史版本可查(因为"当时适用什么"也是一个合法问题)。落地手段是元数据里带 effective_from / effective_to。
② 来源权威性冲突(正式文件 vs 内部聊天记录)——引入来源权重,正式发布的主数据优先;权重必须在检索与排序阶段生效,而不是最后让模型自己判断。
③ 真实矛盾(两处记录确实不一致,无法判断谁对)——不要静默选择其中一个。正确做法是把冲突显式暴露出来("系统中存在两种记录:A 系统显示 X,B 系统显示 Y"),这既诚实又让问题能被修复。
④ 数据质量冲突(空值、格式错误)——在采集清洗阶段解决,不应进入检索层。
核心原则是:知识引擎的第一职责是"不制造虚假确定性",冲突要么按明确规则消解,要么显式暴露。
加分点:最后那句"不制造虚假确定性",是知识治理层面最有价值的表达。 ① 时效性冲突(旧版制度 vs 新版制度)——按生效时间处理:检索时优先返回当前生效版本,但保留历史版本可查(因为"当时适用什么"也是一个合法问题)。落地手段是元数据里带 effective_from / effective_to。
② 来源权威性冲突(正式文件 vs 内部聊天记录)——引入来源权重,正式发布的主数据优先;权重必须在检索与排序阶段生效,而不是最后让模型自己判断。
③ 真实矛盾(两处记录确实不一致,无法判断谁对)——不要静默选择其中一个。正确做法是把冲突显式暴露出来("系统中存在两种记录:A 系统显示 X,B 系统显示 Y"),这既诚实又让问题能被修复。
④ 数据质量冲突(空值、格式错误)——在采集清洗阶段解决,不应进入检索层。
核心原则是:知识引擎的第一职责是"不制造虚假确定性",冲突要么按明确规则消解,要么显式暴露。
结论先行(一句话给出取舍)→ 机制(为什么是这样,涉及哪条链路)→ 代价或边界(这么做放弃了什么)→ 你的实践或数字(真实场景里怎么落地)。 这套结构之所以有效,是因为它天然把「研究问题」和「工程问题」分开了:只有工程问题才配得上第三条和第四条。