Files
aituner/docs/harness-ablation/no-llm-harness-mechanism-20260625.md

483 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# No-LLM Harness Mechanism - 2026-06-25
Status note, 2026-06-26:
本文记录的是当前 rule-based prototype harness 的 no-LLM 机制和已有实验现象。它能证明
AITuner 可以在没有 LLM endpoint 的情况下闭环运行,但不能证明 harness 的完备性、
通用 robustness 或最终系统贡献。最终目标设计已经调整为 declarative intervention
grammar + coverage-relative validator
[`declarative-intervention-harness-design-20260626.md`](declarative-intervention-harness-design-20260626.md)。
本文回答一个核心问题:如果不调用 LLMharness 为什么还能自动找到配置?
结论先说清楚no-LLM 模式下并不是“没有 planner”。当前 harness 本身就是一个
deterministic planner。LLM 在 AITuner 里只是一个可替换的 proposal backend
harness 能从观测、瓶颈归因、候选 family 和 stop validator 中推出下一步时tuning
loop 会直接使用 harness proposal而不会请求 LLM。
## Tune loop 中 LLM 的位置
`study tune` 每轮的决策顺序是:
```text
state + study spec + workload/probe results
|
v
build_harness_context(...)
|
+--> build_harness_stop_proposal(context)
| if true: write harness-stop and exit
|
+--> build_harness_guided_proposal(context)
| if true: run this deterministic proposal
|
+--> call_llm_for_proposal(...)
only if no harness stop/proposal exists
```
因此在 `study.llm.endpoint = null` 的 no-LLM run 中,只要 harness 每轮都能给出
一个 deterministic proposal 或 deterministic stop整个实验就可以完全不调用 LLM。
如果 harness 既不能 propose 也不能 stop且没有 LLM endpointAITuner 会报错,而不是
偷偷退化成随机搜索。
当前 Qwen30B stopfix run 就是这种完整闭环:
```text
.aituner/qwen30b-harness-only-medium-stopfix-dash1-20260624T144701Z/
```
它没有 LLM endpoint但仍完成了 9 个 measured trials并最终由 validator 写出
`harness_stop`
## Harness 做的不是 prompt engineering
Harness 做的事情可以形式化成:
```text
H = (O, B, G, S, V)
O: Observation schema
将 workload、trial probes、SLO failure、launch failure、topology constraints
转成结构化状态。
B: Bottleneck attribution
将 SLO violation 归因到 serving regime例如 ttft_prefill、decode_tpot、
admission_or_queueing、launch_or_memory。
G: Intervention grammar
将 raw knobs 组织成有语义的 candidate families例如 topology、batching、
sequence admission、KV memory headroom。
S: Scoring policy
对候选 intervention 评分,选择最有信息量且最可能提升 SLO-constrained
req/s/GPU 的下一步。
V: Validator / stop policy
阻止非法、重复、已知失败或无意义的 proposal只有在剩余高价值候选被测完后
才允许 stop。
```
LLM 可以读取这些结构化信息并生成 proposal但 no-LLM 时 `H` 自己就能生成
proposal。换句话说我们的核心是把
```text
raw config vector search
```
转成:
```text
mechanism-guided intervention search
```
这就是为什么没有 LLM 也能工作。
## Agent loop 流程图
```mermaid
flowchart TD
A[Baseline or latest measured trial] --> B[Load probe history and trial result]
B --> C[Build workload L-C-A profile]
B --> D[Build TrialProfile]
C --> E[Rank bottleneck hypotheses]
D --> E
E --> F[Generate legal candidate actions]
F --> G[Score candidates]
G --> H{High-value candidate?}
H -- yes --> I[Emit harness-proposal]
I --> J[Run real vLLM trial over search range]
J --> B
H -- no --> K{Validator stop allowed?}
K -- yes --> L[Emit harness-stop]
K -- no --> M{LLM endpoint exists?}
M -- yes --> N[Ask LLM backend]
M -- no --> O[Fail loudly: no proposal source]
```
## Observation: harness 看到什么
每一轮 harness 不看自然语言日志做猜测,而是读结构化状态:
- `StudySpec`
- hardware: GPU 数量、GPU 型号;
- engine: base flags/envs、tunable flags/envs、topology constraints
- trace: request mode、window id、输入长度过滤、输出长度 override
- SLO: TTFT/TPOT rule、target pass rate
- search: load range、tolerance、probe budget。
- `window_summary` / `WorkloadProfile`
- L: request length 分布、tail ratio
- C: prefix/cache reuse
- A: arrival rate、burstiness、interarrival variation。
- 最近 trials
- config patch
- best feasible request rate
- request_rate_per_gpu
- pass rate
- probe history
- latency p50/p95/p99
- SLO failure reason counts
- launch/runtime failure stage。
这些数据会被压成 `recent_trial_diagnostics``trial_profiles`,后续步骤只使用这些结构化
字段。
## Bottleneck classifier: 怎么判断方向
Harness 维护一组 ranked bottleneck hypotheses
```text
ttft_prefill
decode_tpot
admission_or_queueing
launch_or_memory
```
它的输入不是单一阈值,而是多类证据:
- workload default长 prompt tail 更偏向 `ttft_prefill`
- request modedecode-only 且有 TPOT SLO 时更偏向 `decode_tpot`
- probe sequence最近 trial 的 active bottleneck 权重大于旧 trial
- failed reason counts
- `ttft_ms>...` 支持 `ttft_prefill`
- `tpot_ms>...` 支持 `decode_tpot`
- `arrival_lag_s>` / `probe_elapsed_s>` 支持 `admission_or_queueing`
- launch failure / OOM支持 `launch_or_memory`
代码里这不是一个硬编码单标签,而是带 confidence 的 ranked list。例如最近 probe
明确出现 TPOT failure会提高 `decode_tpot` 分数;如果同时 workload 有长 prompt tail
`ttft_prefill` 仍会保留为次级 hypothesis。
## Candidate family: raw knobs 如何变成 intervention
Harness 不直接在所有 tunable flags 上盲采样。它先把 knobs 分成有系统含义的
intervention family
| Family | 代表 knobs | 机制含义 |
| --- | --- | --- |
| topology | `tensor-parallel-size`, `data-parallel-size`, EP knobs | 改变每请求并行度、replica 数量、通信/效率 tradeoff |
| batching | `max-num-batched-tokens`, `enable-chunked-prefill` | 改变 prefill/decode batching 与 HoL blocking |
| admission | `max-num-seqs` | 改变并发 admission 与 TPOT/TTFT tail |
| KV memory | `gpu-memory-utilization` | 改变 KV cache blocks 和可承载并发 |
| failure memory | failed signatures | 阻止重复已知 launch/runtime 失败方向 |
关键点是candidate 来自当前 `StudySpec` 的 tunable schema 和 topology constraints。
例如 topology candidate 只枚举合法 TP/DP/EP 组合;如果 EP 没有直接证据generic
topology search 不会主动引入 EP。
## Scoring: 为什么会先走 topology再走 gmu
Candidate action 的评分大致是:
```text
score = expected_bottleneck_relief * bottleneck_confidence
+ information_gain
+ launch_safety
- regression_risk
```
然后 `experiment_plan.next_action` 选择最高分候选。分数超过阈值时harness 直接生成
proposal否则进入 stop validator 或 LLM fallback。
这套 scoring 体现了几个系统原则:
1. Topology 是 serving 的一阶决策。
当 TP frontier 还没测完,`gpu-memory-utilization``max-num-seqs` 这类 runtime
微调不会抢在 topology 前面。
2. Topology 不是“越大越好”。
评分和最终 winner 都看 `request_rate_per_gpu`,不是 raw request rate。TP4 可能总吞吐
更高,但如果使用更多 GPU 后 per-GPU 效率下降,就不会成为 incumbent。
3. Runtime tuning 必须 anchored on incumbent topology。
当 topology 已经验证过runtime proposal 会 preserve 当前 best topology只在其上
`gpu-memory-utilization``max-num-seqs``max-num-batched-tokens`
4. Measurement 决定最终答案。
Candidate 只是一个 hypothesis是否接受由真实 trial 的 SLO-constrained
`request_rate_per_gpu` 决定。
5. Bad-start recovery 需要先 bracket再微调。
如果 no-LLM run 从一个很高 TP 的初始点开始,且同 DP 下更高 TP frontier 已经不存在
或已测过harness 会优先验证相邻低 TP而不是把当前高 TP 当作 topology 已收敛。
这避免了 `TP=8` 这类坏初始点直接进入 `gpu-memory-utilization` 微调。
6. Pathological runtime 起点需要跳回正常工作区间。
`gpu-memory-utilization` 的常规策略是在 settled topology 上小步 hill-climb
但如果初始值明显低于正常工作区间,例如 `0.5`harness 会先跳到 nominal floor
`0.9`,再按 `0.02` 步长向 safe ceiling `0.97` 验证。
## Validator stop: 为什么不会过早停止
Harness stop 不是“找到一个不错配置就停”。当前 stop validator 包含几个条件:
- `search_high_saturated_by_incumbent`
- incumbent 的最高 feasible probe 已经贴近 configured search high
- 说明当前测量范围已被打满。
- `topology_frontier_requires_probe`
- 如果 active bottleneck 仍要求更高 TP frontier 且未测,禁止 stop。
- `experiment_plan_has_high_value_candidate`
- 如果还有高分候选,禁止 stop。
- `post_incumbent_validation_exhausted`
- strong incumbent 后至少要有 post-incumbent validation
- validation 覆盖 topology/runtime family 或达到足够数量;
- 没有任何 validation trial 超过 incumbent
- 才允许 clean stop。
所以 validator 的作用是 fail-safe
```text
wrong proposal 最多浪费一个 trial
wrong stop 会终止搜索,所以必须由 deterministic validator 授权。
```
## Qwen30B no-LLM run 中具体发生了什么
Run:
```text
qwen30b-harness-only-medium-stopfix-dash1-20260624T144701Z
```
设置:
- Model: `Qwen/Qwen3-30B-A3B`
- Engine: community vLLM 0.20
- Hardware: 8x H20, 允许 TP/DP/EP frontier
- Trace: chat 0-8k, output 128, replay time scale 0.1
- SLO: target pass rate 0.95, TTFT step rule, TPOT 50ms
- LLM endpoint: `null`
真实 trial path:
| Trial | Source | Config patch | req/s/GPU | pass rate | Harness 解释 |
| --- | --- | --- | ---: | ---: | --- |
| 0001 | baseline | `{}` | 2.2000 | 1.0000 | 建立 baseline 和 probe evidence |
| 0002 | harness | `TP=2` | 3.2583 | 1.0000 | latency/SLO pressure 下先测 adjacent TP |
| 0003 | harness | `TP=4` | 2.0917 | 1.0000 | 验证更高 TP frontierraw 总吞吐高但 per-GPU 低 |
| 0004 | harness | `TP=2, gmu=0.92` | 3.2583 | 1.0000 | topology 已 settle开始 incumbent topology 上的 KV headroom climb |
| 0005 | harness | `TP=2, gmu=0.94` | 3.2583 | 1.0000 | 继续小步 hill-climb未改善但未失败 |
| 0006 | harness | `TP=2, gmu=0.96` | 3.3333 | 1.0000 | KV headroom 带来更高 feasible frontier |
| 0007 | harness | `TP=2, gmu=0.97` | 3.4333 | 1.0000 | 达到 safe ceiling成为 incumbent |
| 0008 | harness | `TP=4, DP=2` | 1.0458 | 1.0000 | post-incumbent topology validation没有超过 incumbent |
| 0009 | harness | `TP=8` | 1.0458 | 1.0000 | 继续 frontier validation没有超过 incumbent |
| 0010 | harness stop | stop | - | - | validator: `post_incumbent_validation_exhausted` |
这个过程里没有外部 LLM 决策。每一步 proposal 都来自 harness
1. baseline 观测到当前 engine 在 SLO 下的可行 frontier
2. bottleneck/机制模型认为 topology 是一阶干预;
3. 测 TP2接受因为 per-GPU 从 2.2 提到 3.2583
4. 测 TP4拒绝为 incumbent因为 per-GPU 降到 2.0917
5. topology frontier settle 后,在 TP2 上小步提升 `gpu-memory-utilization`
6. `gmu=0.97` 达到 3.4333
7. 再测 nearby topology确认没有更好
8. validator 授权 stop。
## 为什么这不是写死 Qwen30B
这条路径看起来像“harness 知道答案是 TP2+gmu0.97”,但代码机制不是这样写的。
没有写死的部分:
- 没有写死 model name
- 没有写死 Qwen30B
- 没有写死 `TP=2` 是最终答案;
- 没有写死 `gmu=0.97` 一定最好;
- 没有跳过真实测量;
- 没有把 TP4/TP8 直接判负,而是实际运行并比较。
真正写入 harness 的 domain knowledge 是:
- TP/DP/EP 是 topology family必须满足 topology constraints
- topology 通常是一阶 serving intervention要先于 runtime 微调被验证;
- raw throughput 不等于目标,跨 topology 比较要用 `request_rate_per_gpu`
- `gpu-memory-utilization` 是 KV memory headroom 微调,只应在 incumbent topology 上小步 hill-climb
- launch failure 和 tested signatures 是 hard negative evidence
- stop 必须由 validator 授权,不能由 proposer 自己说停就停。
这是一种系统机制约束,不是 case-specific prompt。
## 它和 BO / raw heuristic 的区别
普通 BO 或 raw heuristic 的搜索空间通常是:
```text
config = {tp, dp, ep, gmu, max_num_seqs, max_num_batched_tokens, ...}
score = measured req/s/GPU
```
这会产生几个问题:
- 它不知道哪些 knobs 是 topology family哪些是 runtime family
- 它可能在没测 TP frontier 前浪费大量 trial 调 runtime
- 它可能重复已知 launch failure
- 它可能把 raw throughput 高但 GPU efficiency 差的配置误当方向;
- 它很难解释“这个 trial 试图证伪哪个瓶颈 hypothesis”。
Harness-shaped search space 是:
```text
state -> bottleneck hypothesis -> legal intervention family -> measured verdict
```
因此 BO、bandit、LLM、deterministic heuristic 都可以接在 harness 后面。它们优化的不是
raw knob vector而是有 serving 语义的 intervention graph。
这也是我们新 framing 的核心:
```text
black-box optimization
-> grey-box / mechanism-guided experimental optimization
```
## 当前还需要补的证据
No-LLM Qwen30B run 证明了 deterministic harness 可以完整闭环,但 paper 还需要继续补:
1. Planner-agnostic ablation
- `raw BO` vs `harness-guided BO`
- `raw heuristic` vs `harness deterministic policy`
- 证明收益来自 harness substrate而不是某个 LLM。
2. Mechanism ablation
- no attribution
- shuffled attribution
- no topology-first
- no intervention grammar
- no validator/failure memory。
3. Near-optimum evidence
- 在 1-2 个 case 做局部 grid
- 证明 harness path 找到的是 near-optimal region不只是一个可行 config。
4. Cross-case robustness
- 再选 decode-heavy 或 long-prefill case
- 验证不同 workload/SLO 下 candidate family 会发生合理切换。
5. Bad-start recovery
- 从非可信初始配置开始,例如 `TP=8, max-num-seqs=8, gmu=0.5`
- 证明 harness 不是只能从“已经比较合理”的 base config 出发;
- 观察它是否能先恢复 topology再恢复 runtime headroom并最终回到同一 near-optimal
region。
## Bad-start recovery 审计 - 2026-06-26
用户提出的问题是:如果我们不是从可信 base config 开始,而是从一个恶意或不合理的
配置开始,例如:
```text
TP=8, DP=1, max-num-seqs=8, gpu-memory-utilization=0.5
```
no-LLM harness 是否仍能自动找到正确方向?
目前结论要分开说:
1. **旧 planner 不能直接 claim 任意坏起点可恢复。**
本地合成审计显示,旧逻辑会把 `TP=8` 误当作 topology frontier 已收敛,并把下一步
proposal 设为 `gpu-memory-utilization=0.52`。这会在坏 topology 和坏 runtime 上
做很慢的小步爬坡,不能作为 robust evidence。
2. **已补 planner 机制。**
当前 harness 增加了两个 no-LLM deterministic recovery rules
- `bad_start_topology_bracket`:当当前 anchor 在高 TP且没有未测的更高 TP frontier 时,
先测相邻低 TP例如 `TP=8 -> TP=4`
- `gmu_nominal_floor`:当 settled topology 上的 `gpu-memory-utilization < 0.9` 时,
先跳到 `0.9`,再做常规 `0.92/0.94/.../0.97` hill-climb。
3. **已加本地回归测试,但还没做真机证明。**
已通过的 planner tests
- `test_harness_brackets_down_from_bad_high_tp_start_before_runtime_tuning`
- `test_harness_jumps_low_gpu_mem_util_to_nominal_floor_after_topology_settles`
- 以及已有 topology-first / gmu-climb 相关回归测试。
因此当前状态是planner 侧已经能给出正确方向paper 级别还需要真机 bad-start
recovery run 来确认真实 vLLM 测量下是否稳定收敛。
## 准备中的真机实验
实验目的不是再证明默认起点能 work而是证明
```text
same workload + same SLO + same no-LLM harness
不同初始 config
-> 是否收敛到同一 near-optimal region
-> 是否保持可解释 trial path
```
Base spec 使用已验证的 Qwen30B community vLLM 0.20 harness setup
```text
configs/examples/dash0_qwen30b_a3b_community_vllm020_harness.json
```
运行时需要设置:
```json
{
"llm": {
"use_harness": true,
"endpoint": null
}
}
```
建议最小矩阵:
| Case | Base flags 变化 | 要验证的机制 | 预期 trial path |
| --- | --- | --- | --- |
| trusted-start-control | 保持现有可信 base | 对照已有 stopfix run | `TP=2 -> TP=4 -> TP=2+gmu climb -> stop` |
| bad-topology | `TP=8, DP=1` | 高 TP 起点是否会向下 bracket | `TP8 baseline -> TP4 -> TP2/或同等 better topology -> runtime` |
| bad-runtime | `TP=2, DP=1, gmu=0.5, max-num-seqs=8` | 低 KV headroom 是否跳回正常区间 | `gmu 0.5 baseline -> gmu 0.9 -> 0.92/...` |
| combined-bad | `TP=8, DP=1, gmu=0.5, max-num-seqs=8` | topology recovery 和 runtime recovery 能否串起来 | `TP8 -> TP4 -> TP2/nearby -> gmu 0.9 -> climb -> stop` |
成功判据:
- 不配置 LLM endpoint所有 proposal 来自 harness
- 不重复相同 config signature
- high-TP 起点必须先出现相邻低 TP probe而不是先做 `gmu=0.52`
- low-gmu 起点必须先跳到 `0.9`,而不是 `0.52`
- 在 12 个 measured trials 内达到 reference stopfix best 的 `>=95%`
```text
reference best = 3.4333 req/s/GPU
95% threshold = 3.2616 req/s/GPU
```
- 最终 stop 必须是 validator 授权,例如 `harness_stop`,而不是因为没有 proposal source
失败退出。
如果真机结果失败,需要保留失败路径并分析是哪类机制不足:
- topology bracket 找到低 TP但 runtime 仍无法恢复;
- `max-num-seqs=8` 导致 admission 太差,需要 admission recovery floor
- baseline 自身全不可行,当前 harness 缺少 completed incumbent不能进入正常 guided loop
- vLLM launch/OOM 造成 failure memory 覆盖了可恢复路径。
## 一句话总结
No-LLM harness 能自动找到配置,是因为它已经实现了一个面向 serving 机制的实验 planner
先把 trial 观测归因成 bottleneck再把 bottleneck 映射成合法 intervention family
SLO-constrained req/s/GPU 真实测量更新 incumbent最后由 validator 判断是否停止。
LLM 只是这个 planner 的一个可替换 proposal backend而不是 AITuner 的必要核心。