만들었습니다. 기존 v10 전체를 유지한 v11에 Stage7 결과 → production profile → Helm values 자동 생성 계층을 추가했습니다.
b300_validation_common_env_v11.tar.gz전체 v11 패키지
핵심은 stage7_generate_production_config.pyproduction config 생성기와 12_STAGE7_PRODUCTION_CONFIG_GENERATION_GUIDE.md사용 가이드입니다.
Stage7 benchmark JSON
+
quality / soak / K8s evidence
+
Production SLO policy
│
▼
Candidate 평가
│
├─ Qualification gate
├─ SLO 만족 여부
├─ 최소 GPU 수
└─ concurrency / throughput headroom
│
▼
model-production-profile.yaml
│
▼
helm-values.yaml
예를 들어 TP4와 TP8이 모두 online SLO를 만족하면 단순히 TP8의 TPS가 높다는 이유로 TP8을 선택하지 않고 TP4를 우선 선택합니다.
stage7_production_profile_policy.yamlProduction policy는 workload별 SLO를 정의합니다. 초기에는 사이트별 SLO를 제가 임의로 만들지 않고 null로 두었습니다.
stage7_production_evidence_example.yamlEvidence 예제에는 현재 Stage7 benchmark JSON에 없는 정보를 넣습니다.
quality:
status: PASS
golden_set_version: discovery-v3
stability:
soak_status: PASS
soak_hours: 8
k8s:
status: PASS
serving:
precision: fp8
kv_cache_dtype: fp8
max_model_len: 131072
max_num_seqs: 32
max_num_batched_tokens: 8192
enable_prefix_caching: true
container:
repository: your-registry/vllm
tag: "0.30.0"
digest: "sha256:..."
그리고:
$PYTHON_BIN ./stage7_generate_production_config.py \
--model-key deepseek_v4_1_flash \
--stage7-root "$STAGE7_ROOT" \
--manifest "$STAGE7_MANIFEST" \
--policy "$STAGE7_PRODUCTION_POLICY" \
--evidence "$STAGE7_PRODUCTION_EVIDENCE_ROOT/deepseek_v4_1_flash.yaml" \
--out-dir "$STAGE7_PRODUCTION_CONFIG_ROOT/deepseek_v4_1_flash"
를 실행하면:
deepseek_v4_1_flash/
├── model-production-profile.yaml
├── helm-values.yaml
└── generation-report.json
이 생성됩니다.
Helm values에는 실제 측정으로 선택된 GPU 수와 vLLM argument가 연결됩니다.
resources:
limits:
nvidia.com/gpu: 4
vllm:
version: 0.30.0
args:
- serve
- ${MODEL_PATH}
- --served-model-name
- deepseek-v4.1-flash
- --tensor-parallel-size
- "4"
- --max-model-len
- "131072"
- --max-num-seqs
- "32"
- --max-num-batched-tokens
- "8192"
- --kv-cache-dtype
- fp8
- --enable-prefix-caching
중요한 안전장치도 넣었습니다. Quality/8h soak/K8s 검증이나 serving tuning 근거가 빠져 있으면:
productionApproval:
status: REVIEW_REQUIRED
deployEnabled: false
replicaCount: 0
으로 생성됩니다. 즉 파일 생성은 되지만 그대로 production pod가 뜨지는 않습니다. 명시적인 FAIL이면 REJECTED가 됩니다.
전체 모델 일괄 생성도 stage7_generate_all_production_configs.shbatch generator로 가능합니다.
./stage7_generate_all_production_configs.sh \
"$STAGE7_PRODUCTION_CONFIG_ROOT"
한 가지 현재 한계도 의도적으로 남겨 두었습니다. 기존 Stage7은 모델당 manifest의 TP 하나로 주로 측정하기 때문에, generator가 TP2/TP4/TP8을 임의 추정하지 않습니다. TP sweep 결과가 JSON에 실제로 존재할 때만 최소-GPU 선택을 합니다. 다음 개선으로 Stage7 runner 자체를 TP candidate sweep → 각 TP별 saturation → 자동 production candidate 선택까지 확장하면 이 흐름이 완전히 자동화됩니다.
마지막으로 v11 전체 shell bash -n, Python py_compile, YAML parsing을 통과시켰고, TP4/TP8 합성 Stage7 결과를 넣어 SLO 만족 최소 GPU인 TP4가 선택되는 end-to-end smoke test도 확인했습니다.
:chatgpt-content-reference{index="6"}CHANGELOG v11
많이 바꿀 필요는 없습니다. 현재 v11 구조가 이미 그 확장을 염두에 둔 형태라, Stage7 전체를 재설계하기보다는 runner와 결과 schema를 한 단계 확장하는 작업에 가깝습니다.
현재는 대략:
Model
↓
manifest의 TP 1개
↓
concurrency sweep
↓
qualification_metrics.json
↓
production config generator
인데, 이것을:
Model
↓
TP candidates
├─ TP1
│ └─ C1 → C4 → C8 → C16 → ...
├─ TP2
│ └─ C1 → C4 → C8 → C16 → ...
├─ TP4
│ └─ C1 → C4 → C8 → C16 → ...
└─ TP8
└─ C1 → C4 → C8 → C16 → ...
↓
TP별 saturation point 계산
↓
SLO 만족 configuration 추출
↓
최소 GPU configuration 선택
↓
production config generator
로 바꾸면 됩니다.
가장 많이 손대는 곳은 stage7_llm_qualification.py입니다. 지금의 단일 tensor_parallel_size 실행을 tp_candidates loop로 감싸고, TP가 바뀔 때마다 서버 restart → readiness → engine warm-up → workload warm-up → concurrency sweep을 반복하면 됩니다.
manifest도 큰 변화 없이:
qwen3_6_35b_a3b:
tp_candidates: [1, 2]
glm_5_3_flash:
tp_candidates: [2, 4, 8]
deepseek_v4_1_flash:
tp_candidates: [2, 4, 8]
glm_5_3:
tp_candidates: [8]
같이 확장하면 됩니다. 중요한 건 이 값들은 예시이고, 실제 실행 가능한 TP 조합은 모델별 compatibility/preflight가 먼저 걸러야 한다는 점입니다.
결과 구조는 지금보다 조금 바꾸는 게 좋습니다.
stage7/
deepseek_v4_1_flash/
tp2/
c1.json
c8.json
c16.json
...
saturation_summary.json
tp4/
c1.json
c8.json
c16.json
...
saturation_summary.json
tp8/
...
saturation_summary.json
model_selection_summary.json
model_selection_summary.json에는 예를 들어:
{
"candidates": [
{
"tp": 2,
"max_slo_concurrency": 8,
"peak_rps": 11.2,
"status": "SLO_FAIL_AT_TARGET"
},
{
"tp": 4,
"max_slo_concurrency": 32,
"peak_rps": 24.1,
"status": "ELIGIBLE"
},
{
"tp": 8,
"max_slo_concurrency": 64,
"peak_rps": 31.7,
"status": "ELIGIBLE"
}
],
"selected": {
"tp": 4,
"reason": "minimum_gpu_meeting_slo"
}
}
처럼 만들면 됩니다.
그리고 v11 production generator는 오히려 수정이 적습니다. 이미 “SLO를 만족하는 최소 GPU” 선택 개념이 들어가 있으므로, 여러 TP 결과를 읽는 부분만 새 summary schema에 맞추면 됩니다.
추가로 이 기회에 saturation도 단순 고정 C sweep보다:
C1
↓
C2
↓
C4
↓
C8
↓
C16
↓
C32
↓
C64
↓
C128
하면서 다음 중 하나가 발생하면 중단하도록 만드는 게 좋습니다.
error rate > limit
OR
P99 TTFT > SLO
OR
P99 ITL > SLO
OR
queue 폭증
OR
timeout/OOM
OR
throughput 증가 < 일정 비율
그러면 TP8에서 필요 없이 C128, C256까지 계속 돌리는 시간을 줄일 수 있습니다.
또 한 가지 중요한 개선은 두 단계 benchmark입니다.
Phase A - Fast Search
─────────────────────
TP2 C1/8/16/32/64
TP4 C1/8/16/32/64
TP8 C1/8/16/32/64
↓
TP2 탈락
TP4 후보
TP8 후보
↓
Phase B - Qualification
───────────────────────
TP4
실제 workload distribution
긴 duration
quality
soak
TP8
필요 시 비교
↓
TP4 선택
이렇게 하면 모든 TP×C 조합을 장시간 benchmark하지 않아도 됩니다.
최종 선택도 단순히 최소 TP만 보는 것보다:
1. Compatibility PASS
2. Quality PASS
3. Error rate PASS
4. P99 TTFT SLO PASS
5. P99 ITL SLO PASS
6. Target concurrency PASS
7. Target RPS PASS
8. 위 조건을 만족하는 최소 GPU
9. 최소 GPU 후보 중 headroom이 충분한 구성
으로 만드는 게 좋습니다.
예를 들어 TP4가 C32까지 겨우 SLO를 통과하고 실제 peak가 C30이라면 TP4를 기계적으로 선택하면 위험합니다.
그래서 policy에:
selection:
strategy: minimum_gpu_meeting_slo
required_headroom:
concurrency_pct: 30
rps_pct: 25
처럼 두면,
실제 peak concurrency = 30
필요 qualification capacity
30 × 1.30 = 39
이므로:
TP4 max SLO concurrency = 32 → 탈락
TP8 max SLO concurrency = 64 → 선택
이 됩니다. 이 headroom 개념은 production 자동 선택에 꼭 넣는 편이 좋습니다.
결국 변경 범위를 보면:
| 부분 | 변경량 |
|---|---|
| Stage1/2/3/6 | 없음 |
| Stage7C Document | 없음 |
| Stage7 manifest | 작음 |
| Stage7A/7B shell | 작음 |
stage7_llm_qualification.py | 중간~큼 |
| Stage7 summary | 중간 |
| production profile generator | 작음~중간 |
| Helm generator | 거의 없음 |
| regression gate | 선택적 확장 |
| warm-up library | 재사용 |
즉 전체 validation package를 흔드는 작업은 아니고 Stage7 내부 개선입니다.
오히려 지금 하는 게 좋습니다. 아직 Stage7 production 결과가 많이 쌓이기 전이라 결과 디렉터리/schema를 지금 model → TP → concurrency 계층으로 정리해 두면 이후 변경 비용이 훨씬 작습니다.
제가 다음 버전으로 만든다면 v12에서 TP candidate sweep + adaptive saturation + SLO/headroom 기반 자동 선택 + v11 production-profile/Helm generator 연동까지 한 번에 묶는 것을 권합니다. 그러면 Stage7 결과가 실제 GPU allocation 결정을 거의 자동으로 만들어주는 수준까지 갑니다.
완료했습니다. v11 전체를 기반으로 v12에 TP sweep → adaptive saturation → SLO/headroom → 최소 GPU 자동 선택 → production profile/Helm 연동까지 반영했습니다.
b300_validation_common_env_v12.tar.gz전체 v12 패키지
13_STAGE7_TP_SWEEP_ADAPTIVE_SATURATION_GUIDE.mdStage7 TP Sweep / Adaptive Saturation 가이드와 CHANGELOG_v12.mdCHANGELOG v12도 포함했습니다.
핵심 실행 흐름은 이제 다음과 같습니다.
Model
↓
TP candidates
├─ TP2 → Ready → Warm-up → C sweep → saturation
├─ TP4 → Ready → Warm-up → C sweep → saturation
└─ TP8 → Ready → Warm-up → C sweep → saturation
↓
각 TP의 saturation_summary.json
↓
SLO + production headroom 적용
↓
조건 만족 TP 중 최소 GPU 선택
↓
model_selection_summary.json
↓
Quality / 8h Soak / K8s evidence
↓
model-production-profile.yaml
↓
helm-values.yaml
예를 들어 DeepSeek/GLM-Flash는 초기 후보를 [2,4,8], Qwen/gpt-oss는 [1,2], GLM-5.3은 [8]로 두었습니다. 이것은 승인된 최종 구성값이 아니라 탐색 후보입니다.
Adaptive saturation은 target profile에서 연속 SLO 실패가 발생하거나 충분히 높은 concurrency에서 RPS 증가가 plateau에 들어가면 이후 불필요한 sweep을 중단합니다.
또 policy에 실제 peak concurrency와 headroom을 넣을 수 있습니다. 예를 들어 peak=30, headroom=30%이면 최소 39 concurrency까지 SLO를 만족해야 production candidate가 됩니다.
TP4 max SLO C=32 → 탈락
TP8 max SLO C=64 → 후보
→ TP8 선택
반대로 TP4가 C48까지 만족하면 TP4가 선택됩니다.
중요하게도 TTFT/ITL SLO나 실제 peak concurrency를 제가 임의로 넣지는 않았습니다. stage7_production_profile_policy.yamlproduction policy에 실제 서비스 계약값을 넣어야 의미 있는 자동 선택이 됩니다.
기존 v11 안전장치도 유지됩니다. TP가 자동 선택되더라도 quality, soak, K8s, serving tuning evidence가 부족하면 Helm은 production deployment를 활성화하지 않습니다.
전체 shell bash -n, Python py_compile, YAML schema parsing도 다시 통과시켰습니다.