베슬에이아이
경력근거: 고객 환경에 맞는 PoC의 성공 지표를 정의하고 실행해 기술적 fit을 검증
※ 실제 산출물이 아닌 AI 예측 시안입니다.
공고가 FDE 업무로 'PoC 설계 및 실행', '1차 기술 지원 및 에스컬레이션', 'Tech Sales 프로세스 표준화 — 반복되는 기술 이슈 대응 프로세스와 PoC 템플릿을 Runbook/Solution 형태로 정립' 셋을 나란히 적었습니다. 이 포트폴리오는 그 셋이 만나는 자리를 만듭니다. 반복되는 이슈를 Runbook 으로 정립한다는 말은 곧 대응을 데이터로 옮긴다는 뜻이고, 그렇게 옮겨야 1차 진단이 사람 손을 떠납니다. 자격요건의 'Python 등 언어로 스크립트를 작성하고 로그·에러를 분석해 문제를 진단할 수 있는 능력' 이 그대로 골조입니다. 이 포트폴리오가 보여주는 것은 비정형 로그를 규칙표와 맞춰 판정하고 미매칭을 남기는 기술이며, GPU 클러스터 운영이나 분산 학습 튜닝 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
'학습부터 배포까지 end-to-end MLOps 플랫폼'. 서빙 배포·검증이 FDE 의 핵심.
'클라우드·온프레미스 동일 경험'. 환경 무관 배포·검증이 직격.
'컴퓨팅 자원 효율·비용 절감'. 지연·비용 검증이 1주 단위.
고객사에서 실패한 GPU 실행을 원인별로 나눠 보여줍니다. 실행 로그의 꼬리와 종료 코드를 받아 Runbook 규칙표의 증상 패턴과 맞춰 원인 코드를 정하고, 규칙이 정한 1차 조치와 에스컬레이션 대상을 붙입니다. 판정에 쓴 로그 줄은 그대로 인용해 남깁니다. 어느 규칙에도 걸리지 않으면 원인을 지어내지 않고 미매칭으로 남겨 사람이 볼 자리로 보냅니다. 실행 로그와 Runbook 은 실 고객사 데이터 대신 지원자가 직접 돌린 실행과 공개 오류 규격으로 만든 더미를 가정합니다.
고객사 클러스터에서 밤사이 학습이 죽었다는 연락을 받고 로그를 처음부터 읽어 내려가며 원인을 짚던 FDE 입니다. CUDA 메모리 부족인지 NCCL 통신 지연인지 쿼터 초과인지는 로그 몇 줄이면 갈리는데, 그 몇 줄을 찾는 일을 매번 손으로 하던 사람입니다.
실패한 실행의 로그 꼬리와 종료 코드를 Runbook 규칙표의 증상 패턴과 맞추면, 원인 코드와 1차 조치가 규칙으로 정해지고 판정에 쓴 로그 줄이 근거로 남는다는 가정입니다. 규칙에 없는 실패는 미매칭으로 빠지므로 Runbook 이 덮지 못하는 구간이 그대로 드러납니다.
실패한 GPU 실행 로그를 받아 Runbook 규칙표와 맞춰 원인 코드를 정하고, 규칙이 정한 1차 조치와 에스컬레이션 대상을 붙여 원인별로 묶은 리포트를 터미널과 Markdown 파일로 내는 CLI 가 도는 완결품입니다. 규칙에 안 걸리는 실행은 미매칭으로 남깁니다.
직접 돌려 만든 실패 실행 40건에 손으로 붙인 정답 원인과 대조해 일치율을 내고, 미매칭이 몰리는 증상을 모아 Runbook 에 없는 구간을 목록으로 냅니다.
Runbook 규칙을 수백 건 규모로 늘려 증상 패턴이 겹칠 때 우선순위로 하나를 고르게 하고, 규칙을 고쳤을 때 옛 판정이 바뀌는지 회귀로 확인하는 단계입니다.
FDE 가 실패한 실행 로그를 넣으면 원인 코드와 1차 조치, 에스컬레이션 대상이 원인별로 묶여 나오는 과정을 시연합니다.
직접 돌려 만든 실패 실행 40건과 손으로 붙인 정답 원인을 대조해 일치율을 냅니다. 단, 정답과 로그를 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
종료 코드가 비었거나 GPU 표기가 흔들리거나 Runbook 에 없는 증상이 섞인 입력 30종을 넣어도 출력 형식이 안 깨지고 미매칭으로 빠지는 비율을 보여줍니다.
Runbook 규칙을 수백 건으로 늘렸을 때 증상 패턴이 겹치는 실행에서 우선순위가 같은 규칙을 고르는지 회귀로 확인합니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 작성자가 직접 돌린 실행의 자가채점이며, 실제 진단 적중률은 베슬에이아이의 고객사 클러스터 로그와 실 Runbook 이 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아니므로, 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.
정답을 작성자가 붙였으니 잘 맞는 게 당연하므로, Runbook 에 없는 증상과 규칙이 겹치는 증상을 일부러 섞어 쉬운 문제만 푸는 함정을 피합니다.
이 포트폴리오가 보여주는 것은 비정형 로그를 규칙표와 맞춰 판정하고 미매칭을 남기는 기술이며, GPU 클러스터 운영이나 분산 학습 튜닝 전문성은 주장하지 않습니다. 원인 판정은 규칙이 하고 LLM 은 담당자가 읽을 요약 문장만 맡습니다.
원인이 맞았다고 조치가 통하는 것은 아니어서 같은 CUDA 메모리 부족이라도 모델과 클러스터에 따라 처방이 갈리므로, 조치를 단정하는 문구를 쓰지 않습니다.
실제 도입 때는 고객사마다 Runbook 과 조직 구조가 달라 규칙과 에스컬레이션 대상을 새로 채워야 하므로, 규칙 이관을 도입 단계 과제로 둡니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
고객사 클러스터에서 돌린 학습·추론 실행의 종료 코드와 로그 꼬리입니다. 지원자가 작은 GPU 인스턴스에서 일부러 실패시켜 모을 수 있는 공개 오류 규격만 씁니다. 정상 기동 두 건, 같은 원인이 다른 프레임워크에서 나온 건, GPU 표기가 흔들린 건, 종료 코드가 비어 스케줄링 단계에서 막힌 건을 섞었습니다. 원인 코드와 조치는 이 표에 두지 않습니다.
| run_id | cluster | framework | started_at | duration_sec | exit_code | gpu_type_raw | log_tail |
|---|---|---|---|---|---|---|---|
| run-1001 | cust-a-seoul | pytorch | 2026-08-18T02:11:00Z | 412 | 1 | A100-80G | RuntimeError: CUDA out of memory. Trie… |
| run-1002 | cust-a-seoul | pytorch | 2026-08-18T03:40:00Z | 1,810 | 1 | A100 80GB | torch.distributed.DistBackendError: NC… |
| run-1003 | cust-b-us | vllm | 2026-08-18T05:02:00Z | 8 | 127 | H100 | Failed to pull image "registry.interna… |
| run-1004 | cust-b-us | vllm | 2026-08-18T06:20:00Z | — | — | H100 | admission webhook denied the request: … |
| run-1005 | cust-a-seoul | pytorch | 2026-08-18T09:15:00Z | 33 | 1 | A100-80G | FileNotFoundError: [Errno 2] No such f… |
아래 JSON Schema 를 그대로 만족하는 실행 로그 행을 60개 더 만들어 주세요. framework 는 pytorch·vllm·sglang 을 5:3:2 로 섞고, log_tail 은 실제 CUDA·NCCL·containerd·Kubernetes 오류 문구를 그대로 쓰며, 2할은 정상 기동 로그로 둡니다. gpu_type_raw 는 A100-80G·A100 80GB·h100 처럼 표기를 흔들어 주세요. 원인이나 조치는 넣지 마세요.
{"type": "object", "properties": {"run_id": {"type": "string"}, "cluster": {"type": "string"}, "framework": {"type": "string", "enum": ["pytorch", "vllm", "sglang"]}, "started_at": {"type": "string"}, "duration_sec": {"type": ["number", "null"]}, "exit_code": {"type": ["integer", "null"]}, "gpu_type_raw": {"type": "string"}, "log_tail": {"type": "string"}}, "required": ["run_id", "cluster", "framework", "started_at", "log_tail"]}{"type": "object", "properties": {"run_id": {"type": "string"}, "cluster": {"type": "string"}, "framework": {"type": "string", "enum": ["pytorch", "vllm", "sglang"]}, "started_at": {"type": "string"}, "duration_sec": {"type": ["number", "null"]}, "exit_code": {"type": ["integer", "null"]}, "gpu_type_raw": {"type": "string"}, "log_tail": {"type": "string"}}, "required": ["run_id", "cluster", "framework", "started_at", "log_tail"]}반복되는 기술 이슈 대응을 정리한 Runbook 입니다. 증상 패턴과 원인 코드, 1차 조치, 에스컬레이션 대상을 한 행에 둡니다. 같은 원인에 증상 패턴이 둘 이상 붙고 우선순위로 하나를 고르게 했습니다. 로그에 나오는 증상 중 일부는 일부러 넣지 않아 미매칭이 도출되게 둡니다.
| rule_no | symptom_pattern | cause_code | priority | first_action | escalate_to | registered_on |
|---|---|---|---|---|---|---|
| RB-01 | CUDA out of memory | gpu_oom | 10 | 배치 크기를 절반으로 줄이거나 gradient checkpointin… | — | 2026-03-04 |
| RB-02 | container exceeded memory limit | gpu_oom | 20 | 컨테이너 메모리 상한을 워크로드 실측치 위로 올리고 다시 돌립니다. | — | 2026-04-11 |
| RB-03 | NCCL error | nccl_timeout | 10 | NCCL_DEBUG=INFO 로 다시 돌려 어느 랭크에서 멈추는지 확… | SRE | 2026-03-04 |
| RB-04 | watchdog caught collective operation t… | nccl_timeout | 5 | 타임아웃 값을 늘리기 전에 랭크별 진행 로그를 맞춰 지연된 랭크를 먼… | SRE | 2026-05-20 |
| RB-05 | manifest unknown | image_pull_failed | 10 | 이미지 태그가 레지스트리에 있는지 확인하고 없으면 빌드 파이프라인을 … | — | 2026-03-04 |
아래 JSON Schema 를 그대로 만족하는 Runbook 규칙 행을 40개 더 만들어 주세요. 같은 cause_code 에 증상 패턴을 2~3개씩 붙이고 priority 로 순서를 정합니다. 실행 로그에 나오는 증상 중 일부는 일부러 넣지 마세요 — 미매칭이 있어야 Runbook 의 구멍이 드러납니다.
{"type": "object", "properties": {"rule_no": {"type": "string"}, "symptom_pattern": {"type": "string"}, "cause_code": {"type": "string"}, "priority": {"type": "integer"}, "first_action": {"type": "string"}, "escalate_to": {"type": ["string", "null"]}, "registered_on": {"type": "string"}}, "required": ["rule_no", "symptom_pattern", "cause_code", "priority", "first_action"]}{"type": "object", "properties": {"rule_no": {"type": "string"}, "symptom_pattern": {"type": "string"}, "cause_code": {"type": "string"}, "priority": {"type": "integer"}, "first_action": {"type": "string"}, "escalate_to": {"type": ["string", "null"]}, "registered_on": {"type": "string"}}, "required": ["rule_no", "symptom_pattern", "cause_code", "priority", "first_action"]}| Python | 로그 꼬리 파싱과 증상 패턴 매칭, 규칙 우선순위 비교를 맡습니다. |
| Kubernetes | 쿼터 초과·이미지 pull 실패처럼 스케줄링 단계 실패를 읽기 위해 이벤트 메시지 형식을 씁니다. |
| PyTorch | 학습 실패 로그를 만들기 위해 작은 모델을 일부러 실패시키는 실행에 씁니다. |
| vLLM / SGLang | 추론 서버 기동 로그와 실패 로그를 만드는 데 씁니다. |
✗ fail → 미매칭이 절반을 넘으면 Runbook 규칙을 먼저 늘립니다.
✓ pass → 2주차 정답 대조로 넘어갑니다.
✗ fail → 어긋난 유형을 모아 증상 패턴을 다시 씁니다.
✓ pass → 3주차 규칙 확장으로 넘어갑니다.
실행 한 건마다 Runbook 규칙과 맞춰 원인 코드를 정하고, 규칙이 정한 1차 조치와 에스컬레이션 대상을 붙입니다. 어느 규칙에도 안 걸리면 rule_unmatched 로 남겨 Runbook 의 구멍을 드러냅니다.
{"type": "object", "properties": {"verdict_id": {"type": "string"}, "run_id": {"type": "string"}, "cause_code": {"type": "string", "enum": ["run_succeeded", "gpu_oom", "nccl_timeout", "image_pull_failed", "quota_exceeded", "checkpoint_missing", "dataset_missing", "config_mismatch", "rule_unmatched"]}, "matched_rule_no": {"type": ["string", "null"]}, "evidence": {"type": "array", "items": {"type": "object", "properties": {"field": {"type": "string"}, "agg": {"type": ["string", "null"]}, "value": {}}, "required": ["field", "value"]}}, "first_action": {"type": ["string", "null"]}, "escalate_to": {"type": ["string", "null"]}, "summary": {"type": "string"}, "hedge": {"type": ["string", "null"]}}, "required": ["verdict_id", "run_id", "cause_code", "matched_rule_no", "evidence", "summary"]}[
{
"verdict_id": "vd-001",
"run_id": "run-1006",
"cause_code": "run_succeeded",
"matched_rule_no": "RB-10",
"evidence": [
{
"field": "log_tail",
"agg": null,
"value": "INFO server started on 0.0.0.0:30000, 128 running requests, avg ttft 182ms"
},
{
"field": "exit_code",
"agg": null,
"value": 0
}
],
"first_action": "조치가 필요하지 않습니다. 정상 기동으로 기록합니다.",
"escalate_to": null,
"summary": "종료 코드가 0이고 로그에 기동 완료 문구가 있어 정상 기동으로 기록합니다.",
"hedge": null
},
{
"verdict_id": "vd-002",
"run_id": "run-1011",
"cause_code": "run_succeeded",
"matched_rule_no": "RB-10",
"evidence": [
{
"field": "log_tail",
"agg": null,
"value": "INFO server started on 0.0.0.0:30000, 64 running requests, avg ttft 210ms"
},
{
"field": "exit_code",
"agg": null,
"value": 0
}
],
"first_action": "조치가 필요하지 않습니다. 정상 기동으로 기록합니다.",
"escalate_to": null,
"summary": "종료 코드가 0이고 기동 완료 문구가 있어 정상 기동으로 기록합니다.",
"hedge": null
},
{
"verdict_id": "vd-003",
"run_id": "run-1001",
"cause_code": "gpu_oom",
"matched_rule_no": "RB-01",
"evidence": [
{
"field": "log_tail",
"agg": null,
"value": "RuntimeError: CUDA out of memory. Tried to allocate 2.20 GiB (GPU 0; 79.15 GiB total capacity; 76.02 GiB already allocated)"
},
{
"field": "symptom_pattern",
"agg": null,
"value": "CUDA out of memory"
}
],
"first_action": "배치 크기를 절반으로 줄이거나 gradient checkpointing 을 켜고 같은 설정으로 다시 돌립니다.",
"escalate_to": null,
"summary": "로그에 CUDA 메모리 부족 문구가 있어 RB-01 이 걸렸고 배치 축소를 1차 조치로 냅니다.",
"hedge": null
},
{
"verdict_id": "vd-004",
"run_id": "run-1002",
"cause_code": "nccl_timeout",
"matched_rule_no": "RB-04",
"evidence": [
{
"field": "log_tail",
"agg": null,
"value": "torch.distributed.DistBackendError: NCCL error: unhandled system error, watchdog caught collective operation timeout: WorkNCCL(SeqNum=1204, OpType=ALLREDUCE)"
},
{
"field": "symptom_pattern",
"agg": null,
"value": "watchdog caught collective operation timeout"
},
{
"field": "priority",
"agg": null,
"value": 5
}
],
"first_action": "타임아웃 값을 늘리기 전에 랭크별 진행 로그를 맞춰 지연된 랭크를 먼저 찾습니다.",
"escalate_to": "SRE",
"summary": "NCCL 규칙 둘이 걸려 우선순위가 앞선 RB-04 를 골랐고 SRE 로 올립니다.",
"hedge": "두 규칙이 같은 로그에 걸려 우선순위로 하나를 골랐습니다."
},
{
"verdict_id": "vd-005",
"run_id": "run-1009",
"cause_code": "image_pull_failed",
"matched_rule_no": "RB-06",
"evidence": [
{
"field": "log_tail",
"agg": null,
"value": "Failed to pull image \"registry.internal/vllm-serve:latest\": rpc error: code = Unauthorized desc = authentication required"
},
{
"field": "symptom_pattern",
"agg": null,
"value": "authentication required"
}
],
"first_action": "클러스터의 레지스트리 인증 정보를 갱신하고 다시 받습니다.",
"escalate_to": "SRE",
"summary": "레지스트리 인증 실패 문구가 있어 RB-06 이 걸렸고 인증 정보 갱신을 1차 조치로 냅니다.",
"hedge": null
},
{
"verdict_id": "vd-006",
"run_id": "run-1013",
"cause_code": "quota_exceeded",
"matched_rule_no": "RB-07",
"evidence": [
{
"field": "log_tail",
"agg": null,
"value": "admission webhook denied the request: exceeded quota: gpu-quota, requested: nvidia.com/gpu=4, used: nvidia.com/gpu=6, limited: nvidia.com/gpu=8"
},
{
"field": "exit_code",
"agg": null,
"value": null
}
],
"first_action": "고객사 쿼터 잔여를 확인하고 모자라면 증설 요청을 올립니다.",
"escalate_to": "계정 담당",
"summary": "스케줄링 단계에서 쿼터가 막아 종료 코드가 남지 않았고 RB-07 로 계정 담당에게 올립니다.",
"hedge": "실행이 시작되지 않아 duration_sec 와 exit_code 가 비어 있습니다."
},
{
"verdict_id": "vd-007",
"run_id": "run-1014",
"cause_code": "rule_unmatched",
"matched_rule_no": null,
"evidence": [
{
"field": "log_tail",
"agg": null,
"value": "ValueError: Tokenizer class LlamaTokenizerFast does not exist or is not currently imported"
},
{
"field": "rule_no",
"agg": "count",
"value": 12
}
],
"first_action": null,
"escalate_to": null,
"summary": "Runbook 규칙 열두 건 어느 증상 패턴에도 걸리지 않아 원인을 지어내지 않고 미매칭으로 남깁니다.",
"hedge": "이 증상은 Runbook 에 아직 없습니다. 2주차에 구멍 목록으로 모읍니다."
}
][자동 검증 · 코드가 판정합니다] 1. cause_code 가 enum 아홉 값 중 하나인지 확인합니다. 2. verdict_id·run_id·cause_code·matched_rule_no·evidence·summary 가 모두 채워졌는지 확인합니다. 3. matched_rule_no 가 Runbook 규칙표에 실재하는 규칙 번호인지 대조합니다. 4. matched_rule_no 가 있으면 그 규칙의 cause_code 와 판정이 같은지 대조합니다. 5. matched_rule_no 가 있으면 first_action 과 escalate_to 가 그 규칙 행의 값과 같은지 대조합니다. 6. evidence 의 field 이름이 실행 로그와 Runbook 에 실재하는 컬럼인지 대조합니다. 7. agg 가 없는 evidence 의 value 가 그 컬럼에 수록된 행 값과 같은지 확인합니다. 8. 규칙의 symptom_pattern 이 그 실행의 log_tail 에 문자열 그대로 있는지 확인합니다. 9. cause_code 가 rule_unmatched 이면 matched_rule_no 와 first_action 이 null 인지 확인합니다. 10. summary 가 존댓말로 끝나는지 확인합니다. [평가 러너 · 2주차] 직접 돌려 만든 실패 실행 40건에 손으로 붙인 정답 원인과 대조해 일치율과 원인별 분포를 내고, 미매칭이 몰리는 증상을 모아 Runbook 에 없는 구간을 목록으로 냅니다. [수동 검증 · 사람이 봅니다] 1. 증상 패턴이 둘 이상 걸릴 때 우선순위가 맞는지 표본으로 확인합니다. 2. 에스컬레이션 대상이 실제 조직 구조와 맞는지 고객사마다 담당자가 정합니다.