21979 字
110 分钟
2026-11-03 AI Agent 面试训练
AI Agent 面试训练
2026-11-03

2026-11-03 AI Agent 面试训练#

今日学习主题#

代理指标的失效:当”绿”不等于”对”,如何重建一条可判定的证据链

今天的五道题从同一个问题出发——我们看到的大多数数字都是代理指标:CPU 利用率是”忙不忙”的代理,Faithfulness 是”对不对”的代理,离线通过率是”线上好不好”的代理,HPA 的 CPU 目标是”该不该扩”的代理,栈的栈顶元素是”栈里最小值是多少”的代理。代理指标在度量对象与被度量事实分离时会静默失效。重建判定链的方法是一致的:先问这个指标度量的是哪个对象,再问它失效时会出现什么形态,最后准备一条不依赖它的独立判定路径。

  • B01:CPU 利用率、饱和度与火焰图分别度量什么,为什么”三项全绿”仍可能是错的。
  • B02:RAG 评测的分层指标与其循环论证风险,为什么答案对不等于检索对。
  • S01:离线评测全绿而线上掉 11 个点,如何把结果指标下钻到 step 级并定位到编排层。
  • S02:压测通过的容量在真实斜坡流量下崩溃,如何把”扩容”从代理信号换成排队信号并纳入下游上界。
  • L01:最小栈用一个辅助栈把全局聚合量变成 O(1),考察不变式设计。

题目速览#

编号题目 ID题目名称题型一级类型难度一句话考察点
B01Q-20261103-B01CPU 100% 是不是结论:性能分析的度量对象与判定依据非 Agent 基础操作系统与网络基础题(中高)USE 三项与火焰图各自能回答什么、不能回答什么,以及平均值与 on-CPU 口径的失效点
B02Q-20261103-B02答案对了,能说明检索对了吗:RAG 评测的分层与归因Agent 基础RAG 与搜索基础题(中高)检索层与生成层指标的分工、reference-free 的代价、答案正确 ≠ 检索正确
S01Q-20261103-S01离线评测全绿,线上成功率从 82% 掉到 71%Agent 场景Agent 评测与可观测性(兼 AI Agent 核心)场景题(高)结果指标下钻到 step 级、工具错误语义分离、评测集覆盖缺口与失效模式回流
S02Q-20261103-S02压测通过的容量,开抢就崩:HPA 信号错配与下游容量上界非 Agent 场景软件工程与平台工程(兼操作系统与网络)场景题(高)扩容滞后链路的时间预算、代理信号的错配、副本放大与下游容量的乘法关系
L01Q-20261103-L01155. 最小栈LeetCode栈与队列(辅助栈 / 不变式)medium(未直接核验)用同步辅助栈维护前缀最小值,重复最小值与不变式的严格表述

B01 · 非 Agent 基础题#

题目 ID:Q-20261103-B01 一级类型:操作系统与网络 二级主题:CPU 与内存性能分析(USE 方法、火焰图、on-CPU / off-CPU、采样与平均的偏差) 标签:性能分析、USE 方法、火焰图、采样偏差、饱和度

题目#

一个在线服务 P99 从 40 ms 涨到 900 ms。监控面板显示:CPU 利用率 62%(5 分钟平均)、内存剩余 30%、磁盘 busy 40%、无错误计数、网络吞吐远低于带宽上限。团队按”CPU 打满”的方向排查,加了一倍机器,P99 只从 900 ms 降到 870 ms。

请回答:

  1. USE 方法要求对每种资源检查哪三个指标,它们各自的定义是什么?这套指标能回答什么问题,明确不能回答什么问题?
  2. 在 USE 三项”看起来都不高”的情况下,哪三种失效形态会让这套面板给出错误结论?
  3. 团队用 CPU 火焰图定位”最宽的那块”,据此优化了一个热点函数,P99 没有变化。火焰图的 x 轴、y 轴和宽度分别代表什么?为什么”最宽的块”常常不是该优化的地方?

先思考#

  • 先想清楚”资源视角”和”请求视角”是两套不同的度量:一个回答”哪个资源是瓶颈”,一个回答”这个请求为什么慢”。
  • 再想”平均值”对什么敏感、对什么免疫:一个 5 分钟平均的利用率,能表达一秒钟内发生的事吗?
  • 然后区分”在用 CPU”和”在等别的东西”:一个线程在等锁、等磁盘、等下游时,CPU 是忙的还是闲的?
  • 最后问:火焰图上的样本是在什么时刻采集的?那些时刻线程在做什么?不在做什么?

参考答案#

结论:这套面板”全绿”是因为它度量的是资源的时间平均忙闲程度,而故障发生在排队与等待上;USE 只覆盖瓶颈与错误两类问题,火焰图默认只覆盖 on-CPU,两者都不直接度量请求时延。

准确定义:USE(Utilization Saturation and Errors)方法可以概括为一句话——“For every resource, check utilization, saturation, and errors.”(对每一种资源,检查利用率、饱和度与错误)。三项的定义分别是:

  • utilization:资源忙于服务工作的平均时间(“the average time that the resource was busy servicing work”),通常表达为一段时间内的百分比。
  • saturation:资源有多余工作无法服务、通常处于排队的程度(“the degree to which the resource has extra work which it can’t service, often queued”),通常表达为队列长度。
  • errors:错误事件的计数(“the count of error events”)。

适用边界:USE 的定位是在性能调查的早期使用,用于识别系统性瓶颈(“It’s intended to be used early in a performance investigation, to identify systemic bottlenecks”)。它只能发现特定类型的问题——“It will, however, only find certain types of issues – bottlenecks and errors – and should be considered as one tool in a larger toolbox.” 延迟类问题需要基于延迟的方法论(原文点名 Method R)或后续的工作负载刻画(workload characterization)与下钻分析(drill-down analysis)。硬件缓存(如 MMU TLB、CPU cache)被有意排除在常规 USE 资源之外,因为缓存是在高利用率下提升性能的,而不是在高利用率下劣化的,命中率应在排除系统性瓶颈之后再查。

三种让”全绿”失效的形态:

  1. 时间平均掩盖突发。官方给出的判读原话是:利用率在较长时间段(数秒到数分钟)上测量时,“a total utilization of, say, 70% can hide short bursts of 100% utilization”。原文还记录了一个反直觉案例:客户的监控工具报告 CPU 利用率从不超过 80%,但真实故障是 CPU 饱和造成的延迟——因为监控报的是 5 分钟平均,而其中 CPU 会连续数秒打满 100%。题目中的 62% 完全可以是”大部分时间很闲 + 每秒数十毫秒打满”的平均结果。
  2. 低利用率不排除饱和。原文明确指出:“A burst of high utilization can cause saturation and performance issues, even though utilization is low when averaged over a long interval.” 饱和的正确判据是队列长度或调度延迟(原文 CPU 饱和指标示例为 “run-queue length or scheduler latency”),而”任何非零饱和都可能是问题”(“any degree of saturation can be a problem (non-zero)”)。只挂利用率不挂 run queue / scheduler latency,等于放弃了唯一能直接看到排队的那一项。
  3. errors 被静默吞掉。原文强调错误必须调查,因为”they can degrade performance, and may not be immediately noticed when the failure mode is recoverable”,典型就是失败后被重试的操作和冗余设备池中失效的设备。题目里”无错误计数”往往只是没采集到应用层的重试与软错误,而不是真的没有。

火焰图的读法与”最宽的块”陷阱:官方定义是——x 轴是栈样本总体,按字母序排列,不是时间的流逝(“The x-axis shows the stack profile population, sorted alphabetically (it is not the passage of time)”);y 轴是栈深度,从底部 0 开始计数;每个矩形是一个栈帧,帧越宽表示它在栈中出现的次数越多(“The wider a frame is, the more often it was present in the stacks”);顶边表示 on-CPU 的部分,下方是它的祖先调用链(“The top edge shows what is on-CPU, and beneath it is its ancestry”)。

由此得到三个陷阱:

  • 火焰图默认只覆盖 on-CPU。锁等待、I/O 等待、调度延迟都不在这张图上——线程的 CPU 样本为零时它根本不会出现。这类等待要用专门的 off-CPU 火焰图(官方扩展类型之一)。题目中 P99 变慢而 CPU 只到 62%,正是”时间在 CPU 之外”的典型形态。
  • 宽度是出现频次,不是调用次数,也不是耗时。它是采样命中的次数占比;一个被高频调用但每次很短的函数,和一个调用少但每次很长的函数,可能得到相近的宽度。
  • x 轴不是时间,看不到时间模式。官方明确说明:火焰图按字母序重排样本以最大化帧合并、更好呈现全貌,而把时间放在 x 轴的是 flame chart(最早由 Chrome WebKit Web Inspector 引入),周期性活动需要 FlameScope 这类按时间范围切分的工具。所以”最宽的块”完全可能是把分散在整个观察窗口里的样本合并后的结果,而不是某个时刻的持续热点。

与相近概念的区别:

对比前者后者
USE vs 请求视角指标资源视角:哪个资源是瓶颈;输出是”CPU 饱和 / 磁盘繁忙”请求视角:这个请求为什么慢;输出是”某类请求 P99 = 900 ms”
utilization vs saturation忙不忙;可以在排队尚未形成时很高排不排队;任何非零都可能是问题
火焰图 vs flame chartx 轴按字母序重排,最大化合并,看全貌x 轴是时间流逝,可研究时间模式与周期性
采样 profiler vs 函数级 tracing有间隙、开销低、样本有偏精确、开销高,会扰动被观测目标

典型应用(通用工程):建立一条从”红灯”到”证据”的四层链——请求时延分层(按接口/租户/ percentile)→ 服务内阶段耗时 → 资源 USE 三项 → 代码路径火焰图(先 on-CPU,再 off-CPU)。每一次下钻都必须换一个更接近事实的度量对象,而不是换一个更漂亮的图表。容量评估不能只看平均利用率,饱和(run queue、队列长度、调度延迟)才是容量耗尽的直接证据。

面试现场回答(1–2 分钟版本):

我不会先改机器,先换度量对象。USE 要求对每种资源查三项:利用率是资源忙于服务工作的平均时间,饱和度是有多少活排着队干不了,错误是错误事件计数。这套方法用于调查早期快速定位瓶颈和错误,但它只解决瓶颈和错误两类问题,不直接回答”这个请求为什么慢”。

这个面板全绿有三种可能失效:第一,62% 是 5 分钟平均,官方明确说过 70% 的平均可以隐藏秒级的 100% 突发,我见过利用率从没超过 80% 但真实原因是每秒打满几秒的调度延迟;第二,低利用率不等于无饱和,饱和要看 run queue 和 scheduler latency,而且任何非零饱和都可能是问题——我们根本没挂这两个指标;第三,错误被静默吞掉了,失败后重试的操作属于可恢复失败,性能差但不报错。

加机器只降了 30 ms,说明我们加错了资源。火焰图那边:x 轴是栈样本总体按字母序排列,不是时间流逝;宽度是样本中出现频次;顶边是 on-CPU。所以默认火焰图看不见锁等待、I/O 和调度延迟——那些要用 off-CPU 火焰图。最宽的块只是采样命中最多,可能是大量短调用的合并,而且按字母序重排会把它从整个窗口里拢到一起,不代表某个时刻的持续热点。

我的下一步是:先按请求类型拆 P99 确认是不是全局问题,然后挂上 CPU 的 scheduler latency 和 run queue,同时采一份 off-CPU 火焰图,最后才谈优化哪个函数。

关键点#

  1. USE 只覆盖瓶颈与错误:官方原话是只会发现 “bottlenecks and errors”,延迟类问题需要 latency-based 方法论或 workload characterization / drill-down。
  2. 饱和是独立的第二项,且任何非零都可能是问题:利用率是”忙不忙”,饱和是”排不排队”,两者必须分别采集。
  3. 平均值是最大的谎言来源:长周期平均利用率会隐藏短时 100% 突发;低平均利用率不排除饱和。
  4. 火焰图只覆盖 on-CPU,x 轴不是时间,宽度是采样命中频次而非耗时或调用次数。
  5. 不可抢占资源与可抢占资源的 70% 含义不同:磁盘在利用率超 70% 后会频繁出现排队延迟,而 CPU 几乎可在任意时刻被抢占。

常见误区#

  1. 把平均 CPU 利用率当成并发度或健康度结论。错误原因:利用率是”平均忙的时间占比”,既不包含排队信息(saturation 才是),也会被时间平均抹掉突发。官方记录过一个 5 分钟平均从不超过 80%、却因秒级 100% 突发导致 CPU 饱和延迟的真实案例。
  2. 把火焰图最宽的块当成必然的优化点。错误原因:宽度是采样命中频次;默认火焰图只含 on-CPU,等待型瓶颈根本不在图上;且 x 轴按字母序重排会把分散在整个窗口的样本合并,看不出”某个时刻”的热点。结果是优化了真正的 CPU 消耗者,而故障在等待侧。
  3. 认为”USE 三项全绿”就可以排除资源问题,直接去改应用代码。错误原因:USE 的清单是”about thirty metrics, some of which can’t be measured, and some of which are tricky to measure”——没挂上的指标不等于不存在;尤其 CPU 的 errors(可修正 ECC、faulted CPU)与饱和类指标在多数系统里默认没有采集。

追问#

追问:如果 P99 变慢但 USE 三项全绿、off-CPU 火焰图也看不出明显等待,你怎么继续?

回答要点:

  • 先确认度量窗口:把 5 分钟平均改成 1 秒甚至 100 毫秒粒度,重新看利用率与队列,突发形态常在降采样中消失。
  • 转向工作负载刻画(workload characterization):先回答”谁在请求、请求什么、为什么请求”,很多”性能问题”其实是请求构成变化(某个下游超时导致重试、某类输入体积翻倍、缓存命中率变化)。
  • 用排队分解把时延拆成服务时间与排队时间:若服务时间没变而排队时间涨,说明是到达率或并发度问题,不是代码热点。
  • 检查依赖侧:下游 P99 的变化会通过同步调用直接变成本服务的等待,而本服务的 USE 面板完全看不到——这与 B01 的结论一致,必须有一条不依赖本服务指标的独立判定路径。
  • 承认边界:如果上述都无果,说明问题在更长的时间尺度或非资源维度(锁竞争、GC、连接耗尽),应使用对应的专门方法论,而不是继续加宽 USE 清单。

延伸学习#

  • Brendan Gregg《The USE Method(Utilization Saturation and Errors)》,官方页面:https://www.brendangregg.com/usemethod.html —— 含三项的精确定义、完整资源清单(约 30 个指标)、Suggested Interpretations 与”低利用率不等于无饱和”的反直觉案例。
  • Brendan Gregg《Flame Graphs》官方页面:https://www.brendangregg.com/flamegraphs.html —— 含 x/y 轴定义、宽度语义、on-CPU 边界、icicle 与 flame chart 的区别;同一站点另有 Off-CPU Flame Graphs 专页可作下一步。

B02 · AI Agent 基础题#

题目 ID:Q-20261103-B02 一级类型:RAG 与搜索 二级主题:RAG 评测设计(检索层与生成层指标分工、reference-free 评测的代价、归因顺序与失效边界) 标签:RAG 评测、Faithfulness、Context Precision、reference-free、归因

题目#

一个企业制度问答系统,线上人工抽检正确率 78%。团队用 Ragas 跑了一轮离线评测,得到:

  • faithfulness = 0.91
  • context precision = 0.62

负责人据此判断”生成没问题,是检索差”,把下一季度的资源全部投入检索优化,并停止了对提示词和生成侧的检查。

请回答:

  1. faithfulness 与 context precision 各自度量什么对象、依赖哪些输入、如何计算?它们分别需要 ground truth 吗?
  2. 从这组数字能推出什么结论,不能推出什么结论?请给出至少一个”这组数字很好但系统其实是错的”的具体反例。
  3. 这套指标在 Agent 系统里应该记录在哪一层(最终答案层还是工具调用层),为什么?

先思考#

  • 先问每个指标的”参照物”:faithfulness 是拿答案跟什么比?context precision 是拿检索结果跟什么比?参照物不同,结论的成立条件就不同。
  • 再问”参照物本身可信吗”:如果 context precision 在没有标准答案时拿生成结果当参照,那么”生成错”会不会连带把检索判成对的?
  • 然后构造反例:能不能让 faithfulness = 1.0 而答案在业务上是错的?
  • 最后想记录粒度:Agent 一次会话可能检索 5 次,你只在最后记一个 faithfulness,能定位到哪一次检索吗?

参考答案#

结论:这组数字只能支持”答案与检索到的上下文高度自洽、检索排序质量偏低”这一条结论;它不能支持”生成没问题”,更不能支持”把资源全部压到检索”。faithfulness 度量的是对上下文的忠实度而非对世界的正确性,而 context precision 在无 ground truth 时以生成结果为参照,本身就存在循环论证风险。

准确定义与计算(依据 Ragas 官方文档):

  • Faithfulness:度量 response 与 retrieved context 的事实一致性,取值 0–1,越高越一致。原文定义:“The Faithfulness metric measures how factually consistent a response is with the retrieved context.” 判定标准原话是 “A response is considered faithful if all its claims can be supported by the retrieved context.” 计算分三步:① 识别 response 中的所有 claim;② 逐条检查该 claim 是否能由 retrieved context 推出;③ 计算 Faithfulness = 被上下文支持的 claim 数 / response 中 claim 总数。它不需要 ground truth,输入只需 user_input、response、retrieved_contexts。
  • Context Precision:度量检索器把相关 chunk 排在前面的能力,“assesses the degree to which relevant chunks in the retrieved context are placed at the top of the ranking”。它是各 rank 上 precision@k 的加权均值:Precision@k = TP@k / (TP@k + FP@k),Context Precision@K = Σ(Precision@k × v_k) / top-K 中相关项总数,其中 v_k 是第 k 位的相关性指示(0/1)。它是位置敏感的:文档给出的例子里,无关块排在第二位时分数不变(≈1.0),排到第一位时降到 ≈0.5。
  • 是否需要 ground truth:Faithfulness 明确不需要。Context Precision 有两种形态——有 reference 时用 reference 逐个比对 chunk(ContextPrecision,官方示例传 reference);无 reference 时用生成的 response 代替参照(ContextUtilization,官方说明 “Use this when you don’t have a reference answer but have the response that was generated”,旧 API 名为 LLMContextPrecisionWithoutReference)。此外还有完全不用 LLM 的 IDBasedContextPrecision(比较检索到的 ID 与参考 ID 集合)与基于编辑距离的 NonLLMContextPrecisionWithReference。

适用边界:Ragas 的原始定位是 reference-free evaluation,论文摘要原话是提出一套 “which can be used to evaluate these different dimensions without having to rely on ground truth human annotations”,目的是”faster evaluation cycles”。这既是它的价值也是它的边界:省掉人工标注的代价是参照物退化。这些指标是相对比较工具(用于版本 A/B 与趋势),不是绝对质量证明;分数同时取决于判定模型、提示词与 claim 切分粒度,不能反向推出业务正确率。

反例(数字很好但系统是错的):问”2025 年差旅报销标准是多少”,检索返回的是 2024 版制度(已废止,索引未更新)。生成的答案逐句都来自该上下文 → faithfulness = 1.0;而业务答案是错的。这说明 faithfulness 保证的是”内部一致”,不是”对世界为真”。 同理,若模型靠参数知识答对了但检索全是噪声,最终答案正确、context precision 很低——这时”检索差”是真的,但危害被掩盖,一旦知识更新就会集中爆发。

能推出 / 不能推出:

能推出不能推出
答案与检索上下文高度自洽(低幻觉率)答案在业务上正确(faithfulness 不判对错)
检索排序质量偏低,相关块常被排在后面检索漏召严重(那是 context recall 的职责,且需要 ground truth)
生成侧”编造”风险相对可控生成侧的表述、完整性、可操作性没问题(都不在 faithfulness 里)
值得优先查检索可以停止检查生成侧(恰恰相反:context precision 无 reference 时以 response 为参照)

在 Agent 系统中的应用:RAG 在 Agent 里通常是一个工具,因此指标必须记在工具调用层而不是最终答案层:

  1. 一次会话可能检索 3–7 次,只记最终答案的 faithfulness 无法定位是哪一次检索拉低了质量,也无法区分”第一次就错”和”重试后错了”。
  2. Agent 具备重试与改写查询的能力,这会产生掩蔽效应:检索失败但整体成功,端到端指标看起来很好,检索层退化被隐藏。因此必须按 (session, step, tool_call) 记录每次检索的指标。
  3. 评测集要按交互形态分层:单跳检索题(一次检索即可答)与多轮工具调用题(需要改写、重试、跨源交叉验证)应分别统计,否则 Agent 的”补救能力”会被计入检索的成功。
  4. 检索指标应与其他工具调用指标(工具选择正确率、参数校验通过率)放在同一条 trace 上,才能把”答非所问”归因到检索、工具还是规划。

与相近概念的区别:

  • faithfulness(对上下文忠实)vs factual correctness(对世界为真):前者不需要 ground truth,后者需要。前者高而后者低 = “一本正经地引用了错误的源”。
  • context precision(排序质量 / 惩罚噪声)vs context recall(覆盖度 / 惩罚漏召):precision 高不代表该找的都找到了。recall 类指标依赖 ground truth,本轮未逐页核验其公式。
  • reference-free 指标 vs 有 reference 指标:前者省成本但参照物可能是生成结果本身;后者可靠但需标注。
  • 检索层失败 vs 生成层失败:答案错 + 检索对 = 生成问题;答案错 + 检索错 = 检索问题;答案对 + 检索错 = 检索有隐患,被模型参数知识掩盖。

面试现场回答(1–2 分钟版本):

我会先说这组数字能推出什么。Faithfulness 度量的是答案和检索到的上下文是否事实一致,算法是把答案拆成 claim,逐条判断能不能从上下文推出来,最后算被支持的 claim 占比,取值 0 到 1,不需要标准答案。Context precision 度量的是检索有没有把相关 chunk 排在前面,它是各 rank 上 precision@k 的加权均值,而且位置敏感——官方例子里无关块排第二位分数不变,排到第一位就掉一半。

那么能推出的是:答案和上下文高度自洽、检索排序质量偏低。不能推出”生成没问题”,理由有两条。第一,faithfulness 只保证内部一致,不保证对世界为真——我举个反例:问 2025 年报销标准,检索召回的是已废止的 2024 版制度,答案句句有出处,faithfulness 满分,但业务答案是错的。第二,context precision 在没有标准答案时是拿生成结果当参照去判断 chunk 相关性的,也就是说生成如果错了,会连带把检索判成对的或错的——这是循环论证。

所以在 Agent 里我会把指标下沉到工具调用层:一次会话可能检索好几次,只记最终答案的一个分数定位不到是哪一次;而且 Agent 会重试和改写查询,检索失败但整体成功会掩盖检索层退化。评测集也要分单跳题和多轮工具调用题分别统计。负责人这个结论我只接受一半——检索确实该查,但生成侧的检查不能停。

关键点#

  1. faithfulness = 被上下文支持的 claim 数 / 总 claim 数,判的是”能否由上下文推出”,不是”是否正确”。
  2. context precision 是位置敏感的排序质量指标:Precision@k = TP@k / (TP@k + FP@k),无关块前置才降分。
  3. reference-free 是有代价的:省掉人工标注的代价是参照物退化为生成结果(ContextUtilization),形成循环论证。
  4. 答案正确 ≠ 检索正确:可能靠参数知识蒙对,隐患会在知识更新后集中爆发。
  5. 在 Agent 中必须记录到工具调用层,并按交互形态(单跳 / 多轮)分层统计,否则重试能力会掩蔽检索退化。

常见误区#

  1. 把 faithfulness 当成正确性指标。错误原因:它的定义就是”response 与 retrieved context 的事实一致性”,参照物是上下文而不是 ground truth。上下文全错而答案自洽时它拿满分。
  2. 认为用了 reference-free 指标就不需要人工标注。错误原因:Ragas 的设计目标是加快迭代周期(“faster evaluation cycles”),而非取代人工。检索层的 recall 类指标必须依赖 ground truth;precision 类在无 reference 时会用 response 当参照。
  3. 用端到端正确率当唯一指标并据此分配优化资源。错误原因:端到端正确率无法归因,且会掩盖”检索错但蒙对”的情形;本题负责人正是因此把资源错误地全部压到检索侧。归因必须分层:先判断”判定本身是否可信”,再看检索层,再看生成层,最后才看端到端。

追问#

追问:如果只能选三个指标做上线门禁,你选什么,阈值怎么定?

回答要点:

  • 分层各取其一:检索侧取一个覆盖度/排序指标(context precision 或 ID-based precision,后者不依赖 LLM 因而更稳定),生成侧取 faithfulness,端到端保留一个可断言指标(如引用有效性与关键字段精确匹配)。凡是能断言的不要用 LLM judge。
  • 阈值靠基线加人工标定,不靠拍脑袋:先在人工标注的小样本上测出”judge 分数 ↔ 人工判定”的一致性,把阈值定在人工认可的分界点;并记录判定模型与提示词版本。
  • 门禁分两级:阻断级(回归集通过率、可断言指标、引用有效性)与告警级(judge 类指标的漂移)。judge 类指标的波动用于观察,不直接阻断发布。
  • 把判定模型变更当作一次门禁变更:换 judge 模型或改 prompt 后,必须重新标定阈值并重跑基线,否则分数不可比。
  • 成本与稳定性:LLM 类指标每次评估都要调用模型,门禁要考虑评估时长;可用 HHEM 类小分类器替代部分判定(官方 faithfulness 页给出该替代路径)。

延伸学习#


S01 · AI Agent 场景题#

题目 ID:Q-20261103-S01 一级类型:Agent 评测与可观测性(兼属 AI Agent 核心) 二级主题:线上故障定位与可观测性(结果指标下钻、工具错误语义、评测集覆盖缺口、失效模式回流) 标签:Agent 可观测性、评测体系、工具调用、重试预算、灰度门禁

题目#

线上成功率从 82% 掉到 71%,离线评测集全绿

业务背景:企业 IT 工单处理 Agent,用户自然语言提交工单,Agent 负责分类、检索制度、调用内部系统处理并回复。42 个工具(其中 11 个为写操作),日均 8 万次工具调用,平均每个会话 6.3 轮、11 次模型调用。

当前架构:入口网关做身份与租户校验 → 编排器(状态机 + 步骤重试)→ 工具网关(统一参数校验、权限判定、错误结构化)→ 31 个业务系统与检索服务。会话状态与检查点存在关系库,trace 落地到可观测平台。

近两周指标:

指标两周前当前
任务成功率82%71%
P50 完成时长41 s58 s
单次会话成本0.31 元0.44 元
离线 golden set(320 条)通过率96%96%

故障现象:

  • 成功率下滑集中在”需要跨 3 个以上系统的工单”,单系统工单几乎无变化。
  • 失败模式 Top 3:① 工具参数校验失败后模型反复重试同一工具,同一工具的连续失败次数从 1.4 涨到 3.8;② 答非所问并给出未引用依据的结论;③ 中途进入长时间空转(> 90 s 无任何进展)。
  • 同期仅两处变更:上周把工具清单从 42 个精简到 31 个(删除 11 个重复工具);检索服务升级了一个依赖库的小版本。

目标:在不全量回滚的前提下把成功率恢复到 ≥ 80%,并建立”不会再重演”的机制。

限制条件:工具清单精简是季度 OKR,不能回滚;不能停服;线上数据含 PII,不得进入离线环境;每天只有一个灰度发布窗口。

需要你回答的取舍问题:

  1. 先修质量还是先修成本?
  2. 离线评测集要不要立刻扩容?扩到多少?
  3. 要不要回滚工具清单?

先思考#

  • 先问”离线全绿”意味着什么:是”系统没坏”,还是”没测到”?看失败集中在哪类输入。
  • 再看三个失败模式有没有共同祖先:参数校验失败 → 重试 → 上下文变长 → 压缩 → 约束丢失 → 答非所问。这像不像一条链?
  • 然后想”能力被删掉”和”参数填错”在错误信息里是否被区分开了。如果没区分,模型会怎么反应?
  • 最后区分三类能力:哪些事必须靠模型做,哪些该由编排层硬性约束,哪些根本不该交给概率性系统。

参考答案#

结论:这不是模型退化,而是”工具契约变更 + 评测集覆盖缺口”叠加的编排层故障。工具精简后,被删工具的意图被模型以”参数变形”的方式落到保留工具上,触发参数校验失败;而错误契约把”能力不存在”和”参数错误”混为一类,模型于是反复重试同一工具,重试既推高成本又污染上下文,长会话进入压缩后约束丢失,出现答非所问。离线集以单系统用例为主,跨系统编排根本没被覆盖,所以通过率不变——这个”全绿”是覆盖缺口的证据,不是系统健康的证据。

问题拆解(四层定界):

  1. 是否真坏:71% 与 82% 的差异来自输入分布还是系统行为?失败集中在跨系统工单、单系统工单无变化 → 不是全局容量或模型问题,是特定输入子集的故障。
  2. 坏在哪一层:按模型层 / 编排层 / 工具层三层拆。同一提示词、同一模型的离线回归通过 → 模型层大概率未退化;同一工具连续失败次数从 1.4 涨到 3.8 → 编排层的重试预算事实上失控;工具层参数校验失败率上升 → 工具契约或调用方参数来源发生了变化。
  3. 坏在哪一步:需要 trace 上的 step 级指标:每步的 tool_name、error_class、retry_index、step_latency、tokens。没有 step 级数据,成功率这个结果指标无法下钻。
  4. 哪个变更是原因:两处变更需分别验证。工具精简与”参数校验失败”存在机制上的直接关联(意图无处可去);检索依赖升级更可能影响召回质量而非参数校验。按变更前后分桶对比,不能因为”最近改了 A”就认定 A。

核心方案:

  1. 工具错误语义升级为结构化契约(止血,当天可做)。把工具返回的错误分成四类并强制契约化:capability_not_found(该能力不存在)、invalid_argument(参数不合法,附字段级原因)、upstream_error(下游失败,可重试)、permission_denied(越权,不可重试)。关键动作是把 “能力不存在”从”参数错误”中分离出来——当前模型收到的只有”参数错误”,它唯一能做的合理动作就是”改改参数再试一次”,这正是 3.8 次连续失败的来源。
  2. 重试预算硬约束(止血)。同一工具同一语义指纹连续失败 ≤ 2 次;单会话总重试 ≤ 6 次;超过即强制换策略(先检索工具清单 / 换个系统)或升级人工。带指数退避与抖动。
  3. 失败轨迹的上下文治理(止血)。把失败尝试压成一行结构化摘要:“尝试过 X(原因:capability_not_found),已排除”,而不是把完整报错与参数保留在上下文里。工具结果永远优先于对话历史被清理。
  4. 评测补集(本周)。按线上真实输入分布补充跨系统工单用例(至少 60 条,覆盖 3 系统 / 4 系统 / 含写操作三类),每条用例必须声明判定方式(断言 / judge / 人工)与失效模式标签。新增三个可断言指标:工具调用正确性(期望工具集合的精确/集合匹配)、每会话重试次数上界、引用有效性(引用 ID 是否存在且内容匹配)。
  5. 观测补维度(本周)。失败会话 100% 采样,成功会话按 5% 尾部采样(保留 P99 形态);trace 上落 tool_name / error_class / retry_index / step_latency_ms / tokens_in / tokens_out / prompt_version / model / tool_manifest_version / retrieval_version。成本必须能归因到 (tenant, session, step, tool)。
  6. 变更门禁(本周)。工具清单变更视为破坏性变更,发布前必须在影子环境跑完整 golden set + 跨系统补集,并额外对比工具调用分布是否发生迁移(若某被删工具的调用量被邻近工具吸收,就是本次故障的直接前兆)。

关键执行流程:

  • D0(止血):错误契约四类上线 + 重试硬上限 + 失败轨迹摘要化 → 灰度 10% → 观察 24 小时的”连续失败次数分布”与”无进展率”。
  • D1–D2(归因验证):按两个变更分别做分桶对比;在影子环境回放 30 条真实失败会话(脱敏后的结构化参数与错误码,不含 PII 原文),确认”工具精简”是主因。
  • D3–D5(机制化):补集 + 可断言指标 + 变更门禁 + 采样策略上线。
  • D6+(灰度):按租户分桶灰度,守护指标越界自动回滚。

技术选型与选择依据:

决策点选择依据备选方案与代价
错误语义自研结构化错误契约(error_class + 字段级原因 + retryable + side_effect)错误分类是确定性能力,应放在传统软件层;让模型从自然语言报错里猜原因是概率性能力,不稳定且消耗 token保留自然语言报错、靠提示词教模型分辨——成本低但不可靠,且每次换模型都要重调
重试策略硬上限 + 强制换策略 / 升级人工重试的边际收益快速衰减(同一指纹第 3 次成功率极低),而成本与延迟线性增长,且污染上下文无上限重试——表面成功率可能更高,但成本与尾延迟失控,且形成上下文污染
采样失败全采 + 成功尾部采样归因只需要失败样本的完整信息;成功样本用于基线与分布全量采样——成本随调用量线性增长;纯头部采样——看不到尾部形态
判定方式可断言优先(工具调用、重试次数、引用有效性),judge 只用于”答非所问”可断言指标确定、便宜、可回归;judge 有偏差且需版本化全 judge——受位置/冗长偏好影响,且评估成本高
变更门禁工具清单变更走破坏性变更流程清单是模型可观察的”能力面”,改它等价于改 API视作普通配置发布——本次故障即由此产生

方案取舍:

  • 先修质量还是先修成本:先修质量。成本上升是重试放大的结果,不是独立故障。直接压成本(降模型规格、砍上下文)会同时掩盖失败信号并恶化质量——这与 B01 的教训一致:修代理指标不等于修问题。
  • 先扩量还是先补覆盖:先补覆盖缺口。盲目把 320 条扩到 1000 条,若仍按单系统分布采样,通过率依旧全绿。正确做法是按线上输入类型分层抽样,并把每一条线上失效模式沉淀为至少一条用例。
  • 是否回滚工具清单:不回滚。回滚会带回 11 个重复工具导致的工具选择歧义,只是换一种失败形态。正确做法是保留精简成果,同时把”能力不存在”变成模型可理解、可据此换路的明确信号。

失败路径、边界条件、超时、重试、幂等与恢复:

  • 工具调用三态:成功 / 可重试失败 / 终态失败。permission_denied 与 capability_not_found 必须是终态,不得进入重试。
  • 超时 ≠ 未执行:写类工具超时后状态未知,必须由幂等键兜底,键为 (tool_name, 归一化参数指纹, 会话 ID) 的哈希,落在工具网关的确定性层。
  • 幂等与去重:写操作在网关侧做指纹去重,覆盖上游系统无幂等能力的情况;去重窗口须长于最大重试时长。
  • 空转恢复:会话级检查点记录”已完成的步骤与副作用”;超过 90 s 无进展即进入 no_progress 状态,触发一次策略切换,仍无进展则升级人工并保留完整诊断包(trace ID、已尝试工具、失败原因序列)。
  • 人工接管:接管的输入回填到上下文作为高优先级事实;等待不受会话寿命约束(持久化挂起 + 信号恢复)。
  • 降级方向:检索服务不可用或 judge 不可用时,走向”降低自动化程度”(转人工 / 只做分类),不得走向”降低判定标准”(让模型自由发挥)。
  • 上下文压缩:压缩是概率性操作,必须有确定性兜底——纯裁剪路径必须可用;pinned 层(约束、已完成副作用、关键标识符)不可被压缩掉。

安全、权限、成本、延迟与可靠性分析:

  • 安全:工具精简后权限面变小是收益,但必须确认被删工具的权限没有被保留工具的”宽参数”重新打开(例如被删的是”仅查本人订单”,保留的是”按用户 ID 查订单”)。错误契约不得把内部堆栈、SQL、内部主机名回传给模型。越权尝试必须独立计数并告警,它是攻击信号而非普通失败。
  • 权限:权限判定在工具网关这一唯一确定性执行点,不在提示词里。
  • 成本:成本归因到 (tenant, session, step, tool),派生指标”重试 token 占比”应单独监控——它是本次故障最早的可见信号之一。
  • 延迟:P50 从 41 s 涨到 58 s 主要来自重试轮次而非单步变慢,用 step 级 P95 + 重试次数分布验证;若单步 P95 未变而会话 P50 变长,即可确认是轮次增加。
  • 可靠性:灰度按租户分桶;守护指标 = 成功率、重试次数 P95、无进展率、单次成本 P95,任一越界自动回滚;每天一个发布窗口意味着回滚窗口也要预留。

评测指标、测试方法与上线后观测:

  • 门禁指标(阻断级):golden set 通过率(按单系统 / 跨系统分层统计)、工具调用准确率(集合匹配,可断言)、每会话重试次数 P95(可断言)、引用有效性(可断言)。
  • 门禁指标(告警级):faithfulness / context precision 等 judge 类指标的漂移、单次成本 P95、P50/P95 完成时长。
  • 线上观测:失败模式 Top-N 日报;失败会话 trace 100% 可查;按 prompt_version / model / tool_manifest_version / retrieval_version 四维分桶对比成功率与成本——版本维度是本次故障能否在 30 分钟内定位的关键。
  • 回归测试方法:影子环境回放(脱敏后的结构化轨迹)、A/B 灰度、多次运行取统计口径(单次对比对概率性系统不可信)。

三层能力归属(本题必须区分):

  • 模型本身的概率性能力:意图识别、参数生成、根据错误反馈调整策略、判断”答非所问”(judge)。都可能错,都要有外部约束。
  • Agent 编排、状态与工作流能力:重试预算、状态机、上下文压缩、空转检测、升级人工。这些必须由确定性代码实现,不能交给模型自觉。
  • 传统软件系统的确定性能力:参数校验、错误分类(error_class)、幂等键、权限判定、采样与指标、灰度与自动回滚、trace 落库。

关键点#

  1. “离线全绿”在这里是覆盖缺口的证据,不是健康的证据:失败集中在跨系统工单、单系统无变化,说明故障在特定输入子集,而评测集没有覆盖该子集。
  2. 三个失败模式有共同祖先:能力不存在被误报为参数错误 → 反复重试 → 成本与上下文同时膨胀 → 压缩后约束丢失 → 答非所问。修根因(错误语义 + 重试预算)一次解决三个现象。
  3. 必须区分三类能力:错误分类、参数校验、幂等键、采样与灰度回滚属确定性系统;重试预算、状态机、空转检测、上下文压缩属编排层,也必须确定性实现;只有意图识别与策略调整属于模型的概率性能力。
  4. 可断言指标优先于 judge:工具调用正确性、重试次数上界、引用有效性都可断言,只有”答非所问”需要 judge,且 judge 必须版本化。
  5. 版本维度是定位速度的关键:trace 上必须落 prompt_version / model / tool_manifest_version / retrieval_version,否则无法区分两处变更各自的贡献。

追问#

追问 1:如果确认是模型退化(同一提示词换模型版本后失败率上升),处置有什么不同?

回答要点:

  • 先确认再行动:单次对比对概率性系统不可信,必须用同一 golden set 跑多次(如 3–5 次)取统计口径,并比较置信区间;同时固定 temperature / seed 与 system_fingerprint 以缩小非目标变量。
  • 处置路径不同:工具契约问题改的是确定性层(改完立竿见影且可回归);模型退化改的是概率性层,处置是网关层模型回退 + 提示词适配 + 可能的微调,且需要更长观察窗。
  • 回退也是变更:把模型版本回退当作一次配置变更走灰度,守护指标同上。
  • 长期机制:模型版本必须是可一键切换的配置,且每次切换都要有对应的回归基线;保留”旧模型可用”的逃生通道。

追问 2:怎么避免离线评测集长期与线上分布脱钩?

回答要点:

  • 失效模式回流机制:每周从失败 trace 中抽样,人工标注后沉淀为用例,并打上失效模式标签(工具选择错误 / 参数错误 / 检索漏召 / 上下文污染 / 越权)。
  • 分布对齐:按线上输入类型分层抽样(单系统 / 跨系统 / 含写操作 / 长会话),每层保底条数,而不是整体随机。
  • 用例生命周期:每条用例声明判定方式与失效模式;产品与制度变更后同步作废或更新过期用例,避免”用旧正确答案判定新系统”。
  • 漂移观测:监控”线上失败模式中未被任何用例覆盖的比例”,这个比例本身就是评测集健康度指标。

追问 3:成本涨了 42% 但成功率只掉 11 个点,值得投入修吗?

回答要点:

  • 值得,因为同源:成本上升与成功率下降都来自重试放大,修重试同时解决两者;且重试会污染上下文造成二次退化(答非所问),这部分损失尚未完全体现在当前成功率里。
  • 但要分开核算:必须确认没有独立的成本泄漏——如上下文无上限增长、提示缓存命中率下降(工具清单变更会让前缀失效)、检索召回变多导致上下文变长。这三项各自对应不同处置。
  • 量化口径:把成本拆成”有效 token”与”浪费 token(重试 + 被压缩丢弃 + 未命中缓存)“,浪费占比是比总成本更敏感的工程指标。

常见误区#

  1. 看到离线全绿就判定”线上问题是环境或数据问题”。错误原因:golden set 的覆盖缺口本身就是产品缺陷;本次故障中,跨系统工单从未被覆盖,“通过率不变”恰恰是最强的不利证据。
  2. 直接降低模型规格或裁剪上下文来压成本。错误原因:成本上升是重试放大的结果,压成本会掩盖失败信号并造成质量二次劣化;正确顺序是先定位重试根因。
  3. 把所有失败归因到最近一次变更。错误原因:相关性不等于因果。同期有两处变更,必须按版本维度分桶对比;本次真正的机制关联是”工具精简 → 意图无处可去 → 参数变形 → 校验失败”,而检索依赖升级需要单独证伪。

小型实践(30–60 分钟)#

取 30 条线上失败会话的 trace,做三件事:① 给每一步标注 error_class 与”这次重试是否必要”(必要的定义:换工具或换参数且带来了新信息);② 计算”可避免重试占比”与”重试 token 占比”两个派生指标;③ 从中挑 5 条改写成可断言的回归用例(断言目标是工具调用集合与重试次数上界,而不是最终答案文本),并给每条写上失效模式标签。

延伸学习#

  • Ragas 官方指标文档(Faithfulness / Context Precision):用于把 judge 类指标与可断言指标分开,见 B02 延伸学习。
  • OpenTelemetry GenAI 语义约定(open-telemetry/semantic-conventions-genai):agent 与工具调用 span 的模型化方式;注意该约定当前整体状态仍为 Development(gen_ai.* 专属属性均为 Development,仅继承的 error.type / server.address / server.port 为 Stable),落地时应把它当作内部约定而非稳定契约(该状态为 2026-11-02 配置维护时第 5 次复核的结论,本轮沿用未再核验)。

S02 · 非 AI Agent 场景题#

题目 ID:Q-20261103-S02 一级类型:软件工程与平台工程(兼属操作系统与网络) 二级主题:Kubernetes 扩缩容与容量治理(HPA 信号与滞后链路、QoS 与驱逐、下游容量上界、入口准入控制) 标签:Kubernetes、HPA、容量规划、限流、QoS

题目#

压测通过的容量,开抢就崩

业务背景:电商订单服务,部署在 Kubernetes 集群,Deployment 固定 12 副本。单副本 requests: cpu=1, memory=1Gi,limits: cpu=2, memory=2Gi。每个副本维护 20 个数据库连接,数据库总连接上限 300。Pod 从启动到 Ready 需要 45 秒(含 JVM 预热)。

当前架构:负载均衡 → 网关(限流与鉴权)→ 订单服务(12 副本)→ 数据库主从。HPA 已配置:targetCPUUtilizationPercentage 语义下的 averageUtilization: 70,同步周期 15 秒(默认),缩容稳定窗口 5 分钟(默认)。节点池支持自动扩容,新节点就绪约 3 分钟。

压测结论(大促前两周):逐步加压到 6000 RPS,P95 = 180 ms,通过。

大促开抢当天:

  • 流量在 30 秒内从 800 RPS 冲到 5200 RPS。
  • 随后 3 分钟内 P95 从 190 ms 涨到 4.2 秒,错误率 6%。
  • 部分 Pod 状态为 OOMKilled,节点出现 MemoryPressure 条件。
  • 开抢后约 2 分钟才发生第一次扩容,最终扩到 24 副本;此后数据库连接池被打满(24 × 20 = 480 > 300),大量请求阻塞在获取连接上。
  • 整个开抢期间 CPU 平均利用率只有 55%,未达到 70% 的扩容目标。

目标:让 30 秒内 5 倍流量突增可承受(P95 < 400 ms),且不打爆数据库。

限制条件:数据库连接上限 300 短期内不能调整;节点池扩容需要 3 分钟;不能靠无限加副本解决问题;不能为了容量牺牲下单主链路的可用性。

需要你回答的取舍问题:

  1. HPA 应该用 CPU 还是 RPS / 在途请求数作为扩容信号?
  2. 提前扩容(定时 / 预测)还是纯 reactive 扩容?
  3. 放大副本还是在入口限流?

先思考#

  • 先算时间账:突增窗口是 30 秒,而扩容链路包含哪些环节?每个环节各多久?加起来够不够?
  • 再算容量账:数据库 300 个连接,每个副本 20 个,最多能有几个副本?扩到 24 会发生什么?
  • 然后问”CPU 55%“这个数字:服务在等数据库连接的时候,CPU 是忙的还是闲的?用 CPU 当信号,能不能看到”连接不够”这件事?
  • 最后想故障形态:如果注定有一部分请求要失败,你希望它们”全部超时”还是”部分快速失败”?

参考答案#

结论:问题不在”没配 HPA”,而在三件事叠加——信号错配、滞后不可控、下游容量未纳入上界。CPU 平均只有 55% 说明瓶颈根本不在 CPU(在数据库连接与下游),用 CPU 做扩容信号必然滞后且永不达标;而 45 秒就绪 + 15 秒同步周期 + 可能的 3 分钟节点扩容,意味着纯 reactive 扩容在时间上不可能覆盖 30 秒的 5 倍突增。因此方案是:以数据库容量反推副本上界 → 定时提前扩容建立基线 → 用在途请求数/队列等待作为 reactive 信号 → 入口有界排队与按优先级限流 → 连接池按副本数自适应。

问题拆解:

  1. 时间预算:突增窗口 30 秒;扩容链路 = HPA 同步周期 15 s + 调度与镜像拉取 + Pod 就绪 45 s + 可能需要的新节点 3 min。即使一切顺利也 ≥ 60 秒,是突增窗口的两倍以上 → 纯 reactive 在物理上不可能。
  2. 信号预算:CPU 平均利用率 55% < 70% 目标,HPA 按公式不会扩;而 P95 已崩 → 饱和资源不是 CPU。用 CPU 当信号,等于用一个与故障无关的量做决策。
  3. 容量预算:数据库 300 连接 ÷ 每副本 20 = 副本上限 15。扩到 24 必然打爆连接池 → 扩容不是免费的,它会把压力转移到下游。
  4. 内存与 QoS:requests(1Gi) ≠ limits(2Gi) → Pod 的 QoS 为 Burstable。节点内存压力时 kubelet 会主动驱逐 Pod 回收资源,且驱逐不尊重 PodDisruptionBudget 与 terminationGracePeriodSeconds(硬驱逐阈值为 0 秒宽限,立即关闭)→ PDB 保护不了这类故障。
  5. 验证预算:压测用的是”逐步加压到 6000 RPS”的稳态,而真实流量是”30 秒 5 倍斜坡”。压测形态与真实形态不匹配,通过结论无效。

核心方案:

  1. 换扩容信号:从 CPU 换成 每副本在途请求数或队列等待时间(custom / external metrics),保留 CPU 作为辅助下限信号。依据:HPA 的 averageUtilization 是”当前使用量 ÷ 该 Pod 的 request”的百分比再对所有 Pod 取平均——它是相对 request 的代理指标,服务瓶颈不在 CPU 时该信号恒不达标。
  2. 提前扩容建立基线:大促前 10 分钟用定时任务把 minReplicas 提到容量预算算出的基线(15 副本),reactive 只负责尖峰余量;窗口结束后自动收缩。依据:45 秒就绪 + 可能的 3 分钟节点扩容,任何 reactive 都来不及。
  3. 副本上界硬约束为 15,由数据库容量反推,写进 HPA 的 maxReplicas 并在 CI 中校验(改池大小必须同步改上界)。
  4. 连接池按副本数自适应:池大小 = min(⌊300 / 副本数⌋, 单副本上限),通过配置下发或启动探针读取;中期引入连接池代理(pgbouncer 类),把”连接数 × 副本数”的乘法关系解耦。
  5. 入口准入控制:网关侧按接口/租户分级的并发准入 + 有界队列 + deadline;队列满时按关键性拒绝(保下单,牺牲推荐、报表、导出);被拒请求返回”可判定”的错误码与 Retry-After。
  6. 就绪与初始化参数对齐:配置 startupProbe 覆盖 JVM 预热期;把 --horizontal-pod-autoscaler-cpu-initialization-period(默认 5 分钟)与 --horizontal-pod-autoscaler-initial-readiness-delay(默认 30 秒)对齐真实启动时长。依据:官方文档明确,未就绪 Pod 与缺失指标的 Pod 在扩容计算中被保守假设为消耗 0%,会抑制扩容幅度——这正是”开抢后 2 分钟才扩”的放大器之一。
  7. 内存与 QoS 治理:关键服务把 memory requests = limits 使其进入 Guaranteed(官方判据:Pod 中每个容器都必须设置 memory/CPU 的 limit 与 request,且 limit 必须等于 request;该判定对 init 容器同样适用)。sidecar 单独设限,避免把关键容器挤爆。把节点硬驱逐阈值(memory.available<100Mi)与 kubelet 监控间隔(housekeeping-interval 默认 10 s)纳入容量评估——驱逐是事后动作,不是保护机制。

关键执行流程:

  1. 容量预算表:单副本稳态吞吐(压测实测)→ 目标峰值 RPS → 需要的副本数 → 与数据库上界取 min → 得到 maxReplicas;再算”扩容决策时延”(指标越界到新 Pod Ready 的实测值)→ 与突增窗口比较 → 决定提前扩容的提前量。
  2. 信号改造:接入 custom metrics(每副本在途数),HPA 改为 type: Pods 或外部指标;CPU 降为辅助。
  3. 提前扩容:定时任务改 minReplicas,窗口结束回调。
  4. 池自适应与代理:先配置化,再引入代理。
  5. 入口限流:按优先级分桶 + 有界队列 + Retry-After。
  6. 压测复现:必须包含 30 秒 5 倍斜坡场景,而不只是稳态 6000 RPS。
  7. 灰度与演练:每次大促前跑一次容量演练,把”扩容决策时延”做成 SLO。

技术选型与选择依据:

决策点选择依据备选方案与代价
扩容信号在途请求数 / 队列等待(custom metrics)直接对应排队,与用户感知的延迟同源CPU averageUtilization——代理指标,瓶颈不在 CPU 时恒不达标;RPS per pod——更直观但不感知服务时间变化
扩容时机定时提前扩容 + reactive 余量扩容链路 ≥ 60 s > 30 s 突增窗口,reactive 物理上不可能纯 reactive——必然滞后;纯固定容量——常态成本过高
副本上界由数据库容量反推并硬编码副本 × 连接数是乘法,无上界的扩容等于把故障转移给 DB无限扩容——短暂压住延迟,随后 DB 雪崩,故障更严重
连接池先按副本数自适应,中期上池代理自适应改动小、见效快;代理是通用解但需要额外组件与运维直接调大 DB 上限——只是把瓶颈后移到 DB 的 CPU 与上下文切换
过载保护入口有界队列 + 按优先级拒绝让故障形态从”全部超时”变成”部分快速失败”,可保住主链路无限排队——请求排队到超时,客户端重试进一步放大,形成雪崩

方案取舍:

  • 先扩容还是先限流:先定上界再扩容。即”扩到能扩的上界(15),剩下的用限流拒”。否则扩容会把故障转移到数据库,而数据库的故障恢复时间远长于应用。
  • 提前扩容的成本:常态多跑 N 个副本的成本 vs 一次大促故障的成本。用”大促窗口 + 自动收缩”把额外成本限制在窗口内;同时应评估是否用低优先级负载填充这些副本以提高利用率。
  • 是否提高 requests 让 CPU 信号更敏感:会降低节点装箱密度、提高常态成本,且仍然度量错误的资源。更合理的是直接换信号;如果暂时不能换,可短期降低 request 使 CPU 利用率数值变敏感,但必须同时意识到这会改变调度语义与装箱。
  • 强一致性与吞吐:本场景不涉及数据一致性取舍,但要注意限流拒绝会改变”下单成功率”的统计口径——可用性指标必须按关键性分层统计,否则整体成功率会掩盖主链路的健康。

失败路径、边界条件、超时、重试、幂等与恢复:

  • 扩容失败路径:镜像拉取失败、节点资源不足、命名空间配额不足、云配额上限 → 需独立告警,并在入口侧降低准入(因为已知容量不足)。
  • 就绪失败:startupProbe 未通过 → Pod 不进入 endpoints,且 HPA 将其计入”未就绪”并按 0% 消耗保守假设,抑制扩容 → 必须让初始化参数与真实启动时长对齐。
  • 缩容抖动:缩容稳定窗口默认 5 分钟,控制器取窗口内的最高推荐值,因此缩容是渐近的。不应为了省成本把它调到很小,否则会在流量波动时反复扩缩。
  • 客户端重试放大:扩容期间的请求失败会触发客户端重试,进一步打满队列 → 网关必须做重试折叠(同一请求签名的并发重试合并),被拒响应带 Retry-After 与明确错误码,可重试性与幂等性分开声明。
  • 幂等:下单请求必须携带幂等键;限流拒绝后客户端重试不会因为重复提交造成重复下单——这是”限流会返回失败”这一设计能被接受的前提。
  • 恢复:节点 MemoryPressure 后 kubelet 可能同时驱逐多个 Pod,且不尊重 PDB;恢复依赖控制器重建(Deployment 会补副本),但重建同样要 45 秒就绪 → 恢复期内必须依靠入口限流保护,而不是等待扩容。
  • OOM 边界:OOMKilled 说明容器触及 memory limit(2Gi)。把 request 调到接近真实工作集,或把关键容器的 request = limit,可以让调度与驱逐行为可预测。

性能、可用性与成本分析:

  • 性能:P95 < 400 ms 的目标必须分解为”排队时间 + 服务时间 + 下游时间”三段,各自设阈值。只盯总的 P95 无法定位;而本场景中排队与下游(获取连接)是主要部分。
  • 可用性:副本上界 + 限流使故障形态从”全部超时”变为”部分快速失败”。可用性指标应按关键性分层(下单 / 查询 / 报表),整体成功率是误导性指标。
  • 成本:提前扩容的窗口成本、常驻基线的成本、限流造成的放弃成交额,三者应与故障成本一起进入决策表;常态应通过 HPA 缩容稳定窗口与低优先级负载填充来控制。
  • 安全:节点池自动扩容涉及云凭证与配额,须设置上限与审批;镜像拉取与节点加入须在可信网络中完成。

验证指标与上线后观测:

  • 压测必须复现真实形态:30 秒内 5 倍斜坡,而非仅稳态 6000 RPS;同时做一次”节点丢失”演练验证重建时长。
  • 核心指标:P95 / P99 及其三段分解;每副本在途请求数;队列等待 P95;扩容决策时延(指标越界 → 新 Pod Ready 的实测耗时,作为 SLO);数据库连接数与水位;OOMKilled 次数;kubelet 驱逐次数(MemoryPressure 持续时长);按优先级分桶的被拒请求比例。
  • HPA 可观测:关注 HPA 的推荐副本数与实际副本数的差值、以及”因未就绪 Pod 导致扩容被抑制”的事件——后者是本题中最容易被忽略的信号。
  • 上线后:每次大促前跑容量演练;把容量预算表做成可执行的检查(CI 校验 maxReplicas × pool_size ≤ DB 上限)。

关键点#

  1. 弹性需要三个条件同时成立:信号正确、滞后可控、下游有余量。本题三个条件全部不满足。
  2. HPA 的 CPU averageUtilization 是相对 request 的时间平均代理指标:瓶颈在 off-CPU 等待时它恒不达标,且平均会抹平个别繁忙副本。
  3. 副本数 × 每副本连接数是乘法:扩容会把压力转移到下游,maxReplicas 必须由下游容量反推,而不是由流量除以单副本吞吐得出。
  4. 未就绪 Pod 会抑制扩容:HPA 对未就绪与缺指标的 Pod 按 0% 消耗做保守假设,45 秒就绪期与初始化参数不匹配会显著放大滞后。
  5. PDB 保护不了节点压力驱逐:官方明确驱逐不尊重 PDB 与 terminationGracePeriodSeconds;关键服务要靠 QoS 类、真实内存 request 与容量余量。

追问#

追问 1:如果数据库连接上限可以调,能不能直接调大解决?

回答要点:

  • 只能缓解,不能解决。数据库的处理能力(CPU、锁、上下文切换)才是真正的上界;连接数增大后,活跃并发上升会拖慢每个查询,延迟反而上升,最终仍会崩,只是崩的位置更靠近 DB。
  • 正确做法是把”每副本连接预算”变成部署参数:扩容时联动收缩池大小,使总连接数恒定;或者引入连接池代理,把 N×M 的连接关系变成代理层的固定小连接池。
  • 容量预算的方向是反的:不是”DB 能撑多少副本”,而是”业务峰值需要多少副本,因此每个副本只能分到多少连接”。

追问 2:为什么 CPU 平均利用率只有 55%,P95 却崩了?

回答要点:

  • 瓶颈在数据库连接等待,属于 off-CPU 等待:线程在等连接时 CPU 是空闲的,因此 CPU 利用率不会上升(这与 B01 的 on-CPU / off-CPU 区分是同一个结构)。
  • HPA 的 averageUtilization 是”使用量 ÷ request”的百分比再取平均,55% 意味着大部分副本都没到扩容阈值,平均值进一步把个别繁忙副本抹平。
  • 平均值还会掩盖突发:即使 CPU 真的是瓶颈,长周期平均也会隐藏秒级打满。正确信号是排队类指标(在途数、队列等待),它直接对应用户感知的延迟。

追问 3:PodDisruptionBudget 能不能防止这次的 Pod 被驱逐?

回答要点:

  • 不能。官方明确:节点压力驱逐时 “The kubelet does not respect your configured PodDisruptionBudget or the pod’s terminationGracePeriodSeconds”;使用硬驱逐阈值时宽限期为 0 秒,立即关闭。
  • PDB 只约束自愿中断(如节点排空、集群升级这类由 API 发起的驱逐),它保护不了资源压力导致的驱逐。
  • 因此关键服务要靠 QoS 类(Guaranteed)+ 真实的内存 request + 节点余量 + 容量上界来保护,而不是靠 PDB;同时应理解 QoS 类在 Pod 创建时确定且生命周期内不变,改资源导致 QoS 变化会被控制面直接拒绝。

常见误区#

  1. 认为配了 HPA 就等于拥有了弹性。错误原因:弹性受限于”信号正确 + 滞后可控 + 下游有余量”三个条件。本题滞后链路(15 s 周期 + 45 s 就绪 + 可能 3 min 节点)远长于 30 秒突增窗口,且信号本身错配。
  2. 用平均 CPU 利用率作为容量信号。错误原因:它是相对 request 的时间平均忙闲度,既看不到 off-CPU 等待(本题的真实瓶颈),也会被平均抹平个别副本的繁忙。
  3. 只扩应用层不看下游容量。错误原因:副本数 × 每副本连接数是乘法关系,无上界的扩容把故障从应用层转移到数据库,而数据库的恢复时间更长、影响面更大。正确顺序是先算下游上界,再定 maxReplicas。

小型实践(30–60 分钟)#

写一个容量预算脚本或表格,输入:单副本稳态吞吐(压测实测 RPS)、目标峰值 RPS、Pod 就绪时长、HPA 同步周期、节点扩容时长、下游连接上限、每副本连接数。输出:① 需要的副本数;② 由下游反推的 maxReplicas 与二者取 min 的结果;③ 扩容决策时延估算,以及与突增窗口比较后的结论(是否需要提前扩容、需提前多久);④ 入口限流阈值与按优先级的拒绝顺序。同时在本地对现有 Deployment 清单做静态审查:确认 QoS 类(是否 Guaranteed)、requests 与 limits 是否相等、startupProbe 是否覆盖预热期、HPA 的 maxReplicas × pool_size 是否超过 DB 上限。

延伸学习#


L01 · LeetCode#

题目 ID:Q-20261103-L01 一级类型:栈与队列(辅助栈 / 不变式设计) 二级主题:用同步辅助栈维护前缀最小值 标签:LeetCode、栈、设计题、不变式

题目#

设计一个支持 push、pop、top 操作,并能在常数时间内检索到最小元素的栈。实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int value) 将元素 value 推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

英文原题附加要求:每个函数的时间复杂度都必须是 O(1)(“You must implement a solution with O(1) time complexity for each function”)。

先思考#

  • 先想一个最朴素的方案:栈里只存数据,getMin 时遍历一遍。它违反了哪一条要求?在什么调用比例下它会成为瓶颈?
  • 再想”能不能把答案提前算好”:如果我在每一次 push 的时候,就把”到当前为止的最小值”记下来,push 时已知哪些信息?
  • 然后想 pop:弹出一个元素后,之前记下来的那些”到某处为止的最小值”里,哪些还有效、哪些必须一起失效?它们放在什么结构里最自然?
  • 最后考虑重复值:连续 push 三个 5,再 pop 两个,getMin 应该还是 5。你的结构会不会把 5 提前丢掉?

参考答案#

题号 / 名称 / 难度 / 链接:

  • 题号:155
  • 中文名:最小栈;英文名:Min Stack
  • 难度:medium(⚠️ 本次中英文两个官方页面均未渲染难度标签,此分类按 LeetCode 标准分类记录,未直接核验)
  • 官方链接(已核验页面可访问且内容一致):
  • 英文页面实时数据(会变动):Accepted 3,024,053 / 5.1M,Acceptance Rate 58.8%;标签为 Stack、Design

输入、输出、约束与示例:

  • 输入:操作名数组与参数数组(构造器形式)。
  • 输出:每个操作的返回值,void 操作返回 null。
  • 约束(中英文页一致):
    • -2^31 <= val <= 2^31 - 1
    • pop、top、getMin 总是在非空栈上调用
    • push、pop、top、getMin 总共最多调用 3 * 10^4 次

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.

解题思路:

  1. 直观方案与其局限:只用一个列表存数据,getMin 时 min(self._data) 遍历全栈。空间 O(1) 额外、实现最简,但 getMin 是 O(n)。题目要求每个操作 O(1),因此在 getMin 被频繁调用(例如 3 万次调用中一半是 getMin)时整体退化到 O(n²) 量级——这就是它不可接受的原因。另一个直观想法是”缓存一个最小值变量”,但它在 pop 掉当前最小值后无法回答”次小值是多少”,除非重新遍历。

  2. 推荐方案的推导:把”缓存一个最小值”推广为”缓存每一个前缀的最小值”。设数据栈为 data,辅助栈为 mins,令

    不变式:mins[i] == min(data[0..i]),且 len(mins) == len(data) 恒成立。

    • push(v):新前缀 [0..n] 的最小值 = min(旧前缀最小值, v) = min(mins[-1], v)(栈空时即 v)。这是 O(1),且维持了不变式。
    • pop():移除最后一个元素,同时移除 mins 的最后一个元素。由于 mins 与 data 等长,剩下的 mins[i] 仍然精确描述剩下的 data[0..i] 的前缀最小值——不变式在 pop 后自动保持,不需要重算。
    • top():data[-1],O(1)。
    • getMin():mins[-1],正是整个栈的前缀最小值,O(1)。

    关键点在于:辅助栈不是”历史最小值的列表”,而是”与每个栈位置对齐的前缀最小值序列”。正因为对齐,pop 才是”同步弹一个”而不是”重新计算”。

  3. 正确性说明:用数学归纳法。初始时两栈皆空,不变式平凡成立。设 push 前不变式成立,push 后 mins[n] = min(mins[n-1], v) = min(min(data[0..n-1]), v) = min(data[0..n]),成立。设 pop 前不变式成立,pop 后 data 与 mins 同步移除末位,对任意 i < n-1,mins[i] 与 data[0..i] 的对应关系未变,成立。因此任意时刻 mins[-1] == min(data),getMin 返回正确值。

  4. 复杂度:四操作均为 O(1) 时间;空间 O(n),辅助栈最坏与主栈等长(严格递减输入时每个元素都要进 mins;若改用”仅在新值 ≤ 当前最小值时入栈”的压缩写法,最好可到 O(1) 额外,但最坏仍为 O(n),且 pop 需要一次相等判断)。

Python 参考代码:

class MinStack:
def __init__(self):
self._data = []
self._mins = []
def push(self, val: int) -> None:
self._data.append(val)
if not self._mins:
self._mins.append(val)
else:
self._mins.append(val if val < self._mins[-1] else self._mins[-1])
def pop(self) -> None:
self._data.pop()
self._mins.pop()
def top(self) -> int:
return self._data[-1]
def getMin(self) -> int:
return self._mins[-1]

边界情况:

  1. 重复的最小值:连续 push 多个相同最小值时,同步辅助栈(每个位置都记)天然正确;若采用”仅更小才入栈”的压缩写法,必须改成”≤ 当前最小值时入栈”并同步出栈,或用 (值, 计数) 二元组,否则 pop 掉一个最小值时会把其余同值最小值一起丢掉。
  2. 最小值在栈顶:pop 后 getMin 必须回退到次小值,同步出栈自动满足。
  3. 全负数与极值:val 可取到 -2^31 与 2^31 - 1;本解法只做比较与存储,不涉及算术,不存在溢出问题(差值编码变体会涉及大数相减,需更大整数类型)。
  4. 单元素栈:push 一个元素后立即 getMin,应返回该元素;mins 为空分支必须正确处理。
  5. 调用次数 3×10^4:递归实现会在长输入下爆栈,必须迭代实现——本解法只用列表操作,无此问题。
  6. 题目保证 pop / top / getMin 在非空栈上调用,因此实现中不必处理空栈;若在面试中被追问,应明确这是题目给出的前提,而不是”不需要考虑”。

测试用例:

#操作序列期望输出覆盖点
1MinStack, push(-2), push(0), push(-3), getMin, pop, top, getMin[null,null,null,null,-3,null,0,-2]官方示例;pop 后回退到次小值
2MinStack, push(5), push(5), push(5), getMin, pop, getMin, pop, getMin[null,null,null,null,5,null,5,null,5]重复最小值必须逐个存活
3MinStack, push(0), push(1), push(0), getMin, pop, getMin[null,null,null,null,0,null,0]最小值与非最小值交替;零值
4MinStack, push(-2147483648), push(2147483647), getMin, top, pop, getMin[null,null,null,-2147483648,2147483647,null,-2147483648]int 边界值
5MinStack, push(3), pop, push(2), push(1), getMin, top[null,null,null,null,null,null,1,1]栈被 pop 空后重新填充,辅助栈同步

(以上用例已在本机对参考代码执行并通过,另与”每次 getMin 遍历全栈”的朴素实现做了 3000 组随机操作序列对拍,结果完全一致。)

面试官可能提出的变体或追问:

变体:如果额外空间只能使用 O(1)(不允许辅助栈),怎么办?

回答要点:用差值编码——栈里存 val - current_min 的差值,另用一个变量保存当前最小值。push(v):若为首次,存 0 并令 cur_min = v;否则存 d = v - cur_min,若 d < 0 则更新 cur_min = v。pop():弹出 d,若 d < 0 说明被弹的是历史最小值,需还原 cur_min = cur_min - d。getMin() 返回 cur_min。代价是差值可能超出 32 位整数范围(v 与 cur_min 分别取极值时差值约为 2^32),实现时必须用更大宽度的整数类型——这正是它比辅助栈更容易出错的地方,也是面试中值得主动指出来的边界。若空间不是硬约束,辅助栈更清晰、更难写错。

可迁移的解题能力:

  1. 把”全局聚合量”变成”与位置对齐的前缀量”:最小值、最大值、前缀和、单调性标记都可以用这个模式把查询从 O(n) 降到 O(1)。关键不在于”多开一个栈”,而在于让辅助结构与主结构同步伸缩,从而使撤销操作免费。
  2. 不变式驱动的设计与归纳证明:先写出 mins[i] == min(data[0..i]),再让每个操作去维护它。这比”先写 push 再想 pop”要稳,也是把算法题讲清楚的标准方式。
  3. 撤销可逆性的判断:能用 O(1) 维护,当且仅当该聚合量的”撤销”是局部的(min/max/和可逆,中位数、众数不可逆——后者需要堆或计数结构的额外支持)。
  4. 与 AI Agent 工程的关系(仅在自然联系处):这与 Agent 会话状态设计同构——检查点里保存”派生量”还是”重算派生量”,本质就是辅助栈与朴素遍历的取舍。把”到当前为止的结论”随每一步同步落盘,恢复时无需重放全部历史;但派生量必须与原始状态同步失效(对应 pop 时同步弹辅助栈),否则就会出现”状态回滚了、结论没回滚”的不一致。

关键点#

  1. 不变式是 mins[i] == min(data[0..i]) 且两栈等长——这是 pop 能 O(1) 同步出栈的根本原因。
  2. 压缩写法必须处理重复最小值:只在 val <= 当前最小值 时入栈(或用计数对),否则会提前丢掉同值最小值。
  3. 题目保证非空调用是前提而非可忽略项;追问时应能说清这一点。
  4. 差值编码变体存在整数宽度陷阱,需要指出而不是回避。
  5. 空间是 O(n) 最坏、O(1) 最好(压缩写法),面试中要主动说明两种写法的取舍。

常见误区#

  1. 只缓存一个最小值变量,pop 后重新遍历求次小值。错误原因:这使 pop 退化为 O(n),违反了题目”每个函数 O(1)“的明确要求;在 3 万次调用规模下会被明显放大。
  2. 用”严格小于”作为辅助栈入栈条件(if val < mins[-1])。错误原因:连续 push 相同的多个最小值时只记录一次,pop 掉其中一个后 mins 提前清空或丢失,后续 getMin 返回错误值(用例 2 正是为此设计)。
  3. 认为辅助栈方案”浪费空间”而直接上差值编码。错误原因:差值编码在 val 取 -2^31 而 cur_min 取 2^31 - 1 时差值约为 2^32,超出 32 位整数;在 Python 中虽无溢出,但在 Java / Go / C++ 中必须用 64 位整数,属于典型的”为了省空间引入正确性风险”。

延伸学习#

  • LeetCode 官方题页(中英文,见上):约束、示例与 O(1) 要求的原始出处。
  • 延伸练习方向(本轮未核验页面内容,仅作为下一步训练方向):LeetCode 232 用栈实现队列(两个栈的摊销 O(1))与 LeetCode 716 最大栈(需要同时支持 O(1) 的 popMax,辅助栈需支持删除,难度高于本题)。

延伸资料#

按「官方文档 / 标准规范 > 原始论文 > 官方工程博客 > 可信技术组织 > 可验证技术文章」的优先级给出,均为本次任务已核验的一手来源(除明确标注”未核验”者)。

B01 · 性能分析的度量对象

  1. Brendan Gregg《The USE Method(Utilization Saturation and Errors)》—— https://www.brendangregg.com/usemethod.html 。三项的精确定义、“For every resource, check utilization, saturation, and errors”、约 30 项指标清单、Suggested Interpretations 与”低平均利用率不等于无饱和”的真实案例。
  2. Brendan Gregg《Flame Graphs》—— https://www.brendangregg.com/flamegraphs.html 。x 轴是栈样本总体按字母序排列而非时间流逝、宽度是出现频次、顶边为 on-CPU、icicle 与 flame chart 的区别;同站另有 Off-CPU Flame Graphs 专页可作延伸。

B02 · RAG 评测设计

  1. Ragas 官方文档:Faithfulness(https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/faithfulness/)与 Context Precision(https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/context_precision/)——公式、有无 reference 的两种形态、ID-based 与非 LLM 变体。
  2. arXiv:2309.15217《Ragas: Automated Evaluation of Retrieval Augmented Generation》(Es、James、Espinosa-Anke、Schockaert;2023-09-26 v1,2025-04-28 v2)——reference-free 评测的原始论文,明确”without having to rely on ground truth human annotations”的取舍。

S01 · Agent 线上故障定位与评测

  1. OpenTelemetry GenAI 语义约定仓库 open-telemetry/semantic-conventions-genai——agent 与工具调用 span 的模型化方式。注意:该约定当前整体状态仍为 Development(gen_ai.* 专属属性均为 Development,仅继承的 error.type / server.address / server.port 为 Stable)。该状态为 2026-11-02 配置维护时第 5 次复核的结论,本轮沿用未再逐页核验。
  2. Ragas 官方指标文档(同上)——用于区分”可断言指标”与”LLM judge 指标”的边界。

S02 · Kubernetes 扩缩容与容量治理

  1. 《Configure Quality of Service for Pods》—— https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/ 。Guaranteed / Burstable / BestEffort 的精确判据,QoS 类在创建时确定且生命周期内不可变。
  2. 《Horizontal Pod Autoscaling》—— https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ 。desiredReplicas = ceil(currentReplicas × currentMetricValue / desiredMetricValue)、容差默认 0.1、同步周期默认 15 s、缩容稳定窗口默认 5 min、未就绪与缺指标 Pod 的保守假设。
  3. 《Node-pressure Eviction》—— https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/ 。memory.available 的计算(来自 cgroupfs、排除 inactive_file)、硬驱逐阈值默认 memory.available<100Mi、housekeeping-interval 默认 10 s、驱逐不尊重 PDB 与 terminationGracePeriodSeconds。

L01 · LeetCode 155

  1. LeetCode 官方题页(中文 https://leetcode.cn/problems/min-stack/ ;英文 https://leetcode.com/problems/min-stack/ )——约束、示例与 O(1) 要求的原始出处。两侧页面本次均未渲染难度标签,难度 medium 按标准分类记录,标注「未直接核验」。
  2. 延伸训练方向(未核验页面内容,仅作下一步方向):LeetCode 232 用栈实现队列、LeetCode 716 最大栈。

当日重点#

  1. 代理指标必须标明它度量的是哪个对象:CPU 利用率度量的是”忙”,不是”排队”;faithfulness 度量的是”对上下文忠实”,不是”对世界为真”;离线通过率度量的是”评测集覆盖到的部分”,不是”线上”。
  2. 每一项代理指标都要准备一条不依赖它的独立判定路径:USE 之外是饱和度与队列长度;judge 之外是可断言指标;HPA 之外是在途请求数与队列等待。
  3. 降级方向的正确顺序:能力缺失走向”降低自动化程度”(转人工),而不是”降低判定标准”。
  4. 容量与弹性是两个问题:容量由下游反推上界,弹性由滞后链路的时间预算决定;两者都不由 CPU 平均利用率决定。
  5. 失败语义要结构化:capability_not_found 与 invalid_argument 必须分离,否则模型唯一能做的”合理动作”就是反复重试同一工具。
  6. 算法层面:把全局聚合量变成与位置对齐的前缀量,并让辅助结构与主结构同步伸缩——这是把查询从 O(n) 降到 O(1) 的通用模式。

归档与去重记录#

配置读取状态#

  • 配置读取:成功。文件 ../题库配置.md,版本 8(last_maintained: 2026-11-02)。
  • 本次为 v8 生效后第 2 次每日出题。无暂停类型;「观察中的新技术」8 项均未标记「允许试学」,本次未从观察项出题。
  • 未修改配置文件。运行前已确认目标目录与父目录仍无 AGENTS.md / CLAUDE.md。

去重结果#

  • 去重窗口:30 天(2026-10-04 至 2026-11-03)。参考来源:题目索引.md(95 条 / indexed_runs: 17)、精选/README.md(4 条)、README.md。未读取更早的完整题目正文。
  • 逐题比对结论:
题目 ID与近期题目的关系结论
Q-20261103-B01与 2026-10-14 B01(容器 CPU 配额与 CFS 限流)、2026-10-27 B01(事件循环与 I/O 模型)同属操作系统与网络不重复。前两者分别考察”配额是带宽而非并行度约束”与”阻塞调用隔离位置”;本题考察的是度量对象本身(USE 三项、平均值、on-CPU/off-CPU 口径),核心结论是”指标全绿仍可能错”
Q-20261103-B02与 2026-10-13 B03(混合检索融合与重排归因)、2026-10-23 B02(Query Rewrite)、2026-10-29 B02(Graph RAG)同属 RAG 与搜索;与 2026-10-27 B02(Golden Dataset 分层)同属评测不重复。前者考察检索链路的构建与归因顺序,2026-10-27 B02 考察评测集分层与离线/线上分工;本题考察的是评测指标的分层定义与 reference-free 的循环论证风险,核心结论是”答案对不等于检索对”
Q-20261103-S01与 2026-10-22 B02(Trace / Span 数据模型)、2026-10-27 B02(Golden Dataset 分层)相邻不重复。本题的核心方案是工具错误语义分离 + 重试预算 + 评测集覆盖缺口,故障现象是”离线全绿而线上掉 11 个点”,与前述两题的考察点不同
Q-20261103-S02与 2026-11-02 S02(备份与 PITR)、2026-10-19 S02(发布期 502)、2026-10-23 S01(GPU 容量规划)相邻不重复。本题核心是扩容信号错配 + 滞后链路时间预算 + 下游容量上界,属集群调度与弹性维度,与”恢复演练""优雅终止""推理排队”三种故障形态不同
Q-20261103-L01已用题号:146、3、215、739、875、124、207、142、547、560、39、1109、435、208、92、516、31(另 322 已删未登记,仍规避)无题号重复。算法模式为「栈 + 同步辅助栈 / 不变式设计」,窗口内首次出现
  • 类型集中度自查:上一轮已标注「工具与互操作协议在最近 5 次 Agent 场景题中出现 4 次,下次 S01 应轮换到 AI Agent 核心 / Agent 评测与可观测性 / RAG 与搜索」。本轮 S01 已按该建议轮换到「Agent 评测与可观测性」(兼 AI Agent 核心),工具与互操作协议本轮未出题。
  • 场景题类型使用情况:本轮新增「线上故障定位与可观测性」(Agent 场景,首次)与「Kubernetes 扩缩容与容量治理」(非 Agent 场景,首次)。

覆盖变化与下一周期建议#

  • 本轮填补的标注缺口:操作系统与网络「CPU 与内存性能分析」(B01)、RAG 与搜索「RAG 评测设计」(B02)。
  • 覆盖次数(索引窗口内,写入索引前的值 +1):操作系统与网络 7→8、RAG 与搜索 5→6、Agent 评测与可观测性 4→5、软件工程与平台工程 7→8。
  • 下一周期优先方向:AI 安全与治理(4,路径与地址约束一致性的独立出题、SSRF 边界、跨站调用 Origin 校验)、LLM 应用工程(4,批处理与延迟的联合调优、跨厂商缓存收益对比)、上下文工程与能力封装(6,剩余缺口「上下文写入与选择策略」)、数据库与存储(9,执行计划回归的上线门禁、分区表统计盲区)、分布式系统(9,时钟不确定区间的工程落地)。
  • LeetCode 下一轮建议轮换:单调队列应用型、栈与队列应用型(232 / 946)、Trie 变体(211)、二维差分、状压 / 位运算;避免连续出现栈设计、原地数组变换、区间 DP、链表操作、Trie、贪心、差分 / 前缀和、回溯、并查集、图论、二分主导模式。

本次参考的历史题目与文件#

  • 题目索引.md(95 条主表、indexed_runs: 17、total_featured: 4)
  • 精选/README.md(4 条精选题目,含复习节奏表)
  • README.md(每日训练导航表)
  • 题库配置.md(版本 8,只读)
  • 未读取窗口外的历史训练文件正文。

保存与同步状态#

  • 本地保存:成功(路径 2026-11/2026-11-03-AI-Agent-面试训练.md)。
  • 远端同步:未验证。写入本地 Obsidian 目录不等于 iCloud 或其他远端已同步,本次未做独立验证,不声称已同步。
  • 本次执行未触发精选(用户未提出明确精选请求),未收到作答反馈,未修改任何历史训练文件正文。
2026-11-03 AI Agent 面试训练
https://vissssa.github.io/posts/ai-agent-interview-2026-11-03/
作者
Siegward
发布于
2026-11-03
许可协议
CC BY-NC-SA 4.0