From b3df1b6d9bd3e60758ef3a8301e7c0f42ab3301b Mon Sep 17 00:00:00 2001 From: jmj Date: Thu, 17 Sep 2026 18:35:47 +0900 Subject: [PATCH] =?UTF-8?q?docs(ai):=20LLM=20=EC=A0=9C=EA=B3=B5=EC=9E=90?= =?UTF-8?q?=20=EA=B2=80=ED=86=A0=20=EB=B3=B4=EA=B3=A0=EC=84=9C=20+=20?= =?UTF-8?q?=ED=9B=84=EB=B3=B4=20=EB=AA=A8=EB=8D=B8=20=ED=8F=89=EA=B0=80=20?= =?UTF-8?q?=ED=95=98=EB=84=A4=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로컬 LLM(Ollama, GTX 1660 Ti 6GB)과 게이트웨이 오픈 가중치 모델을 운영 체인 그대로 실측 비교. - ai/scripts/llm_eval: 라벨 케이스(질문 풀 5·꼬리질문 14·코칭 3, 운영 토큰 분포 반영), 원시 실행(run_eval), 규칙 기반 자동 지표(analyze), 2개 계열 판정자 블라인드 채점(judge) - 기존 단일 케이스 스크립트 scripts/llm_bench.py 는 하네스로 대체되어 삭제 - docs/research/llm-provider-evaluation-2026-09.md: 결론·품질·형식 준수·지연·비용·회의 결정 사항 - docs/research/llm-eval-2026-09: 자동 지표 요약, 판정 결과, 합성 케이스 원시 출력, GPU 적재 로그 --- ai/scripts/llm_bench.py | 291 -------- ai/scripts/llm_eval/README.md | 31 + ai/scripts/llm_eval/analyze.py | 298 ++++++++ ai/scripts/llm_eval/cases.py | 476 ++++++++++++ ai/scripts/llm_eval/judge.py | 258 +++++++ ai/scripts/llm_eval/run_eval.py | 338 +++++++++ docs/README.md | 3 + .../auto-metrics-summary.json | 682 ++++++++++++++++++ .../llm-eval-2026-09/eval-judge-table.json | 157 ++++ .../llm-eval-2026-09/eval-judge.jsonl | 44 ++ .../llm-eval-2026-09/gpu-placement.log | 16 + .../raw/gw-gemini-3.1-pro.jsonl | 10 + .../raw/gw-gemini-3.5-flash-lite.jsonl | 78 ++ .../llm-eval-2026-09/raw/gw-gemma-4-31b.jsonl | 61 ++ .../raw/gw-gpt-oss-120b-mt2048.jsonl | 42 ++ .../raw/gw-gpt-oss-120b.jsonl | 61 ++ .../raw/gw-llama-4-maverick.jsonl | 61 ++ .../llm-eval-2026-09/raw/gw-solar-pro4.jsonl | 61 ++ .../raw/local-ax4-light.jsonl | 80 ++ .../raw/local-kanana2-3b.jsonl | 63 ++ .../raw/local-midm2-mini.jsonl | 80 ++ .../raw/local-qwen3-4b-instruct.jsonl | 80 ++ .../raw/local-qwen3.5-4b.jsonl | 80 ++ .../llm-provider-evaluation-2026-09.md | 125 ++++ 24 files changed, 3185 insertions(+), 291 deletions(-) delete mode 100644 ai/scripts/llm_bench.py create mode 100644 ai/scripts/llm_eval/README.md create mode 100644 ai/scripts/llm_eval/analyze.py create mode 100644 ai/scripts/llm_eval/cases.py create mode 100644 ai/scripts/llm_eval/judge.py create mode 100644 ai/scripts/llm_eval/run_eval.py create mode 100644 docs/research/llm-eval-2026-09/auto-metrics-summary.json create mode 100644 docs/research/llm-eval-2026-09/eval-judge-table.json create mode 100644 docs/research/llm-eval-2026-09/eval-judge.jsonl create mode 100644 docs/research/llm-eval-2026-09/gpu-placement.log create mode 100644 docs/research/llm-eval-2026-09/raw/gw-gemini-3.1-pro.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/gw-gemini-3.5-flash-lite.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/gw-gemma-4-31b.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b-mt2048.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/gw-llama-4-maverick.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/gw-solar-pro4.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/local-ax4-light.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/local-kanana2-3b.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/local-midm2-mini.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/local-qwen3-4b-instruct.jsonl create mode 100644 docs/research/llm-eval-2026-09/raw/local-qwen3.5-4b.jsonl create mode 100644 docs/research/llm-provider-evaluation-2026-09.md diff --git a/ai/scripts/llm_bench.py b/ai/scripts/llm_bench.py deleted file mode 100644 index 1fbd9be..0000000 --- a/ai/scripts/llm_bench.py +++ /dev/null @@ -1,291 +0,0 @@ -"""LLM 후보(게이트웨이 vs 로컬 Ollama 등) 를 실제 체인으로 비교하는 벤치마크. - -실제 프롬프트·파서(question_generation / followup_generation) 를 그대로 태우므로 -"이 모델이 우리 JSON 스키마를 지키는가, 한국어 품질은 어떤가, 지연은 얼마인가" 를 -운영 코드와 같은 조건에서 본다. - -사용 예 (stackup-ai 컨테이너 안에서): - python scripts/llm_bench.py --base-url http://ollama:11434/v1 --api-key ollama \ - --model qwen3:4b --runs 2 --out /tmp/bench-qwen3-4b.json - python scripts/llm_bench.py --model gemini-3.5-flash-lite --runs 2 # 게이트웨이 기본값 - ---extra-body 로 공급자 전용 옵션을 넘길 수 있다 (예: Ollama qwen3 thinking 끄기 - '{"think": false}'). -""" - -from __future__ import annotations - -import argparse -import asyncio -import json -import statistics -import sys -import time -from typing import Any - -from ai_server.chain.followup_generation_chain import ( - build_streaming_followup_generator, -) -from ai_server.chain.question_generation_chain import ( - LlmQuestionGenerator, - build_question_generation_chain, -) -from ai_server.config.settings import Settings - -SAMPLE_RESUME_MD = """# 이력서 — 김도현 (백엔드 개발자, 3년차) - -## 요약 -- Spring Boot / Kotlin 기반 커머스 주문·정산 도메인 3년 -- MSA 전환 프로젝트에서 주문 서비스 분리 및 Kafka 이벤트 파이프라인 설계 -- 장애 대응: 결제 승인 지연으로 인한 중복 주문 이슈를 멱등 키 + Outbox 패턴으로 해결 - -## 경력 -### (주)마켓온 — 백엔드 개발자 (2023.03 ~ 현재) -- 주문/결제 도메인 담당. 일 평균 주문 12만 건 처리 -- 모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 - Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일 -- 정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계) -- 결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 - 해결, 중복 주문 0건 달성 - -### 스타트업 인턴 — 서버 개발 (2022.07 ~ 2022.12) -- Node.js/Express 기반 사내 예약 시스템 API 개발, Jest 테스트 커버리지 70% 달성 - -## 프로젝트 -### 실시간 재고 동기화 (2024) -- Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환) -- 재고 불일치 건수 월 200건 → 3건 - -## 기술 스택 -Kotlin, Java 17, Spring Boot 3, JPA/QueryDSL, PostgreSQL, Kafka, Redis, Docker, GitHub Actions -""" - -SAMPLE_FOLLOWUP = { - "job_category": "BACKEND", - "mode": "TECHNICAL", - "previous_question": ( - "결제 승인 콜백 지연으로 중복 주문이 발생했던 문제를 멱등 키와 Outbox 패턴으로 " - "해결하셨다고 했는데, 두 가지를 함께 쓴 이유와 각각이 어떤 실패 케이스를 막아주는지 설명해 주세요." - ), - "answer_text": ( - "네, 먼저 멱등 키는 같은 결제 승인 콜백이 두 번 들어와도 주문이 한 번만 생성되게 하려고 " - "썼습니다. PG사에서 타임아웃 후 재전송을 하다 보니 같은 승인 건이 두 번 오는 경우가 있었고, " - "결제 키를 유니크 제약으로 걸어서 두 번째 요청은 기존 주문을 그대로 돌려주도록 했습니다. " - "Outbox 는 주문 저장이랑 Kafka 이벤트 발행이 하나의 트랜잭션이 아니어서, 주문은 저장됐는데 " - "이벤트가 안 나가는 경우가 있었어요. 그래서 이벤트를 같은 DB 트랜잭션 안에서 outbox 테이블에 " - "먼저 쓰고, 별도 릴레이가 폴링해서 발행하도록 바꿨습니다." - ), - "context": "(none)", - "parent_category": "PROJECT", - "expected_signal": "멱등성과 트랜잭션 경계에 대한 이해, 실패 케이스를 구체적으로 구분하는지", - "history": "(none)", -} - - -def _settings(args: argparse.Namespace) -> Settings: - over: dict[str, Any] = {} - if args.base_url: - over["llm_base_url"] = args.base_url - if args.api_key is not None: - over["llm_api_key"] = args.api_key - if args.model: - over["llm_pro_model"] = args.model - over["llm_flash_model"] = args.model - over["llm_pro_timeout_sec"] = args.timeout - over["llm_flash_timeout_sec"] = args.timeout - if args.max_tokens: - over["llm_flash_max_tokens"] = args.max_tokens - return Settings(**over) - - -def _patch_extra_body(chain: Any, extra_body: dict[str, Any] | None) -> None: - """체인 안의 ChatOpenAI 에 extra_body 를 주입 (공급자 전용 옵션 실험용).""" - if not extra_body: - return - from langchain_openai import ChatOpenAI - - def visit(node: Any) -> None: - if isinstance(node, ChatOpenAI): - node.extra_body = {**(node.extra_body or {}), **extra_body} - return - for attr in ("steps", "first", "middle", "last", "bound"): - child = getattr(node, attr, None) - if child is None: - continue - if isinstance(child, (list, tuple)): - for c in child: - visit(c) - else: - visit(child) - - visit(chain) - - -async def bench_questions( - settings: Settings, runs: int, extra_body: dict | None -) -> dict: - chain = build_question_generation_chain(settings) - _patch_extra_body(chain, extra_body) - gen = LlmQuestionGenerator(chain) - samples: list[dict[str, Any]] = [] - for i in range(runs): - t0 = time.perf_counter() - try: - pool = await gen.generate( - job_categories=["BACKEND"], - mode="TECHNICAL", - max_questions=3, - context=SAMPLE_RESUME_MD, - ) - elapsed = time.perf_counter() - t0 - samples.append( - { - "ok": True, - "latency_sec": round(elapsed, 2), - "questions": [q.model_dump(by_alias=True) for q in pool.questions], - } - ) - except Exception as exc: # noqa: BLE001 — 벤치는 실패 사유를 기록만 한다 - elapsed = time.perf_counter() - t0 - samples.append( - { - "ok": False, - "latency_sec": round(elapsed, 2), - "error": f"{type(exc).__name__}: {str(exc)[:400]}", - } - ) - print( - f" questions run {i + 1}/{runs}: ok={samples[-1]['ok']} {samples[-1]['latency_sec']}s", - file=sys.stderr, - ) - return _summarize("questions", samples) - - -async def bench_followup( - settings: Settings, runs: int, extra_body: dict | None -) -> dict: - # 운영 경로(followup_consumer → StreamingFollowupGenerator.stream, // 태그) - # 를 그대로 태운다. build_followup_generation_chain(JSON 파서) 는 운영에서 쓰이지 않는다. - gen = build_streaming_followup_generator(settings) - _patch_extra_body(gen._llm, extra_body) # noqa: SLF001 — 벤치 전용 주입 - samples: list[dict[str, Any]] = [] - for i in range(runs): - t0 = time.perf_counter() - first_token_at: list[float] = [] - - def on_token(_delta: str) -> None: - if not first_token_at: - first_token_at.append(time.perf_counter() - t0) - - try: - res = await gen.stream(on_question_token=on_token, **SAMPLE_FOLLOWUP) - elapsed = time.perf_counter() - t0 - samples.append( - { - "ok": True, - "latency_sec": round(elapsed, 2), - "first_question_token_sec": ( - round(first_token_at[0], 2) if first_token_at else None - ), - "followup_question": res.followup_question, - "answer_intent": res.answer_intent, - "answer_evaluation": ( - res.answer_evaluation.model_dump(by_alias=True) - if res.answer_evaluation - else None - ), - } - ) - except Exception as exc: # noqa: BLE001 - elapsed = time.perf_counter() - t0 - samples.append( - { - "ok": False, - "latency_sec": round(elapsed, 2), - "error": f"{type(exc).__name__}: {str(exc)[:400]}", - } - ) - print( - f" followup run {i + 1}/{runs}: ok={samples[-1]['ok']} {samples[-1]['latency_sec']}s", - file=sys.stderr, - ) - return _summarize("followup", samples) - - -def _summarize(name: str, samples: list[dict[str, Any]]) -> dict: - oks = [s for s in samples if s["ok"]] - lat = [s["latency_sec"] for s in oks] - return { - "chain": name, - "runs": len(samples), - "success": len(oks), - "latency_median_sec": round(statistics.median(lat), 2) if lat else None, - "latency_max_sec": max(lat) if lat else None, - "samples": samples, - } - - -async def main() -> int: - ap = argparse.ArgumentParser( - description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter - ) - ap.add_argument( - "--base-url", - default="", - help="OpenAI 호환 base URL (기본: settings.llm_base_url)", - ) - ap.add_argument( - "--api-key", default=None, help="API key (Ollama 는 아무 값이나, 예: ollama)" - ) - ap.add_argument( - "--model", default="", help="pro/flash 둘 다 이 모델로 (기본: settings 값)" - ) - ap.add_argument("--runs", type=int, default=2) - ap.add_argument("--timeout", type=float, default=180.0) - ap.add_argument( - "--max-tokens", type=int, default=0, help="flash max_tokens 덮어쓰기 (0=기본)" - ) - ap.add_argument("--extra-body", default="", help="JSON. 예: '{\"think\": false}'") - ap.add_argument("--only", choices=["questions", "followup"], default=None) - ap.add_argument("--out", default="", help="결과 JSON 저장 경로") - args = ap.parse_args() - - settings = _settings(args) - extra_body = json.loads(args.extra_body) if args.extra_body else None - label = args.model or f"{settings.llm_pro_model}/{settings.llm_flash_model}" - print( - f"== bench model={label} base_url={settings.llm_base_url} runs={args.runs}", - file=sys.stderr, - ) - - # 1회 워밍업 호출 지연(모델 로드)을 분리해 보기 위해 첫 run 도 그대로 기록한다. - results: list[dict] = [] - if args.only in (None, "questions"): - results.append(await bench_questions(settings, args.runs, extra_body)) - if args.only in (None, "followup"): - results.append(await bench_followup(settings, args.runs, extra_body)) - - report = { - "model": label, - "base_url": settings.llm_base_url, - "extra_body": extra_body, - "results": results, - } - text = json.dumps(report, ensure_ascii=False, indent=2) - if args.out: - with open(args.out, "w", encoding="utf-8") as f: - f.write(text) - print(f"saved {args.out}", file=sys.stderr) - else: - print(text) - for r in results: - print( - f"{r['chain']:<10} success={r['success']}/{r['runs']} " - f"median={r['latency_median_sec']}s max={r['latency_max_sec']}s", - file=sys.stderr, - ) - return 0 - - -if __name__ == "__main__": - raise SystemExit(asyncio.run(main())) diff --git a/ai/scripts/llm_eval/README.md b/ai/scripts/llm_eval/README.md new file mode 100644 index 0000000..ba9b02c --- /dev/null +++ b/ai/scripts/llm_eval/README.md @@ -0,0 +1,31 @@ +# LLM 후보 평가 하네스 + +운영 체인(질문 풀 생성 · 스트리밍 꼬리질문 · 답변 코칭)을 그대로 태워 후보 모델을 비교한다. +케이스는 합성 데이터이며, 입력 크기는 운영 `ai_request_logs` 분포(질문 풀 입력 p90 4.7k 토큰 등)에 맞췄다. + +## 구성 + +| 파일 | 역할 | +|---|---| +| `cases.py` | 라벨이 붙은 케이스: 질문 풀 5개(긴 문맥 p90 포함), 꼬리질문 14개(강한·약한·모름·재설명·확인형·사실 불일치 등), 코칭 3개 | +| `run_eval.py` | 후보 1개를 돌려 원시 결과 JSONL 저장. `--latency` 는 콜드스타트, 코칭 15건×동시 5, 그 도중 꼬리질문 지연 측정 | +| `analyze.py` | 규칙 기반 자동 지표 (태그 준수, 의도 정확도, 점수 라벨·사실대조 규칙, 근거 인용 검증, 중복, 외국 문자, 지연) | +| `judge.py` | 블라인드 비교 채점. 판정 모델 2개(gemini-3.1-pro-preview, claude-opus-5)로 자기 계열 선호 편향 상쇄 | + +## 실행 (stackup-ai 컨테이너 안) + +```bash +# 게이트웨이 모델 (컨테이너 env 의 LLM_BASE_URL/LLM_API_KEY 사용) +python run_eval.py --label gw-flash-lite --model gemini-3.5-flash-lite --latency --out /tmp/eval/gw-flash-lite.jsonl + +# 로컬 Ollama (num_ctx 8192 파생 모델 필수 — 기본 4096 은 질문 풀 프롬프트를 조용히 자른다) +python run_eval.py --label local-x --base-url http://ollama:11434/v1 --api-key ollama \ + --model <8k 파생 모델> --latency --out /tmp/eval/local-x.jsonl +# thinking 기본 on 모델(qwen3.5, gemma4)은 --extra-body '{"reasoning_effort": "none"}' + +python analyze.py /tmp/eval/*.jsonl > summary.json +python judge.py --out judge.jsonl /tmp/eval/*.jsonl > judge-table.json +``` + +주의: reasoning 을 끌 수 없는 모델(gpt-oss)은 운영 `LLM_FLASH_MAX_TOKENS=512` 에서 추론이 토큰을 다 써 +꼬리질문이 비어 나온다. 공정 비교가 필요하면 `--flash-max-tokens 2048`. diff --git a/ai/scripts/llm_eval/analyze.py b/ai/scripts/llm_eval/analyze.py new file mode 100644 index 0000000..713e63c --- /dev/null +++ b/ai/scripts/llm_eval/analyze.py @@ -0,0 +1,298 @@ +"""run_eval.py 가 남긴 JSONL 들을 자동 지표로 집계한다 (LLM 판정 없이 규칙 기반). + +python analyze.py /tmp/eval/*.jsonl > summary.json +""" + +from __future__ import annotations + +import json +import re +import statistics +import sys +from collections import defaultdict +from typing import Any + +sys.path.insert(0, __file__.rsplit("/", 1)[0]) +from cases import COACHING_CASES, FOLLOWUP_CASES, QUESTION_CASES # noqa: E402 + +HAN = re.compile(r"[一-鿿㐀-䶿]") +KANA = re.compile(r"[぀-ヿ]") +OTHER_SCRIPT = re.compile(r"[Ѐ-ӿ฀-๿؀-ۿ]") # 키릴·태국·아랍 +HANGUL = re.compile(r"[가-힣]") +MARKDOWN = re.compile(r"(\*\*|^#+\s|`|^\s*[-*]\s)", re.M) +DIGITS = re.compile(r"\d+(?:\.\d+)?") + +F_BY_ID = {c["id"]: c for c in FOLLOWUP_CASES} +Q_BY_ID = {c["id"]: c for c in QUESTION_CASES} +C_BY_ID = {c["id"]: c for c in COACHING_CASES} + + +def pct(n: int, d: int) -> float | None: + return round(100.0 * n / d, 1) if d else None + + +def med(xs: list[float]) -> float | None: + xs = [x for x in xs if x is not None] + return round(statistics.median(xs), 2) if xs else None + + +def p90(xs: list[float]) -> float | None: + xs = sorted(x for x in xs if x is not None) + if not xs: + return None + return round(xs[min(len(xs) - 1, int(round(0.9 * (len(xs) - 1))))], 2) + + +def script_issue(text: str) -> bool: + return bool(HAN.search(text) or KANA.search(text) or OTHER_SCRIPT.search(text)) + + +def ngrams(s: str, n: int = 2) -> set[str]: + s = re.sub(r"\s+", "", s) + return {s[i : i + n] for i in range(max(0, len(s) - n + 1))} + + +def jaccard(a: str, b: str) -> float: + A, B = ngrams(a), ngrams(b) + return len(A & B) / len(A | B) if A and B else 0.0 + + +def grounded(evidence: str, context: str) -> bool: + """근거 인용이 컨텍스트에 실제로 있는가 (공백 제거 후 4-gram 60% 이상 일치).""" + ev = re.sub(r"\s+", "", evidence) + ctx = re.sub(r"\s+", "", context) + grams = [ev[i : i + 4] for i in range(max(0, len(ev) - 3))] + if not grams: + return False + return sum(1 for g in grams if g in ctx) / len(grams) >= 0.6 + + +def analyze_followup(recs: list[dict]) -> dict[str, Any]: + main = [r for r in recs if r["suite"] == "followup"] + ok = [r for r in main if r["ok"]] + out: dict[str, Any] = {"calls": len(main), "success_pct": pct(len(ok), len(main))} + + tag_ok = intent_hit = 0 + score_checks = score_hits = corr_checks = corr_hits = 0 + lengths: list[int] = [] + script_bad = 0 + per_case_intent: dict[str, list[str]] = defaultdict(list) + spec_by_case: dict[str, list[float]] = defaultdict(list) + for r in ok: + case = F_BY_ID[r["case_id"]] + q = r.get("followup_question") or "" + ev = r.get("answer_evaluation") + # 태그 준수: 질문에 태그 잔해가 없고, 평가 meta 파싱 성공(모름/재설명 제외 시 필수) + tags_clean = "<" not in q and len(q) < 400 + # 확인형 단답은 프롬프트가 점수 null 을 지시 → AnswerEvaluation(specificity: float) 검증에서 + # meta 가 None 이 되는 것이 운영 정상 동작이므로 준수로 본다. + meta_optional = ( + case["expect_intent"] != "NORMAL" or case.get("expect_scores") == "null" + ) + if tags_clean and (ev is not None or meta_optional): + tag_ok += 1 + per_case_intent[case["id"]].append(r.get("answer_intent")) + if r.get("answer_intent") == case["expect_intent"]: + intent_hit += 1 + lengths.append(len(q)) + if script_issue(q): + script_bad += 1 + spec = ev.get("specificity") if ev else None + if spec is not None: + spec_by_case[case["id"]].append(spec) + exp = case.get("expect_scores") + if exp and case["expect_intent"] == "NORMAL": + score_checks += 1 + if exp == "high" and spec is not None and spec >= 3: + score_hits += 1 + elif exp == "low" and spec is not None and spec <= 2: + score_hits += 1 + elif exp == "null" and spec is None: + score_hits += 1 + exp_c = case.get("expect_correctness") + if exp_c and case["expect_intent"] == "NORMAL": + corr = ev.get("correctness") if ev else None + corr_checks += 1 + if exp_c == "null" and corr is None: + corr_hits += 1 + elif exp_c == "low" and corr is not None and corr <= 2: + corr_hits += 1 + elif exp_c == "high" and corr is not None and corr >= 3: + corr_hits += 1 + + # 판별력: 같은 질문의 강한 답 vs 약한 답 구체성 점수 차 + def gap(strong: str, weak: str) -> float | None: + a, b = med(spec_by_case.get(strong, [])), med(spec_by_case.get(weak, [])) + return round(a - b, 2) if a is not None and b is not None else None + + out.update( + tag_compliance_pct=pct(tag_ok, len(ok)), + intent_accuracy_pct=pct(intent_hit, len(ok)), + intent_misses={ + cid: [i for i in v if i != F_BY_ID[cid]["expect_intent"]] + for cid, v in per_case_intent.items() + if any(i != F_BY_ID[cid]["expect_intent"] for i in v) + }, + score_label_accuracy_pct=pct(score_hits, score_checks), + correctness_rule_accuracy_pct=pct(corr_hits, corr_checks), + discrimination_gap_backend=gap("f-strong-backend", "f-weak-vague"), + discrimination_gap_personality=gap( + "f-personality-star", "f-personality-rambling" + ), + question_len_median=med(lengths), + question_len_le60_pct=pct(sum(1 for x in lengths if x <= 60), len(lengths)), + non_korean_script_pct=pct(script_bad, len(ok)), + latency_median=med([r["latency_sec"] for r in ok]), + latency_p90=p90([r["latency_sec"] for r in ok]), + ttft_median=med([r.get("ttft_sec") for r in ok]), + ttft_p90=p90([r.get("ttft_sec") for r in ok]), + over_3s_pct=pct(sum(1 for r in ok if r["latency_sec"] > 3), len(ok)), + over_10s_timeout_pct=pct(sum(1 for r in ok if r["latency_sec"] > 10), len(ok)), + ) + for tag in (":cold", ":after-cold", ":during-fanout"): + rs = [r for r in recs if r["suite"] == "followup" + tag] + if rs: + out["latency" + tag.replace(":", "_").replace("-", "_")] = ( + rs[0]["latency_sec"] if rs[0]["ok"] else "ERR" + ) + return out + + +def analyze_questions(recs: list[dict]) -> dict[str, Any]: + main = [r for r in recs if r["suite"] == "questions"] + ok = [r for r in main if r["ok"]] + out: dict[str, Any] = {"calls": len(main), "success_pct": pct(len(ok), len(main))} + errors = [r["error"][:160] for r in main if not r["ok"]] + count_exact = mode_fit = job_ok = multi_ok = multi_checks = 0 + ev_required = ev_present = ev_grounded = ev_nonempty = 0 + dup_pairs = total_pairs = recent_dup = 0 + q_total = len_le80 = script_bad = md_bad = 0 + long_ok = [] + for r in ok: + case = Q_BY_ID[r["case_id"]] + qs = r["questions"] + if len(qs) == case["max_questions"]: + count_exact += 1 + cats = [q["category"] for q in qs] + if case["mode"] == "PERSONALITY": + mode_fit += cats.count("BEHAVIORAL") >= max(1, len(cats) // 2 + 1) + elif case["mode"] == "TECHNICAL": + mode_fit += cats.count("BEHAVIORAL") <= len(cats) // 3 + else: + mode_fit += len(set(cats)) >= 3 + jobs = [q.get("job_category") for q in qs] + job_ok += all(j in case["job_categories"] for j in jobs) + if len(case["job_categories"]) > 1: + multi_checks += 1 + multi_ok += all(j in jobs for j in case["job_categories"]) + for q in qs: + q_total += 1 + text = q["question"] + len_le80 += len(text) <= 80 + script_bad += script_issue( + text + q.get("target_evidence", "") + q.get("expected_signal", "") + ) + md_bad += bool(MARKDOWN.search(text)) + evid = q.get("target_evidence") or "" + if q["category"] in ("PROJECT_DEEP_DIVE", "TECH_CHOICE"): + ev_required += 1 + ev_present += bool(evid.strip()) + if evid.strip(): + ev_nonempty += 1 + ev_grounded += grounded( + evid, case["context"] + (case.get("self_introduction") or "") + ) + for i in range(len(qs)): + for j in range(i + 1, len(qs)): + total_pairs += 1 + dup_pairs += jaccard(qs[i]["question"], qs[j]["question"]) >= 0.5 + for rq in case.get("recent_questions") or []: + recent_dup += any(jaccard(rq, q["question"]) >= 0.5 for q in qs) + if case["id"] == "q-long-context-p90": + long_ok.append(len(qs) == case["max_questions"]) + out.update( + errors=errors[:3], + count_exact_pct=pct(count_exact, len(ok)), + mode_category_fit_pct=pct(mode_fit, len(ok)), + job_category_valid_pct=pct(job_ok, len(ok)), + multi_job_coverage_pct=pct(multi_ok, multi_checks), + evidence_present_when_required_pct=pct(ev_present, ev_required), + evidence_grounded_pct=pct(ev_grounded, ev_nonempty), + near_duplicate_pair_pct=pct(dup_pairs, total_pairs), + repeated_recent_question_count=recent_dup, + question_len_le80_pct=pct(len_le80, q_total), + non_korean_script_pct=pct(script_bad, q_total), + markdown_in_question_pct=pct(md_bad, q_total), + long_context_success=f"{sum(long_ok)}/{len([r for r in main if r['case_id'] == 'q-long-context-p90'])}", + latency_median=med([r["latency_sec"] for r in ok]), + latency_p90=p90([r["latency_sec"] for r in ok]), + ) + return out + + +def analyze_coaching(recs: list[dict]) -> dict[str, Any]: + main = [r for r in recs if r["suite"] == "coaching"] + ok = [r for r in main if r["ok"]] + out: dict[str, Any] = {"calls": len(main), "success_pct": pct(len(ok), len(main))} + invented = checks = script_bad = one_line = 0 + for r in ok: + case = C_BY_ID[r["case_id"]] + c = r["coaching"] + body = (c.get("model_answer") or "") + (c.get("answer_rewrite") or "") + source = case["answer"] + case["rag_context"] + case["question"] + nums = {n for n in DIGITS.findall(body) if len(n) >= 2} + checks += 1 + # 자료에 없는 2자리 이상 수치를 만들어 냈는가 (지어낸 실적 대리 지표) + invented += any(n not in source for n in nums) + script_bad += script_issue(body + (c.get("coaching_comment") or "")) + cc = (c.get("coaching_comment") or "").strip() + one_line += bool(cc) and "\n" not in cc and not MARKDOWN.search(cc) + out.update( + invented_numbers_pct=pct(invented, checks), + non_korean_script_pct=pct(script_bad, len(ok)), + comment_one_line_pct=pct(one_line, len(ok)), + latency_median=med([r["latency_sec"] for r in ok]), + latency_p90=p90([r["latency_sec"] for r in ok]), + ) + fan = [r for r in recs if r["suite"] == "coaching:fanout15x5"] + wall = [r for r in recs if r["suite"] == "fanout_wall"] + if fan: + out["fanout15x5_success"] = f"{sum(r['ok'] for r in fan)}/{len(fan)}" + out["fanout15x5_wall_sec"] = wall[0]["wall_sec"] if wall else None + out["fanout15x5_per_call_p90"] = p90([r["latency_sec"] for r in fan if r["ok"]]) + return out + + +def main() -> None: + by_label: dict[str, list[dict]] = defaultdict(list) + for path in sys.argv[1:]: + with open(path, encoding="utf-8") as f: + for line in f: + line = line.strip() + if line: + rec = json.loads(line) + by_label[rec["label"]].append(rec) + summary = {} + for label, recs in sorted(by_label.items()): + summary[label] = { + "followup": ( + analyze_followup(recs) + if any(r["suite"].startswith("followup") for r in recs) + else None + ), + "questions": ( + analyze_questions(recs) + if any(r["suite"] == "questions" for r in recs) + else None + ), + "coaching": ( + analyze_coaching(recs) + if any(r["suite"].startswith("coaching") for r in recs) + else None + ), + } + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/ai/scripts/llm_eval/cases.py b/ai/scripts/llm_eval/cases.py new file mode 100644 index 0000000..3cd0902 --- /dev/null +++ b/ai/scripts/llm_eval/cases.py @@ -0,0 +1,476 @@ +"""LLM 후보 평가용 라벨링 케이스 세트 (합성 데이터 — 실제 사용자 데이터 아님). + +케이스 설계 근거 (운영 ai_request_logs / interview_messages 집계, 2026-09-17): +- 질문 풀 입력 토큰 p50 3,141 / p90 4,722 / max 4,869 (Gemini 토크나이저 기준) +- 지원자 답변 길이 p50 162자 / p90 425자 / max 2,583자 +- 피드백 코칭은 세션당 ~15건 fan-out, 동시성 5 +""" + +from __future__ import annotations + +RESUME_BACKEND = """# 이력서 — 김도현 (백엔드 개발자, 3년차) + +## 요약 +- Spring Boot / Kotlin 기반 커머스 주문·정산 도메인 3년 +- MSA 전환 프로젝트에서 주문 서비스 분리 및 Kafka 이벤트 파이프라인 설계 +- 장애 대응: 결제 승인 지연으로 인한 중복 주문 이슈를 멱등 키 + Outbox 패턴으로 해결 + +## 경력 +### (주)마켓온 — 백엔드 개발자 (2023.03 ~ 현재) +- 주문/결제 도메인 담당. 일 평균 주문 12만 건 처리 +- 모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 + Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일 +- 정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계) +- 결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 + 해결, 중복 주문 0건 달성 + +### 스타트업 인턴 — 서버 개발 (2022.07 ~ 2022.12) +- Node.js/Express 기반 사내 예약 시스템 API 개발, Jest 테스트 커버리지 70% 달성 + +## 프로젝트 +### 실시간 재고 동기화 (2024) +- Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환) +- 재고 불일치 건수 월 200건 → 3건 + +## 기술 스택 +Kotlin, Java 17, Spring Boot 3, JPA/QueryDSL, PostgreSQL, Kafka, Redis, Docker, GitHub Actions +""" + +REPO_FRONTEND = """# GitHub 레포 분석 — park-sy/travel-planner (React 18 + TypeScript) + +## 개요 +여행 일정 공유 웹앱. 월간 활성 사용자 약 3천 명(README 기준). Vite + React 18 + TypeScript, +상태 관리는 Zustand, 서버 상태는 TanStack Query v5. + +## 핵심 구현 +- 일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 + (커밋 메시지: "virtualize timeline, INP 480ms -> 120ms") +- 지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱 +- 오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. + 충돌은 last-write-wins (TODO 주석: "CRDT 검토 필요") +- 이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환 + +## 테스트/품질 +- Vitest 단위 테스트 42개, Playwright E2E 6개 +- Lighthouse 성능 점수 68 → 91 (PR #57 설명) + +## 기술 스택 +React 18, TypeScript, Vite, Zustand, TanStack Query, react-window, Dexie, Vitest, Playwright +""" + +RESUME_INFRA_DBA = """# 이력서 — 이서연 (인프라/DBA, 4년차) + +## 경력 +### (주)핀링크 — 플랫폼 엔지니어 (2022.01 ~ 현재) +- EKS 기반 쿠버네티스 클러스터 3개 운영 (파드 약 400개) +- HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영 +- Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리 +- ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분 +- PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms + (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할) +- 장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용 + +## 자격/기술 +CKA, AWS SAA / Kubernetes, EKS, Terraform, ArgoCD, Prometheus, Grafana, PostgreSQL, Redis +""" + +COVER_LETTER = """# 자기소개서 — 최민준 (백엔드 지원) + +## 지원동기 +학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 +있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 +'멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다. + +## 협업 경험 +캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. +저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, +이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 다만 초반에 제 방식이 옳다고 +고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 +바꿨습니다. + +## 실패 경험 +알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. +원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다. +""" + +SELF_INTRO_BACKEND = ( + "안녕하세요, 커머스 주문 결제 도메인에서 3년 동안 백엔드를 개발한 김도현입니다. " + "모놀리식을 MSA로 전환하면서 주문 서비스를 분리했고, 결제 콜백 지연으로 생긴 중복 주문 문제를 " + "멱등 키와 Outbox 패턴으로 해결한 경험이 가장 기억에 남습니다. 대용량 트래픽에서도 데이터 " + "정합성을 지키는 서버를 만드는 데 관심이 많습니다." +) + + +def _long_context() -> str: + """운영 p90(Gemini ~4.7k 토큰) 수준의 다문서 컨텍스트.""" + return "\n\n".join( + [ + RESUME_BACKEND, + RESUME_BACKEND.replace("김도현", "김도현(경력기술서 상세)").replace( + "## 기술 스택", + "## 상세 회고\n- 각 프로젝트의 의사결정 배경과 대안 비교는 면접에서 설명 가능\n## 기술 스택", + ), + REPO_FRONTEND.replace("park-sy/travel-planner", "kim-dh/order-admin") + .replace("여행 일정 공유 웹앱", "주문 관리 어드민") + .replace("React 18", "React 18 (사이드 프로젝트)"), + COVER_LETTER.replace("최민준", "김도현"), + ] + ) + + +# --------------------------------------------------------------------------- +# 질문 풀 생성 (Pro 티어) 케이스 +# --------------------------------------------------------------------------- +QUESTION_CASES = [ + { + "id": "q-backend-tech", + "job_categories": ["BACKEND"], + "mode": "TECHNICAL", + "max_questions": 5, + "context": RESUME_BACKEND, + "self_introduction": SELF_INTRO_BACKEND, + }, + { + "id": "q-frontend-repo", + "job_categories": ["FRONTEND"], + "mode": "TECHNICAL", + "max_questions": 5, + "context": REPO_FRONTEND, + "self_introduction": None, + }, + { + "id": "q-infra-dba-multi", + "job_categories": ["INFRA", "DBA"], + "mode": "INTEGRATED", + "max_questions": 6, + "context": RESUME_INFRA_DBA, + "self_introduction": None, + }, + { + "id": "q-personality-coverletter", + "job_categories": ["BACKEND"], + "mode": "PERSONALITY", + "max_questions": 5, + "context": COVER_LETTER, + "self_introduction": None, + }, + { + "id": "q-long-context-p90", + "job_categories": ["BACKEND"], + "mode": "TECHNICAL", + "max_questions": 5, + "context": _long_context(), + "self_introduction": SELF_INTRO_BACKEND, + "recent_questions": [ + "결제 승인 콜백 지연으로 인한 중복 주문을 멱등 키와 Outbox 로 해결한 과정을 설명해 주세요.", + "정산 배치를 5시간에서 40분으로 줄인 방법은 무엇인가요?", + ], + }, +] + +# --------------------------------------------------------------------------- +# 꼬리질문 (Flash 티어, 스트리밍 태그 출력) 케이스 — 라벨 포함 +# expect_intent: 정답 의도 +# expect_scores: "null" (확인형 단답/모름) | "low" (spec<=2) | "high" (spec>=3) | None(무관) +# expect_correctness: "null" (컨텍스트 없음) | "low" (<=2, 사실 불일치) | "high" (>=3) | None +# --------------------------------------------------------------------------- +_Q_OUTBOX = ( + "결제 승인 콜백 지연으로 중복 주문이 발생했던 문제를 멱등 키와 Outbox 패턴으로 해결하셨다고 " + "했는데, 두 가지를 함께 쓴 이유와 각각이 어떤 실패 케이스를 막는지 설명해 주세요." +) +_SIG_OUTBOX = "멱등성과 트랜잭션 경계에 대한 이해, 실패 케이스를 구체적으로 구분하는지" + +FOLLOWUP_CASES = [ + { + "id": "f-strong-backend", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "parent_category": "PROJECT_DEEP_DIVE", + "previous_question": _Q_OUTBOX, + "expected_signal": _SIG_OUTBOX, + "answer_text": ( + "멱등 키는 같은 결제 승인 콜백이 두 번 들어와도 주문이 한 번만 생성되게 하려고 썼습니다. " + "PG사가 타임아웃 후 재전송하면서 같은 승인 건이 두 번 오는 경우가 있었고, 결제 키에 유니크 " + "제약을 걸어 두 번째 요청은 기존 주문을 그대로 돌려주도록 했습니다. Outbox 는 주문 저장과 " + "Kafka 발행이 한 트랜잭션이 아니어서 주문은 저장됐는데 이벤트가 안 나가는 경우를 막으려고 " + "도입했습니다. 이벤트를 같은 DB 트랜잭션에서 outbox 테이블에 쓰고 릴레이가 폴링해 발행합니다. " + "도입 후 중복 주문은 월 30건에서 0건이 됐습니다." + ), + "context": "(none)", + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "high", + "expect_correctness": "null", + }, + { + "id": "f-weak-vague", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "parent_category": "PROJECT_DEEP_DIVE", + "previous_question": _Q_OUTBOX, + "expected_signal": _SIG_OUTBOX, + "answer_text": "그냥 중복이 안 생기게 잘 처리했고요, 트랜잭션도 잘 관리해서 문제없이 해결됐습니다.", + "context": "(none)", + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "low", + "expect_correctness": "null", + }, + { + "id": "f-dont-know-explicit", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "parent_category": "CS_FUNDAMENTAL", + "previous_question": "PostgreSQL 의 MVCC 에서 오래 열린 트랜잭션이 vacuum 에 어떤 영향을 주는지 설명해 주세요.", + "expected_signal": "xmin horizon 과 dead tuple 회수 지연, 테이블 bloat 연결", + "answer_text": "음... 그 부분은 솔직히 잘 모르겠습니다. 다음 질문으로 넘어가도 될까요?", + "context": "(none)", + "history": "(none)", + "expect_intent": "DONT_KNOW", + "expect_scores": None, + "expect_correctness": "null", + }, + { + "id": "f-dont-know-stt", + "job_category": "FRONTEND", + "mode": "TECHNICAL", + "parent_category": "CS_FUNDAMENTAL", + "previous_question": "React 18 의 automatic batching 이 이전 버전과 어떻게 다른지 설명해 주세요.", + "expected_signal": "setTimeout/Promise 등 비동기 콜백 내부 업데이트도 배칭된다는 점", + "answer_text": "어 그 음 배칭이요 그거는 어 제가 공부를 안 해서 어 모르겠어요 죄송합니다", + "context": "(none)", + "history": "(none)", + "expect_intent": "DONT_KNOW", + "expect_scores": None, + "expect_correctness": "null", + }, + { + "id": "f-clarification", + "job_category": "INFRA", + "mode": "TECHNICAL", + "parent_category": "TECH_CHOICE", + "previous_question": "HPA 기준을 CPU 70% 로 잡으신 근거와, 트래픽 피크에 사전 스케일아웃을 병행한 이유를 설명해 주세요.", + "expected_signal": "HPA 반응 지연(메트릭 수집·파드 기동 시간)과 예측 가능한 피크의 구분", + "answer_text": "죄송한데 질문이 조금 길어서요, 무엇을 여쭤보시는 건지 좀 더 쉽게 다시 말씀해 주실 수 있을까요?", + "context": "(none)", + "history": "(none)", + "expect_intent": "CLARIFICATION", + "expect_scores": None, + "expect_correctness": "null", + }, + { + "id": "f-confirm-short", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "parent_category": "PROJECT_DEEP_DIVE", + "previous_question": "그럼 outbox 릴레이는 별도 프로세스로 폴링하신 건가요?", + "expected_signal": "(none)", + "answer_text": "네, 맞습니다.", + "context": "(none)", + "history": ( + "면접관: 멱등 키와 Outbox 를 함께 쓴 이유는?\n" + "지원자: 재전송 콜백 중복과 발행 누락을 각각 막으려고 썼습니다. 릴레이가 outbox 테이블을 읽어 발행합니다." + ), + "expect_intent": "NORMAL", + "expect_scores": "null", + "expect_correctness": "null", + }, + { + "id": "f-infra-fact-error", + "job_category": "INFRA", + "mode": "TECHNICAL", + "parent_category": "TECH_CHOICE", + "previous_question": "HPA 기준과 트래픽 피크 대응 방식을 어떻게 설계하셨는지 설명해 주세요.", + "expected_signal": "HPA 메트릭 선택 근거와 사전 스케일아웃 병행 이유", + "answer_text": ( + "HPA 는 메모리 50% 를 기준으로 잡았습니다. 저희 서비스는 메모리를 많이 써서요. 피크 대응은 " + "따로 한 건 없고 HPA 가 알아서 늘려줬습니다." + ), + "context": RESUME_INFRA_DBA, + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "low", + "expect_correctness": "low", + }, + { + "id": "f-dba-correct-with-context", + "job_category": "DBA", + "mode": "TECHNICAL", + "parent_category": "PROJECT_DEEP_DIVE", + "previous_question": "슬로우 쿼리 p95 를 2.3초에서 180ms 로 줄인 과정을 설명해 주세요.", + "expected_signal": "원인 진단 방법(EXPLAIN 등)과 인덱스·파티셔닝·vacuum 각각의 기여 구분", + "answer_text": ( + "먼저 pg_stat_statements 로 상위 쿼리를 뽑고 EXPLAIN ANALYZE 로 보니 거래내역 조회가 " + "seq scan 을 타고 있었습니다. (user_id, created_at) 복합 인덱스로 바꾸고, 거래내역 테이블을 " + "월 단위로 파티셔닝해서 최근 3개월 조회는 파티션 프루닝이 되게 했습니다. autovacuum 은 " + "scale_factor 를 0.2에서 0.05로 낮춰 dead tuple 이 쌓이지 않게 했고요. 인덱스 변경만으로 " + "p95 가 900ms 까지 내려갔고 파티셔닝 후 180ms 가 됐습니다." + ), + "context": RESUME_INFRA_DBA, + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "high", + "expect_correctness": "high", + }, + { + "id": "f-frontend-strong", + "job_category": "FRONTEND", + "mode": "TECHNICAL", + "parent_category": "PROJECT_DEEP_DIVE", + "previous_question": "타임라인 스크롤 끊김을 react-window 가상화로 해결하신 과정을 설명해 주세요.", + "expected_signal": "병목 측정 방법과 가상화의 트레이드오프(동적 높이, 접근성, 검색)", + "answer_text": ( + "React DevTools Profiler 로 보니 항목 2천 개가 전부 리렌더링되면서 INP 가 480ms 까지 " + "나왔습니다. react-window 의 VariableSizeList 로 화면에 보이는 30개 정도만 렌더하게 했고 " + "INP 가 120ms 로 줄었습니다. 대신 항목 높이가 내용에 따라 달라서 높이 캐시를 따로 뒀고, " + "브라우저 Ctrl+F 검색이 안 되는 문제는 자체 검색 박스로 대체했습니다." + ), + "context": REPO_FRONTEND, + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "high", + "expect_correctness": "high", + }, + { + "id": "f-personality-star", + "job_category": "BACKEND", + "mode": "PERSONALITY", + "parent_category": "BEHAVIORAL", + "previous_question": "팀원과 의견이 충돌했던 경험과 그것을 어떻게 해결했는지 말씀해 주세요.", + "expected_signal": "본인의 구체적 행동과 정량적 결과, 이후 달라진 점(STAR)", + "answer_text": ( + "캡스톤에서 프론트 팀원과 API 스펙 해석이 달라 통합 직전에 2주가 밀렸습니다. 제가 맡은 건 " + "통합 일정을 되돌리는 거였고요. 그래서 OpenAPI 명세를 먼저 쓰고 Mock 서버를 띄워 프론트가 " + "병렬로 개발하게 제안했습니다. 다음 스프린트부터 통합 이슈가 3건에서 0건이 됐습니다. 다만 " + "처음엔 제 방식만 고집해서 팀원과 감정이 상했고, 그 뒤로는 결정 전에 대안 두 개를 같이 " + "비교하는 식으로 바꿨습니다." + ), + "context": "(none)", + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "high", + "expect_correctness": "null", + }, + { + "id": "f-personality-rambling", + "job_category": "BACKEND", + "mode": "PERSONALITY", + "parent_category": "BEHAVIORAL", + "previous_question": "팀원과 의견이 충돌했던 경험과 그것을 어떻게 해결했는지 말씀해 주세요.", + "expected_signal": "본인의 구체적 행동과 정량적 결과, 이후 달라진 점(STAR)", + "answer_text": ( + "저는 원래 사람들이랑 잘 지내는 편이라서 크게 싸운 적은 없는 것 같고요, 그래도 의견이 다를 " + "때는 서로 대화를 많이 하는 게 중요하다고 생각합니다. 소통이 제일 중요하니까요. 팀워크가 " + "좋으면 결과도 좋게 나온다고 봅니다." + ), + "context": "(none)", + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "low", + "expect_correctness": "null", + }, + { + "id": "f-stt-messy-normal", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "parent_category": "TECH_CHOICE", + "previous_question": "재고 동시성 제어를 낙관적 락에서 분산 락으로 바꾼 이유가 무엇인가요?", + "expected_signal": "충돌 빈도·재시도 비용과 락 방식 트레이드오프 이해", + "answer_text": ( + "어 그러니까 음 처음에는 낙관적 락으로 했는데요 어 타임세일 때 같은 상품에 요청이 한 번에 " + "몰리니까 버전 충돌이 너무 많이 나서 재시도가 막 계속 돌았어요 음 그래서 재시도 때문에 오히려 " + "DB 부하가 커져서 어 레디스 분산 락으로 바꿨고 그 다음에 불일치가 월 200건에서 3건으로 줄었습니다" + ), + "context": "(none)", + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "high", + "expect_correctness": "null", + }, + { + "id": "f-long-answer-history", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "parent_category": "PROJECT_DEEP_DIVE", + "previous_question": "MSA 전환에서 주문 서비스의 DB 를 분리할 때 데이터 정합성은 어떻게 보장하셨나요?", + "expected_signal": "분산 트랜잭션 대안(Saga/이벤트)과 보상 처리, 조회 모델 분리", + "answer_text": ( + "주문 DB 를 분리하면서 가장 걱정했던 게 주문과 결제, 재고가 서로 다른 DB 에 있게 되니까 기존처럼 " + "하나의 트랜잭션으로 묶을 수가 없다는 점이었습니다. 2PC 도 검토했는데 코디네이터 장애 시 전체가 " + "막히고 Kafka 와도 잘 맞지 않아서 제외했습니다. 그래서 코레오그래피 방식의 Saga 로 갔습니다. 주문이 " + "생성되면 OrderCreated 이벤트를 outbox 로 발행하고, 결제 서비스가 소비해서 승인하면 PaymentApproved, " + "실패하면 PaymentFailed 를 발행합니다. 재고 서비스는 PaymentApproved 를 받아 차감하고, 재고가 부족하면 " + "StockReserveFailed 를 내보내서 결제 서비스가 취소를 하고 주문 서비스가 주문 상태를 CANCELLED 로 " + "바꾸는 보상 흐름을 만들었습니다. 각 소비자는 이벤트 ID 로 멱등 처리를 했고요. 운영하면서 문제가 됐던 " + "건 보상 이벤트가 유실되면 주문이 PENDING 에 계속 남는 경우였는데, 30분 이상 PENDING 인 주문을 찾아 " + "상태를 재조회하는 스위퍼 배치를 붙여서 해결했습니다. 조회 쪽은 주문 목록 화면이 결제 상태까지 " + "보여줘야 해서, 이벤트를 받아 만드는 읽기 전용 뷰 테이블을 따로 두었습니다. 이 구조로 전환한 뒤 " + "정합성 불일치 신고는 분기에 한두 건 수준으로 유지되고 있습니다." + ), + "context": "(none)", + "history": ( + "면접관: 모놀리식에서 MSA 로 전환하게 된 계기는?\n" + "지원자: 배포 주기가 2주였고 주문 쪽 변경이 전체 배포를 막아서 주문 서비스부터 분리했습니다.\n" + "면접관: 서비스 간 통신은 동기와 비동기 중 무엇을 택했나요?\n" + "지원자: 주문-결제-재고 흐름은 Kafka 비동기, 조회성 호출만 REST 동기로 했습니다." + ), + "expect_intent": "NORMAL", + "expect_scores": "high", + "expect_correctness": "null", + }, + { + "id": "f-english-mixed", + "job_category": "FRONTEND", + "mode": "TECHNICAL", + "parent_category": "TECH_CHOICE", + "previous_question": "서버 상태 관리에 TanStack Query 를 선택한 이유는 무엇인가요?", + "expected_signal": "캐싱·stale 관리·중복 요청 제거 등 서버 상태 특성과 클라이언트 상태 구분", + "answer_text": ( + "Zustand 로 fetch 결과까지 들고 있으니까 cache invalidation 을 직접 짜야 했고 stale data 버그가 " + "자주 났습니다. TanStack Query 로 옮기면서 staleTime 을 화면별로 다르게 주고, mutation 후에 " + "invalidateQueries 로 목록만 갱신했습니다. 같은 query key 요청이 dedupe 되니까 네트워크 요청도 " + "40% 정도 줄었습니다." + ), + "context": "(none)", + "history": "(none)", + "expect_intent": "NORMAL", + "expect_scores": "high", + "expect_correctness": "null", + }, +] + +# --------------------------------------------------------------------------- +# 답변 코칭 (Flash 티어, 피드백 fan-out) 케이스 +# --------------------------------------------------------------------------- +COACHING_CASES = [ + { + "id": "c-weak-backend", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "target_role": "", + "question": _Q_OUTBOX, + "expected_signal": _SIG_OUTBOX, + "answer": FOLLOWUP_CASES[1]["answer_text"], + "rag_context": RESUME_BACKEND, + }, + { + "id": "c-dont-know-cs", + "job_category": "BACKEND", + "mode": "TECHNICAL", + "target_role": "", + "question": FOLLOWUP_CASES[2]["previous_question"], + "expected_signal": FOLLOWUP_CASES[2]["expected_signal"], + "answer": FOLLOWUP_CASES[2]["answer_text"], + "rag_context": "(none)", + }, + { + "id": "c-personality-rambling", + "job_category": "BACKEND", + "mode": "PERSONALITY", + "target_role": "", + "question": FOLLOWUP_CASES[10]["previous_question"], + "expected_signal": FOLLOWUP_CASES[10]["expected_signal"], + "answer": FOLLOWUP_CASES[10]["answer_text"], + "rag_context": COVER_LETTER, + }, +] diff --git a/ai/scripts/llm_eval/judge.py b/ai/scripts/llm_eval/judge.py new file mode 100644 index 0000000..f9783f7 --- /dev/null +++ b/ai/scripts/llm_eval/judge.py @@ -0,0 +1,258 @@ +"""블라인드 LLM 판정: 같은 케이스에 대한 후보 모델 출력을 익명 라벨(A,B,C…)로 섞어 채점. + +- 판정 모델 2개(서로 다른 계열)로 자기 계열 선호 편향을 상쇄: gemini-3.1-pro-preview, claude-opus-5 +- 판정자는 어떤 모델의 출력인지 모른다. 순서는 판정 호출마다 무작위. + +python judge.py --out /tmp/eval/judge.jsonl /tmp/eval/*.jsonl +""" + +from __future__ import annotations + +import argparse +import asyncio +import json +import os +import random +import re +import string +import sys +from collections import defaultdict + +import httpx + +sys.path.insert(0, os.path.dirname(__file__)) +from cases import COACHING_CASES, FOLLOWUP_CASES, QUESTION_CASES # noqa: E402 + +JUDGES = ["gemini-3.1-pro-preview", "claude-opus-5"] + +F_BY_ID = {c["id"]: c for c in FOLLOWUP_CASES} +Q_BY_ID = {c["id"]: c for c in QUESTION_CASES} +C_BY_ID = {c["id"]: c for c in COACHING_CASES} + +SYSTEM = ( + "당신은 IT 기술면접 서비스의 품질 평가자입니다. 같은 입력에 대해 여러 익명 후보(A, B, C…)가 만든 " + "출력을 비교 채점합니다. 후보가 어떤 모델인지 추측하지 말고, 출력 내용만 보고 엄격하고 일관되게 " + "1~5 정수로 채점하세요 (5=실제 시니어 면접관 수준, 3=쓸 만하나 뚜렷한 약점, 1=사용 불가). " + "반드시 JSON 만 출력합니다." +) + +FOLLOWUP_RUBRIC = ( + "채점 기준 (각 1~5):\n" + "- relevance: 지원자 답변의 특정 대목(수치·주장·기술 선택)을 짚는가. 답변 의도(모름/재설명 요청/확인형 단답)에 " + "알맞게 대응하는가. 재설명 요청이면 직전 질문을 쉽게 다시 설명했는가.\n" + "- depth: 기대 신호 중 놓친 부분이나 가장 약한 축을 파고들어 면접 변별력이 있는가. 이미 한 대화를 반복하지 않는가. " + "사소하거나 뻔한 질문(예: 키의 길이·형식)은 낮게.\n" + "- language: 자연스러운 한국어, 한 문장·간결(대략 60자 이내 권장), 오역·어색한 용어·외국 문자 혼입 없음.\n" + "- overall: 실제 서비스에 그대로 내보낼 만한가 종합.\n" +) + +QUESTIONS_RUBRIC = ( + "채점 기준 (각 1~5, 후보의 질문 풀 전체를 하나로 평가):\n" + "- grounding: 모든 질문이 지원자 자료(자기소개·이력서·레포·자소서)의 구체적 사실에 근거하는가. 자료에 없는 " + "내용을 지어내거나 누구나 답할 수 있는 교과서 질문이면 크게 감점. target_evidence 가 자료와 일치하는가.\n" + "- coverage: 질문들이 서로 다른 주제를 다루고 요청한 면접 모드·직군(복수면 고르게)에 맞게 분배되었는가. " + "최근 받은 질문과 중복되지 않는가.\n" + "- depth: 실제 면접에서 역량을 변별할 수 있는 깊이인가.\n" + "- language: 자연스러운 한국어, 간결(80자 내외), 오역·어색한 용어 없음.\n" + "- overall: 실제 서비스에 그대로 내보낼 만한가 종합.\n" +) + +COACHING_RUBRIC = ( + "채점 기준 (각 1~5):\n" + "- usefulness: 지원자가 다음에 더 잘 답하도록 실질적이고 구체적인 방향을 주는가.\n" + "- faithfulness: 지원자 자료/답변에 없는 경험·수치·실적을 사실처럼 지어내지 않았는가 (지어냈으면 1~2).\n" + "- rewrite: answer_rewrite 가 지원자의 실제 답변을 출발점으로 개선했는가 (완전히 다른 답으로 대체하면 감점).\n" + "- language: 자연스러운 한국어, coaching_comment 는 한 문장.\n" + "- overall: 실제 서비스에 그대로 내보낼 만한가 종합.\n" +) + + +def _clip(s: str, n: int) -> str: + return s if len(s) <= n else s[:n] + " …(생략)" + + +def build_items(recs_by_label: dict[str, list[dict]]): + """(suite, case_id) → {label: output_text}""" + items: dict[tuple[str, str], dict[str, str]] = defaultdict(dict) + for label, recs in recs_by_label.items(): + for r in recs: + if not r.get("ok") or r.get("rep") != 0: + continue + if r["suite"] == "followup": + items[("followup", r["case_id"])][ + label + ] = f"[분류한 답변 의도] {r.get('answer_intent')}\n[꼬리질문] {r.get('followup_question')}" + elif r["suite"] == "questions": + lines = [ + f"{i + 1}. ({q['category']}/{q.get('job_category')}) {q['question']}\n" + f" 근거: {q.get('target_evidence') or '(없음)'}" + for i, q in enumerate(r["questions"]) + ] + items[("questions", r["case_id"])][label] = ( + "\n".join(lines) or "(질문 0개)" + ) + elif r["suite"] == "coaching": + c = r["coaching"] + items[("coaching", r["case_id"])][label] = ( + f"[model_answer]\n{c.get('model_answer')}\n[answer_rewrite]\n{c.get('answer_rewrite')}\n" + f"[coaching_comment] {c.get('coaching_comment')}" + ) + return items + + +def case_brief(suite: str, cid: str) -> str: + if suite == "followup": + c = F_BY_ID[cid] + return ( + f"직군 {c['job_category']} / 모드 {c['mode']} / 직전 질문 카테고리 {c['parent_category']}\n" + f"이미 나눈 대화:\n{c['history']}\n\n직전 질문: {c['previous_question']}\n" + f"기대 신호: {c['expected_signal']}\n지원자 답변: {c['answer_text']}\n" + f"검색 문서 컨텍스트:\n{_clip(c['context'], 1500)}" + ) + if suite == "questions": + c = Q_BY_ID[cid] + return ( + f"직군 {', '.join(c['job_categories'])} / 모드 {c['mode']} / 요청 질문 수 {c['max_questions']}\n" + f"자기소개: {c.get('self_introduction') or '(없음)'}\n" + f"최근 받은 질문(중복 금지): {c.get('recent_questions') or '(없음)'}\n" + f"지원자 자료:\n{_clip(c['context'], 6000)}" + ) + c = C_BY_ID[cid] + return ( + f"직군 {c['job_category']} / 모드 {c['mode']}\n질문: {c['question']}\n기대 신호: {c['expected_signal']}\n" + f"지원자 실제 답변: {c['answer']}\n지원자 자료:\n{_clip(c['rag_context'], 2500)}" + ) + + +RUBRIC = { + "followup": FOLLOWUP_RUBRIC, + "questions": QUESTIONS_RUBRIC, + "coaching": COACHING_RUBRIC, +} +KEYS = { + "followup": ["relevance", "depth", "language", "overall"], + "questions": ["grounding", "coverage", "depth", "language", "overall"], + "coaching": ["usefulness", "faithfulness", "rewrite", "language", "overall"], +} + + +async def judge_one( + client, base_url, api_key, judge, suite, cid, cands: dict[str, str], rng +): + labels = list(cands) + rng.shuffle(labels) + letters = list(string.ascii_uppercase[: len(labels)]) + mapping = dict(zip(letters, labels)) + blocks = "\n\n".join(f"### 후보 {L}\n{cands[mapping[L]]}" for L in letters) + keys = KEYS[suite] + schema = ( + "{" + + ", ".join(f'"{k}": 1-5' for k in keys) + + ', "issue": "가장 큰 문제 한 줄"}' + ) + user = ( + f"## 입력\n{case_brief(suite, cid)}\n\n## {RUBRIC[suite]}\n## 후보 출력\n{blocks}\n\n" + f'## 출력 형식\n{{"ratings": {{"A": {schema}, "B": ...}}}} — 모든 후보({", ".join(letters)})를 빠짐없이.' + ) + body = { + "model": judge, + "messages": [ + {"role": "system", "content": SYSTEM}, + {"role": "user", "content": user}, + ], + "max_tokens": 16000, + "temperature": 0, + } + for attempt in range(3): + try: + resp = await client.post( + f"{base_url}/chat/completions", + headers={"Authorization": f"Bearer {api_key}"}, + json=body, + timeout=300, + ) + resp.raise_for_status() + text = resp.json()["choices"][0]["message"]["content"] or "" + m = re.search(r"\{.*\}", text, re.S) + data = json.loads(m.group(0))["ratings"] + return { + "judge": judge, + "suite": suite, + "case_id": cid, + "ratings": {mapping[L]: data[L] for L in letters if L in data}, + "n_candidates": len(letters), + } + except Exception as exc: # noqa: BLE001 + err = f"{type(exc).__name__}: {str(exc)[:200]}" + await asyncio.sleep(3 * (attempt + 1)) + return {"judge": judge, "suite": suite, "case_id": cid, "error": err} + + +async def main() -> None: + ap = argparse.ArgumentParser() + ap.add_argument("--out", required=True) + ap.add_argument("--exclude", default="", help="쉼표로 구분한 label 제외") + ap.add_argument("--concurrency", type=int, default=4) + ap.add_argument("paths", nargs="+") + args = ap.parse_args() + exclude = {x for x in args.exclude.split(",") if x} + + recs_by_label: dict[str, list[dict]] = defaultdict(list) + for p in args.paths: + with open(p, encoding="utf-8") as f: + for line in f: + if line.strip(): + r = json.loads(line) + if r["label"] not in exclude: + recs_by_label[r["label"]].append(r) + items = build_items(recs_by_label) + base_url = os.environ["LLM_BASE_URL"].rstrip("/") + api_key = os.environ["LLM_API_KEY"] + rng = random.Random(20260917) + sem = asyncio.Semaphore(args.concurrency) + async with httpx.AsyncClient() as client: + + async def run(judge, key, cands): + async with sem: + res = await judge_one( + client, base_url, api_key, judge, key[0], key[1], cands, rng + ) + print( + f" {judge:<24} {key[0]:<9} {key[1]:<28} {'ERR ' + res['error'] if 'error' in res else 'ok'}", + file=sys.stderr, + ) + return res + + tasks = [ + run(j, k, c) + for k, c in sorted(items.items()) + for j in JUDGES + if len(c) >= 2 + ] + results = await asyncio.gather(*tasks) + with open(args.out, "w", encoding="utf-8") as f: + for r in results: + f.write(json.dumps(r, ensure_ascii=False) + "\n") + + # 집계: label × suite × judge 평균, 그리고 두 판정자 평균 + agg: dict = defaultdict(lambda: defaultdict(lambda: defaultdict(list))) + for r in results: + for label, sc in (r.get("ratings") or {}).items(): + try: + agg[label][r["suite"]][r["judge"]].append(float(sc["overall"])) + except Exception: # noqa: BLE001 + pass + table = {} + for label, suites in agg.items(): + table[label] = {} + for suite, judges in suites.items(): + per = {j: round(sum(v) / len(v), 2) for j, v in judges.items() if v} + table[label][suite] = { + **per, + "mean": round(sum(per.values()) / len(per), 2) if per else None, + } + print(json.dumps(table, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/ai/scripts/llm_eval/run_eval.py b/ai/scripts/llm_eval/run_eval.py new file mode 100644 index 0000000..18b22ff --- /dev/null +++ b/ai/scripts/llm_eval/run_eval.py @@ -0,0 +1,338 @@ +"""후보 LLM 을 운영 체인 그대로 태워 원시 결과를 JSONL 로 남긴다. + +stackup-ai 컨테이너 안에서 실행 (운영 의존성·네트워크 그대로): + python run_eval.py --label qwen3-4b --base-url http://ollama:11434/v1 --api-key ollama \ + --model stackup-qwen3-4b-instruct-8k --suites followup,questions,coaching --reps 3 \ + --latency --out /tmp/eval/qwen3-4b.jsonl +게이트웨이 모델은 --base-url/--api-key 생략 (컨테이너 env 의 LLM_BASE_URL/LLM_API_KEY 사용). + +측정: +- followup: 운영 StreamingFollowupGenerator.stream (첫 질문 토큰 시점 TTFT 포함) +- questions: 운영 질문 풀 체인 (PydanticOutputParser) +- coaching: 운영 답변 코칭 체인 +- --latency: 콜드스타트(ollama 언로드 후 첫 호출), 피드백 fan-out 동시성(15건/동시 5), + fan-out 도중 꼬리질문 지연 +""" + +from __future__ import annotations + +import argparse +import asyncio +import json +import os +import sys +import time +import urllib.request +from typing import Any + +from langchain_core.callbacks import AsyncCallbackHandler + +sys.path.insert(0, os.path.dirname(__file__)) + +from cases import COACHING_CASES, FOLLOWUP_CASES, QUESTION_CASES # noqa: E402 + +from ai_server.chain.feedback_generation_chain import ( # noqa: E402 + LlmAnswerCoach, + build_answer_coaching_chain, +) +from ai_server.chain.followup_generation_chain import ( # noqa: E402 + build_streaming_followup_generator, +) +from ai_server.chain.question_generation_chain import ( # noqa: E402 + LlmQuestionGenerator, + build_question_generation_chain, +) +from ai_server.config.settings import Settings # noqa: E402 + + +class UsageCapture(AsyncCallbackHandler): + def __init__(self) -> None: + self.in_tokens: int | None = None + self.out_tokens: int | None = None + + async def on_llm_end(self, response, **kwargs: Any) -> None: # noqa: ANN001 + try: + gen = response.generations[0][0] + meta = getattr(getattr(gen, "message", None), "usage_metadata", None) + if meta: + self.in_tokens = meta.get("input_tokens") + self.out_tokens = meta.get("output_tokens") + return + except Exception: # noqa: BLE001 + pass + usage = (response.llm_output or {}).get("token_usage") or {} + self.in_tokens = usage.get("prompt_tokens", self.in_tokens) + self.out_tokens = usage.get("completion_tokens", self.out_tokens) + + +EXTRA_BODY: dict[str, Any] = {} + + +def _apply_extra_body(node: Any) -> None: + """체인/LLM 트리 안의 ChatOpenAI 에 extra_body 주입 (예: reasoning_effort=none).""" + if not EXTRA_BODY: + return + from langchain_openai import ChatOpenAI + + if isinstance(node, ChatOpenAI): + node.extra_body = {**(node.extra_body or {}), **EXTRA_BODY} + return + for attr in ("steps", "first", "middle", "last", "bound"): + child = getattr(node, attr, None) + if child is None: + continue + for c in child if isinstance(child, (list, tuple)) else [child]: + _apply_extra_body(c) + + +def make_settings(args: argparse.Namespace) -> Settings: + over: dict[str, Any] = { + "llm_pro_timeout_sec": args.timeout, + "llm_flash_timeout_sec": args.timeout, + "llm_pro_model": args.model, + "llm_flash_model": args.model, + } + if args.base_url: + over["llm_base_url"] = args.base_url + if args.api_key is not None: + over["llm_api_key"] = args.api_key + if args.flash_max_tokens: + over["llm_flash_max_tokens"] = args.flash_max_tokens + return Settings(**over) + + +def _emit(fh, rec: dict[str, Any]) -> None: + fh.write(json.dumps(rec, ensure_ascii=False) + "\n") + fh.flush() + status = "ok " if rec["ok"] else "ERR" + extra = f" ttft={rec.get('ttft_sec')}" if rec.get("ttft_sec") is not None else "" + print( + f" [{status}] {rec['suite']:<9} {rec['case_id']:<28} rep{rec['rep']} " + f"{rec['latency_sec']:>6}s{extra} out={rec.get('out_tokens')}", + file=sys.stderr, + ) + + +async def run_followup( + settings: Settings, case: dict, rep: int, label: str, tag: str = "" +) -> dict: + gen = build_streaming_followup_generator(settings) + gen._llm.stream_usage = True # noqa: SLF001 + cap = UsageCapture() + gen._llm.callbacks = [cap] # noqa: SLF001 + _apply_extra_body(gen._llm) # noqa: SLF001 + kwargs = { + k: case[k] + for k in ( + "job_category", + "mode", + "previous_question", + "answer_text", + "context", + "parent_category", + "expected_signal", + "history", + ) + } + t0 = time.perf_counter() + first: list[float] = [] + + def on_tok(_d: str) -> None: + if not first: + first.append(time.perf_counter() - t0) + + rec: dict[str, Any] = { + "label": label, + "suite": "followup" + tag, + "case_id": case["id"], + "rep": rep, + } + try: + res = await gen.stream(on_question_token=on_tok, **kwargs) + rec.update( + ok=True, + followup_question=res.followup_question, + answer_intent=res.answer_intent, + answer_evaluation=( + res.answer_evaluation.model_dump() if res.answer_evaluation else None + ), + ) + except Exception as exc: # noqa: BLE001 + rec.update(ok=False, error=f"{type(exc).__name__}: {str(exc)[:500]}") + rec["latency_sec"] = round(time.perf_counter() - t0, 3) + rec["ttft_sec"] = round(first[0], 3) if first else None + rec["in_tokens"], rec["out_tokens"] = cap.in_tokens, cap.out_tokens + return rec + + +async def run_questions(settings: Settings, case: dict, rep: int, label: str) -> dict: + cap = UsageCapture() + base = build_question_generation_chain(settings) + _apply_extra_body(base) + chain = base.with_config(callbacks=[cap]) + gen = LlmQuestionGenerator(chain) + t0 = time.perf_counter() + rec: dict[str, Any] = { + "label": label, + "suite": "questions", + "case_id": case["id"], + "rep": rep, + } + try: + pool = await gen.generate( + job_categories=case["job_categories"], + mode=case["mode"], + max_questions=case["max_questions"], + context=case["context"], + recent_questions=case.get("recent_questions"), + self_introduction=case.get("self_introduction"), + ) + rec.update(ok=True, questions=[q.model_dump() for q in pool.questions]) + except Exception as exc: # noqa: BLE001 + rec.update(ok=False, error=f"{type(exc).__name__}: {str(exc)[:800]}") + rec["latency_sec"] = round(time.perf_counter() - t0, 3) + rec["in_tokens"], rec["out_tokens"] = cap.in_tokens, cap.out_tokens + return rec + + +async def run_coaching( + settings: Settings, case: dict, rep: int, label: str, tag: str = "" +) -> dict: + cap = UsageCapture() + base = build_answer_coaching_chain(settings) + _apply_extra_body(base) + chain = base.with_config(callbacks=[cap]) + coach = LlmAnswerCoach(chain) + t0 = time.perf_counter() + rec: dict[str, Any] = { + "label": label, + "suite": "coaching" + tag, + "case_id": case["id"], + "rep": rep, + } + try: + res = await coach.coach( + **{ + k: case[k] + for k in ( + "job_category", + "mode", + "target_role", + "question", + "expected_signal", + "answer", + "rag_context", + ) + } + ) + rec.update(ok=True, coaching=res.model_dump()) + except Exception as exc: # noqa: BLE001 + rec.update(ok=False, error=f"{type(exc).__name__}: {str(exc)[:500]}") + rec["latency_sec"] = round(time.perf_counter() - t0, 3) + rec["in_tokens"], rec["out_tokens"] = cap.in_tokens, cap.out_tokens + return rec + + +def ollama_unload(base_url: str, model: str) -> None: + root = base_url.rstrip("/").removesuffix("/v1") + body = json.dumps({"model": model, "keep_alive": 0}).encode() + req = urllib.request.Request( + f"{root}/api/generate", data=body, headers={"Content-Type": "application/json"} + ) + urllib.request.urlopen(req, timeout=60).read() + + +async def latency_suite(settings: Settings, args: argparse.Namespace, fh) -> None: + label = args.label + is_ollama = "11434" in (args.base_url or "") + # 1) 콜드스타트: 언로드 후 첫 꼬리질문 + if is_ollama: + ollama_unload(args.base_url, args.model) + await asyncio.sleep(2) + for i, case in enumerate(FOLLOWUP_CASES[:2]): + rec = await run_followup( + settings, case, i, label, tag=":cold" if i == 0 else ":after-cold" + ) + _emit(fh, rec) + + # 2) 피드백 fan-out: 코칭 15건을 동시성 5 로 (운영 FEEDBACK_COACHING_CONCURRENCY=5) + sem = asyncio.Semaphore(5) + jobs = [COACHING_CASES[i % len(COACHING_CASES)] for i in range(15)] + + async def one(i: int, case: dict) -> dict: + async with sem: + return await run_coaching(settings, case, i, label, tag=":fanout15x5") + + t0 = time.perf_counter() + + # 3) fan-out 시작 3초 뒤 다른 사용자의 꼬리질문이 들어온다고 가정 + async def contending_followup() -> dict: + await asyncio.sleep(3) + return await run_followup( + settings, FOLLOWUP_CASES[0], 0, label, tag=":during-fanout" + ) + + results = await asyncio.gather( + *(one(i, c) for i, c in enumerate(jobs)), contending_followup() + ) + wall = round(time.perf_counter() - t0, 3) + for rec in results: + _emit(fh, rec) + fh.write( + json.dumps( + {"label": label, "suite": "fanout_wall", "wall_sec": wall, "ok": True} + ) + + "\n" + ) + print(f" fan-out 15x5 wall={wall}s", file=sys.stderr) + + +async def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--label", required=True) + ap.add_argument("--model", required=True) + ap.add_argument("--base-url", default="") + ap.add_argument("--api-key", default=None) + ap.add_argument("--suites", default="followup,questions,coaching") + ap.add_argument("--reps", type=int, default=3) + ap.add_argument("--question-reps", type=int, default=2) + ap.add_argument("--timeout", type=float, default=240.0) + ap.add_argument("--flash-max-tokens", type=int, default=0) + ap.add_argument("--latency", action="store_true") + ap.add_argument( + "--extra-body", default="", help='JSON, 예: \'{"reasoning_effort": "none"}\'' + ) + ap.add_argument("--out", required=True) + args = ap.parse_args() + + settings = make_settings(args) + if args.extra_body: + EXTRA_BODY.update(json.loads(args.extra_body)) + os.makedirs(os.path.dirname(args.out) or ".", exist_ok=True) + suites = [s for s in args.suites.split(",") if s] + print( + f"== {args.label} model={args.model} base={settings.llm_base_url}", + file=sys.stderr, + ) + with open(args.out, "a", encoding="utf-8") as fh: + if "followup" in suites: + # 워밍업 1회 (결과 기록 안 함) — 로드 시간과 품질 측정을 분리 + await run_followup(settings, FOLLOWUP_CASES[0], -1, args.label) + for rep in range(args.reps): + for case in FOLLOWUP_CASES: + _emit(fh, await run_followup(settings, case, rep, args.label)) + if "coaching" in suites: + for rep in range(args.reps): + for case in COACHING_CASES: + _emit(fh, await run_coaching(settings, case, rep, args.label)) + if "questions" in suites: + for rep in range(args.question_reps): + for case in QUESTION_CASES: + _emit(fh, await run_questions(settings, case, rep, args.label)) + if args.latency: + await latency_suite(settings, args, fh) + return 0 + + +if __name__ == "__main__": + raise SystemExit(asyncio.run(main())) diff --git a/docs/README.md b/docs/README.md index 5e5b500..1936f10 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,6 +28,9 @@ - [`observability.md`](./observability.md) — X-Trace-Id, 로깅 레벨, AI 요청 로깅 - [`environment.md`](./environment.md) — 환경 변수, 로컬/스테이징/운영 분리 +### 조사·의사결정 기록 +- [`research/llm-provider-evaluation-2026-09.md`](./research/llm-provider-evaluation-2026-09.md) — 로컬 LLM·오픈 모델 대안 실측 비교 (품질 블라인드 채점·지연·비용) + ### 협업 - [`coding-conventions.md`](./coding-conventions.md) — 언어별 공통 코딩 규약 - [`git-conventions.md`](./git-conventions.md) — 브랜치 전략, 커밋 컨벤션, PR 템플릿 diff --git a/docs/research/llm-eval-2026-09/auto-metrics-summary.json b/docs/research/llm-eval-2026-09/auto-metrics-summary.json new file mode 100644 index 0000000..5c5872a --- /dev/null +++ b/docs/research/llm-eval-2026-09/auto-metrics-summary.json @@ -0,0 +1,682 @@ +{ + "gw-gemini-3.1-pro": { + "followup": null, + "questions": { + "calls": 10, + "success_pct": 100.0, + "errors": [], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 100.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 17.3, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "2/2", + "latency_median": 24.74, + "latency_p90": 26.52 + }, + "coaching": null + }, + "gw-gemini-3.5-flash-lite": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 100.0, + "intent_accuracy_pct": 100.0, + "intent_misses": {}, + "score_label_accuracy_pct": 100.0, + "correctness_rule_accuracy_pct": 100.0, + "discrimination_gap_backend": 3.0, + "discrimination_gap_personality": 2.0, + "question_len_median": 76.5, + "question_len_le60_pct": 21.4, + "non_korean_script_pct": 0.0, + "latency_median": 2.04, + "latency_p90": 5.82, + "ttft_median": 1.54, + "ttft_p90": 5.71, + "over_3s_pct": 16.7, + "over_10s_timeout_pct": 0.0, + "latency_during_fanout": 2.077 + }, + "questions": { + "calls": 10, + "success_pct": 90.0, + "errors": [ + "OutputParserException: Invalid json output: ```json\n{\n \"questions\": [\n {\n \"category\": \"PROJECT_DEEP_DIVE\",\n \"question\": \"모놀리식에서 주문 서비스를 분리할 때 사용한 " + ], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 100.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 44.7, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "1/2", + "latency_median": 4.19, + "latency_p90": 4.68 + }, + "coaching": { + "calls": 9, + "success_pct": 100.0, + "invented_numbers_pct": 0.0, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 100.0, + "latency_median": 3.03, + "latency_p90": 3.37, + "fanout15x5_success": "15/15", + "fanout15x5_wall_sec": 10.826, + "fanout15x5_per_call_p90": 4.57 + } + }, + "gw-gemma-4-31b": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 100.0, + "intent_accuracy_pct": 100.0, + "intent_misses": {}, + "score_label_accuracy_pct": 100.0, + "correctness_rule_accuracy_pct": 100.0, + "discrimination_gap_backend": 3.0, + "discrimination_gap_personality": 3.0, + "question_len_median": 65.5, + "question_len_le60_pct": 40.5, + "non_korean_script_pct": 0.0, + "latency_median": 9.16, + "latency_p90": 54.28, + "ttft_median": 3.18, + "ttft_p90": 11.73, + "over_3s_pct": 100.0, + "over_10s_timeout_pct": 47.6 + }, + "questions": { + "calls": 10, + "success_pct": 100.0, + "errors": [], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 100.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 84.6, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "2/2", + "latency_median": 43.68, + "latency_p90": 50.06 + }, + "coaching": { + "calls": 9, + "success_pct": 100.0, + "invented_numbers_pct": 0.0, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 100.0, + "latency_median": 22.56, + "latency_p90": 26.88 + } + }, + "gw-gpt-oss-120b": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 54.8, + "intent_accuracy_pct": 100.0, + "intent_misses": {}, + "score_label_accuracy_pct": 42.4, + "correctness_rule_accuracy_pct": 72.7, + "discrimination_gap_backend": 4.0, + "discrimination_gap_personality": null, + "question_len_median": 43.0, + "question_len_le60_pct": 71.4, + "non_korean_script_pct": 0.0, + "latency_median": 4.87, + "latency_p90": 6.9, + "ttft_median": 3.88, + "ttft_p90": 5.27, + "over_3s_pct": 97.6, + "over_10s_timeout_pct": 0.0 + }, + "questions": { + "calls": 10, + "success_pct": 100.0, + "errors": [], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 90.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 96.2, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "2/2", + "latency_median": 15.38, + "latency_p90": 17.68 + }, + "coaching": { + "calls": 9, + "success_pct": 100.0, + "invented_numbers_pct": 11.1, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 100.0, + "latency_median": 8.88, + "latency_p90": 10.57 + } + }, + "gw-llama-4-maverick": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 100.0, + "intent_accuracy_pct": 92.9, + "intent_misses": { + "f-weak-vague": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ] + }, + "score_label_accuracy_pct": 90.9, + "correctness_rule_accuracy_pct": 81.8, + "discrimination_gap_backend": 3.0, + "discrimination_gap_personality": 2.0, + "question_len_median": 49.0, + "question_len_le60_pct": 66.7, + "non_korean_script_pct": 0.0, + "latency_median": 1.85, + "latency_p90": 2.75, + "ttft_median": 1.32, + "ttft_p90": 1.61, + "over_3s_pct": 0.0, + "over_10s_timeout_pct": 0.0 + }, + "questions": { + "calls": 10, + "success_pct": 100.0, + "errors": [], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 100.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 96.2, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "2/2", + "latency_median": 7.27, + "latency_p90": 8.21 + }, + "coaching": { + "calls": 9, + "success_pct": 100.0, + "invented_numbers_pct": 0.0, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 100.0, + "latency_median": 3.82, + "latency_p90": 4.45 + } + }, + "gw-solar-pro4": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 100.0, + "intent_accuracy_pct": 95.2, + "intent_misses": { + "f-weak-vague": [ + "DONT_KNOW", + "DONT_KNOW" + ] + }, + "score_label_accuracy_pct": 87.9, + "correctness_rule_accuracy_pct": 100.0, + "discrimination_gap_backend": 2.0, + "discrimination_gap_personality": 2.0, + "question_len_median": 103.0, + "question_len_le60_pct": 9.5, + "non_korean_script_pct": 0.0, + "latency_median": 2.32, + "latency_p90": 4.43, + "ttft_median": 1.3, + "ttft_p90": 2.27, + "over_3s_pct": 23.8, + "over_10s_timeout_pct": 0.0 + }, + "questions": { + "calls": 10, + "success_pct": 100.0, + "errors": [], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 80.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 0.0, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "2/2", + "latency_median": 16.23, + "latency_p90": 21.14 + }, + "coaching": { + "calls": 9, + "success_pct": 100.0, + "invented_numbers_pct": 0.0, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 88.9, + "latency_median": 5.32, + "latency_p90": 10.06 + } + }, + "local-ax4-light": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 100.0, + "intent_accuracy_pct": 90.5, + "intent_misses": { + "f-weak-vague": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-confirm-short": [ + "DONT_KNOW" + ] + }, + "score_label_accuracy_pct": 75.8, + "correctness_rule_accuracy_pct": 54.5, + "discrimination_gap_backend": 3.0, + "discrimination_gap_personality": 1.0, + "question_len_median": 73.5, + "question_len_le60_pct": 23.8, + "non_korean_script_pct": 0.0, + "latency_median": 4.26, + "latency_p90": 6.41, + "ttft_median": 2.08, + "ttft_p90": 3.93, + "over_3s_pct": 83.3, + "over_10s_timeout_pct": 2.4, + "latency_cold": 12.152, + "latency_after_cold": 2.745, + "latency_during_fanout": 81.17 + }, + "questions": { + "calls": 10, + "success_pct": 70.0, + "errors": [ + "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"EKS 클러스터 운영 시 HPA를 CP", + "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"주문 서비스 MSA 전환 시 Kafka", + "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"EKS 클러스터 운영 시 HPA를 CP" + ], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 100.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": null, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 91.4, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 28.6, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "1/2", + "latency_median": 35.08, + "latency_p90": 38.43 + }, + "coaching": { + "calls": 9, + "success_pct": 88.9, + "invented_numbers_pct": 0.0, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 100.0, + "latency_median": 14.86, + "latency_p90": 15.5, + "fanout15x5_success": "15/15", + "fanout15x5_wall_sec": 231.365, + "fanout15x5_per_call_p90": 84.04 + } + }, + "local-kanana2-3b": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 28.6, + "intent_accuracy_pct": 78.6, + "intent_misses": { + "f-dont-know-explicit": [ + "NORMAL", + "NORMAL", + "NORMAL" + ], + "f-dont-know-stt": [ + "NORMAL", + "NORMAL", + "NORMAL" + ], + "f-clarification": [ + "NORMAL", + "NORMAL", + "NORMAL" + ] + }, + "score_label_accuracy_pct": 9.1, + "correctness_rule_accuracy_pct": 72.7, + "discrimination_gap_backend": null, + "discrimination_gap_personality": null, + "question_len_median": 61.0, + "question_len_le60_pct": 0.0, + "non_korean_script_pct": 0.0, + "latency_median": 1.14, + "latency_p90": 222.66, + "ttft_median": null, + "ttft_p90": null, + "over_3s_pct": 23.8, + "over_10s_timeout_pct": 16.7, + "latency_cold": 3.345, + "latency_after_cold": 0.628 + }, + "questions": { + "calls": 10, + "success_pct": 0.0, + "errors": [ + "OutputParserException: Invalid json output: 증 뉴 관 관 적 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.lan", + "OutputParserException: Invalid json output: 관 구 구 구 구 구 구 구 관 관 구 관 관 관 구 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, vis", + "OutputParserException: Invalid json output: 구 구 관 관 관 구 관 관 관 연 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https" + ], + "count_exact_pct": null, + "mode_category_fit_pct": null, + "job_category_valid_pct": null, + "multi_job_coverage_pct": null, + "evidence_present_when_required_pct": null, + "evidence_grounded_pct": null, + "near_duplicate_pair_pct": null, + "repeated_recent_question_count": 0, + "question_len_le80_pct": null, + "non_korean_script_pct": null, + "markdown_in_question_pct": null, + "long_context_success": "0/2", + "latency_median": null, + "latency_p90": null + }, + "coaching": { + "calls": 9, + "success_pct": 0.0, + "invented_numbers_pct": null, + "non_korean_script_pct": null, + "comment_one_line_pct": null, + "latency_median": null, + "latency_p90": null + } + }, + "local-midm2-mini": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 28.6, + "intent_accuracy_pct": 14.3, + "intent_misses": { + "f-strong-backend": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-weak-vague": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-clarification": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-confirm-short": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-infra-fact-error": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-dba-correct-with-context": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-frontend-strong": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-personality-star": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-personality-rambling": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-stt-messy-normal": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-long-answer-history": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ], + "f-english-mixed": [ + "DONT_KNOW", + "DONT_KNOW", + "DONT_KNOW" + ] + }, + "score_label_accuracy_pct": 9.1, + "correctness_rule_accuracy_pct": 72.7, + "discrimination_gap_backend": null, + "discrimination_gap_personality": null, + "question_len_median": 81.5, + "question_len_le60_pct": 16.7, + "non_korean_script_pct": 0.0, + "latency_median": 1.9, + "latency_p90": 3.08, + "ttft_median": null, + "ttft_p90": null, + "over_3s_pct": 14.3, + "over_10s_timeout_pct": 0.0, + "latency_cold": 7.673, + "latency_after_cold": 1.192, + "latency_during_fanout": 33.094 + }, + "questions": { + "calls": 10, + "success_pct": 30.0, + "errors": [ + "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"React 18에서 virtualize timeline 구현 시 성능 개선을 위해 window 가", + "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"Terraform으로 VPC와 RDS를 환경별로 분리하신 경험에서, 실제 개발환경과 운영환경 간의", + "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"알림 봇 개발 시 동시 쓰기 락 문제를 해결하기 위해 PostgreSQL로 전환하셨다고 하셨는데," + ], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 100.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": null, + "evidence_present_when_required_pct": 90.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 1, + "question_len_le80_pct": 66.7, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "1/2", + "latency_median": 17.24, + "latency_p90": 20.8 + }, + "coaching": { + "calls": 9, + "success_pct": 0.0, + "invented_numbers_pct": null, + "non_korean_script_pct": null, + "comment_one_line_pct": null, + "latency_median": null, + "latency_p90": null, + "fanout15x5_success": "0/15", + "fanout15x5_wall_sec": 99.15, + "fanout15x5_per_call_p90": null + } + }, + "local-qwen3-4b-instruct": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 100.0, + "intent_accuracy_pct": 100.0, + "intent_misses": {}, + "score_label_accuracy_pct": 81.8, + "correctness_rule_accuracy_pct": 57.6, + "discrimination_gap_backend": 2.0, + "discrimination_gap_personality": 2.0, + "question_len_median": 92.5, + "question_len_le60_pct": 19.0, + "non_korean_script_pct": 0.0, + "latency_median": 3.3, + "latency_p90": 5.47, + "ttft_median": 1.73, + "ttft_p90": 3.52, + "over_3s_pct": 54.8, + "over_10s_timeout_pct": 0.0, + "latency_cold": 10.665, + "latency_after_cold": 2.651, + "latency_during_fanout": 78.779 + }, + "questions": { + "calls": 10, + "success_pct": 90.0, + "errors": [ + "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"알림 봇 프로젝트에서 SQLite를 사" + ], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 88.9, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 53.2, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "2/2", + "latency_median": 31.43, + "latency_p90": 39.3 + }, + "coaching": { + "calls": 9, + "success_pct": 100.0, + "invented_numbers_pct": 0.0, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 100.0, + "latency_median": 12.83, + "latency_p90": 17.97, + "fanout15x5_success": "15/15", + "fanout15x5_wall_sec": 224.064, + "fanout15x5_per_call_p90": 81.05 + } + }, + "local-qwen3.5-4b": { + "followup": { + "calls": 42, + "success_pct": 100.0, + "tag_compliance_pct": 33.3, + "intent_accuracy_pct": 92.9, + "intent_misses": { + "f-weak-vague": [ + "DONT_KNOW" + ], + "f-confirm-short": [ + "DONT_KNOW" + ], + "f-personality-rambling": [ + "CLARIFICATION" + ] + }, + "score_label_accuracy_pct": 18.2, + "correctness_rule_accuracy_pct": 69.7, + "discrimination_gap_backend": 2.0, + "discrimination_gap_personality": null, + "question_len_median": 60.0, + "question_len_le60_pct": 54.8, + "non_korean_script_pct": 0.0, + "latency_median": 6.37, + "latency_p90": 7.56, + "ttft_median": 3.97, + "ttft_p90": 4.97, + "over_3s_pct": 100.0, + "over_10s_timeout_pct": 0.0, + "latency_cold": 15.47, + "latency_after_cold": 6.643, + "latency_during_fanout": 111.486 + }, + "questions": { + "calls": 10, + "success_pct": 50.0, + "errors": [ + "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"결제 콜백 지연 시 중복 주문을 멱등 키와 Outbox 패턴으로", + "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"Outbox 패턴을 도입할 때, Kafka 메시지 발행과 DB ", + "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"2000 개 이상의 타임라인 항목에서 가상화를 도입해 성능을 4" + ], + "count_exact_pct": 100.0, + "mode_category_fit_pct": 100.0, + "job_category_valid_pct": 100.0, + "multi_job_coverage_pct": 100.0, + "evidence_present_when_required_pct": 100.0, + "evidence_grounded_pct": 100.0, + "near_duplicate_pair_pct": 0.0, + "repeated_recent_question_count": 0, + "question_len_le80_pct": 40.7, + "non_korean_script_pct": 0.0, + "markdown_in_question_pct": 0.0, + "long_context_success": "0/2", + "latency_median": 41.02, + "latency_p90": 51.08 + }, + "coaching": { + "calls": 9, + "success_pct": 100.0, + "invented_numbers_pct": 0.0, + "non_korean_script_pct": 0.0, + "comment_one_line_pct": 100.0, + "latency_median": 18.87, + "latency_p90": 19.72, + "fanout15x5_success": "15/15", + "fanout15x5_wall_sec": 304.74, + "fanout15x5_per_call_p90": 110.82 + } + } +} diff --git a/docs/research/llm-eval-2026-09/eval-judge-table.json b/docs/research/llm-eval-2026-09/eval-judge-table.json new file mode 100644 index 0000000..b19158f --- /dev/null +++ b/docs/research/llm-eval-2026-09/eval-judge-table.json @@ -0,0 +1,157 @@ +{ + "gw-llama-4-maverick": { + "coaching": { + "gemini-3.1-pro-preview": 2.33, + "claude-opus-5": 3.0, + "mean": 2.67 + }, + "followup": { + "gemini-3.1-pro-preview": 2.71, + "claude-opus-5": 3.29, + "mean": 3.0 + }, + "questions": { + "gemini-3.1-pro-preview": 1.8, + "claude-opus-5": 2.8, + "mean": 2.3 + } + }, + "gw-solar-pro4": { + "coaching": { + "gemini-3.1-pro-preview": 4.0, + "claude-opus-5": 4.67, + "mean": 4.33 + }, + "followup": { + "gemini-3.1-pro-preview": 3.36, + "claude-opus-5": 3.79, + "mean": 3.58 + }, + "questions": { + "gemini-3.1-pro-preview": 3.0, + "claude-opus-5": 3.8, + "mean": 3.4 + } + }, + "gw-gemini-3.5-flash-lite": { + "coaching": { + "gemini-3.1-pro-preview": 4.0, + "claude-opus-5": 4.33, + "mean": 4.17 + }, + "followup": { + "gemini-3.1-pro-preview": 4.43, + "claude-opus-5": 4.0, + "mean": 4.21 + }, + "questions": { + "gemini-3.1-pro-preview": 4.2, + "claude-opus-5": 4.2, + "mean": 4.2 + } + }, + "gw-gemma-4-31b": { + "coaching": { + "gemini-3.1-pro-preview": 4.67, + "claude-opus-5": 4.0, + "mean": 4.33 + }, + "followup": { + "gemini-3.1-pro-preview": 4.86, + "claude-opus-5": 3.93, + "mean": 4.4 + }, + "questions": { + "gemini-3.1-pro-preview": 4.6, + "claude-opus-5": 4.0, + "mean": 4.3 + } + }, + "local-qwen3-4b-instruct": { + "coaching": { + "gemini-3.1-pro-preview": 2.0, + "claude-opus-5": 2.33, + "mean": 2.17 + }, + "followup": { + "gemini-3.1-pro-preview": 2.43, + "claude-opus-5": 2.57, + "mean": 2.5 + }, + "questions": { + "gemini-3.1-pro-preview": 3.2, + "claude-opus-5": 3.0, + "mean": 3.1 + } + }, + "local-qwen3.5-4b": { + "coaching": { + "gemini-3.1-pro-preview": 1.67, + "claude-opus-5": 2.0, + "mean": 1.83 + }, + "followup": { + "gemini-3.1-pro-preview": 2.21, + "claude-opus-5": 2.71, + "mean": 2.46 + }, + "questions": { + "gemini-3.1-pro-preview": 2.33, + "claude-opus-5": 2.67, + "mean": 2.5 + } + }, + "local-ax4-light": { + "coaching": { + "gemini-3.1-pro-preview": 2.0, + "claude-opus-5": 2.33, + "mean": 2.17 + }, + "followup": { + "gemini-3.1-pro-preview": 1.71, + "claude-opus-5": 2.14, + "mean": 1.93 + }, + "questions": { + "gemini-3.1-pro-preview": 2.33, + "claude-opus-5": 2.67, + "mean": 2.5 + } + }, + "gw-gpt-oss-120b": { + "coaching": { + "gemini-3.1-pro-preview": 2.0, + "claude-opus-5": 2.67, + "mean": 2.33 + }, + "followup": { + "gemini-3.1-pro-preview": 3.0, + "claude-opus-5": 3.29, + "mean": 3.15 + }, + "questions": { + "gemini-3.1-pro-preview": 3.0, + "claude-opus-5": 2.4, + "mean": 2.7 + } + }, + "local-midm2-mini": { + "followup": { + "gemini-3.1-pro-preview": 1.36, + "claude-opus-5": 1.64, + "mean": 1.5 + }, + "questions": { + "gemini-3.1-pro-preview": 2.0, + "claude-opus-5": 2.0, + "mean": 2.0 + } + }, + "gw-gemini-3.1-pro": { + "questions": { + "gemini-3.1-pro-preview": 4.6, + "claude-opus-5": 4.4, + "mean": 4.5 + } + } +} diff --git a/docs/research/llm-eval-2026-09/eval-judge.jsonl b/docs/research/llm-eval-2026-09/eval-judge.jsonl new file mode 100644 index 0000000..bba8e87 --- /dev/null +++ b/docs/research/llm-eval-2026-09/eval-judge.jsonl @@ -0,0 +1,44 @@ +{"judge": "gemini-3.1-pro-preview", "suite": "coaching", "case_id": "c-dont-know-cs", "ratings": {"gw-llama-4-maverick": {"usefulness": 2, "faithfulness": 5, "rewrite": 1, "language": 5, "overall": 2, "issue": "지원자의 실제 답변('모르겠습니다')을 무시하고 완전히 새로운 정답으로 대체함"}, "gw-solar-pro4": {"usefulness": 5, "faithfulness": 5, "rewrite": 4, "language": 5, "overall": 4, "issue": "모르는 상황에서의 대처법을 잘 보여주나, 재작성된 답변이 모른다고 한 것치고는 지나치게 완벽한 정답을 포함하여 다소 비현실적임"}, "gw-gemini-3.5-flash-lite": {"usefulness": 5, "faithfulness": 5, "rewrite": 4, "language": 5, "overall": 4, "issue": "지원자의 답변을 바탕으로 개선 방향을 잘 제시했으나, 재작성된 답변에 정답의 핵심 키워드가 너무 많이 포함되어 다소 작위적임"}, "gw-gemma-4-31b": {"usefulness": 5, "faithfulness": 5, "rewrite": 5, "language": 5, "overall": 5, "issue": "지원자가 모르는 상황에서 아는 지식을 최대한 활용해 대답하는 가장 현실적이고 훌륭한 개선 방향을 제시함"}, "local-qwen3-4b-instruct": {"usefulness": 2, "faithfulness": 5, "rewrite": 1, "language": 5, "overall": 2, "issue": "지원자의 실제 답변을 전혀 반영하지 않고 모범 답안으로 완전히 대체함"}, "local-qwen3.5-4b": {"usefulness": 2, "faithfulness": 5, "rewrite": 1, "language": 4, "overall": 1, "issue": "지원자의 답변을 무시하고 정답으로 대체했으며, 코칭 코멘트가 지원자에게 직접 건네는 조언 형태가 아님"}, "local-ax4-light": {"usefulness": 2, "faithfulness": 5, "rewrite": 1, "language": 4, "overall": 1, "issue": "기술 지식을 묻는 질문임에도 부적절하게 STAR 기법을 적용했으며 지원자의 답변을 완전히 대체함"}, "gw-gpt-oss-120b": {"usefulness": 2, "faithfulness": 5, "rewrite": 1, "language": 5, "overall": 2, "issue": "지원자의 포기하는 답변을 출발점으로 삼지 않고 모범 답안으로 완전히 대체함"}}, "n_candidates": 8} +{"judge": "claude-opus-5", "suite": "coaching", "case_id": "c-dont-know-cs", "ratings": {"gw-llama-4-maverick": {"usefulness": 3, "faithfulness": 5, "rewrite": 2, "language": 4, "overall": 3, "issue": "answer_rewrite가 '모르겠다'는 실제 답변을 출발점으로 삼지 않고 모범답안 요약으로 대체했고 코칭도 일반론에 그침"}, "gw-gemini-3.5-flash-lite": {"usefulness": 5, "faithfulness": 4, "rewrite": 5, "language": 5, "overall": 5, "issue": "rewrite에서 지원자가 실제로 언급하지 않은 xmin horizon 이해 수준을 다소 후하게 부여한 점은 있으나 '모른다'는 톤은 잘 유지"}, "local-qwen3.5-4b": {"usefulness": 2, "faithfulness": 3, "rewrite": 2, "language": 2, "overall": 2, "issue": "model_answer에 'reclaim list' 같은 부정확 용어와 코칭 문장이 섞여 있고 coaching_comment가 지원자용 피드백이 아닌 시스템 지시문처럼 작성됨"}, "gw-gemma-4-31b": {"usefulness": 4, "faithfulness": 5, "rewrite": 4, "language": 5, "overall": 4, "issue": "rewrite가 솔직한 톤은 잘 살렸으나 기술 내용이 거의 없어 개선 폭이 작음"}, "local-qwen3-4b-instruct": {"usefulness": 3, "faithfulness": 4, "rewrite": 2, "language": 3, "overall": 2, "issue": "가시성 판단 설명이 뒤엉켜 부정확하고 rewrite가 model_answer를 거의 그대로 복사해 지원자 답변과 무관"}, "gw-gpt-oss-120b": {"usefulness": 3, "faithfulness": 3, "rewrite": 2, "language": 3, "overall": 2, "issue": "VACUUM FREEZE로 xmin horizon을 앞당길 수 있다는 잘못된 대응책과 'horizon보다 작아진다'·'볼 수 있을 때' 같은 논리 오류, rewrite도 전면 대체"}, "gw-solar-pro4": {"usefulness": 5, "faithfulness": 5, "rewrite": 5, "language": 5, "overall": 5, "issue": "기술 설명·rewrite·코칭 모두 양호하며 굳이 꼽자면 대응 방안 나열이 다소 일반적"}, "local-ax4-light": {"usefulness": 2, "faithfulness": 3, "rewrite": 2, "language": 3, "overall": 2, "issue": "'xmin horizon을 확장' 등 메커니즘 서술이 부정확하고 rewrite가 면접 구어체가 아닌 불릿 문서 형태로 실제 답변과 단절됨"}}, "n_candidates": 8} +{"judge": "gemini-3.1-pro-preview", "suite": "coaching", "case_id": "c-personality-rambling", "ratings": {"gw-gemma-4-31b": {"usefulness": 5, "faithfulness": 5, "rewrite": 5, "language": 5, "overall": 5, "issue": "지원자의 실제 답변 뉘앙스를 잘 살려 자연스럽게 개선함"}, "gw-solar-pro4": {"usefulness": 5, "faithfulness": 5, "rewrite": 2, "language": 5, "overall": 3, "issue": "실제 답변을 출발점으로 삼지 않고 완전히 새로운 답변으로 대체함"}, "local-qwen3-4b-instruct": {"usefulness": 4, "faithfulness": 5, "rewrite": 1, "language": 5, "overall": 2, "issue": "모범 답안과 재작성 답안이 거의 동일하며 실제 답변의 흔적이 없음"}, "gw-gpt-oss-120b": {"usefulness": 4, "faithfulness": 2, "rewrite": 2, "language": 5, "overall": 2, "issue": "자료에 없는 '프로젝트 일정이 2주 앞당겨졌다'는 내용을 지어냄"}, "gw-gemini-3.5-flash-lite": {"usefulness": 5, "faithfulness": 5, "rewrite": 2, "language": 5, "overall": 3, "issue": "실제 답변을 개선하지 않고 완전히 새로운 답변으로 대체함"}, "gw-llama-4-maverick": {"usefulness": 4, "faithfulness": 2, "rewrite": 2, "language": 5, "overall": 2, "issue": "'제안에 동의하지 않아 2주 지연되었다'며 자소서의 인과관계를 왜곡함"}, "local-ax4-light": {"usefulness": 4, "faithfulness": 5, "rewrite": 2, "language": 5, "overall": 3, "issue": "실제 답변의 내용을 전혀 반영하지 않고 새로 작성함"}, "local-qwen3.5-4b": {"usefulness": 4, "faithfulness": 5, "rewrite": 1, "language": 2, "overall": 1, "issue": "'감정 상을 초래한' 등 한국어가 어색하며 모범 답안과 재작성 답안이 동일함"}}, "n_candidates": 8} +{"judge": "claude-opus-5", "suite": "coaching", "case_id": "c-personality-rambling", "ratings": {"gw-llama-4-maverick": {"usefulness": 3, "faithfulness": 3, "rewrite": 3, "language": 4, "overall": 3, "issue": "'팀원이 동의하지 않아 2주 지연'이라는 자료에 없는 갈등 원인을 지어냈고, 코칭 코멘트가 일반론에 머문다."}, "gw-gemma-4-31b": {"usefulness": 4, "faithfulness": 4, "rewrite": 5, "language": 4, "overall": 4, "issue": "'프로젝트를 성공적으로 마쳤다' 등 약한 과장과 구어 답변에 어울리지 않는 마크다운 강조 표기."}, "local-ax4-light": {"usefulness": 3, "faithfulness": 4, "rewrite": 3, "language": 3, "overall": 3, "issue": "'우리는 …제안했습니다'처럼 행위 주체가 흐려 본인 행동(Action)이 약하고 내용이 얇다."}, "local-qwen3.5-4b": {"usefulness": 3, "faithfulness": 4, "rewrite": 2, "language": 2, "overall": 2, "issue": "answer_rewrite가 model_answer와 완전히 동일한 복붙이고 '감정 상을 초래', '2 주' 등 비문·띄어쓰기 오류가 많다."}, "gw-gemini-3.5-flash-lite": {"usefulness": 4, "faithfulness": 5, "rewrite": 4, "language": 5, "overall": 4, "issue": "model_answer에서 초반 고집·감정 상함이라는 자기 성찰 신호가 빠져 재구성 답변과 톤이 어긋난다."}, "gw-solar-pro4": {"usefulness": 5, "faithfulness": 5, "rewrite": 5, "language": 5, "overall": 5, "issue": "rewrite가 model_answer와 거의 동일해 두 항목의 차별성이 약한 정도가 유일한 아쉬움."}, "local-qwen3-4b-instruct": {"usefulness": 3, "faithfulness": 3, "rewrite": 3, "language": 3, "overall": 3, "issue": "'현재는 모두의 입장을 반영한 합의 도출에 집중' 등 근거 없는 현재 행태를 덧붙이고 '있었어요' 구어체가 섞여 톤이 불안정하다."}, "gw-gpt-oss-120b": {"usefulness": 3, "faithfulness": 2, "rewrite": 3, "language": 3, "overall": 2, "issue": "'전체 일정 2주 단축', '이후 갈등 크게 감소' 등 자료에 없는 성과를 사실처럼 지어냈다."}}, "n_candidates": 8} +{"judge": "gemini-3.1-pro-preview", "suite": "coaching", "case_id": "c-weak-backend", "ratings": {"local-qwen3.5-4b": {"usefulness": 3, "faithfulness": 5, "rewrite": 3, "language": 5, "overall": 3, "issue": "결제 승인 콜백 지연 문제를 외부 HTTP 요청이 아닌 내부 Kafka 메시지 재전송 문제로 잘못 해석함"}, "local-qwen3-4b-instruct": {"usefulness": 2, "faithfulness": 5, "rewrite": 2, "language": 5, "overall": 2, "issue": "Outbox 패턴을 지연된 콜백을 임시 저장하는 용도로 잘못 설명하여 기술적 오류가 있음"}, "gw-gpt-oss-120b": {"usefulness": 4, "faithfulness": 5, "rewrite": 1, "language": 5, "overall": 2, "issue": "answer_rewrite에 STAR 포맷(상황, 과제 등)을 그대로 노출하여 구어체 답변으로 부적절함"}, "gw-gemma-4-31b": {"usefulness": 4, "faithfulness": 5, "rewrite": 3, "language": 5, "overall": 4, "issue": "무난하고 깔끔하게 작성되었으나, 원본 답변의 뉘앙스를 살리기보다는 완전히 새로운 모범 답안을 제시함"}, "local-ax4-light": {"usefulness": 2, "faithfulness": 5, "rewrite": 2, "language": 5, "overall": 2, "issue": "Outbox 패턴이 DB에 즉시 저장하지 않는다는 치명적인 기술적 오류가 포함됨"}, "gw-solar-pro4": {"usefulness": 5, "faithfulness": 5, "rewrite": 4, "language": 5, "overall": 5, "issue": "원본 답변의 '중복'과 '트랜잭션' 키워드를 자연스럽게 확장하여 기술적 맥락과 실패 케이스를 가장 정확하게 짚어냄"}, "gw-llama-4-maverick": {"usefulness": 3, "faithfulness": 5, "rewrite": 3, "language": 5, "overall": 3, "issue": "설명이 다소 평이하고 구체적인 실패 케이스에 대한 깊이가 부족함"}, "gw-gemini-3.5-flash-lite": {"usefulness": 5, "faithfulness": 5, "rewrite": 4, "language": 5, "overall": 5, "issue": "Dual Write 등 전문 용어를 적절히 사용하여 원본 답변을 훌륭하게 개선함"}}, "n_candidates": 8} +{"judge": "claude-opus-5", "suite": "coaching", "case_id": "c-weak-backend", "ratings": {"local-ax4-light": {"usefulness": 2, "faithfulness": 3, "rewrite": 2, "language": 4, "overall": 2, "issue": "Outbox를 '트랜잭션 완료 전까지 DB에 기록하지 않는 구조'로 잘못 설명해 핵심 개념(dual-write 해결)이 틀렸고, 코칭 코멘트도 답변 내용과 겉도는 일반론이다."}, "gw-gpt-oss-120b": {"usefulness": 5, "faithfulness": 4, "rewrite": 4, "language": 4, "overall": 4, "issue": "내용·구조는 우수하나 '장애 복구 시간이 크게 단축'처럼 자료에 없는 성과를 덧붙였고, Outbox가 '중복 전송'까지 막는다는 설명은 부정확(at-least-once)하다."}, "gw-gemini-3.5-flash-lite": {"usefulness": 4, "faithfulness": 5, "rewrite": 4, "language": 5, "overall": 4, "issue": "멱등 키(중복 요청)와 Outbox(dual write) 구분은 정확하지만 '왜 둘을 함께'에 대한 상호 보완 논리와 재시도·후속 소비자 중복 처리 언급이 얕다."}, "local-qwen3.5-4b": {"usefulness": 2, "faithfulness": 3, "rewrite": 3, "language": 3, "overall": 2, "issue": "'멱등 키가 Kafka 재전송을 방지', 'Outbox가 중복 발행 방지'처럼 두 패턴의 역할을 혼동해 설명했고, 실제 문제인 결제 콜백 중복 유입 시나리오가 빠졌다."}, "gw-llama-4-maverick": {"usefulness": 3, "faithfulness": 4, "rewrite": 3, "language": 4, "overall": 3, "issue": "개념 설명은 대체로 맞지만 교과서적 일반론에 머물러 실패 케이스 구분이 구체적이지 않고, 코칭 코멘트도 질문 문구를 되풀이한다."}, "local-qwen3-4b-instruct": {"usefulness": 2, "faithfulness": 3, "rewrite": 2, "language": 4, "overall": 2, "issue": "Outbox를 '미도달 결제 이벤트를 임시 보관해 재처리하는 대기 큐'로 오해했고, 리라이트에서 '결제 대기 중 상태 유지' 등 자료에 없는 설계 디테일을 지어냈다."}, "gw-gemma-4-31b": {"usefulness": 4, "faithfulness": 4, "rewrite": 4, "language": 5, "overall": 4, "issue": "정확하고 읽기 좋으나 '주문-결제 데이터 불일치를 완전히 해결'은 과장이며, at-least-once 이후 소비자 측 멱등 처리 연결이 빠졌다."}, "gw-solar-pro4": {"usefulness": 4, "faithfulness": 4, "rewrite": 4, "language": 5, "overall": 4, "issue": "'왜 둘 다'라는 질문 의도에 잘 답했지만 Kafka 이벤트 발행까지 한 트랜잭션에 묶었다는 표현은 Outbox의 핵심(이벤트 레코드만 동일 트랜잭션)과 어긋난다."}}, "n_candidates": 8} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-clarification", "ratings": {"local-qwen3.5-4b": {"relevance": 2, "depth": 1, "language": 4, "overall": 2, "issue": "질문의 초점을 임의로 변경하고 기대 신호(정답)를 노출함"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "어려운 용어를 쉽게 풀어서 다시 질문하여 재설명 요청에 완벽히 대응함"}, "local-qwen3-4b-instruct": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "지원자의 재설명 요청에도 불구하고 원래 질문의 어려운 용어를 그대로 반복함"}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "원래 질문을 그대로 반복하여 재설명 요청에 대응하지 못함"}, "gw-solar-pro4": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "면접관이 파악해야 할 기대 신호(정답)를 질문에서 직접 말해버림"}, "gw-gpt-oss-120b": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "용어를 쉽게 풀어서 간결하고 자연스럽게 재질문함"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "사전 스케일아웃의 의미를 쉽게 풀어서 명확하게 재설명함"}, "gw-llama-4-maverick": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "원래 질문의 핵심(70% 기준, 사전 스케일아웃 병행)을 누락하고 다른 질문을 함"}, "local-midm2-mini": {"relevance": 1, "depth": 2, "language": 4, "overall": 1, "issue": "답변 의도를 잘못 분류(DONT_KNOW)하고 질문의 절반을 누락함"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-clarification", "ratings": {"gw-llama-4-maverick": {"relevance": 3, "depth": 4, "language": 5, "overall": 4, "issue": "재설명 요청인데 다시 풀어주지 않고 다른 질문으로 전환(70% 근거 축 누락)"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 3, "language": 4, "overall": 4, "issue": "용어를 풀어 잘 재설명했으나 문장이 다소 길고 새 변별 축은 없음"}, "gw-solar-pro4": {"relevance": 4, "depth": 2, "language": 3, "overall": 3, "issue": "기대 신호(메트릭 수집·기동 지연)를 그대로 알려줘 정답 누설, 문장도 장황"}, "local-ax4-light": {"relevance": 3, "depth": 2, "language": 5, "overall": 3, "issue": "원 질문을 거의 그대로 반복해 '쉽게 다시 설명' 요구를 충족하지 못함"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 2, "language": 5, "overall": 4, "issue": "간결하나 용어 풀이가 최소 수준이라 이해 곤란이 해소될지 불확실"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "의도를 DONT_KNOW로 오분류하고 사전 스케일아웃 축을 누락한 채 압박"}, "local-qwen3.5-4b": {"relevance": 2, "depth": 2, "language": 2, "overall": 2, "issue": "면접관이 설명해야 할 대목을 지원자에게 설명 요청하는 비문, 답도 흘림"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 3, "language": 4, "overall": 4, "issue": "쉬운 재설명은 우수하나 문장이 길고 정답 힌트 없이 새 축은 없음"}, "local-qwen3-4b-instruct": {"relevance": 3, "depth": 2, "language": 5, "overall": 3, "issue": "'쉽게'라는 말만 붙였을 뿐 표현을 실제로 풀어주지 않음"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-confirm-short", "ratings": {"local-ax4-light": {"relevance": 3, "depth": 3, "language": 4, "overall": 3, "issue": "질문이 다소 포괄적이고 교과서적임"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "핵심적인 기술적 고민(배치, 장애 처리)을 매우 깊이 있게 파고듦"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "폴링의 핵심 트레이드오프(DB 부하)를 짚으며 주기와 배치를 묻는 훌륭한 질문"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "무난하고 적절한 질문이나 C에 비해 기술적 맥락(DB 부하 등) 제시가 부족함"}, "local-qwen3.5-4b": {"relevance": 4, "depth": 2, "language": 5, "overall": 2, "issue": "단순히 시간만 묻는 단답형 유도 질문으로 변별력이 낮음"}, "local-midm2-mini": {"relevance": 2, "depth": 3, "language": 4, "overall": 2, "issue": "답변 의도를 DONT_KNOW로 잘못 분류함"}, "local-qwen3-4b-instruct": {"relevance": 1, "depth": 1, "language": 2, "overall": 1, "issue": "직전 질문을 그대로 반복함"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 2, "language": 5, "overall": 2, "issue": "단순히 주기만 묻고 있어 깊이가 얕음"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "간결하고 명확하게 주기와 설정 기준을 묻는 좋은 질문"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-confirm-short", "ratings": {"gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 3, "overall": 4, "issue": "두 개 이상의 질문을 한 문장에 묶어 다소 길고 부담스럽다"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 3, "language": 4, "overall": 3, "issue": "폴링 주기만 물어 중복 발행·경합 등 핵심 리스크를 놓침"}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "이미 설명한 릴레이 동작·이점을 다시 물어 대화 반복"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 2, "language": 5, "overall": 3, "issue": "주기 수치만 확인하는 단순 질문으로 변별력이 낮음"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "'몇 초'라는 사소한 수치 확인에 그침"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "DB 부하 관점은 좋으나 중복 발행·다중 인스턴스 경합은 미탐색"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 3, "overall": 2, "issue": "확인형 긍정 답변을 DONT_KNOW로 오분류하고 기술 스택만 물음"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "주기 설정 기준에 머물러 설계 리스크까지 파고들지 못함"}, "local-qwen3-4b-instruct": {"relevance": 1, "depth": 1, "language": 2, "overall": 1, "issue": "직전 질문을 그대로 반복하고 지원자 말투까지 섞여 사용 불가"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-dba-correct-with-context", "ratings": {"gw-solar-pro4": {"relevance": 3, "depth": 2, "language": 3, "overall": 2, "issue": "질문이 너무 길고 두 가지를 동시에 물어보며, 확인 방법이 뻔함"}, "local-ax4-light": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 이미 수치로 명확히 답변한 내용을 그대로 다시 질문함"}, "gw-gpt-oss-120b": {"relevance": 5, "depth": 4, "language": 5, "overall": 4, "issue": "핵심을 잘 짚었으나 autovacuum의 기여도를 구체적인 수치로 요구하는 것은 다소 무리일 수 있음"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 5, "language": 5, "overall": 5, "issue": "없음"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 4, "language": 3, "overall": 3, "issue": "'각각 어느 정도'라는 표현이 문맥상 어색함"}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "답변 의도 분류 오류(DONT_KNOW 아님) 및 파티셔닝 기준 컬럼을 묻는 뻔한 질문"}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 3, "language": 3, "overall": 3, "issue": "질문이 권장 길이를 초과하여 다소 장황함"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "없음"}, "local-qwen3.5-4b": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 이미 답변한 인덱스 기여 비중(2.3초 -> 900ms)을 다시 질문함"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-dba-correct-with-context", "ratings": {"local-ax4-light": {"relevance": 3, "depth": 1, "language": 5, "overall": 2, "issue": "지원자가 이미 900ms→180ms로 단계별 기여를 말했는데 그대로 되묻는 중복 질문"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "autovacuum 기여를 수치로만 요구해 메커니즘 설명 여지를 좁힘"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "가장 약한 축(vacuum)을 잘 짚었지만 bloat·플랜 변화 등 방향 제시가 없어 다소 포괄적"}, "gw-llama-4-maverick": {"relevance": 3, "depth": 2, "language": 5, "overall": 3, "issue": "index vs index-only 확인형 단답 질문으로 변별력이 낮음"}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 3, "language": 3, "overall": 3, "issue": "두 문장·예시 나열로 장황하고 이미 언급된 진단 과정과 상당 부분 겹침"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "구체적으로 답한 답변을 DONT_KNOW로 오분류하고 파티션 키라는 사소한 질문으로 흐름"}, "gw-solar-pro4": {"relevance": 4, "depth": 4, "language": 2, "overall": 3, "issue": "측정·검증 관점은 좋으나 두 문장 장문으로 면접 질문 형식에 부적합"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "단일 항목에 '각각'을 쓴 표현이 어색하나 미싱 축을 정확히 겨냥"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 3, "overall": 2, "issue": "이미 답한 인덱스 효과를 '기여 비중'으로 애매하게 재질문하고 표기 공백이 어색"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-dont-know-explicit", "ratings": {"local-qwen3-4b-instruct": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "모른다고 답변한 지원자에게 모르는 이유를 묻는 것은 매우 부적절함"}, "local-ax4-light": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "모른다고 한 질문을 더 어려운 용어를 추가하여 그대로 다시 질문함"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "모른다는 답변에 맞춰 VACUUM의 기초 개념으로 난이도를 낮춰 적절히 질문함"}, "gw-solar-pro4": {"relevance": 2, "depth": 1, "language": 4, "overall": 2, "issue": "면접관이 정답을 설명해주겠다고 제안하는 것은 평가 목적에 맞지 않음"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "난이도를 낮춘 것은 좋으나 '이해하고 계신가요?'는 예/아니오 단답을 유도함"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "지원자의 상황을 수용하고 MVCC 기초 개념으로 부드럽게 유도하여 매우 자연스러움"}, "local-qwen3.5-4b": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "모른다고 답변한 주제에 대해 오히려 더 깊은 세부 개념을 묻고 있음"}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 설명하지 않았음에도 설명했다고 가정하는 환각 오류"}, "gw-gpt-oss-120b": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "모른다고 한 직전 질문을 토씨 하나 바꾸지 않고 그대로 다시 질문함"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-dont-know-explicit", "ratings": {"gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "모름 대응으로 난이도를 낮춘 점은 좋으나 두 가지를 묶어 물어 다소 길다"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 2, "language": 5, "overall": 3, "issue": "예/아니오로 끝나는 확인형이라 변별력이 거의 없음"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "vacuum 역할로 한 단계 낮춘 적절한 질문이나 xmin 축 연결은 다음 턴 과제로 남음"}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "모른다고 한 내용을 오히려 더 어렵게 그대로 되물음"}, "local-qwen3-4b-instruct": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "모르는 이유를 캐묻는 비면접적·압박성 질문"}, "local-qwen3.5-4b": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "모른다고 한 핵심 개념(xmin horizon)을 난이도 낮춤 없이 재질문"}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 2, "overall": 1, "issue": "설명한 적 없는 답변을 회고하듯 물어 문맥이 성립하지 않음"}, "gw-gpt-oss-120b": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "직전 질문을 거의 그대로 반복해 대화가 진전되지 않음"}, "gw-solar-pro4": {"relevance": 3, "depth": 2, "language": 3, "overall": 2, "issue": "재설명 요청이 아닌데 기대 신호를 그대로 노출하며 답을 알려주려 함"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-dont-know-stt", "ratings": {"local-qwen3-4b-instruct": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 모른다고 답변했음에도 특정 내용을 언급했다고 잘못 가정함(Hallucination)."}, "gw-gemini-3.5-flash-lite": {"relevance": 3, "depth": 3, "language": 4, "overall": 3, "issue": "모른다는 답변에 대해 이전 버전의 동작 방식을 묻는 것은 여전히 지원자에게 어려울 수 있음."}, "gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "모른다는 답변을 수용하고 배칭의 기본 개념으로 난이도를 낮춰 질문하여 매우 적절함."}, "local-qwen3.5-4b": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 모른다고 했으나 오히려 더 심화된 질문을 던져 대화 흐름에 어긋남."}, "gw-gpt-oss-120b": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "모른다는 지원자에게 직전 질문을 거의 그대로 다시 물어봄."}, "local-ax4-light": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자의 모른다는 답변을 무시하고 직전 질문을 반복 및 심화함."}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자의 모른다는 답변을 무시하고 직전 질문을 반복함."}, "gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 4, "overall": 3, "issue": "모른다는 답변을 수용하고 이전 버전의 지식을 묻지만 어투가 다소 직설적이고 문장이 김."}, "gw-solar-pro4": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자의 모른다는 답변을 무시하고 기대 신호를 포함해 다시 질문함."}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-dont-know-stt", "ratings": {"local-qwen3-4b-instruct": {"relevance": 1, "depth": 1, "language": 3, "overall": 1, "issue": "지원자가 하지 않은 말을 '말씀하셨는데'라고 날조해 모름 답변에 전혀 맞지 않음"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "'전혀 모르겠다고 하셨는데' 표현이 다소 직설적이고 문장이 긴 편"}, "gw-solar-pro4": {"relevance": 2, "depth": 2, "language": 3, "overall": 2, "issue": "직전 질문을 거의 그대로 반복하면서 기대 신호(정답)까지 노출해 변별력이 사라짐"}, "local-qwen3.5-4b": {"relevance": 2, "depth": 3, "language": 5, "overall": 3, "issue": "모른다는 지원자에게 오히려 더 깊은 '왜'를 물어 대화가 끊길 가능성이 큼"}, "gw-gpt-oss-120b": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "난이도 조정 없이 같은 질문을 예시 요구로 바꿔 되물음"}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "직전 질문의 재진술 수준이라 모름 대응으로서 실익이 없음"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "이전 버전 동작으로 난이도를 낮춘 적절한 전환, 큰 결함 없음"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 3, "overall": 2, "issue": "질문 반복에 더해 정답 포인트를 알려주고 문장도 두 개로 장황함"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "배려 후 기본 개념으로 낮춘 점은 좋으나 문장이 길고 에둘러 표현됨"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-english-mixed", "ratings": {"local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 5, "overall": 2, "issue": "지원자가 이미 dedupe 때문이라고 명시한 내용을 다시 묻고 있음."}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 3, "language": 5, "overall": 4, "issue": "무난하지만 기술적 깊이보다는 단순 사례 확인에 가까움."}, "local-midm2-mini": {"relevance": 2, "depth": 3, "language": 5, "overall": 2, "issue": "답변 의도를 DONT_KNOW로 잘못 분류함."}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "없음."}, "gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "평이한 사례 확인 질문."}, "gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 5, "overall": 4, "issue": "없음."}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "무난한 질문."}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "평이한 사례 확인 질문."}, "local-ax4-light": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 이미 설명한 내용을 그대로 다시 설명해달라고 요구함."}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-english-mixed", "ratings": {"local-ax4-light": {"relevance": 2, "depth": 1, "language": 2, "overall": 2, "issue": "이미 답변한 내용을 그대로 다시 묻는 중복 질문이고 문장이 장황함"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "값 자체를 묻는 부분은 다소 지엽적이나 근거를 함께 물어 보완됨"}, "local-midm2-mini": {"relevance": 2, "depth": 3, "language": 4, "overall": 2, "issue": "구체적으로 답했는데 의도를 DONT_KNOW로 오분류함"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "문장이 다소 길지만 캐시 무효화 범위라는 약한 축을 정확히 파고듦"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 5, "overall": 4, "issue": "설정 사례 확인 수준이라 데이터 특성에 대한 판단 근거까지는 못 끌어냄"}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 3, "language": 3, "overall": 3, "issue": "'예시나, 어떤 화면에서 얼마나' 부분이 어색하고 질문 초점이 흐림"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "40% 수치의 측정 방식이 아닌 위치만 물어 변별력이 제한적"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "좋은 기준 질문이나 D처럼 무효화 범위 설계까지는 파고들지 못함"}, "local-qwen3.5-4b": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "양자택일 프레임이라 답변이 단답으로 닫힐 여지가 있음"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-frontend-strong", "ratings": {"local-ax4-light": {"relevance": 3, "depth": 3, "language": 3, "overall": 2, "issue": "이미 답변한 렌더링 성능 개선 여부를 중복해서 질문함"}, "local-qwen3-4b-instruct": {"relevance": 5, "depth": 4, "language": 5, "overall": 4, "issue": "무난하고 간결하게 캐시 구현 방식을 물어봄"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "답변 의도 분류 오류(DONT_KNOW 아님), 사소한 수치(30개)에 집착함"}, "gw-llama-4-maverick": {"relevance": 5, "depth": 4, "language": 3, "overall": 3, "issue": "문장 끝에 어색한 물음표('설명해 주세요?')"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 5, "overall": 4, "issue": "간결하고 명확하게 캐시 구조를 질문함"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "캐시의 '갱신 전략'을 물어 실무적인 깊이가 뛰어남"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "지원자가 이미 Profiler로 측정했다고 언급한 내용을 다시 묻는 뉘앙스"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "초기 추정치 오류 및 콘텐츠 변경 시의 보정 방법을 묻는 매우 훌륭한 심층 질문"}, "gw-gpt-oss-120b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "기대 신호 중 지원자가 누락한 '접근성' 이슈를 정확하고 간결하게 짚어냄"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-frontend-strong", "ratings": {"local-ax4-light": {"relevance": 3, "depth": 2, "language": 2, "overall": 2, "issue": "이미 답한 개선 효과를 다시 묻고 두 문장으로 장황하며 '궁금합니다' 오타"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 3, "overall": 3, "issue": "높이 캐시 관리라는 무난한 재확인 수준이고 '설명해 주세요?' 어미가 어색"}, "gw-solar-pro4": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "접근성·검색 트레이드오프는 비었고 길이가 다소 길다"}, "local-qwen3.5-4b": {"relevance": 4, "depth": 3, "language": 3, "overall": 3, "issue": "Profiler/Lighthouse로 INP를 측정한다는 전제가 부정확하고 문장이 어색"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "캐시 자료구조만 묻는 수준으로 변별력이 제한적"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 3, "language": 4, "overall": 3, "issue": "갱신 전략을 묻지만 계기·보정 맥락이 없어 깊이가 얕음"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 5, "language": 5, "overall": 5, "issue": "지원자 수치를 직접 인용하지 않아 연결이 다소 약함"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 2, "overall": 1, "issue": "의도를 DONT_KNOW로 오분류하고 '30개' 숫자라는 사소한 지점을 장황하게 캐묻음"}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 2, "language": 4, "overall": 3, "issue": "답변을 인용만 하고 '구현 방식'을 막연히 되묻는 수준"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-infra-fact-error", "ratings": {"gw-solar-pro4": {"relevance": 2, "depth": 2, "language": 3, "overall": 2, "issue": "지원자의 답변(메모리 50%, 피크 대응 안 함)을 전혀 듣지 않은 것처럼 이력서 내용만 묻고 있음."}, "gw-gpt-oss-120b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "이력서와의 모순을 명확히 짚지 않고 소극적으로 확인만 함."}, "gw-llama-4-maverick": {"relevance": 3, "depth": 3, "language": 4, "overall": 3, "issue": "답변에 대한 꼬리질문으로는 무난하나, 이력서 내용과의 명백한 모순이라는 가장 중요한 변별 포인트를 놓침."}, "local-ax4-light": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 방금 '피크 대응은 따로 안 했다'고 답했는데 CronJob 운영 이유를 묻는 모순된 질문."}, "local-qwen3.5-4b": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "모순을 짚었으나 '실제 설계는 어땠나요'라는 질문이 다소 모호함."}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "이력서와 답변의 모순을 매우 정확하고 자연스럽게 짚어내어 압박/검증 질문으로 훌륭함."}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "모순을 정확히 짚었으나 문장이 다소 길어짐."}, "local-qwen3-4b-instruct": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "이력서에 명시된 내용(CPU 70%)과의 모순을 파악하지 못하고 일반론적인 질문을 던짐."}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 3, "overall": 1, "issue": "답변 의도 분류(DONT_KNOW)가 틀렸으며, 질문 내용도 이력서와 답변을 혼동하여 어색함."}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-infra-fact-error", "ratings": {"gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "메모리 기준 선택 근거나 피크 리스크까지 한 걸음 더 파고들지는 못함"}, "gw-llama-4-maverick": {"relevance": 3, "depth": 2, "language": 5, "overall": 3, "issue": "이력서와의 모순(CPU 70%·CronJob)을 놓치고 변별력 낮은 일반 질문에 머묾"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 3, "language": 5, "overall": 4, "issue": "예/아니오 확인형에 가까워 설계 근거를 끌어내는 힘이 약함"}, "local-midm2-mini": {"relevance": 2, "depth": 3, "language": 3, "overall": 2, "issue": "의도를 DONT_KNOW로 오분류하고 CPU 70%를 지원자 발언처럼 전제해 혼란"}, "gw-solar-pro4": {"relevance": 4, "depth": 4, "language": 3, "overall": 4, "issue": "두 질문을 한 문장에 몰아 길고, 답변과 이력서의 모순은 짚지 않음"}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 3, "language": 4, "overall": 3, "issue": "'CPU가 더 일반적이지 않나'는 유도성 일반론이고 사전 스케일아웃 축은 누락"}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 3, "overall": 2, "issue": "직전 질문을 거의 반복하고 CronJob 운영을 사실로 전제해 답변과 어긋남"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 4, "overall": 5, "issue": "모순을 정확히 짚었으나 문장이 다소 길고 두 축을 한 번에 물음"}, "local-qwen3.5-4b": {"relevance": 5, "depth": 3, "language": 5, "overall": 4, "issue": "'실제 설계는 어땠나요'가 모호해 답변 방향이 흐려질 수 있음"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-long-answer-history", "ratings": {"local-qwen3.5-4b": {"relevance": 2, "depth": 1, "language": 5, "overall": 2, "issue": "지원자가 이미 설명한 보상 흐름의 실행 시점을 다시 묻고 있음"}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "답변 의도를 DONT_KNOW로 잘못 분류했으며, 비동기 이벤트 간의 시간차를 묻는 어색한 질문"}, "local-ax4-light": {"relevance": 1, "depth": 1, "language": 5, "overall": 1, "issue": "지원자가 이미 상세히 설명한 Saga 패턴 적용 이유와 보상 흐름을 그대로 다시 요구함"}, "local-qwen3-4b-instruct": {"relevance": 2, "depth": 1, "language": 3, "overall": 1, "issue": "질문이 지나치게 길고 복잡하며, 이미 답변한 이벤트 유실 시 대처 방안을 다시 묻고 있음"}, "gw-llama-4-maverick": {"relevance": 1, "depth": 1, "language": 5, "overall": 1, "issue": "지원자가 이미 스위퍼 배치를 통한 보완 방법을 설명했음에도 다시 묻고 있음"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "스위퍼 배치에 대해 묻는 것은 좋으나, 분산 트랜잭션의 핵심보다는 단순 스케줄링 구현에 치우침"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "Outbox 패턴의 핵심인 이벤트 릴레이(CDC, Polling 등) 메커니즘을 정확히 파고든 훌륭한 질문"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "스위퍼 배치 실행 시 발생할 수 있는 레이스 컨디션 문제를 짚어 실무적 깊이가 매우 뛰어남"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "배치 처리 시 발생할 수 있는 상태 불일치 및 중복 실행 방지책을 날카롭게 파고듦"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-long-answer-history", "ratings": {"gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "스위퍼 레이스 컨디션을 잘 짚었으나 문장이 다소 길고 만연체"}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 3, "overall": 1, "issue": "의도 분류(DONT_KNOW) 오판에 질문 자체가 '이벤트 발행 시간차 설정'으로 기술적으로 성립하지 않음"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "outbox 릴레이 방식이라는 유효한 지점이지만 '구체적 메커니즘'이라 범위가 넓고 변별력이 다소 낮음"}, "local-qwen3-4b-instruct": {"relevance": 3, "depth": 2, "language": 2, "overall": 2, "issue": "답변 내용을 그대로 되풀이하며 한 문장에 질문을 여러 개 뭉쳐 장황함"}, "local-ax4-light": {"relevance": 2, "depth": 1, "language": 4, "overall": 2, "issue": "Saga 선택 이유와 보상 흐름은 이미 상세히 답변된 내용으로 완전한 반복"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "거의 없음, 문장이 권장 길이를 약간 초과"}, "gw-gpt-oss-120b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "스케줄링 방식 등 정합성 변별력이 낮은 구현 디테일에 머묾"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 5, "overall": 2, "issue": "보상 흐름 실행 시점은 답변에서 이미 서술된 내용으로 새 정보를 끌어내지 못함"}, "gw-llama-4-maverick": {"relevance": 3, "depth": 2, "language": 5, "overall": 2, "issue": "스위퍼 배치라는 보완책을 이미 말했는데 다시 묻는 중복 질문"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-personality-rambling", "ratings": {"gw-solar-pro4": {"relevance": 4, "depth": 5, "language": 4, "overall": 4, "issue": "무난하게 구체적인 사례와 행동을 요구함"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "지원자의 답변을 인용하며 구체적인 사례와 성과를 자연스럽게 요구함"}, "gw-gpt-oss-120b": {"relevance": 2, "depth": 4, "language": 3, "overall": 2, "issue": "지원자가 특정 경험을 언급하지 않았음에도 '그때'라고 지칭하여 문맥이 어색함"}, "local-ax4-light": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "지원자의 답변 내용을 직접 짚어주지는 않으나 무난한 꼬리질문임"}, "local-qwen3-4b-instruct": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "지원자의 핵심 단어(소통)를 짚으며 구체적 행동과 결과를 잘 이끌어냄"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "과거의 구체적인 경험(STAR)을 묻지 않고 일반적인 대화 방식에 대해서만 묻고 있어 변별력이 낮음"}, "local-midm2-mini": {"relevance": 2, "depth": 4, "language": 4, "overall": 2, "issue": "지원자가 모른다고 답한 것이 아님에도 답변 의도를 DONT_KNOW로 오분류함"}, "local-qwen3.5-4b": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "지원자의 답변을 잘 인용했으나 문장 연결이 다소 매끄럽지 않음"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "지원자의 답변 특징을 정확히 짚어내며 구체적인 상황과 행동을 간결하게 요구함"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-personality-rambling", "ratings": {"gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "대화 방식만 묻고 사례·결과(정량) 축을 전혀 파고들지 못함"}, "local-ax4-light": {"relevance": 3, "depth": 3, "language": 3, "overall": 3, "issue": "직전 질문을 거의 그대로 반복하는 일반형 재요청이라 변별력이 낮고 문장이 장황함"}, "gw-solar-pro4": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "상황·행동은 잘 파고들지만 결과/정량 신호가 빠지고 문장이 다소 긺"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "'있나요' 형태라 예/아니오 단답으로 빠질 여지가 있음"}, "local-qwen3.5-4b": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "대화 방식+성과를 한 문장에 묶어 다소 길고, 구체 상황(S) 요구가 약함"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 5, "language": 3, "overall": 4, "issue": "상황·행동·수치 세 가지를 한꺼번에 물어 질문이 길고 답하기 부담스러움"}, "local-midm2-mini": {"relevance": 2, "depth": 3, "language": 3, "overall": 2, "issue": "의도 분류를 DONT_KNOW로 오판했고 따옴표 남발에 질문도 장황함"}, "local-qwen3-4b-instruct": {"relevance": 5, "depth": 4, "language": 5, "overall": 5, "issue": "구체 사례(상황) 명시 요구가 살짝 약해 다시 원론적 답이 나올 수 있음"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 5, "overall": 4, "issue": "상황·행동은 짚었으나 결과·이후 변화(정량) 축을 묻지 않음"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-personality-star", "ratings": {"local-qwen3.5-4b": {"relevance": 3, "depth": 3, "language": 4, "overall": 3, "issue": "인성/행동 질문의 맥락에서 벗어나 기술적인 트레이드오프를 묻고 있음."}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "갈등 상황과 해결 과정을 깊이 있게 파고드는 훌륭한 질문이나 길이가 다소 긺."}, "local-qwen3-4b-instruct": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "인성 질문 맥락에 맞지 않으며, 명세의 항목 수 등 사소한 기술적 디테일을 물어 변별력이 낮음."}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "지원자가 개선한 행동 양식(대안 비교)이 실제 어떻게 적용되었는지 검증하는 간결하고 좋은 질문."}, "local-midm2-mini": {"relevance": 1, "depth": 2, "language": 5, "overall": 1, "issue": "충실한 답변임에도 답변 의도를 DONT_KNOW로 잘못 분류함."}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "개선된 행동 이후의 긍정적 변화를 구체적 사례로 묻는 좋은 질문이나 길이가 다소 긺."}, "local-ax4-light": {"relevance": 2, "depth": 1, "language": 4, "overall": 2, "issue": "지원자가 이미 구체적으로 설명한 해결 과정과 결과를 그대로 다시 묻고 있어 무의미함."}, "gw-gpt-oss-120b": {"relevance": 3, "depth": 3, "language": 5, "overall": 3, "issue": "이후에 방식을 바꿨다는 맥락을 간과하고, 특정 단일 사건에서 두 대안을 비교한 것처럼 질문해 다소 어색함."}, "gw-llama-4-maverick": {"relevance": 2, "depth": 1, "language": 5, "overall": 2, "issue": "당시에는 본인 방식을 고집했다고 답변했음에도, 당시에 비교한 대안을 물어 문맥을 전혀 파악하지 못함."}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-personality-star", "ratings": {"gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "두 가지를 한 번에 묻고 문장이 다소 길다"}, "local-ax4-light": {"relevance": 3, "depth": 2, "language": 3, "overall": 2, "issue": "답변 내용을 요약 반복하며 '더 자세히'만 요구해 변별력이 없다"}, "local-qwen3-4b-instruct": {"relevance": 3, "depth": 1, "language": 3, "overall": 2, "issue": "명세 항목 개수 등 사소한 디테일을 물어 인성 면접 신호와 무관"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 3, "language": 5, "overall": 4, "issue": "달라진 점 확인은 적절하나 충돌 해소 과정 자체는 비켜감"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "분위기 변화라는 다소 주관적 답을 유도해 검증력이 약함"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "대안 비교는 사후 개선점인데 지연 당시 일로 시점을 잘못 연결"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 3, "language": 4, "overall": 2, "issue": "PERSONALITY/BEHAVIORAL 맥락을 벗어나 기술 트레이드오프로 전환"}, "local-midm2-mini": {"relevance": 2, "depth": 3, "language": 4, "overall": 2, "issue": "충실한 STAR 답변을 DONT_KNOW로 오분류"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 3, "language": 5, "overall": 4, "issue": "가장 약한 축인 갈등 봉합 과정 대신 대안 내용만 확인"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-strong-backend", "ratings": {"local-ax4-light": {"relevance": 1, "depth": 1, "language": 5, "overall": 1, "issue": "지원자가 이미 답변한 내용을 그대로 다시 묻고 있음"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "릴레이 발행 실패 시의 정합성 보장 방안을 묻는 좋은 꼬리질문"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "구체적인 SQL이나 로직을 묻는 것은 아키텍처 면접에서 지나치게 지엽적임"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "Outbox 패턴의 특징인 '적어도 한 번 전달'로 인한 중복 발행 문제를 정확히 짚음"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "릴레이 장애가 본 시스템에 미치는 영향을 물어 결합도에 대한 이해를 잘 확인함"}, "gw-gpt-oss-120b": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "이벤트가 누락되는 상황은 지원자가 이미 답변에서 설명했음"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 4, "issue": "질문이 다소 길지만, Outbox의 중복 발행과 멱등성의 경계를 묻는 깊이 있는 질문"}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "답변 의도를 DONT_KNOW로 잘못 분류했으며, 직전 질문을 그대로 반복함"}, "local-qwen3-4b-instruct": {"relevance": 2, "depth": 1, "language": 4, "overall": 1, "issue": "채점 기준에서 명시한 '사소하거나 뻔한 질문(키의 형식)'에 해당함"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-strong-backend", "ratings": {"gw-llama-4-maverick": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "릴레이 장애 영향은 적절하나 다소 일반적이어서 변별력이 최상은 아님"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "구체 SQL 코드 요구로 설계 이해가 아닌 암기·세부 구현에 머묾"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "at-least-once 중복 발행을 잘 짚었으나 멱등 키와의 경계 연결은 약함"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "문장이 다소 길지만 두 기법의 책임 경계를 정확히 파고듦"}, "local-ax4-light": {"relevance": 2, "depth": 1, "language": 4, "overall": 2, "issue": "지원자가 이미 설명한 멱등 키 이유를 그대로 되묻는 반복 질문"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "발행 실패 재시도라는 예상 가능한 범위로 깊이가 보통"}, "gw-gpt-oss-120b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "이벤트 누락 케이스와 해결책은 이미 답변에 있어 내용이 중복됨"}, "local-qwen3-4b-instruct": {"relevance": 3, "depth": 1, "language": 3, "overall": 2, "issue": "키 형식이라는 사소한 세부를 물어 변별력이 거의 없음"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 4, "overall": 1, "issue": "구체적으로 답한 답변을 DONT_KNOW로 오분류하고 직전 질문을 재요청함"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-stt-messy-normal", "ratings": {"local-qwen3.5-4b": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "분산 락 도입 후에는 버전 충돌이 발생하지 않으므로 변경 전후의 충돌 비율을 묻는 것은 기술적으로 어색함."}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 3, "overall": 2, "issue": "지원자가 이미 명확히 밝힌 수치(200건 -> 3건)의 인과관계를 다시 묻고 있어 중복되며 문장이 긺."}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "낙관적 락의 재시도 부하를 해결하기 위한 다른 대안(백오프 등)과 분산 락을 비교하게 하는 훌륭한 질문임."}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "무난하고 간결한 꼬리질문이나, 트레이드오프에 대한 깊은 논의로 이끌기에는 다소 평이함."}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "기대 신호를 잘 짚었으나 '수치로 정확히 말씀해 주실 수 있나요' 같은 표현이 다소 딱딱하고 김."}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "분산 락 도입으로 인해 새롭게 발생할 수 있는 트레이드오프(성능, 예외 처리)를 묻는 매우 깊이 있는 질문임."}, "gw-llama-4-maverick": {"relevance": 3, "depth": 2, "language": 4, "overall": 2, "issue": "200건에서 3건으로의 감소는 명확한 개선인데, 이를 부정하는 듯한 뉘앙스의 질문이라 어색함."}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 4, "overall": 1, "issue": "지원자가 답변을 잘 했음에도 의도를 DONT_KNOW로 잘못 분류했으며, 질문 수준이 너무 낮음."}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 4, "overall": 5, "issue": "기대 신호인 트레이드오프(재시도 비용 vs 락 대기 비용)를 완벽하게 짚었으나 문장이 다소 김."}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-stt-messy-normal", "ratings": {"local-qwen3.5-4b": {"relevance": 3, "depth": 3, "language": 3, "overall": 3, "issue": "답변 대목을 인용하지 않은 일반적 수치 요구이고 문장이 어색함"}, "gw-gemini-3.5-flash-lite": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "두 가지를 한꺼번에 물어 다소 길다"}, "local-midm2-mini": {"relevance": 1, "depth": 1, "language": 3, "overall": 1, "issue": "의도 오분류(DONT_KNOW)에 레디스 정의를 묻는 무의미한 질문"}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 2, "overall": 2, "issue": "이미 말한 200건→3건 수치를 다시 설명하라는 중복 질문이며 장황함"}, "local-qwen3-4b-instruct": {"relevance": 3, "depth": 3, "language": 3, "overall": 3, "issue": "수치 재요구에 머물고 분산 락 쪽 비용 트레이드오프는 놓침"}, "gw-gemma-4-31b": {"relevance": 4, "depth": 5, "language": 5, "overall": 4, "issue": "간결하고 대안 비교를 잘 파지만 지원자 수치 인용이 없음"}, "gw-gpt-oss-120b": {"relevance": 3, "depth": 3, "language": 4, "overall": 3, "issue": "측정치 확인 수준이라 트레이드오프 판단 변별력이 약함"}, "gw-llama-4-maverick": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "효과 검증만 찔러 락 방식 트레이드오프 축은 덜 다룸"}, "gw-solar-pro4": {"relevance": 5, "depth": 5, "language": 3, "overall": 4, "issue": "기대 신호를 정확히 겨냥했지만 한 문장에 질문 두 개로 길고 숨차다"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "followup", "case_id": "f-weak-vague", "ratings": {"local-ax4-light": {"relevance": 2, "depth": 2, "language": 5, "overall": 2, "issue": "지원자의 답변을 반영하지 않고 이전 질문을 단순 반복함"}, "gw-gpt-oss-120b": {"relevance": 2, "depth": 2, "language": 5, "overall": 2, "issue": "지원자의 답변을 반영하지 않고 이전 질문의 일부를 단순 반복함"}, "local-qwen3-4b-instruct": {"relevance": 4, "depth": 4, "language": 4, "overall": 4, "issue": "지원자의 답변을 잘 짚고 핵심을 다시 물었으나 문장이 다소 김"}, "gw-solar-pro4": {"relevance": 2, "depth": 1, "language": 4, "overall": 1, "issue": "괄호 안에 정답(실패 케이스 예시)을 직접 제시하여 면접 변별력을 없앰"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 5, "overall": 4, "issue": "지원자의 회피성 답변을 정확히 인용하며 원래 의도한 핵심을 다시 요구함"}, "gw-gemma-4-31b": {"relevance": 5, "depth": 5, "language": 5, "overall": 5, "issue": "회피성 답변을 짚은 뒤, 하나의 기술(멱등 키)로 좁혀 구체적 검증 시점을 묻는 훌륭한 압박 질문"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 5, "overall": 2, "issue": "지원자의 답변을 반영하지 않았으며 질문이 너무 포괄적임"}, "gw-llama-4-maverick": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "지원자의 답변을 반영하지 않고 이전 질문을 다르게 포장하여 반복함"}, "local-qwen3.5-4b": {"relevance": 3, "depth": 3, "language": 5, "overall": 3, "issue": "원래 질문의 핵심 기술 중 하나인 Outbox 패턴에 대한 검증이 누락됨"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "followup", "case_id": "f-weak-vague", "ratings": {"gw-gemma-4-31b": {"relevance": 5, "depth": 4, "language": 5, "overall": 4, "issue": "멱등 키 검증 시점으로 잘 좁혔으나 Outbox 축은 완전히 빠져 기대 신호 절반만 검증"}, "local-qwen3.5-4b": {"relevance": 4, "depth": 3, "language": 5, "overall": 3, "issue": "Outbox 대신 '트랜잭션 관리'로 뭉뚱그려 두 기술의 구분 변별력이 약함"}, "local-midm2-mini": {"relevance": 2, "depth": 2, "language": 4, "overall": 2, "issue": "회피성 답변을 DONT_KNOW로 오분류하고 '좀 더 설명'식 막연한 재요청에 그침"}, "local-ax4-light": {"relevance": 2, "depth": 2, "language": 5, "overall": 2, "issue": "직전 질문의 '함께 쓴 이유'를 거의 그대로 반복해 새 정보 획득이 없음"}, "gw-gemini-3.5-flash-lite": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "답변 인용과 두 축 모두 짚었으나 문장이 다소 길고 초점이 넓음"}, "local-qwen3-4b-instruct": {"relevance": 5, "depth": 4, "language": 4, "overall": 4, "issue": "지원자 주장 두 개를 잘 되짚었지만 문장이 길고 원질문과 표현 중복이 있음"}, "gw-llama-4-maverick": {"relevance": 3, "depth": 3, "language": 4, "overall": 3, "issue": "의도 오분류 상태에서 구현 방식까지 한꺼번에 물어 초점이 분산됨"}, "gw-solar-pro4": {"relevance": 3, "depth": 4, "language": 3, "overall": 3, "issue": "예시로 정답(콜백 중복·메시지 유실)을 먼저 알려줘 변별력을 스스로 깎고 문장이 장황함"}, "gw-gpt-oss-120b": {"relevance": 4, "depth": 4, "language": 5, "overall": 4, "issue": "간결하고 두 축을 모두 묻지만 지원자의 두루뭉실한 발언을 직접 인용해 압박하지 않음"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "questions", "case_id": "q-backend-tech", "ratings": {"gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 5, "language": 4, "overall": 5, "issue": "질문의 깊이와 구체성이 매우 뛰어나나, 길이가 80자를 다소 초과함"}, "gw-solar-pro4": {"grounding": 5, "coverage": 5, "depth": 5, "language": 3, "overall": 4, "issue": "질문의 변별력은 훌륭하지만 길이가 130자에 달할 정도로 지나치게 김"}, "local-midm2-mini": {"grounding": 2, "coverage": 3, "depth": 2, "language": 4, "overall": 2, "issue": "일부 질문의 근거가 없고(없음), 질문 내용이 지나치게 포괄적임"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 4, "depth": 4, "language": 5, "overall": 4, "issue": "TECHNICAL 모드임에도 BEHAVIORAL 태그가 포함됨"}, "gw-gpt-oss-120b": {"grounding": 5, "coverage": 4, "depth": 4, "language": 4, "overall": 4, "issue": "TECHNICAL 모드임에도 BEHAVIORAL 태그가 포함됨"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 5, "depth": 4, "language": 5, "overall": 5, "issue": "적절한 길이와 구체적인 기술적 상황을 묻는 좋은 질문들로 구성됨"}, "gw-llama-4-maverick": {"grounding": 4, "coverage": 5, "depth": 2, "language": 4, "overall": 2, "issue": "질문이 '어떻게 해결했나요?' 식으로 너무 단편적이고 깊이가 얕음"}, "local-ax4-light": {"grounding": 4, "coverage": 3, "depth": 3, "language": 4, "overall": 3, "issue": "BEHAVIORAL 태그가 포함되었으며, 질문이 다소 평이하고 포괄적임"}, "local-qwen3-4b-instruct": {"grounding": 5, "coverage": 5, "depth": 4, "language": 4, "overall": 4, "issue": "질문이 구체적이나 일부 질문(Q1, Q4) 간 데이터 정합성 주제가 다소 겹침"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "questions", "case_id": "q-backend-tech", "ratings": {"gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 5, "language": 4, "overall": 5, "issue": "질문 문장이 80자를 다소 넘어 길지만 내용·근거는 흠잡을 데 없음"}, "gw-llama-4-maverick": {"grounding": 4, "coverage": 4, "depth": 2, "language": 5, "overall": 3, "issue": "이력서 문장을 그대로 되묻는 수준이라 변별력 있는 후속 깊이가 없음"}, "local-ax4-light": {"grounding": 4, "coverage": 2, "depth": 3, "language": 4, "overall": 3, "issue": "TECHNICAL 모드인데 BEHAVIORAL 포함, 2·3번이 Outbox 주제로 중복"}, "gw-solar-pro4": {"grounding": 5, "coverage": 5, "depth": 5, "language": 4, "overall": 5, "issue": "질문이 상당히 길어 구술 면접에서 한 번에 전달되기 어려움"}, "gw-gpt-oss-120b": {"grounding": 4, "coverage": 3, "depth": 3, "language": 4, "overall": 3, "issue": "Kotlin 선택 이유는 일반론에 가깝고, TECHNICAL 모드에 BEHAVIORAL 질문 혼입"}, "local-qwen3-4b-instruct": {"grounding": 4, "coverage": 3, "depth": 3, "language": 3, "overall": 3, "issue": "4번이 Outbox 교과서 질문이자 1번과 주제 중복, 문장이 번역투로 어색"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 4, "depth": 4, "language": 5, "overall": 4, "issue": "5번이 '경험이 있나요' 예/아니오형이며 TECHNICAL 모드에 BEHAVIORAL 배치"}, "local-midm2-mini": {"grounding": 2, "coverage": 2, "depth": 2, "language": 4, "overall": 2, "issue": "4·5번은 근거가 비어 있고 리더십·일반론 질문이라 자료 기반이 아님"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 4, "depth": 4, "language": 5, "overall": 4, "issue": "4번 태그가 CS_FUNDAMENTAL인데 실제로는 프로젝트 심화 질문으로 분류 불일치"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "questions", "case_id": "q-frontend-repo", "ratings": {"gw-gpt-oss-120b": {"grounding": 5, "coverage": 4, "depth": 3, "language": 4, "overall": 3, "issue": "단순히 '설명해 주세요' 위주의 평이한 질문으로 깊이가 다소 얕음"}, "local-ax4-light": {"grounding": 3, "coverage": 2, "depth": 3, "language": 4, "overall": 2, "issue": "TECHNICAL 모드임에도 BEHAVIORAL 질문이 포함되었으며, 테스트와 성능 점수를 억지로 연결함"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 5, "depth": 5, "language": 5, "overall": 5, "issue": "간결하면서도 핵심적인 트레이드오프와 기술적 의도를 묻는 훌륭한 질문들"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 5, "depth": 5, "language": 5, "overall": 5, "issue": "브라우저 메인 스레드 부하, 렌더링 파이프라인 등 프론트엔드 심층 지식을 잘 이끌어내는 우수한 질문"}, "gw-llama-4-maverick": {"grounding": 5, "coverage": 4, "depth": 2, "language": 3, "overall": 2, "issue": "질문이 너무 짧고 단답형을 유도하여 면접용으로 부적합함"}, "gw-solar-pro4": {"grounding": 5, "coverage": 5, "depth": 5, "language": 4, "overall": 5, "issue": "질문이 다소 길지만, 실무 면접관 수준의 매우 깊이 있고 구체적인 상황을 묻는 훌륭한 세트"}, "local-qwen3.5-4b": {"grounding": 4, "coverage": 3, "depth": 4, "language": 2, "overall": 2, "issue": "과도한 띄어쓰기 오류(명사와 조사 분리 등)가 있으며 TECHNICAL 모드에 어긋나는 질문 포함"}, "gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 5, "language": 5, "overall": 5, "issue": "리액트 렌더링 사이클, 테스트 도구의 역할 분담 등 실무 역량을 검증하기에 매우 적절한 질문"}, "local-qwen3-4b-instruct": {"grounding": 5, "coverage": 4, "depth": 3, "language": 4, "overall": 3, "issue": "질문이 다소 장황하며, 기술적 깊이를 파고들기보다는 표면적인 설명만을 요구함"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "questions", "case_id": "q-frontend-repo", "ratings": {"gw-solar-pro4": {"grounding": 5, "coverage": 5, "depth": 5, "language": 4, "overall": 5, "issue": "질문 문장이 100자를 넘어 다소 길고 한 질문에 두세 가지를 동시에 물음"}, "gw-llama-4-maverick": {"grounding": 5, "coverage": 4, "depth": 2, "language": 5, "overall": 3, "issue": "자료에 이미 적힌 사실을 되묻는 수준으로 후속 검증 깊이가 없음"}, "local-qwen3-4b-instruct": {"grounding": 4, "coverage": 4, "depth": 3, "language": 3, "overall": 3, "issue": "'효율성은 어떻게 평가되나요' 등 어색한 서술형 표현과 자료 재확인성 질문"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 5, "depth": 5, "language": 5, "overall": 5, "issue": "Lighthouse 질문을 CS_FUNDAMENTAL로 분류한 태깅이 다소 부정확"}, "gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 4, "language": 5, "overall": 4, "issue": "3번은 '캐싱 없던 시점의 성능 저하'를 전제하여 자료에 없는 사실을 가정"}, "gw-gpt-oss-120b": {"grounding": 3, "coverage": 3, "depth": 2, "language": 3, "overall": 2, "issue": "Zustand vs Redux 등 교과서형 질문 위주이고 조사 오류('Zustand을', 'URL를') 존재"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 3, "depth": 4, "language": 5, "overall": 4, "issue": "오프라인 동기화 주제에 2문항이 몰려 주제 분산이 약함"}, "local-qwen3.5-4b": {"grounding": 4, "coverage": 3, "depth": 4, "language": 3, "overall": 3, "issue": "TECHNICAL 모드인데 BEHAVIORAL 문항 포함, 숫자 띄어쓰기('2000 개') 어색"}, "local-ax4-light": {"grounding": 2, "coverage": 2, "depth": 2, "language": 3, "overall": 2, "issue": "없는 자기소개서를 근거로 팀 갈등 질문을 지어내고 테스트와 Lighthouse 개선을 잘못 연결"}}, "n_candidates": 9} +{"judge": "gemini-3.1-pro-preview", "suite": "questions", "case_id": "q-infra-dba-multi", "ratings": {"gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 5, "language": 4, "overall": 4, "issue": "질문의 깊이는 훌륭하나 길이가 다소 길어(110~130자) 간결성이 떨어짐"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 5, "depth": 4, "language": 5, "overall": 5, "issue": "없음"}, "gw-solar-pro4": {"grounding": 2, "coverage": 5, "depth": 5, "language": 2, "overall": 2, "issue": "이력서에 없는 내용(우선순위 충돌)을 지어내어 질문했으며, 질문 길이가 지나치게 긺(최대 180자)"}, "local-qwen3-4b-instruct": {"grounding": 5, "coverage": 5, "depth": 4, "language": 5, "overall": 4, "issue": "무난하고 깔끔하나 일부 질문의 변별력이 살짝 아쉬움"}, "gw-llama-4-maverick": {"grounding": 5, "coverage": 5, "depth": 2, "language": 3, "overall": 2, "issue": "질문이 '효과는?', '장점은?' 수준으로 너무 단조롭고 깊이가 얕음"}, "local-qwen3.5-4b": {"grounding": 2, "coverage": 4, "depth": 3, "language": 4, "overall": 2, "issue": "이력서에 근거하지 않은 일반적인 인성/경험 질문(의견 충돌, 가장 큰 성취)이 포함됨"}, "gw-gpt-oss-120b": {"grounding": 5, "coverage": 5, "depth": 3, "language": 4, "overall": 3, "issue": "질문이 다소 평이하고 '설명해 주세요' 식의 단순 나열이 많아 변별력이 낮음"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 5, "depth": 5, "language": 5, "overall": 5, "issue": "없음"}}, "n_candidates": 8} +{"judge": "claude-opus-5", "suite": "questions", "case_id": "q-infra-dba-multi", "ratings": {"gw-solar-pro4": {"grounding": 5, "coverage": 4, "depth": 5, "language": 3, "overall": 4, "issue": "모든 질문이 120자 이상으로 과도하게 길고 다중 질문이 겹쳐 면접 발화로 부적합"}, "local-qwen3-4b-instruct": {"grounding": 5, "coverage": 4, "depth": 3, "language": 4, "overall": 3, "issue": "이력서 문구를 되묻는 '이유는 무엇인가요' 수준이 많아 변별력이 약함"}, "gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 5, "language": 4, "overall": 5, "issue": "'궁금합니다' 오타와 일부 질문 길이 초과"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 4, "depth": 4, "language": 5, "overall": 4, "issue": "workspace의 '보안 이점'처럼 전제가 다소 어긋난 유도성 질문 포함"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 4, "depth": 4, "language": 5, "overall": 4, "issue": "근거 인용이 원문 통째로 붙어 target_evidence 정밀도가 낮고 후속 압박 깊이는 평범"}, "local-qwen3.5-4b": {"grounding": 3, "coverage": 3, "depth": 3, "language": 2, "overall": 2, "issue": "6문항 중 2개가 근거 없는 상투적 질문이고 '2.3 초/40 분' 등 띄어쓰기·용어 오류 다수"}, "gw-gpt-oss-120b": {"grounding": 4, "coverage": 4, "depth": 3, "language": 5, "overall": 3, "issue": "이력서 성과를 요약 설명하라는 개괄형이 많아 깊이 파고드는 압박이 부족"}, "gw-llama-4-maverick": {"grounding": 3, "coverage": 3, "depth": 2, "language": 3, "overall": 2, "issue": "'~작업들과 그 효과는?' 식 이력서 복창 질문으로 역량 변별이 거의 불가"}}, "n_candidates": 8} +{"judge": "gemini-3.1-pro-preview", "suite": "questions", "case_id": "q-long-context-p90", "ratings": {"gw-gpt-oss-120b": {"grounding": 4, "coverage": 2, "depth": 3, "language": 4, "overall": 2, "issue": "최근 받은 질문과 겹치는 주제(중복 주문)의 질문이 포함됨."}, "gw-llama-4-maverick": {"grounding": 4, "coverage": 1, "depth": 3, "language": 4, "overall": 1, "issue": "최근 받은 질문 중복 및 백엔드 직군임에도 프론트엔드(react-window) 질문이 포함됨."}, "local-qwen3-4b-instruct": {"grounding": 4, "coverage": 2, "depth": 3, "language": 4, "overall": 2, "issue": "최근 받은 질문(결제 콜백 지연)과 중복되는 질문이 다수 포함됨."}, "gw-solar-pro4": {"grounding": 4, "coverage": 2, "depth": 4, "language": 1, "overall": 1, "issue": "질문이 80자 내외 조건을 크게 위반하여 너무 길고, 최근 받은 질문과 중복됨."}, "gw-gemma-4-31b": {"grounding": 4, "coverage": 5, "depth": 4, "language": 5, "overall": 4, "issue": "이력서 상 결제 지연에 사용된 Outbox 패턴을 Kafka 도입과 단정지어 연결한 약간의 비약이 있음."}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 2, "depth": 4, "language": 4, "overall": 2, "issue": "최근 받은 질문(정산 배치 성능 개선)과 중복되는 질문이 포함됨."}, "gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 5, "language": 5, "overall": 5, "issue": "금지된 질문을 잘 피하고 실무적인 깊이가 돋보이는 훌륭한 질문 세트."}}, "n_candidates": 7} +{"judge": "claude-opus-5", "suite": "questions", "case_id": "q-long-context-p90", "ratings": {"gw-gemini-3.1-pro": {"grounding": 5, "coverage": 4, "depth": 5, "language": 5, "overall": 4, "issue": "1번(커밋-발행 원자성)은 사실상 Outbox 답을 유도해 금지된 최근 질문과 주제가 겹칠 위험이 있음"}, "gw-llama-4-maverick": {"grounding": 3, "coverage": 2, "depth": 3, "language": 4, "overall": 3, "issue": "BACKEND/TECHNICAL인데 5번이 react-window·INP 프론트엔드 질문이고 1번은 '고려 사항은?'식 막연한 질문"}, "gw-gpt-oss-120b": {"grounding": 3, "coverage": 3, "depth": 2, "language": 4, "overall": 2, "issue": "2번은 스택 나열에만 근거한 교과서 질문, 3·5번은 멱등키/중복주문 금지 주제 재사용에 격리수준 전제까지 오류적"}, "gw-solar-pro4": {"grounding": 4, "coverage": 2, "depth": 4, "language": 2, "overall": 2, "issue": "3번이 금지된 멱등키+Outbox 질문과 거의 동일하고, 모든 문항이 3중 복합·150자 이상으로 실제 발화 불가"}, "local-qwen3-4b-instruct": {"grounding": 4, "coverage": 3, "depth": 3, "language": 4, "overall": 3, "issue": "2·3번이 멱등키·중복주문 금지 주제와 겹치고 1·4번이 모두 재고 동기화라 주제 분산이 부족"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 4, "depth": 4, "language": 4, "overall": 4, "issue": "3번 정산 배치 병목 질문이 금지된 '5시간→40분' 질문과 주제가 사실상 중복"}, "gw-gemma-4-31b": {"grounding": 4, "coverage": 3, "depth": 4, "language": 5, "overall": 4, "issue": "1번이 Outbox 구현을 직접 물어 금지 질문과 중복이며 해당 근거에는 Outbox 언급이 없어 evidence 불일치"}}, "n_candidates": 7} +{"judge": "gemini-3.1-pro-preview", "suite": "questions", "case_id": "q-personality-coverletter", "ratings": {"local-qwen3.5-4b": {"grounding": 4, "coverage": 3, "depth": 3, "language": 4, "overall": 3, "issue": "DB 마이그레이션 관련 질문이 중복되어 출제됨"}, "local-ax4-light": {"grounding": 4, "coverage": 2, "depth": 3, "language": 3, "overall": 2, "issue": "DB 관련 질문이 3개나 중복되며, 한 문항에 여러 질문이 섞여 있어 산만함"}, "gw-solar-pro4": {"grounding": 4, "coverage": 4, "depth": 5, "language": 2, "overall": 3, "issue": "질문의 깊이는 매우 훌륭하나, 길이가 너무 길어(150자 이상) 구두 면접용으로 부적합함"}, "gw-gemini-3.1-pro": {"grounding": 5, "coverage": 5, "depth": 4, "language": 4, "overall": 4, "issue": "PERSONALITY 모드에 맞게 행동 면접 위주로 잘 구성되었으나 기술적 꼬리질문이 다소 부족함"}, "gw-llama-4-maverick": {"grounding": 4, "coverage": 4, "depth": 2, "language": 4, "overall": 2, "issue": "질문이 너무 짧고 단답형을 유도하여 지원자의 역량을 변별하기 어려움"}, "gw-gpt-oss-120b": {"grounding": 4, "coverage": 4, "depth": 3, "language": 4, "overall": 3, "issue": "질문이 전반적으로 평이하고 교과서적인 수준에 머무름"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 5, "depth": 5, "language": 5, "overall": 5, "issue": "자소서의 맥락을 정확히 짚어내며, 구체적이고 변별력 있는 질문들로 훌륭하게 구성됨"}, "local-qwen3-4b-instruct": {"grounding": 3, "coverage": 4, "depth": 3, "language": 4, "overall": 3, "issue": "자소서에 언급되지 않은 내용(구조적 개선)을 기정사실화하여 묻는 질문이 포함됨"}, "gw-gemini-3.5-flash-lite": {"grounding": 5, "coverage": 5, "depth": 4, "language": 5, "overall": 4, "issue": "PERSONALITY 모드에 적합한 좋은 질문들이나, G 후보에 비해 날카로움이 약간 부족함"}}, "n_candidates": 9} +{"judge": "claude-opus-5", "suite": "questions", "case_id": "q-personality-coverletter", "ratings": {"local-qwen3.5-4b": {"grounding": 4, "coverage": 3, "depth": 3, "language": 3, "overall": 3, "issue": "PERSONALITY 모드인데 기술 심화 질문이 섞이고 4·5번이 동일 실패 경험으로 중복됨"}, "gw-gemma-4-31b": {"grounding": 5, "coverage": 4, "depth": 4, "language": 5, "overall": 4, "issue": "인성 모드임에도 TECH_CHOICE·격리수준 설정 질문이 포함되어 모드 적합도가 약간 흐트러짐"}, "gw-solar-pro4": {"grounding": 4, "coverage": 3, "depth": 4, "language": 2, "overall": 3, "issue": "질문이 3~4문항 결합된 장문이고 5번은 근거 '(없음)'인 교과서형 CS 질문"}, "gw-gpt-oss-120b": {"grounding": 3, "coverage": 3, "depth": 2, "language": 3, "overall": 2, "issue": "누구나 답할 수 있는 일반 질문 수준이고 '불만' 등 표현 오류, 5번은 근거가 빈약한 교과서 질문"}, "local-ax4-light": {"grounding": 3, "coverage": 3, "depth": 3, "language": 3, "overall": 3, "issue": "한 문항에 질문 3개를 묶고 3·5번이 같은 DB 이전 주제로 중복, 근거 문장을 임의로 변형"}, "local-qwen3-4b-instruct": {"grounding": 4, "coverage": 3, "depth": 3, "language": 3, "overall": 3, "issue": "인성 모드에 격리수준 설명 등 지식형 질문이 들어가고 5번은 자료에 없는 '구조적 개선'을 전제"}, "gw-llama-4-maverick": {"grounding": 4, "coverage": 3, "depth": 2, "language": 3, "overall": 3, "issue": "자소서에 이미 답이 적힌 사실 확인형 질문이 많아 변별력이 낮고 '의사소결정' 오타"}, "gw-gemini-3.1-pro": {"grounding": 5, "coverage": 4, "depth": 4, "language": 4, "overall": 4, "issue": "전부 인성 질문으로 모드 적합하나 5번은 전형적인 비전 질문이고 문장이 다소 길다"}, "gw-gemini-3.5-flash-lite": {"grounding": 4, "coverage": 4, "depth": 3, "language": 4, "overall": 4, "issue": "1번은 내용상 기술 심화인데 BEHAVIORAL로 태깅되고 5번은 일반적 원칙 질문에 머묾"}}, "n_candidates": 9} diff --git a/docs/research/llm-eval-2026-09/gpu-placement.log b/docs/research/llm-eval-2026-09/gpu-placement.log new file mode 100644 index 0000000..69a204c --- /dev/null +++ b/docs/research/llm-eval-2026-09/gpu-placement.log @@ -0,0 +1,16 @@ +16:43:38 stackup-eval-qwen3-4b-instruct-8k try1 :: stackup-eval-qwen3-4b-instruct-8k:latest 81f2e7df722a 4.2 GB 100% GPU 8192 4 minutes from now +16:57:40 qwen3-4b-instruct after-run :: stackup-eval-qwen3-4b-instruct-8k:latest 81f2e7df722a 4.2 GB 100% GPU 8192 4 minutes from now +16:57:40 qwen3-4b-instruct cuda-init-failures-last-40m: 2 +16:57:49 stackup-eval-qwen3.5-4b-8k try1 :: stackup-eval-qwen3.5-4b-8k:latest dd1117801f2c 6.4 GB 29%/71% CPU/GPU 8192 4 minutes from now +17:22:06 qwen3.5-4b after-run :: stackup-eval-qwen3.5-4b-8k:latest dd1117801f2c 6.4 GB 29%/71% CPU/GPU 8192 4 minutes from now +17:22:06 qwen3.5-4b cuda-init-failures-last-40m: 0 +17:22:12 stackup-eval-kanana2-3b-8k try1 :: stackup-eval-kanana2-3b-8k:latest 552c00606745 3.4 GB 100% GPU 8192 4 minutes from now +18:00:32 kanana2-3b after-run :: stackup-eval-kanana2-3b-8k:latest 552c00606745 3.4 GB 100% GPU 8192 4 minutes from now +18:00:32 kanana2-3b cuda-init-failures-last-40m: 0 +18:00:38 stackup-eval-midm2-mini-8k try1 :: stackup-eval-midm2-mini-8k:latest 9b4435b118b1 3.6 GB 100% GPU 8192 4 minutes from now +18:07:47 midm2-mini after-run :: stackup-eval-midm2-mini-8k:latest 9b4435b118b1 3.6 GB 100% GPU 8192 4 minutes from now +18:07:47 midm2-mini cuda-init-failures-last-40m: 0 +18:07:48 gemma4-e2b CREATE FAILED (gemma4:e2b-it-qat) +18:07:56 stackup-eval-ax4-light-8k try1 :: stackup-eval-ax4-light-8k:latest f112ea3ec3d1 5.3 GB 6%/94% CPU/GPU 8192 4 minutes from now +18:23:39 ax4-light after-run :: stackup-eval-ax4-light-8k:latest f112ea3ec3d1 5.3 GB 6%/94% CPU/GPU 8192 4 minutes from now +18:23:39 ax4-light cuda-init-failures-last-40m: 0 diff --git a/docs/research/llm-eval-2026-09/raw/gw-gemini-3.1-pro.jsonl b/docs/research/llm-eval-2026-09/raw/gw-gemini-3.1-pro.jsonl new file mode 100644 index 0000000..f3025fd --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/gw-gemini-3.1-pro.jsonl @@ -0,0 +1,10 @@ +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "자기소개에서 언급하신 Outbox 패턴 구현 시, Outbox 테이블의 이벤트를 Kafka로 발행하는 과정에서 발생할 수 있는 메시지 유실이나 중복 발행 문제는 어떻게 제어하셨나요?", "job_category": "BACKEND", "target_evidence": "결제 콜백 지연으로 생긴 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결한 경험이 가장 기억에 남습니다.", "expected_signal": "Outbox 패턴의 Polling/Tailing 방식 이해, At-least-once 전달 보장 및 Consumer 측의 멱등성 처리 경험을 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "주문 서비스를 MSA로 분리하며 DB도 나누셨는데, 기존 모놀리식에서 Join으로 처리하던 타 도메인과의 데이터 참조 및 정합성 유지는 어떤 방식으로 해결하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL)", "expected_signal": "API Composition, CQRS, 또는 이벤트 기반 데이터 복제 등 분산 환경에서의 데이터 조회 및 정합성 유지 전략에 대한 고민과 선택 이유를 제시해야 합니다."}, {"category": "TECH_CHOICE", "question": "재고 동기화 시 낙관적 락에서 분산 락으로 전환하셨는데, 기존 낙관적 락 환경에서 어떤 성능적/구조적 한계를 겪으셨고 Redis 분산 락은 어떻게 구현하셨나요?", "job_category": "BACKEND", "target_evidence": "동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "충돌이 잦은 환경에서 낙관적 락의 재시도 오버헤드를 이해하고, Redisson 등 분산 락 라이브러리 활용 및 락 타임아웃 처리 경험을 설명해야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 시간을 5시간에서 40분으로 단축하셨는데, 인덱스 재설계와 QueryDSL 튜닝 과정에서 가장 병목이 심했던 쿼리의 실행 계획은 어떻게 개선하셨나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "실행 계획(Explain) 분석 능력, 커버링 인덱스 활용, N+1 문제 해결 등 구체적인 DB 튜닝 경험과 원리 이해도를 보여주어야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "재고 관리에 Redis Write-behind 전략을 적용하셨는데, Redis 인스턴스 장애 시 메모리에만 있던 재고 데이터가 유실될 위험은 어떻게 대비하셨나요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind", "expected_signal": "Redis 영속성(RDB/AOF) 설정, 클러스터링/복제 구조에 대한 이해, 또는 데이터 유실 시 DB 기반 복구 전략을 설명할 수 있어야 합니다."}], "latency_sec": 24.695, "in_tokens": 2857, "out_tokens": 820} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "일정 타임라인에 react-window를 도입해 INP를 480ms에서 120ms로 개선하셨는데, 가상화가 INP 지표 개선에 구체적으로 어떤 영향을 미쳤나요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: 'virtualize timeline, INP 480ms -> 120ms')", "expected_signal": "브라우저의 렌더링 파이프라인을 이해하고, DOM 노드 수 감소가 메인 스레드 블로킹을 줄여 사용자 입력 반응성(INP)을 어떻게 개선하는지 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "오프라인 편집 시 Dexie로 낙관적 업데이트를 구현하셨습니다. 온라인 복귀 시 동기화 과정에서 발생할 수 있는 충돌은 어떻게 처리했으며, CRDT를 검토하신 이유는 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: 'CRDT 검토 필요')", "expected_signal": "오프라인 상태 관리와 데이터 동기화의 복잡성을 이해하고, last-write-wins의 한계와 CRDT가 해결할 수 있는 다중 클라이언트 동시성 문제를 인지하고 있는지 확인합니다."}, {"category": "CS_FUNDAMENTAL", "question": "카카오맵 마커 500개를 렌더링할 때 useMemo로 좌표 변환을 캐싱하셨습니다. 리액트의 렌더링 사이클 관점에서 캐싱이 없었을 때 발생했던 성능 저하의 원인은 무엇이었나요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "React의 리렌더링 조건과 비용이 큰 연산이 메인 스레드에 미치는 영향을 이해하고, 메모이제이션을 통한 불필요한 연산 방지 원리를 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 서버를 거치지 않고 S3 presigned URL을 사용해 클라이언트에서 직접 WebP로 변환해 업로드한 아키텍처의 장단점은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "클라이언트 사이드 이미지 처리의 장점(서버 부하 감소, 네트워크 대역폭 절약)과 단점(클라이언트 기기 성능 의존성, 배터리 소모)을 트레이드오프 관점에서 설명할 수 있어야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "Vitest로 42개의 단위 테스트를, Playwright로 6개의 E2E 테스트를 작성하셨습니다. 두 테스트 도구의 역할을 어떻게 나누었으며, E2E 테스트의 대상으로 삼은 핵심 시나리오는 무엇이었나요?", "job_category": "FRONTEND", "target_evidence": "Vitest 단위 테스트 42개, Playwright E2E 6개", "expected_signal": "단위 테스트와 E2E 테스트의 목적 차이를 명확히 이해하고, 오프라인 동기화나 일정 추가 등 프로젝트의 핵심 비즈니스 로직을 테스트 전략에 어떻게 반영했는지 확인합니다."}], "latency_sec": 24.461, "in_tokens": 2659, "out_tokens": 942} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "EKS 환경에서 HPA 임계치를 CPU 70%로 설정하셨는데, 이 수치를 도출하게 된 테스트 과정이나 근거는 무엇인가요? 또한 CronJob을 통한 사전 스케일아웃과 HPA가 충돌한 적은 없었나요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "부하 테스트 경험, HPA와 Custom Scaling 로직 간의 상호작용 및 파드 라이프사이클에 대한 깊은 이해도를 보여야 합니다."}, {"category": "TECH_CHOICE", "question": "Terraform workspace로 환경을 분리하고 ArgoCD로 배포를 자동화하셨는데, 인프라 변경사항(Terraform)과 애플리케이션 배포(ArgoCD) 간의 의존성이나 적용 순서는 어떻게 관리하셨나요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리 / ArgoCD GitOps 도입", "expected_signal": "IaC와 GitOps 파이프라인 통합 시 발생하는 상태 불일치나 인프라-앱 간의 의존성 문제 해결 능력을 확인합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 슬로우 쿼리 개선 시 거래내역 테이블을 월 단위로 파티셔닝하셨는데, 파티셔닝 도입 전후로 애플리케이션 측의 쿼리 수정이 필요했는지, 그리고 기존 데이터 마이그레이션은 어떻게 진행하셨는지 궁금합니다.", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "대용량 테이블 파티셔닝 전략, 무중단 또는 최소중단 데이터 마이그레이션 경험 및 DB-App 간의 영향도 파악 능력을 평가합니다."}, {"category": "CS_FUNDAMENTAL", "question": "PostgreSQL 튜닝 과정에서 autovacuum을 조정하셨는데, PostgreSQL의 MVCC 구조상 autovacuum이 제때 수행되지 않으면 DB 성능에 구체적으로 어떤 악영향을 미치게 되나요?", "job_category": "DBA", "target_evidence": "autovacuum 튜닝", "expected_signal": "PostgreSQL의 MVCC 아키텍처와 Dead Tuple 누적, Transaction ID Wraparound 등 핵심 내부 동작 원리에 대한 이해도를 확인합니다."}, {"category": "BEHAVIORAL", "question": "작년 3월 RDS 스토리지 풀 장애로 40분간 쓰기 중단이 발생했을 때, 당시 상황을 인지하고 복구하기까지 본인이 취한 구체적인 행동과 이 장애를 통해 팀의 모니터링 프로세스가 어떻게 개선되었는지 말씀해 주세요.", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "위기 상황에서의 대처 능력(STAR), 근본 원인 분석(RCA) 및 재발 방지 대책 수립 과정에서의 주도성과 성찰을 보여야 합니다."}, {"category": "BEHAVIORAL", "question": "배포 리드타임을 1일에서 30분으로 단축하는 과정에서, 기존 배포 방식을 고수하려는 개발팀이나 유관 부서의 저항은 없었나요? 있었다면 어떻게 설득하고 협업을 이끌어내셨는지 경험을 공유해 주세요.", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "새로운 기술이나 프로세스 도입 시 발생하는 조직 내 갈등 해결 능력, 커뮤니케이션 및 변화 관리(Change Management) 역량을 평가합니다."}], "latency_sec": 25.843, "in_tokens": 2651, "out_tokens": 1081} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "학사 공지 알림 봇 운영 중 크롤러가 멈춰 항의를 받았을 때, 구체적으로 어떻게 대처하셨고 이 경험이 백엔드 개발자로서의 책임감에 어떤 영향을 미쳤는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "문제 발생 시의 구체적인 행동(대처)과 이를 통해 얻은 서비스 안정성에 대한 본인만의 가치관(결과/배운 점)을 제시해야 합니다."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 본인의 방식을 고집해 팀원과 감정이 상했던 상황을 설명해 주시고, 이후 '대안 두 가지를 비교하는 방식'으로 바꾸면서 팀의 소통 방식에 어떤 변화가 있었는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "갈등 상황에서의 본인 잘못을 객관적으로 인지하고, 개선된 소통 방식을 적용한 후의 구체적인 결과(팀워크 향상 등)를 설명해야 합니다."}, {"category": "BEHAVIORAL", "question": "프론트엔드와의 API 스펙 해석 차이로 통합이 지연되었을 때, OpenAPI 명세와 Mock 서버 도입을 제안하셨습니다. 당시 팀원들을 어떻게 설득하여 새로운 방식을 도입했는지 그 과정과 결과를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "문제 상황에서 주도적으로 해결책을 제시(Action)하고 팀원을 설득한 커뮤니케이션 과정과 정량적 성과(Result)를 보여야 합니다."}, {"category": "BEHAVIORAL", "question": "알림 봇의 SQLite 동시 쓰기 락 문제로 원인을 찾는 데 3일이 걸렸다고 하셨습니다. 3일 동안 포기하지 않고 문제를 추적했던 구체적인 과정과, 이 실패 경험을 통해 기술적으로 어떤 성장을 이루었는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "어려운 문제에 직면했을 때의 끈기 있는 디버깅 과정(Action)과 실패를 기술적 학습(PostgreSQL, 트랜잭션 격리 수준)으로 승화시킨 결과(Result)를 제시해야 합니다."}, {"category": "BEHAVIORAL", "question": "'멈추지 않는 서비스'의 중요성을 깨닫고, 팀 내 소통 방식을 개선하며, DB 락 문제를 해결한 경험들이 있습니다. 이러한 경험들을 바탕으로, 앞으로 백엔드 개발자로서 어떤 동료로 성장하고 싶은지 본인의 비전을 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다. / 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "과거의 경험(안정성 중시, 유연한 소통, 문제 해결력)을 바탕으로 본인이 지향하는 개발자로서의 명확한 비전과 팀 내 역할을 제시해야 합니다."}], "latency_sec": 24.79, "in_tokens": 2642, "out_tokens": 981} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "주문 서비스를 MSA로 분리하며 Kafka를 도입하셨는데, DB 트랜잭션 커밋과 이벤트 발행 간의 원자성은 어떻게 보장하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "분산 환경에서 트랜잭션과 메시지 발행의 정합성을 맞추기 위한 패턴(예: Outbox 패턴 재활용, 2PC 등)에 대한 이해와 실제 적용 경험을 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "대용량 트래픽 정합성에 관심이 많다고 하셨는데, 재고 동기화 시 낙관적 락에서 분산 락으로 제어 방식을 전환하신 구체적인 배경은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "낙관적 락의 충돌 재시도 비용과 분산 락의 네트워크/인프라 오버헤드를 비교 분석하고, 트래픽 특성에 맞춰 기술을 변경한 타당한 근거를 제시해야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "재고 관리에 Redis Write-behind 패턴을 적용하셨는데, Redis 장애 시 DB에 동기화되지 않은 데이터 유실은 어떻게 방어하셨나요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind", "expected_signal": "비동기 쓰기 방식의 치명적 단점인 데이터 유실 가능성을 인지하고 있으며, AOF/RDB 백업이나 메시지 큐 활용 등 구체적인 장애 대응 전략을 고민했는지 확인합니다."}, {"category": "CS_FUNDAMENTAL", "question": "자소서에 언급된 알림 봇 개발 시, SQLite 동시 쓰기 문제를 해결하기 위해 PostgreSQL의 어떤 트랜잭션 격리 수준을 적용하셨나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로... PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "RDBMS의 트랜잭션 격리 수준(Read Committed, Repeatable Read 등)의 개념을 정확히 이해하고, 겪었던 동시성 문제에 알맞은 수준을 선택했는지 설명해야 합니다."}, {"category": "BEHAVIORAL", "question": "OpenAPI와 Mock 서버 도입 후, 개발 도중 API 스펙이 변경될 때 프론트엔드와의 동기화 및 하위 호환성은 어떻게 관리하셨나요?", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "단순히 도구를 도입한 것을 넘어, 스펙 변경이라는 실제 협업 과정의 병목을 어떻게 소통하고 기술적으로(버전 관리 등) 해결했는지 구체적인 행동(Action)이 드러나야 합니다."}], "latency_sec": 24.867, "in_tokens": 3995, "out_tokens": 864} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "자기소개에서 언급하신 Outbox 패턴 도입 시, 주문 트랜잭션 커밋과 Outbox 테이블 저장, 그리고 Kafka 이벤트 발행 간의 원자성은 구체적으로 어떻게 보장하셨나요?", "job_category": "BACKEND", "target_evidence": "결제 콜백 지연으로 생긴 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결한 경험이 가장 기억에 남습니다.", "expected_signal": "Transactional Outbox 패턴의 핵심인 로컬 트랜잭션 바인딩과 메시지 릴레이(Polling 또는 CDC) 방식을 정확히 이해하고 구현했는지 확인합니다."}, {"category": "TECH_CHOICE", "question": "실시간 재고 동기화 시 낙관적 락에서 분산 락으로 전환하셨는데, 기존 낙관적 락 환경에서 어떤 구체적인 한계나 충돌 이슈를 겪고 전환을 결정하셨나요?", "job_category": "BACKEND", "target_evidence": "동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "트래픽 집중 시 낙관적 락의 잦은 충돌로 인한 재시도 오버헤드 증가 문제를 인지하고, Redis 기반 분산 락의 장단점을 비교하여 설명할 수 있는지 확인합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "주문 서비스를 MSA로 분리하며 DB도 나누셨는데, 기존 모놀리식에서 Join으로 쉽게 처리하던 타 도메인과의 복합 데이터 조회는 어떤 방식으로 해결하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식을 MSA로 전환하면서 주문 서비스를 분리했고 / DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "DB 분리 후 발생하는 데이터 조인 문제에 대해 API Composition, CQRS, 또는 이벤트 기반 데이터 복제 등 실무적인 해결책과 트레이드오프를 이해하고 있는지 확인합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 시간을 5시간에서 40분으로 단축할 때 인덱스 재설계와 QueryDSL 튜닝을 진행하셨는데, 당시 가장 큰 성능 병목을 일으켰던 쿼리 패턴은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "대용량 데이터 처리 시 발생하는 슬로우 쿼리 원인(예: 부적절한 풀 스캔, N+1 문제 등)을 분석하고 인덱스 및 청크 처리를 통해 해결한 구체적 과정을 확인합니다."}, {"category": "CS_FUNDAMENTAL", "question": "대용량 트래픽에서 데이터 정합성을 강조하셨는데, Kafka 이벤트 구독 시 컨슈머 장애나 네트워크 지연으로 인한 메시지 중복 소비 문제는 어떻게 방어하셨나요?", "job_category": "BACKEND", "target_evidence": "대용량 트래픽에서도 데이터 정합성을 지키는 서버를 만드는 데 관심이 많습니다. / Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "Kafka의 At-Least-Once 전달 특성을 이해하고, 컨슈머 측에서 멱등성을 보장하기 위한 설계(DB 유니크 키 제약조건, 상태 체크 등)를 설명할 수 있는지 확인합니다."}], "latency_sec": 26.517, "in_tokens": 2857, "out_tokens": 878} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "일정 타임라인에 react-window를 도입해 INP를 480ms에서 120ms로 개선하셨는데, 가상화 적용 시 스크롤 위치 유지나 동적 높이 아이템 처리에서 겪은 어려움은 없었나요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "가상화 라이브러리의 한계(동적 높이 계산 등)를 이해하고 이를 어떻게 우회하거나 해결했는지 구체적인 경험을 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "오프라인 편집 시 Dexie를 사용해 낙관적 업데이트를 구현하셨습니다. 온라인 복귀 시 last-write-wins 방식으로 동기화할 때 발생할 수 있는 데이터 유실 문제는 어떻게 처리하셨나요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "오프라인 동기화의 충돌 해결 전략과 last-write-wins의 한계를 이해하고, 주석에 남긴 CRDT 등 대안에 대한 고민을 논리적으로 설명할 수 있어야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "카카오맵 마커 500개를 렌더링할 때 useMemo로 좌표 변환을 캐싱하셨는데, 마커 데이터가 빈번하게 업데이트되는 상황이었다면 useMemo의 의존성 배열 관리를 어떻게 최적화하셨을 건가요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "React의 렌더링 사이클과 메모이제이션(useMemo)의 동작 원리를 정확히 이해하고, 불필요한 재계산을 방지하는 방법을 제시할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 서버를 거치지 않고 S3 Presigned URL을 사용하며 클라이언트에서 WebP로 변환하셨습니다. 클라이언트에서 이미지 변환 작업을 수행할 때 브라우저 메인 스레드 블로킹 문제는 없었나요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "클라이언트 사이드 이미지 처리의 장단점(서버 부하 감소 vs 브라우저 리소스 소모)을 이해하고, Web Worker 등의 최적화 방안을 고려했는지 확인합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "Vitest와 Playwright를 함께 사용하셨는데, 프론트엔드 테스트 전략을 세울 때 단위 테스트와 E2E 테스트의 역할을 어떻게 나누셨고, 가장 작성하기 까다로웠던 테스트 케이스는 무엇이었나요?", "job_category": "FRONTEND", "target_evidence": "Vitest 단위 테스트 42개, Playwright E2E 6개", "expected_signal": "프론트엔드 테스트 피라미드를 이해하고, 각 테스트 도구의 목적에 맞게 효율적으로 테스트 코드를 작성한 경험과 트러블슈팅 과정을 설명할 수 있어야 합니다."}], "latency_sec": 22.465, "in_tokens": 2659, "out_tokens": 929} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "월급날 트래픽 피크를 대비해 HPA 외에 CronJob으로 사전 스케일아웃을 구현하셨는데, HPA만으로는 대응이 어려웠던 구체적인 병목 지점이나 지연 요소는 무엇이었나요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "HPA의 스케일링 지연(Cold start 등) 한계를 이해하고, 비즈니스 특성(월급날)에 맞춘 선제적 대응 논리를 설명할 수 있는지 확인합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "거래내역 테이블을 월 단위로 파티셔닝하여 슬로우 쿼리를 개선하셨습니다. 기존 단일 테이블 구조에서 발생했던 성능 저하의 근본 원인과 파티셔닝 후 쿼리 실행 계획의 변화를 설명해주세요.", "job_category": "DBA", "target_evidence": "복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할", "expected_signal": "대용량 데이터 조회 시 인덱스 효율 저하 및 I/O 병목을 이해하고, 파티셔닝을 통한 쿼리 플랜 개선 효과를 설명할 수 있는지 확인합니다."}, {"category": "TECH_CHOICE", "question": "Terraform으로 환경을 분리할 때 디렉토리 분리 방식 대신 Workspace를 선택하신 이유는 무엇인가요? 상태 파일(State) 관리 측면에서 겪은 장단점도 함께 말씀해주세요.", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "Terraform Workspace의 동작 원리와 상태 격리 방식을 이해하고, 실무 환경에서의 장단점을 비교 분석할 수 있는지 확인합니다."}, {"category": "BEHAVIORAL", "question": "RDS 스토리지 풀로 인한 쓰기 중단 장애를 겪으셨는데, 당시 장애 인지부터 복구까지 본인의 구체적인 행동과 이 경험을 통해 시스템적으로 개선한 점을 말씀해주세요.", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 상황에서의 침착한 대응 과정(행동)과 근본 원인 파악 후 자동화된 예방책(결과)을 도출하는 문제 해결 능력을 확인합니다."}, {"category": "CS_FUNDAMENTAL", "question": "ArgoCD를 도입하여 배포 시간을 크게 단축하셨습니다. 기존 Push 기반 배포와 비교할 때, ArgoCD의 Pull 기반 동기화 방식이 쿠버네티스 환경에서 가지는 구조적 이점은 무엇인가요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "GitOps의 핵심 개념인 Pull 모델과 선언적 상태 동기화(Reconciliation)의 원리를 이해하고 보안 및 운영 이점을 설명할 수 있는지 확인합니다."}, {"category": "TECH_CHOICE", "question": "PostgreSQL 슬로우 쿼리 개선 과정에서 autovacuum 튜닝을 진행하셨습니다. 당시 어떤 지표를 보고 튜닝이 필요하다고 판단하셨으며, 구체적으로 어떤 파라미터를 조정하셨나요?", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝...)", "expected_signal": "PostgreSQL의 MVCC 아키텍처와 Dead Tuple 발생 원리를 이해하고, 실무에서 autovacuum 관련 파라미터를 상황에 맞게 튜닝할 수 있는지 확인합니다."}], "latency_sec": 27.528, "in_tokens": 2651, "out_tokens": 1059} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "새벽에 크롤러가 멈춰 사용자들의 항의를 받았을 때, 당시 감정적인 대처와 실무적인 문제 해결을 어떻게 병행하셨나요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "위기 상황에서의 책임감, 스트레스 관리 능력 및 구체적인 후속 조치(재발 방지) 경험을 보여주어야 합니다."}, {"category": "BEHAVIORAL", "question": "API 명세 도입 시 본인의 방식을 고집해 팀원과 감정이 상했다고 하셨는데, 당시 갈등을 구체적으로 어떻게 풀고 관계를 회복하셨나요?", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "자신의 잘못을 인정하는 태도와 적극적인 소통을 통해 팀원과의 갈등을 원만하게 해결한 구체적인 행동(Action)이 드러나야 합니다."}, {"category": "BEHAVIORAL", "question": "OpenAPI와 Mock 서버 도입을 제안하셨을 때, 새로운 방식에 대한 프론트엔드 팀원의 거부감은 없었으며 어떻게 설득하셨나요?", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "상대방의 입장을 이해하고, 새로운 프로세스의 장점을 논리적으로 설명하여 팀의 동의를 이끌어낸 설득 과정이 포함되어야 합니다."}, {"category": "BEHAVIORAL", "question": "SQLite 락 문제를 찾는 데 3일이 걸렸다고 하셨는데, 그 기간 동안 어떤 가설을 세우고 검증했으며 멘탈 관리는 어떻게 하셨나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고...", "expected_signal": "장기화된 트러블슈팅 과정에서의 논리적인 접근법과, 포기하지 않고 끝까지 원인을 규명해낸 끈기를 보여주어야 합니다."}, {"category": "BEHAVIORAL", "question": "결정 전 대안 두 가지를 비교하는 원칙을 세우셨는데, 이 원칙을 실제 프로젝트에 적용해 더 나은 의사결정을 이끌어낸 다른 사례가 있나요?", "job_category": "BACKEND", "target_evidence": "이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "자신의 실패 경험으로부터 얻은 교훈을 내재화하여, 실제 다른 상황에서도 일관되게 적용하고 있는지(Result)를 확인해야 합니다."}], "latency_sec": 19.701, "in_tokens": 2642, "out_tokens": 825} +{"label": "gw-gemini-3.1-pro", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "자기소개에서 대용량 트래픽의 데이터 정합성을 강조하셨는데, 모놀리식에서 MSA로 전환하며 DB를 분리했을 때 분산 환경에서의 트랜잭션과 데이터 정합성은 어떻게 보장하셨나요?", "job_category": "BACKEND", "target_evidence": "자기소개: 대용량 트래픽에서도 데이터 정합성을 지키는 서버를 만드는 데 관심이 많습니다. / 이력서: 모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL)", "expected_signal": "분산 트랜잭션(Saga 패턴 등) 또는 이벤트 기반의 최종적 정합성(Eventual Consistency)에 대한 이해와 실제 적용 경험을 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "실시간 재고 동기화 시 동시성 제어를 위해 낙관적 락에서 분산 락으로 전환하셨는데, 기존 방식의 한계는 무엇이었으며 분산 락 구현 시 데드락이나 락 타임아웃 문제는 어떻게 해결하셨나요?", "job_category": "BACKEND", "target_evidence": "실시간 재고 동기화 (2024) - Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "낙관적 락의 충돌 빈도 증가에 따른 성능 저하를 인지하고, Redis(Redisson 등)를 활용한 분산 락의 안전한 해제 및 타임아웃 설정 경험을 제시해야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "자소서에 알림 봇의 동시 쓰기 문제로 PostgreSQL로 이전하며 트랜잭션 격리 수준을 학습했다고 하셨습니다. 당시 어떤 격리 수준을 선택했으며, 그로 인해 동시성 문제가 어떻게 해결되었는지 설명해 주시겠어요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. ... PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "PostgreSQL의 기본 격리 수준(Read Committed)과 동시 쓰기 상황에서의 동작 원리, 필요시 Repeatable Read 등 상위 수준 적용에 대한 이해를 보여야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "재고 동기화에 Redis 캐시와 DB write-behind 방식을 적용하셨는데, Redis 장애가 발생하거나 비동기 쓰기 지연 중 서버가 다운될 경우 데이터 유실을 막기 위한 복구 전략은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "실시간 재고 동기화 (2024) - Redis 기반 재고 캐시 + DB write-behind", "expected_signal": "Write-behind의 데이터 유실 리스크를 인지하고, Redis AOF/RDB 설정이나 메시지 큐를 활용한 안전한 영속화 전략을 제시할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "주문 서비스 분리 후 Kafka를 도입하셨는데, 주문/결제 도메인 특성상 메시지 유실이나 중복 처리가 치명적일 수 있습니다. Kafka의 어떤 설정(Acks, Offset 등)을 활용해 신뢰성을 확보하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입.", "expected_signal": "Acks=all 설정, 멱등성 프로듀서, 컨슈머의 수동 커밋 등 메시지 전달 보장(At-least-once 등)을 위한 구체적인 Kafka 설정 경험을 설명해야 합니다."}], "latency_sec": 24.613, "in_tokens": 3995, "out_tokens": 979} diff --git a/docs/research/llm-eval-2026-09/raw/gw-gemini-3.5-flash-lite.jsonl b/docs/research/llm-eval-2026-09/raw/gw-gemini-3.5-flash-lite.jsonl new file mode 100644 index 0000000..c9e7ca4 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/gw-gemini-3.5-flash-lite.jsonl @@ -0,0 +1,78 @@ +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "Outbox 테이블을 폴링하는 릴레이에서 발행 실패가 발생하면 데이터 정합성을 어떻게 보장하시나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.79, "ttft_sec": 5.659, "in_tokens": 7545, "out_tokens": 213} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "\"중복이 안 생기게 잘 처리했다\"고 하셨는데, 구체적으로 어떤 실패 케이스에서 멱등 키와 Outbox 패턴이 각각 어떤 역할을 했는지 설명해 주시겠어요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.843, "ttft_sec": 1.469, "in_tokens": 8274, "out_tokens": 325} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "그럼 PostgreSQL의 VACUUM이 어떤 역할을 하는지 알고 계신 범위에서 간략히 말씀해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.004, "ttft_sec": null, "in_tokens": 6665, "out_tokens": 213} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "그럼 React 18 이전 버전에서 비동기 이벤트 안의 상태 업데이트가 어떻게 처리되었는지 아시는 만큼 말씀해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.25, "ttft_sec": null, "in_tokens": 7992, "out_tokens": 300} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "CPU 사용량이 갑자기 높을 때 자동으로 늘려주는 HPA의 기준을 70%로 정한 이유와, 트래픽이 몰리기 전에 미리 서버를 늘려둔 이유를 각각 쉽게 설명해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.993, "ttft_sec": 1.637, "in_tokens": 8208, "out_tokens": 333} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "폴링 방식이라면 DB 부하를 줄이기 위해 주기나 배치 단위를 어떻게 설정하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 8.04, "ttft_sec": 7.519, "in_tokens": 6770, "out_tokens": 196} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "이력서에는 CPU 70%와 사전 스케일아웃 CronJob을 운영하셨다고 되어 있는데, 답변에서 메모리 50%와 HPA 단독 대응이라고 하신 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": 1.0}, "latency_sec": 2.074, "ttft_sec": 1.42, "in_tokens": 9900, "out_tokens": 330} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "인덱스 변경으로 900ms, 파티셔닝 후 180ms로 줄었다고 하셨는데, autovacuum 튜닝은 p95 단축에 각각 어느 정도 기여했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 1.828, "ttft_sec": 1.366, "in_tokens": 10614, "out_tokens": 343} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "항목 높이가 내용에 따라 다를 때 높이 캐시는 구체적으로 어떤 구조로 관리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.313, "ttft_sec": 1.824, "in_tokens": 10446, "out_tokens": 282} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "결정 전에 대안 두 개를 비교하는 방식을 도입하신 뒤, 실제로 팀원과의 소통이나 회의 분위기가 어떻게 달라졌는지 구체적인 사례를 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 1.981, "ttft_sec": 1.55, "in_tokens": 8598, "out_tokens": 300} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "크게 싸운 적이 없다고 하셨는데, 구체적으로 의견 충돌이 발생했던 상황과 본인이 취한 행동을 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.927, "ttft_sec": 1.66, "in_tokens": 8244, "out_tokens": 290} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "월 200건에서 3건으로 줄었다고 하셨는데, 레디스 분산 락을 도입하면서 발생한 성능 저하나 락 획득 실패 시의 예외 처리 비용은 어떻게 관리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.01, "ttft_sec": 1.356, "in_tokens": 9849, "out_tokens": 419} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "보상 이벤트가 유실되어 30분 이상 PENDING인 주문을 처리할 때, 스위퍼 배치가 재조회하는 과정에서 대상 데이터가 이미 다른 상태로 변경되었을 경우의 레이스 컨디션은 어떻게 방지하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.105, "ttft_sec": 1.407, "in_tokens": 12005, "out_tokens": 431} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "네트워크 요청이 40% 감소했다고 하셨는데, 구체적으로 어떤 화면이나 API에서 가장 큰 감소 효과가 나타났나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.343, "ttft_sec": 1.383, "in_tokens": 8328, "out_tokens": 295} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "유니크 제약을 걸어 두 번째 요청을 막는다고 하셨는데, DB 부하가 몰릴 때 유니크 제약 충돌로 인한 락 경합은 어떻게 관리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.157, "ttft_sec": 1.507, "in_tokens": 9054, "out_tokens": 311} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "중복 주문이 안 생기게 잘 처리했다고 하셨는데, 구체적으로 멱등 키와 Outbox 패턴이 각각 어떤 실패 케이스를 막는지 기술적인 동작 방식을 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 0.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.03, "ttft_sec": 1.663, "in_tokens": 8274, "out_tokens": 318} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "오래 열린 트랜잭션이 발생할 때 왜 VACUUM이 정상 동작하지 못하는지, 트랜잭션 ID 기준 관점에서 다시 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.823, "ttft_sec": null, "in_tokens": 7998, "out_tokens": 322} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "그렇다면 상태 업데이트가 일어날 때 리렌더링을 최적화하기 위해 리액트 내부적으로 사용하는 메커니즘에 대해 다른 아시는 부분이 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.991, "ttft_sec": null, "in_tokens": 7992, "out_tokens": 301} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "CPU 사용량이 70%를 넘을 때 자동으로 서버를 늘리는 기준을 정한 이유와, 트래픽이 몰릴 것을 미리 알고 미리 서버를 늘려둔 이유를 각각 쉽게 설명해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 2.147, "ttft_sec": 1.785, "in_tokens": 8208, "out_tokens": 322} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "폴링 방식이라면 DB 부하를 줄이기 위해 주기나 락(Lock) 처리는 어떻게 설계하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.852, "ttft_sec": 1.489, "in_tokens": 6770, "out_tokens": 201} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "이력서에는 CPU 70%와 사전 스케일아웃 CronJob을 운영하셨다고 되어 있는데, 답변에서 메모리 50%와 HPA 단독 대응이라고 하신 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": 0.0}, "latency_sec": 1.713, "ttft_sec": 1.311, "in_tokens": 9900, "out_tokens": 328} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "파티셔닝 후 p95가 180ms로 줄었다고 하셨는데, 파티션 프루닝이 적용되면서 인덱스 스캔 효율이 구체적으로 어떻게 개선되었는지 실행 계획(EXPLAIN)의 어떤 지표로 확인하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 2.573, "ttft_sec": 1.996, "in_tokens": 12383, "out_tokens": 446} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "자체 검색 박스로 대체하셨다고 했는데, 브라우저 기본 Ctrl+F 검색이 안 되는 제약으로 인해 사용자 경험에서 발생한 불편함은 어떻게 보완하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": 5.0}, "latency_sec": 2.74, "ttft_sec": 2.726, "in_tokens": 10446, "out_tokens": 304} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "결정 전에 대안 두 개를 비교하는 방식으로 바꿨다고 하셨는데, 실제로 최근 프로젝트에서 이 방식을 적용해 합의를 이끌어낸 구체적인 사례가 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 2.109, "ttft_sec": 1.843, "in_tokens": 8598, "out_tokens": 315} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "\"크게 싸운 적은 없는 것 같다고 하셨는데, 구체적으로 의견이 부딪혔던 경험과 그때 본인이 취한 행동을 말씀해 주세요.\"", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.904, "ttft_sec": 1.404, "in_tokens": 8244, "out_tokens": 293} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "월 200건에서 3건으로 줄었다고 하셨는데, 레디스 분산 락을 도입하면서 발생한 성능 저하나 락 획득 실패에 대한 대비책은 어떻게 세우셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.963, "ttft_sec": 1.515, "in_tokens": 8442, "out_tokens": 325} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "보상 흐름에서 재고 차감 실패로 30분 이상 PENDING 상태가 된 주문을 스위퍼 배치가 재조회해 처리한다고 하셨는데, 이때 스위퍼가 각 서비스의 원본 DB를 직접 조회하나요 아니면 이벤트 로그나 읽기 전용 뷰를 참조하나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 6.484, "ttft_sec": 5.766, "in_tokens": 12005, "out_tokens": 458} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "네트워크 요청이 40% 정도 줄었다고 하셨는데, 구체적으로 어떤 화면이나 API 호출에서 가장 큰 감소 효과를 보셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.016, "ttft_sec": 1.596, "in_tokens": 8328, "out_tokens": 299} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "Outbox 테이블을 폴링할 때 릴레이 서버가 중복 발행될 가능성은 없나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.621, "ttft_sec": 1.305, "in_tokens": 7545, "out_tokens": 202} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "중복 주문이 안 생기게 잘 처리했다고 하셨는데, 구체적으로 멱등 키와 Outbox 패턴이 각각 어떤 실패 케이스를 막아주는지 기술적인 근거를 들어 설명해 주시겠어요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.89, "ttft_sec": 1.54, "in_tokens": 8274, "out_tokens": 326} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "그럼 PostgreSQL에서 트랜잭션이 시작될 때 부여되는 XID(트랜잭션 ID)의 역할이나 동시성 제어 기본 개념에 대해 아는 만큼 말씀해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.704, "ttft_sec": null, "in_tokens": 7998, "out_tokens": 313} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "그렇다면, 리액트가 렌더링을 최적화하기 위해 상태 업데이트를 하나로 묶는 일반적인 개념인 배칭에 대해서 아는 대로 말씀해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.891, "ttft_sec": null, "in_tokens": 7992, "out_tokens": 319} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "CPU 사용량이 70%를 넘을 때 자동으로 서버를 늘리는 기준을 정하신 이유와, 트래픽이 몰리기 전에 미리 서버를 늘려둔 이유를 각각 말씀해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 1.874, "ttft_sec": 1.519, "in_tokens": 8208, "out_tokens": 320} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "폴링 방식을 쓰셨을 때 DB 부하를 줄이기 위해 어떤 간격이나 락 메커니즘을 적용하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 2.039, "ttft_sec": 1.498, "in_tokens": 8124, "out_tokens": 276} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "이력서에는 CPU 70%와 사전 스케일아웃 CronJob을 운영하셨다고 되어 있는데, 답변에서 메모리 50%와 HPA 단독 대응이라고 하신 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": 1.0}, "latency_sec": 2.034, "ttft_sec": 1.48, "in_tokens": 9900, "out_tokens": 328} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "파티셔닝과 인덱스 변경 각각이 p95 개선에 기여한 폭을 어떻게 측정하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 1.779, "ttft_sec": 1.368, "in_tokens": 10614, "out_tokens": 293} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "자체 검색 박스로 대체하셨다고 했는데, 브라우저 기본 Ctrl+F 검색이 안 되는 제약을 사용자들이 불편해하진 않았나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 6.058, "ttft_sec": 5.759, "in_tokens": 10446, "out_tokens": 304} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "결정 전에 대안 두 개를 같이 비교하는 방식으로 바꾸셨다고 했는데, 구체적으로 어떤 기준을 가지고 비교하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 2.448, "ttft_sec": 1.947, "in_tokens": 8598, "out_tokens": 278} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "크게 싸운 적이 없다고 하셨는데, 대화를 통해 의견 차이를 좁혔던 구체적인 상황과 본인의 행동을 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.834, "ttft_sec": 1.371, "in_tokens": 8244, "out_tokens": 285} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "버전 충돌로 재시도가 증가해 DB 부하가 커졌다고 하셨는데, 레디스 분산 락을 도입하면서 발생한 락 획득 대기나 네트워크 비용 같은 트레이드오프는 어떻게 해결하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.323, "ttft_sec": 1.662, "in_tokens": 9849, "out_tokens": 434} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "보상 흐름에서 재고 차감 실패로 결제 취소 이벤트를 보낼 때, 만약 그 결제 취소 이벤트마저 유실된다면 PENDING 상태 외에 잔여 데이터나 금전적 정합성은 어떻게 처리하시나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 2.351, "ttft_sec": 1.599, "in_tokens": 12005, "out_tokens": 430} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "네트워크 요청이 40% 줄었다고 하셨는데, 구체적으로 어떤 query key 구조로 중복을 제거하셨는지 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 6.173, "ttft_sec": 5.713, "in_tokens": 8328, "out_tokens": 305} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 네트워크 타임아웃으로 인한 **클라이언트의 재요청(중복 호출)**과 **이벤트 유실(Dual Write 문제)**이 복합적으로 작용한 결과였습니다.\n\n이를 해결하기 위해 첫째, **멱등 키(Idempotency Key)**를 도입하여 동일한 결제 요청이 여러 번 들어와도 DB Unique Constraint를 활용해 단 한 번만 주문이 생성되고 이후 요청은 기존 결과를 반환하도록 처리했습니다. 둘째, 주문 DB 저장과 외부 결제/메시지 발행 간의 원자성을 보장하기 위해 **Transactional Outbox 패턴**을 적용했습니다. 비즈니스 로직과 Outbox 테이블에 이벤트를 동일한 로컬 트랜잭션으로 기록한 뒤, 별도 폴링 혹은 CDC 퍼블리셔가 Kafka로 이벤트를 안정적으로 발행하도록 구성하여 **네트워크 장애나 서버 다운 시 이벤트 유실(Dual Write 실패)**을 방지했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 중복 주문이 발생했을 때, 클라이언트의 중복 요청을 막기 위해 **멱등 키(Idempotency Key)**를 DB에 유니크 제약조건으로 걸어 동일 요청이 들어오면 무시되도록 처리했습니다. 또한, DB 저장과 Kafka 이벤트 발행 간의 트랜잭션 불일치로 인한 이벤트 유실을 막기 위해 **Transactional Outbox 패턴**을 적용하여, 주문 데이터와 발행할 이벤트를 동일한 트랜잭션으로 Outbox 테이블에 먼저 기록한 뒤 안전하게 메시지를 발행하도록 구조를 개선했습니다.", "coaching_comment": "모호한 표현 대신 멱등 키가 막는 중복 요청과 Outbox 패턴이 해결하는 Dual Write(이벤트 유실) 문제를 각각 명확히 구분하여 설명해야 합니다."}, "latency_sec": 3.37, "in_tokens": 1382, "out_tokens": 422} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC 환경에서 오래 열린 트랜잭션(Long-running transaction)은 VACUUM의 dead tuple 회수를 지연시키는 핵심 원인입니다. PostgreSQL은 트랜잭션이 시작될 때 부여받는 xmin(가장 오래된 활성 트랜잭션 ID)을 기준으로 이보다 오래된 dead tuple만 안전하게 회수합니다. 따라서 트랜잭션이 끝나지 않고 오래 유지되면 xmin horizon이 갱신되지 않아, 이 기간 동안 발생한 dead tuple들이 VACUUM 대상에서 제외됩니다. 결과적으로 디스크 공간이 재사용되지 못하고 테이블 bloat(비대화) 현상이 발생하여 풀 스캔 성능 저하와 디스크 낭비를 초래하게 됩니다.", "answer_rewrite": "솔직히 정확한 메커니즘까지는 기억나지 않지만, PostgreSQL의 MVCC에서 트랜잭션 ID 관점과 연관이 있는 것으로 알고 있습니다. 오래 열린 트랜잭션이 존재하면 VACUUM이 dead tuple을 정리할 수 있는 기준점(xmin horizon)이 뒤로 당겨지지 않아, 불필요한 데이터가 디스크에 계속 남아 테이블 bloat 문제를 유발하는 것으로 이해하고 있습니다.", "coaching_comment": "모르는 기술 질문이라도 완전히 포기하기보다는 MVCC의 트랜잭션 ID 개념이나 VACUUM의 목적 등 연관된 키워드를 짚어내며 부분적으로 아는 만큼 유추해 답변하는 태도가 좋습니다."}, "latency_sec": 2.674, "in_tokens": 915, "out_tokens": 339} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 직전 2주간 일정이 지연된 갈등 상황이 있었습니다. 저는 서로의 주장을 고집하기보다 명확한 기준이 필요하다고 판단하여, OpenAPI 명세를 먼저 문서화하고 Mock 서버를 구축해 프론트엔드가 병렬로 개발할 수 있는 환경을 제안했습니다. 그 결과 다음 스프린트부터 API 통합 이슈가 3건에서 0건으로 줄어들며 성공적으로 프로젝트를 마칠 수 있었습니다. 이 경험을 통해 기술적 해결책뿐만 아니라, 갈등 상황에서 감정을 배제하고 객관적인 대안을 먼저 제시하는 소통의 중요성을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주간 일정이 지연된 갈등이 있었습니다. 저는 OpenAPI 명세를 선행 작성하고 Mock 서버를 띄워 프론트엔드와 병렬 개발이 가능하도록 구조를 바꿨습니다. 다만 초반에 제 방식을 고집하며 감정이 상했던 점을 반성하고, 이후에는 결정 전에 두 가지 대안을 함께 비교하여 조율하는 방식으로 협업 방식을 개선했습니다.", "coaching_comment": "추상적인 소통 예찬론 대신 이력서의 구체적인 협업 갈등 사례(API 스펙 차이와 해결 방식)를 STAR 구조로 풀어내야 합니다."}, "latency_sec": 2.162, "in_tokens": 1250, "out_tokens": 341} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 네트워크 재시도와 비동기 메시징 환경에서의 원자성 결여가 원인이었습니다. 이를 해결하기 위해 두 가지 패턴을 결합했습니다.\n\n첫째, **멱등 키(Idempotency Key)**는 동일한 결제 요청이나 콜백이 중복 수신되더라도 비즈니스 로직이 단 한 번만 실행되도록 보장합니다. 결제 요청 고유의 키를 유니크 제약조건이 걸린 테이블에 먼저 기록하여, 재시도 요청이 들어와도 기존 결과를 반환하거나 예외 처리하도록 방어했습니다.\n\n둘째, **Transactional Outbox 패턴**은 DB 트랜잭션과 메시지 발행(Kafka) 간의 원자성을 보장합니다. 비즈니스 데이터 저장과 Outbox 테이블 저장을 하나의 로컬 트랜잭션으로 묶어, '주문은 되었으나 이벤트 발행에 실패하는 유령 상태'나 'DB 롤백 후 이벤트가 발행되는 불일치'를 방지했습니다. 이후 별도 폴러나 Debezium 등을 통해 Outbox의 이벤트를 신뢰성 있게 발행하여, 두 가지 장치를 통해 중복 주문 0건을 달성할 수 있었습니다.", "answer_rewrite": "(주)마켓온에서 주문/결제 도메인을 담당하며 겪었던 결제 승인 지연 이슈를 멱등 키와 Outbox 패턴으로 해결했습니다.\n\n**상황 및 과제**: 외부 결제 서버의 콜백 지연으로 클라이언트가 중복 요청을 보내거나, 주문 DB 저장과 Kafka 이벤트 발행 시점이 어긋나 중복 주문이 발생하는 문제가 있었습니다.\n\n**행동**: \n1. **멱등 키 도입**: 결제 요청마다 고유 멱등 키를 생성해 DB에 유니크 제약조건을 걸고, 동일한 요청이 재유입될 경우 중복 실행을 차단했습니다.\n2. **Outbox 패턴 적용**: 주문 데이터 저장과 이벤트 발행용 Outbox 테이블 저장을 동일한 로컬 트랜잭션으로 묶어, 데이터 유실이나 이중 발행을 원천 차단하고 안전하게 Kafka로 이벤트를 전달했습니다.\n\n**결과**: 두 패턴을 결합하여 결제 승인 지연 상황에서도 중복 주문 0건을 달성했습니다.", "coaching_comment": "질문에서 요구한 멱등 키와 Outbox 패턴 각각의 역할과 실패 케이스 방어 원리를 이력서 기반의 구체적인 아키텍처 설명으로 보완해야 합니다."}, "latency_sec": 3.549, "in_tokens": 1382, "out_tokens": 588} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC 환경에서 오래 열린 트랜잭션은 Vacuum의 Dead Tuple 회수를 방해하는 핵심 요인입니다. PostgreSQL은 트랜잭션이 시작될 때 부여받는 xmin을 기준으로 가시성을 판단하는데, 오래 유지되는 트랜잭션이 존재하면 그 트랜잭션의 xmin보다 이전(과거)에 발생한 Dead Tuple이라도 현재 트랜잭션이 참조할 가능성이 있으므로 Vacuum이 이를 삭제하지 못하고 유지하게 됩니다. 이로 인해 Dead Tuple이 쌓이면서 테이블 Bloat이 발생하고, 디스크 공간 낭비는 물론 Sequential Scan 시 불필요한 블록을 읽게 되어 전반적인 쿼리 성능 저하로 이어집니다.", "answer_rewrite": "모르는 기술 개념 질문이라도 단순히 모른다고 넘어가기보다는, MVCC의 가시성 원리나 Vacuum의 역할 등 연관된 개념을 바탕으로 유추해 답변하는 태도가 좋습니다. 예를 들어 '정확한 내부 메커니즘까지는 기억나지 않지만, MVCC는 트랜잭션 ID를 기준으로 데이터의 가시성을 결정하고, Vacuum은 더 이상 필요 없는 Dead Tuple을 정리하는 것으로 알고 있습니다. 따라서 오래 열린 트랜잭션이 있다면 가시성 기준점(xmin horizon)에 영향을 주어 Vacuum이 특정 튜플을 지우지 못하고, 결과적으로 테이블 Bloat 등의 문제를 유발할 것 같습니다'라고 구조화하여 접근할 수 있습니다.", "coaching_comment": "모르는 기술 개념 질문이라도 자신이 아는 연관 개념(MVCC, Vacuum)을 엮어서 논리적인 가설 형태로 답변을 시도하는 것이 좋습니다."}, "latency_sec": 3.135, "in_tokens": 915, "out_tokens": 382} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석의 차이로 통합 직전 2주간 일정이 지연되는 갈등이 있었습니다. 이를 해결하기 위해 먼저 OpenAPI(Swagger) 명세를 기준으로 데이터 구조를 문서화하고, Mock 서버를 도입해 프론트엔드 팀이 병렬로 개발을 이어갈 수 있는 대안을 제시했습니다. 그 결과 소통의 모호함을 없애고 원활하게 연동을 마쳤으며, 이후 스프린트에서는 API 통합 이슈가 3건에서 0건으로 감소했습니다. 이 경험을 통해 기술적 해결책뿐만 아니라, 갈등 상황에서 상대방이 겪는 블로커를 해소해 주는 구조적 접근이 중요하다는 점을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트를 진행할 때, 프론트엔드 팀원과 API 스펙 해석이 달라서 통합 직전 2주 동안 일정이 지연된 갈등 상황이 있었습니다. 저는 이 문제를 해결하기 위해 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트엔드 팀이 대기하지 않고 병렬 개발을 할 수 있도록 제안했습니다. 그 결과 양측의 오해를 줄이고 무사히 연동을 마쳤으며, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄어드는 성과를 얻었습니다. 당시 제 방식을 너무 고집하다가 팀원과 감정이 상한 적도 있어, 이후에는 의사결정 전에 대안 두 가지를 먼저 비교하여 공유하는 방식으로 협업 방식을 개선했습니다.", "coaching_comment": "추상적인 소통 예찬 대신 이력서에 있는 캡스톤 프로젝트의 구체적인 갈등 상황과 해결 과정을 STAR 구조로 명확히 드러내야 합니다."}, "latency_sec": 2.671, "in_tokens": 1250, "out_tokens": 402} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 네트워크 재시도와 비동기 메시징 환경에서의 원자성 결여가 원인이었습니다. 이를 해결하기 위해 두 가지 패턴을 결합해 적용했습니다.\n\n첫째, **멱등 키(Idempotency Key)**는 API 요청 레벨에서 동일한 결제 요청이 중복 처리되는 것을 막습니다. 결제 고유 번호나 클라이언트가 생성한 멱등 키를 유니크 제약 조건으로 관리하여, 동일한 콜백이 여러 번 들어와도 최초 1회만 주문이 생성되고 이후 요청은 예외 처리하거나 기존 결과를 반환하도록 했습니다.\n\n둘째, **Transactional Outbox 패턴**은 DB 트랜잭션과 메시지 발행(Kafka) 사이의 원자성을 보장하기 위해 사용했습니다. 주문 데이터를 DB에 저장하는 것과 Kafka로 이벤트를 발행하는 행위가 하나의 트랜잭션으로 묶이지 않으면, DB 저장 후 메시지 발행 직전에 장애가 났을 때 데이터 유실이나 불일치가 발생합니다. Outbox 테이블에 발행할 이벤트를 주문과 동일 트랜잭션으로 저장한 뒤, 별도 폴링이나 체계로 안전하게 메시지를 발행함으로써 시스템 간 결합으로 인한 유실 실패 케이스를 방어했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 인한 중복 주문 문제는 API 레벨의 중복 요청과 메시지 발행 시점의 트랜잭션 불일치 두 가지 측면에서 접근했습니다. 첫째, 멱등 키 테이블과 유니크 제약 조건을 두어 동일한 결제 콜백이 여러 번 들어오더라도 중복 주문 생성을 원천 차단했습니다. 둘째, 주문 DB 저장과 Kafka 이벤트 발행 간의 원자성을 보장하기 위해 Transactional Outbox 패턴을 도입하여, DB 트랜잭션 내에서 Outbox 테이블에 이벤트를 함께 기록한 뒤 안전하게 메시지를 발행함으로써 네트워크 지연이나 장애 시 데이터 유실 및 불일치 문제를 해결했습니다.", "coaching_comment": "질문에서 요구한 멱등 키와 Outbox 패턴이 각각 어떤 실패 케이스(중복 요청, 메시지 유실/트랜잭션 분리)를 방어하는지 구체적으로 구분하여 설명해야 합니다."}, "latency_sec": 3.231, "in_tokens": 1382, "out_tokens": 523} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": true, "coaching": {"model_answer": "PostgreSQL은 MVCC를 구현하기 위해 각 행에 xmin, xmax 등의 트랜잭션 ID를 기록합니다. 이때 오래 열린 트랜잭션이 존재하면, 해당 트랜잭션의 시작점(또는 그 이전)이 xmin horizon으로 설정되어 이 시점 이후에 생성되거나 삭제된 버전들의 낡은 튜플(dead tuple)을 VACUUM이 안전하게 회수하지 못하게 됩니다. 결과적으로 dead tuple이 쌓이면서 디스크 공간이 낭비되고, sequential scan 성능 저하를 유발하는 테이블 bloat 현상으로 이어지게 됩니다.", "answer_rewrite": "잘 모르는 기술 개념 질문이라도 '모른다'고 바로 넘어가기보다는, MVCC의 기본 개념(행 버전 관리)과 VACUUM의 역할(dead tuple 정리)을 연결지어 유추한 내용을 정중히 답변하는 것이 좋습니다. 예: \"정확한 내부 메커니즘까지는 기억나지 않지만, MVCC는 트랜잭션 격리 수준을 위해 과거 버전을 유지하고, VACUUM은 유효하지 않은 튜플을 정리하는 것으로 알고 있습니다. 따라서 오래 열린 트랜잭션이 있으면 VACUUM이 정리할 수 있는 기준 시점(horizon)이 뒤로 밀려 dead tuple이 쌓이고 bloat이 발생할 수 있을 것으로 이해하고 있습니다.\"", "coaching_comment": "모르는 기술 질문이라도 완전히 포기하기보다 자신이 아는 핵심 개념(MVCC와 VACUUM의 목적)을 엮어 논리적으로 추론하는 태도를 보여주세요."}, "latency_sec": 3.031, "in_tokens": 915, "out_tokens": 367} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 직전 2주간 일정이 지연된 경험이 있습니다. 저는 이 문제를 해결하기 위해 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트엔드 팀원이 병렬로 개발할 수 있는 환경을 제안했습니다. 그 결과 이후 스프린트에서는 API 통합 이슈가 3건에서 0건으로 대폭 줄었습니다. 이 과정을 통해 단순히 소통을 강조하는 것을 넘어, 객관적인 명세와 도구를 활용해 이견을 조율하는 것이 효과적임을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트 진행 중 프론트엔드 팀원과 API 스펙 해석에 대한 이견이 생겨 통합 작업이 2주간 지연된 적이 있습니다. 당시 저는 사전에 OpenAPI 명세를 명확히 작성하고 Mock 서버를 구축하여 프론트엔드 개발이 병렬로 진행될 수 있도록 대안을 제안했습니다. 이 방식을 도입한 이후 다음 스프린트에서는 API 통합 관련 이슈가 3건에서 0건으로 줄어들며 일정을 원활하게 마무리할 수 있었습니다. 초기에는 제 주장을 강하게 내세워 감정이 상하기도 했지만, 이 경험을 계기로 의견 충돌이 생길 때는 감정적 대화보다 구체적인 대안 두 가지를 먼저 비교하여 제시하는 방식으로 협업 방식을 개선했습니다.", "coaching_comment": "추상적인 소통 예찬 대신 자소서에 있는 캡스톤 프로젝트의 구체적인 갈등 해결 과정과 정량적 결과를 STAR 구조로 명확히 드러내야 합니다."}, "latency_sec": 2.463, "in_tokens": 1250, "out_tokens": 378} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 승인 지연 시 중복 주문 문제를 해결하기 위해 적용한 멱등 키와 Outbox 패턴의 구체적인 구현 방식은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "중복 결제 방지를 위한 멱등성 보장 메커니즘과 트랜잭션 안전성을 정확히 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "모놀리식에서 MSA로 전환하면서 주문 서비스를 분리할 때 DB를 PostgreSQL로 분리하고 Kafka를 도입한 이유는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "서비스 분리에 따른 데이터베이스 격리 전략과 이벤트 기반 비동기 통신의 장단점을 이해하고 있는지 평가합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 낙관적 락에서 분산 락으로 전환하게 된 구체적인 동시성 이슈 상황은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "실시간 재고 동기화 (2024) - Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "동시성 제어 방식별 특성을 파악하고 트래픽 상황에 맞는 락 메커니즘을 선택했는지 설명할 수 있어야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "정산 배치 성능을 5시간에서 40분으로 줄일 때 활용한 QueryDSL 튜닝과 인덱스 재설계 과정에서 어떤 실행 계획을 참고하셨나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "대용량 데이터 조회 시 인덱스 스캔 효율과 쿼리 성능 분석 역량을 갖추고 있는지 검증합니다."}, {"category": "TECH_CHOICE", "question": "재고 캐시와 DB 간의 데이터 정합성을 맞추기 위해 write-behind 패턴을 선택했을 때 발생할 수 있는 데이터 유실 위험을 어떻게 방어하셨나요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "Write-behind 패턴의 비동기 캐시 업데이트 구조에서 장애 및 데이터 유실 대응 방안을 알고 있는지 확인합니다."}], "latency_sec": 3.365, "in_tokens": 2857, "out_tokens": 769} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "일정 타임라인에 react-window를 도입해 INP를 480ms에서 120ms로 개선하셨는데, 가상화 적용 시 DOM 재사용과 스크롤 버벅임 방지를 위해 어떤 점을 고려하셨나요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 -> react-window 가상화 도입 (커밋 메시지: virtualize timeline, INP 480ms -> 120ms)", "expected_signal": "가상화 라이브러리의 동작 원리를 이해하고 대량의 DOM 렌더링 최적화 경험을 구체적으로 설명할 수 있는지 확인"}, {"category": "TECH_CHOICE", "question": "지도 마커 500개 렌더링에 클러스터링과 useMemo를 쓰셨는데, useMemo의 의존성 배열 관리에서 불필요한 연산이 발생하지 않도록 어떻게 최적화하셨나요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "React 18 환경에서 useMemo의 메모이제이션 한계와 연산 비용 최적화 기준을 정확히 알고 있는지 검증"}, {"category": "PROJECT_DEEP_DIVE", "question": "오프라인 편집에서 Dexie와 낙관적 업데이트를 사용하셨는데, 충돌 해결 전략으로 적용한 last-write-wins 방식에서 데이터 유실 위험을 어떻게 보완하고자 하셨나요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: CRDT 검토 필요)", "expected_signal": "오프라인 First 아키텍처에서 발생할 수 있는 동시성 이슈와 데이터 충돌 시나리오를 식별하고 대안을 고민해 보았는지 확인"}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 서버가 아닌 클라이언트 측에서 WebP로 변환하는 방식을 택하신 이유는 무엇이며, 브라우저 메인 스레드 부하는 어떻게 관리하셨나요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "클라이언트 자원 소모가 큰 작업을 수행할 때 성능 저하를 방지하기 위한 고려사항(Web Worker 등)을 인지하고 있는지 검증"}, {"category": "CS_FUNDAMENTAL", "question": "Lighthouse 성능 점수를 68점에서 91점으로 끌어올리셨을 때, 브라우저 렌더링 파이프라인 관점에서 가장 크게 영향을 준 병목 원인은 무엇이었나요?", "job_category": "FRONTEND", "target_evidence": "Lighthouse 성능 점수 68 → 91 (PR #57 설명)", "expected_signal": "웹 브라우저의 파싱, 스타일링, 레이아웃 및 페인트 과정에 대한 이해를 바탕으로 성능 지표 개선 과정을 설명할 수 있는지 확인"}], "latency_sec": 3.829, "in_tokens": 2659, "out_tokens": 847} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "EKS 환경에서 월급날 10시 트래픽 피크에 대비해 HPA 외에 CronJob으로 사전 스케일아웃을 적용한 이유와 동작 방식은 무엇인가요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "HPA의 반응형 스케일링 한계를 인지하고 예측 가능한 트래픽에 선제적으로 대응한 아키텍처 설계 역량을 보여야 합니다."}, {"category": "TECH_CHOICE", "question": "Terraform으로 VPC, RDS, EKS를 모듈화하고 dev/stg/prod workspace를 분리하면서 겪은 상태 파일 관리 상의 이슈는 무엇인가요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "Terraform backend 구성 방식과 멀티 환경 관리 시 실수나 병목을 방지한 실무 경험을 설명해야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 거래내역 테이블을 월 단위로 파티셔닝할 때 기존 데이터 마이그레이션과 제약 조건 처리는 어떻게 진행하셨나요?", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "대용량 테이블 파티셔닝 전환 과정에서의 무중단 전략과 쿼리 성능 개선 포인트를 구체적으로 제시해야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "PostgreSQL에서 autovacuum 튜닝을 잘못 설정했을 때 발생할 수 있는 블로팅 현상과 시스템 영향도를 설명해주세요.", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "autovacuum의 동작 원리와 테이블/인덱스 블로팅이 I/O 및 성능에 미치는 영향을 정확히 이해하고 있는지 확인합니다."}, {"category": "BEHAVIORAL", "question": "RDS 스토리지 풀로 쓰기가 중단되었던 장애 상황에서 원인 파악부터 CloudWatch 알람 및 오토스케일링 적용까지 본인의 대처 과정을 STAR 형식으로 설명해주세요.", "job_category": "INFRA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 발생 시 신속한 대응 역량과 재발 방지를 위한 모니터링 및 자동화 개선 조치를 명확히 드러내야 합니다."}, {"category": "TECH_CHOICE", "question": "ArgoCD GitOps 도입 과정에서 기존 배포 방식 대비 승인 절차나 롤백 과정에서 겪었던 가장 큰 도전 과제는 무엇인가요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "GitOps 도입 시 선언형 파이프라인 운영 경험과 보안/권한 관리 측면의 고려 사항을 이해하고 있는지 검증합니다."}], "latency_sec": 4.23, "in_tokens": 2651, "out_tokens": 975} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "알림 봇 DB를 SQLite에서 PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하셨는데, 당시 겪은 동시성 이슈의 원인과 해결 과정을 설명해주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "동시성 이슈의 원인을 정확히 진단하고, 트랜잭션 격리 수준과 DB 전환 과정을 구조화하여 설명할 수 있는지 평가합니다."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 OpenAPI 명세와 Mock 서버를 도입해 협업 방식을 개선하셨는데, 당시 본인의 구체적인 행동과 팀원과의 소통 과정에서 배운 점은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했습니다.", "expected_signal": "갈등 상황에서 기술적 대안을 제시하고 팀의 생산성을 높인 경험을 STAR 기법으로 명확히 전달하는지 평가합니다."}, {"category": "BEHAVIORAL", "question": "초반에 본인 방식만 고집하다 감정이 상했던 경험을 극복하기 위해 대안을 비교하는 방식으로 바꾸셨다고 했는데, 이후 실제 프로젝트에서 이 방식을 적용해 성공한 사례가 있나요?", "job_category": "BACKEND", "target_evidence": "다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "과거의 실패나 갈등 경험을 통해 본인의 협업 태도가 어떻게 성숙해졌는지 객관적으로 성찰하고 있는지 평가합니다."}, {"category": "BEHAVIORAL", "question": "학사 공지 알림 봇 운영 중 크롤러 멈춤으로 항의를 받으셨을 때, 서비스 안정성을 높이기 위해 이후 어떤 모니터링이나 예방 조치를 취하셨나요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 멈추지 않는 서비스가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "운영 중 발생한 장애 경험을 바탕으로 서비스 안정성과 신뢰성을 확보하기 위한 후속 조치와 책임감을 갖추었는지 평가합니다."}, {"category": "BEHAVIORAL", "question": "다수의 사용자가 매일 사용하는 서비스를 운영하며 겪은 기술적 한계를 극복하기 위해, 개발자로서 본인이 가장 중요하게 생각하는 원칙은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다.", "expected_signal": "서비스 운영 경험을 통해 체득한 개발 철학과 엔지니어로서의 가치관이 뚜렷한지 평가합니다."}], "latency_sec": 3.797, "in_tokens": 2642, "out_tokens": 871} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 낙관적 락에서 분산 락으로 전환하게 된 동시성 이슈의 구체적 상황과 성능 트레이드오프는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "실시간 재고 동기화 (2024) - Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "동시성 충돌 빈도와 부하 특성에 따른 락 메커니즘 선택 근거를 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "모놀리식에서 MSA로 전환하며 도입한 PostgreSQL 분리와 Kafka 이벤트 발행 구조에서 분산 트랜잭션과 데이터 정합성을 어떻게 보장하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "분산 환경에서 2PC나 사가 패턴 등 트랜잭션 정합성 유지 전략에 대한 이해를 명확히 드러내야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능을 5시간에서 40분으로 단축할 때 QueryDSL 튜닝과 인덱스 재설계 과정에서 가장 결정적이었던 병목 지점은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "대용량 데이터 조회 시 실행 계획 분석과 쿼리 최적화 과정을 구체적으로 설명할 수 있어야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "알림 봇 개발 당시 SQLite에서 PostgreSQL로 이전하면서 겪었던 트랜잭션 격리 수준 관련 동시성 이슈와 해결 방식을 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "데이터베이스 트랜잭션 격리 수준과 동시성 제어 메커니즘에 대한 깊은 이해를 보여주어야 합니다."}, {"category": "BEHAVIORAL", "question": "프론트엔드 팀원과의 API 스펙 이견으로 2주 지연 위기가 있었을 때 OpenAPI와 Mock 서버를 도입하여 해결한 본인의 구체적 액션과 배운 점은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했습니다.", "expected_signal": "협업 갈등 상황에서 기술적 대안을 제시하여 문제를 해결한 과정과 커뮤니케이션 성찰을 드러내야 합니다."}], "latency_sec": 4.584, "in_tokens": 3995, "out_tokens": 847} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 승인 콜백 지연 시 발생한 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결할 때, 두 메커니즘이 각각 어떤 단계에서 중복을 방지하는지 설명해주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키를 통한 API 요청 중복 차지와 Outbox 패턴을 통한 이벤트 발행의 원자성 보장 메커니즘을 정확히 이해하고 있는지 확인"}, {"category": "TECH_CHOICE", "question": "모놀리식에서 MSA로 전환하면서 주문 서비스를 분리할 때 DB를 분리하셨는데, 마이크로서비스 간 데이터 분산 환경에서 트랜잭션 정합성은 어떻게 유지하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "분산 트랜잭션 환경에서의 데이터 정합성 보장 방안과 이벤트 기반 아키텍처의 트레이드오프에 대한 이해도"}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능을 5시간에서 40분으로 단축할 때 적용한 QueryDSL 튜닝과 청크 단위 처리 방식에서 가장 핵심적으로 고려한 점은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "대용량 데이터 처리 시 메모리 관리와 쿼리 최적화, 인덱스 재설계의 실무 적용 능력"}, {"category": "TECH_CHOICE", "question": "실시간 재고 동기화 프로젝트에서 동시성 제어를 위해 낙관적 락에서 분산 락으로 전환하신 기술적 배경과 선택 기준은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "실시간 재고 동기화 (2024) - Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "경합이 치열한 도메인에서 락 메커니즘 변경에 따른 성능 영향과 트레이드오프 판단력"}, {"category": "CS_FUNDAMENTAL", "question": "Kafka 기반 이벤트 파이프라인을 설계할 때 파티션 키 설정 방식에 따라 순서 보장과 컨슈머 처리량에 어떤 영향이 발생하는지 설명해주세요.", "job_category": "BACKEND", "target_evidence": "주문 서비스를 별도 서비스로 분리 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "메시지 큐 파키셔닝 전략과 순서 보장, 컨슈머 스케일아웃 구조에 대한 CS 지식"}], "latency_sec": 3.804, "in_tokens": 2857, "out_tokens": 802} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "일정 타임라인에서 2천 개 이상 항목 렌더링 시 react-window를 도입해 INP를 480ms에서 120ms로 개선하셨는데, 가상화 구현 시 DOM 재사용으로 인해 겪었던 레이아웃 흔들림이나 스크롤 점프 이슈는 어떻게 해결하셨나요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: virtualize timeline, INP 480ms -> 120ms)", "expected_signal": "가상화 라이브러리의 동작 원리와 동적 높이 측정, 렌더링 성능 최적화 과정에서의 트러블슈팅 경험을 명확히 설명하는지 확인."}, {"category": "TECH_CHOICE", "question": "지도 마커 500개 렌더링에 useMemo로 좌표 변환을 캐싱하셨는데, 맵 줌 레벨이나 드래그 시 불필요한 연산이 발생하지 않도록 캐시 무효화 조건을 어떻게 설계하셨나요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "React의 메모이제이션 훅 활용 기준과 지도 SDK 이벤트 사이의 성능 병목 지점을 정확히 이해하고 있는지 검증."}, {"category": "PROJECT_DEEP_DIVE", "question": "오프라인 편집 기능에서 IndexedDB와 Dexie를 사용해 낙관적 업데이트를 저장하고 동기화할 때, 충돌 해결 전략으로 남겨둔 last-write-wins 방식 대신 CRDT를 도입해야겠다고 판단한 구체적인 동기는 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: CRDT 검토 필요)", "expected_signal": "오프라인 퍼스트 아키텍처의 데이터 동기화 한계를 인지하고 있으며, 분산 환경에서의 충돌 해결 알고리즘에 대한 기술적 관심도를 확인."}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 S3 presigned URL을 사용하고 클라이언트에서 WebP 변환을 거치도록 하셨는데, 브라우저 메인 스레드 블로킹을 막기 위해 변환 작업을 어떻게 분리하셨나요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "대용량 파일 처리 시 브라우저 성능 유지(Web Worker 활용 등) 및 네트워크 최적화 고려 사항을 설명할 수 있는지 평가."}, {"category": "CS_FUNDAMENTAL", "question": "Lighthouse 성능 점수를 68점에서 91점으로 끌어올리는 과정에서 PR #57을 통해 체감 성능에 가장 큰 악영향을 주었던 병목 지점을 어떻게 프로파일링하고 해결하셨나요?", "job_category": "FRONTEND", "target_evidence": "Lighthouse 성능 점수 68 → 91 (PR #57 설명)", "expected_signal": "웹 성능 지표(Core Web Vitals)에 대한 이해도와 실무적인 성능 개선 프로파일링 프로세스를 갖추고 있는지 검증."}], "latency_sec": 5.143, "in_tokens": 2659, "out_tokens": 902} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "EKS 환경에서 월급날 10시 트래픽 피크에 대비해 HPA 외에 사전 스케일아웃 CronJob을 도입한 이유는 무엇인가요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "트래픽 급증 시 HPA의 리액티브한 반응 속도 한계를 인지하고 프로액티브하게 대응한 아키텍처적 판단 근거를 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "Terraform으로 VPC, RDS, EKS 모듈화 시 환경별 dev와 stg 및 prod workspace를 분리한 구체적인 전략은 무엇인가요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "상태 파일(state file) 관리 방식과 환경 간 변경 사항 격리를 위해 어떤 구조를 채택했는지 명확히 이해하고 있는지 평가합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 거래내역 테이블의 슬로우 쿼리 개선을 위해 월 단위 파티셔닝과 autovacuum 튜닝을 각각 어떻게 적용하셨나요?", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "대용량 테이블에서 파티션 프루닝 효과를 극대화한 방법과 autovacuum 파라미터 조율 기준을 구체적으로 설명할 수 있어야 합니다."}, {"category": "BEHAVIORAL", "question": "2024년 3월 RDS 스토리지 풀로 인한 쓰기 중단 장애 당시, 초기 인지부터 스토리지 오토스케일링 적용까지 본인의 대처 과정을 말씀해 주세요.", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "상황 파악 및 원인 규명 과정, 재발 방지를 위한 자동화 조치 도입 과정이 STAR 구조로 드러나야 합니다."}, {"category": "TECH_CHOICE", "question": "ArgoCD를 통한 GitOps 도입으로 배포 리드타임을 단축할 때, 기존 수동 배포 대비 동기화 안정성을 어떻게 확보하셨나요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "Git 리포지토리와 Kubernetes 클러스터 상태 간의 drift 발생 시 대응 방안과 Sync 정책 설정 노하우를 명확히 제시해야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "Kubernetes 환경에서 파드 약 400개를 운영할 때, CPU 리소스 제한(Limit) 설정이 노드 안정성과 스케줄링에 미치는 영향은 무엇인가요?", "job_category": "INFRA", "target_evidence": "EKS 기반 쿠버네티스 클러스터 3개 운영 (파드 약 400개)", "expected_signal": "CPU Throttling 현상에 대한 이해와 Request 및 Limit 설정의 트레이드오프를 인프라 관점에서 정확히 설명할 수 있어야 합니다."}], "latency_sec": 4.682, "in_tokens": 2651, "out_tokens": 967} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "크롤러가 멈춰 공지가 누락되었을 때 동아리원들의 항의를 받은 경험에서, 신뢰를 지키기 위해 후속으로 취한 구체적인 조치는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 멈추지 않는 서비스가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "장애 상황에서 본인의 구체적인 행동과, 이를 통해 배운 서비스 신뢰성에 대한 철학을 STAR 구조로 명확히 제시하는지 검증"}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 갈등을 겪었을 때, 대안을 비교하는 방식으로 소통을 바꾼 구체적인 계기와 과정은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "갈등 상황에서 자신의 고집을 인정하고 대안 비교 방식을 도입하게 된 성찰 과정과 협업 역량을 STAR 구조로 설명하는지 평가"}, {"category": "PROJECT_DEEP_DIVE", "question": "알림 봇 DB를 SQLite에서 PostgreSQL로 이전할 때 트랜잭션 격리 수준을 공부하게 된 계기와, 마이그레이션 과정에서 직면한 가장 큰 기술적 도전은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "동시성 이슈의 원인을 분석하고 DB 전환을 통해 문제를 해결하는 과정에서의 깊이 있는 기술적 이해도 검증"}, {"category": "BEHAVIORAL", "question": "팀 프로젝트 진행 중 자신의 의견이나 방식이 거부되거나 충돌할 때, 이를 조율하고 최종 결정을 이끌어내는 본인만의 방식을 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "의견 충돌 상황에서 감정을 배제하고 객관적인 대안 비교를 통해 합의를 도출하는 태도와 리더십 역량 확인"}, {"category": "BEHAVIORAL", "question": "개발자로서 '멈추지 않는 서비스'를 만들기 위해 스스로 세운 원칙이나 특별히 노력하고 있는 실천 방안은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "과거의 실패 경험을 바탕으로 서비스 안정성과 운영에 대한 주도적인 태도와 장기적인 개발자 비전을 갖추었는지 평가"}], "latency_sec": 4.191, "in_tokens": 2642, "out_tokens": 981} +{"label": "gw-gemini-3.5-flash-lite", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: ```json\n{\n \"questions\": [\n {\n \"category\": \"PROJECT_DEEP_DIVE\",\n \"question\": \"모놀리식에서 주문 서비스를 분리할 때 사용한 Kafka 이벤트 발행/구독 구조에서 메시지 유실 방지를 어떻게 처리하셨나요?\",\n \"jobCategory\": \"BACKEND\",\n \"targetEvidence\": \"모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입.\",\n \"expectedSignal\": \"분산 환경에서의 트랜잭션 보장 방식과 이벤트 발행 실패 시의 복구 메커니즘을 명확히 설명할 수 있어야 합니다.\"\n },\n {\n \"category\": \"TECH_CHOICE\",\n \"question\": \"실시간 재고 동기화 프로젝트에서 동시성 제어를 위해 낙관적 락에서 분산 락으로 전환한 결정적인 이유는 무엇인가요?\",\n \"jobCategory\": \"BACKEND\",\n \"targetEvidence\": \"실시간 재고 동기화 (2024): Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)\",\n \"expectedSignal\": \"트래픽 특성과 충돌 빈도에 따른 락 메커니즘의 장단점 비교 및 기술 선택 근거를 제시해야 합니다.\"\n },\n {\n \"category\": \"PROJECT_D", "latency_sec": 4.189, "in_tokens": 3995, "out_tokens": 845} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 네트워크 재시도와 비동기 메시징 환경에서의 원자성 결여가 원인이었습니다. 이를 해결하기 위해 두 가지를 보완적으로 사용했습니다.\n\n첫째, **멱등 키(Idempotency Key)**는 API 클라이언트나 PG사 콜백이 동일한 요청을 여러 번 보내도 DB에 단 한 번만 반영되도록 보장합니다. 결제 요청 시 고유한 키를 생성하여 DB 유니크 제약조건으로 관리함으로써 **동일한 요청의 중복 실행(중복 결제 및 주문 생성)**을 원천 차단했습니다.\n\n둘째, **Transactional Outbox 패턴**은 비즈니스 DB 트랜잭션과 Kafka 이벤트 발행 간의 원자성을 보장합니다. DB에 주문 데이터를 저장하면서 Outbox 테이블에도 이벤트를 같은 트랜잭션으로 커밋하고, 이후 별도 Poller나 Debezium을 통해 메시지를 브로커로 전송합니다. 이를 통해 **DB 저장 성공 후 메시지 발행 실패로 인한 유실이나, 반대로 메시지가 발행되었으나 DB가 롤백되는 불일치 상태**를 방지했습니다.", "answer_rewrite": "(주)마켓온에서 주문/결제 도메인을 담당하며 결제 승인 콜백 지연으로 발생한 중복 주문을 멱등 키와 Outbox 패턴으로 해결했습니다.\n\n결제 승인 API 호출 시 네트워크 지연으로 PG사 콜백이 중복 유입되는 상황에서, 주문 테이블에 **멱등 키(Idempotency Key) 유니크 제약**을 두어 동일 요청의 중복 처리를 막았습니다. 또한, 주문 상태 변경과 Kafka 이벤트 발행 과정에서 로컬 DB 트랜잭션과 메시지 브로커 간의 원자성을 보장하기 위해 **Transactional Outbox 패턴**을 도입했습니다. 비즈니스 로직과 Outbox 테이블 저장을 단일 트랜잭션으로묶어 이벤트 유실과 중복 발행 문제를 모두 해결하여 중복 주문 0건을 달성했습니다.", "coaching_comment": "모호하고 추상적인 표현 대신 멱등 키가 막는 실패(중복 요청)와 Outbox 패턴이 막는 실패(메시지-DB 불일치)를 각각 명확히 구분하여 설명해야 합니다."}, "latency_sec": 4.567, "in_tokens": 1382, "out_tokens": 530} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL은 MVCC를 구현하기 위해 각 튜플에 `xmin`, `xmax` 등의 트랜잭션 ID 시스템을 사용합니다. 이때 오래 열린 트랜잭션이 존재하면, 해당 트랜잭션의 `xmin`이 전체 시스템의 `xmin horizon` 기준점이 되어 이 트랜잭션보다 나중에 생성된 데드 튜플이라 할지라도 Vacuum이 이를 회수하지 못하고 유지하게 됩니다. 결과적으로 불필요한 공간이 재사용되지 못해 디스크 공간 낭비와 Sequential Scan 성능 저하를 유발하는 Table Bloat 현상으로 이어지므로, 장기 실행 트랜잭션은 모니터링과 관리가 필수적입니다.", "answer_rewrite": "잘 모르는 기술적 개념에 대해서는 솔직하게 인정한 뒤, 아는 범위 내에서 MVCC의 기본 개념이나 관련 현상을 연결 지어 답변하는 것이 좋습니다. 예를 들어 \"오래 열린 트랜잭션이 트랜잭션 ID의 하한선을 붙잡아 두어 Vacuum이 데드 튜플을 정리하지 못하고 Table Bloat를 유발하는 것으로 이해하고 있습니다만, 정확한 내부 메커니즘까지는 기억나지 않습니다\"와 같이 부분적으로 알고 있는 지점을 짚어주면 면접관에게 긍정적인 인상을 줄 수 있습니다.", "coaching_comment": "모르는 질문이라도 완전히 포기하기보다는 자신이 아는 관련 개념(MVCC, Vacuum, Bloat)을 엮어 부분적인 지식이라도 어필하는 태도가 필요합니다."}, "latency_sec": 3.314, "in_tokens": 915, "out_tokens": 357} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 직전 2주간 일정이 지연된 갈등 상황이 있었습니다. 저는 문제를 해결하기 위해 OpenAPI 명세를 먼저 문서화하고 Mock 서버를 구축하여 프론트엔드 팀이 병렬로 개발을 진행할 수 있는 대안을 제안했습니다. 그 결과 다음 스프린트에서 API 통합 관련 이슈가 3건에서 0건으로 감소하며 성공적으로 프로젝트를 마칠 수 있었습니다. 이 경험을 통해 기술적 해결책뿐만 아니라, 내 주장을 고집하기보다 상대방의 입장을 고려해 객관적인 도구와 대안을 제시하는 소통의 중요성을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트 진행 중 프론트엔드 팀원과 API 스펙 해석에 대한 이견이 생겨 통합 직전 2주 동안 일정이 지연된 적이 있습니다. 이를 해결하기 위해 제가 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트엔드 팀이 API 대기 없이 병렬 개발을 할 수 있도록 구조를 개선했습니다. 이 방식을 도입한 이후 다음 스프린트에서는 API 통합 이슈가 3건에서 0건으로 줄어들었습니다. 다만 초기 과정에서 제 방식을 너무 강하게 고집하다 팀원과 감정이 상한 적이 있어, 이후에는 의사결정 시 두 가지 이상의 대안을 먼저 비교 제시하는 방식으로 협업 방식을 개선했습니다.", "coaching_comment": "추상적인 소통 찬양보다는 이력서에 있는 캡스톤 프로젝트의 구체적인 갈등 상황과 정량적 결과(이슈 3건->0건), 그리고 배운 점을 STAR 구조로 명확히 드러내야 합니다."}, "latency_sec": 2.516, "in_tokens": 1250, "out_tokens": 401} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 3, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 멱등성 보장과 메시지 발행의 신뢰성(원자성)을 분리하여 해결했습니다.\n\n첫째, **Transactional Outbox 패턴**은 주문 DB에 데이터를 저장하는 트랜잭션과 결제/이벤트 발행을 위한 Outbox 테이블 저장을 하나의 DB 트랜잭션으로 묶어, 네트워크 단절이나 애플리케이션 다운 시에도 이벤트 누락이나 이중 발행(이중 결제 요청 등)을 방지합니다.\n\n둘째, **멱등 키(Idempotency Key)**는 PG사 콜백이나 클라이언트 재요청이 중복으로 들어왔을 때, 비즈니스 로직이 여러 번 실행되는 것을 막기 위해 고유 키 기반으로 상태를 체크하여 최초 1회만 처리되도록 보장합니다. 즉, Outbox는 '메시지 유실 및 트랜잭션 경계 문제'를 막고, 멱등 키는 '클라이언트나 외부 PG사의 재시도에 따른 중복 실행'을 막는 역할을 분담합니다.", "answer_rewrite": "결제 승인 콜백이 지연되면서 클라이언트나 PG사에서 재요청이 들어와 중복 주문이 발생하는 문제가 있었습니다. 이를 해결하기 위해 두 가지 패턴을 적용했습니다.\n\n우선 **Transactional Outbox 패턴**을 사용해 주문 생성 트랜잭션과 이벤트를 Outbox 테이블에 기록하는 작업을 하나의 트랜잭션으로 묶어, 시스템 장애 시에도 이벤트 유실이나 불완전한 상태 저장을 방지했습니다.\n\n또한, **멱등 키**를 도입하여 결제 요청 시 고유한 키를 기준으로 이미 처리된 주문인지 검증하도록 구현했습니다. 이를 통해 동일한 콜백이 중복으로 수신되더라도 비즈니스 로직이 재실행되지 않고 중복 주문 0건을 달성할 수 있었습니다.", "coaching_comment": "단순히 '잘 처리했다'고 두루뭉술하게 답하기보다, Outbox 패턴이 막는 실패(이벤트 유실/트랜잭션 분리 문제)와 멱등 키가 막는 실패(외부 재시도에 따른 중복 실행)를 각각 명확히 구분하여 설명해야 합니다."}, "latency_sec": 7.309, "in_tokens": 1382, "out_tokens": 521} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 4, "ok": true, "coaching": {"model_answer": "PostgreSQL은 MVCC를 구현하기 위해 UPDATE나 DELETE 시 실제 데이터를 지우지 않고 Dead Tuple을 남깁니다. VACUUM은 이 Dead Tuple을 정리해 공간을 재사용 가능하게 만드는데, 이때 가장 오래 열린 트랜잭션의 `xmin`이 'Xmin Horizon' 역할을 합니다.\n\n즉, 오래 열린 트랜잭션이 존재하면 VACUUM은 그 트랜잭션이 볼 수 있는 시점 이후에 생성된 Dead Tuple을 회수하지 못하고 건너뛰게 됩니다. 이로 인해 Dead Tuple이 쌓이면서 테이블 Bloat(공간 낭비) 현상이 발생하고, 디스크 I/O가 늘어나 전체적인 쿼리 성능 저하로 이어집니다.", "answer_rewrite": "모르는 기술 개념 질문이라도 '모른다'고 바로 넘어가기보다는, MVCC와 VACUUM의 기본 동작 원리를 엮어서 아는 만큼 논리적으로 유추해 답변하는 것이 좋습니다. 예를 들어 다음과 같이 접근할 수 있습니다: \"VACUUM이 Dead Tuple을 정리하는 것으로 알고 있는데, 오래 열린 트랜잭션이 있다면 다른 트랜잭션이 참조할 가능성 때문에 해당 시점의 데이터는 정리하지 못하고 지연시킬 것 같습니다. 이로 인해 공간 회수가 안 되고 디스크 낭비나 성능 저하가 발생할 수 있다고 이해하고 있습니다.\"", "coaching_comment": "모르는 기술 면접 질문이라도 핵심 키워드(MVCC, VACUUM, Dead Tuple)를 바탕으로 아는 범주 내에서 논리적으로 유추해 답변하는 태도가 필요합니다."}, "latency_sec": 2.844, "in_tokens": 915, "out_tokens": 373} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 5, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 직전 2주간 일정이 지연된 갈등 경험이 있습니다. 저는 문제 해결을 위해 OpenAPI 명세를 선행 작성하고 Mock 서버를 구축하여 프론트엔드가 독립적으로 개발을 병렬 진행할 수 있도록 제안했습니다. 그 결과 다음 스프린트부터 API 통합 이슈가 3건에서 0건으로 줄어들며 성공적으로 프로젝트를 마칠 수 있었고, 이 경험을 통해 내 주장을 고집하기보다 객관적인 명세와 대안을 제시하는 방식으로 협업하는 법을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트를 진행할 때, 프론트엔드 팀원과 API 스펙 해석의 차이로 인해 통합 직전 2주 동안 일정이 지연되는 갈등 상황이 있었습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트엔드 팀이 병렬로 개발을 진행할 수 있도록 구조적인 대안을 제안했습니다. 이 과정에서 제 방식을 너무 고집하다 초반에 감정이 상한 적도 있었으나, 이후에는 결정 전에 두 가지 대안을 함께 비교하여 설명하는 방식을 도입했습니다. 그 결과 다음 스프린트에서는 통합 이슈가 3건에서 0건으로 줄어들며 원만하게 협업을 마칠 수 있었습니다.", "coaching_comment": "추상적인 소통 예찬보다는 이력서에 있는 캡스톤 프로젝트의 구체적인 갈등 상황과 해결 과정을 STAR 구조로 명확히 드러내야 합니다."}, "latency_sec": 2.398, "in_tokens": 1250, "out_tokens": 367} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 6, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 네트워크 재시도로 인한 **중복 요청(Duplicate Request)**과 DB 트랜잭션과 메시지 발행 사이의 **원자성 상실(Dual Write)**이라는 두 가지 실패 포인트가 동시에 존재했기 때문에, 각각을 방어하기 위해 멱등 키와 Outbox 패턴을 함께 적용했습니다.\n\n첫째, **멱등 키(Idempotency Key)**는 결제 요청이나 콜백 시 클라이언트 또는 PG사로부터 전달받은 고유 식별자를 DB Unique Constraint로 관리하여, 동일한 요청이 네트워크 재시도 등으로 여러 번 들어오더라도 최초 1회만 처리되고 이후는 안전하게 무시되도록 **중복 요청 실패 케이스**를 막습니다.\n\n둘째, **Transactional Outbox 패턴**은 주문 DB에 주문 상태를 저장하는 트랜잭션과 Kafka로 결제 완료 이벤트를 발행하는 행위가 원자적으로 묶이지 않아 발생하는 **데이터 유실 또는 불일치 케이스(Dual Write 문제)**를 해결합니다. 주문 생성 시 동일한 로컬 트랜잭션 내에 Outbox 테이블에 이벤트 레코드를 함께 기록하고, 별도의 Relay 프로세스(또는 Debezium 등 CDC)를 통해 안전하게 Kafka로 발행함으로써 시스템 장애 시에도 메시지 유실 없는 안정적인 이벤트 파이프라인을 구축했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 중복 주문이 발생했을 때, 네트워크 재시도로 인한 중복 요청과 이벤트 유실 문제를 동시에 해결하기 위해 멱등 키와 Outbox 패턴을 도입했습니다.\n\n먼저 **멱등 키**는 결제 요청마다 고유한 키를 발급하고 DB의 Unique 제약 조건을 활용해, 동일한 콜백이 여러 번 들어오더라도 단 한 번만 처리되도록 **중복 요청 실패 케이스**를 방어했습니다.\n\n그리고 **Transactional Outbox 패턴**은 주문 정보를 저장하는 DB 트랜잭션과 Kafka 이벤트 발행 사이의 **원자성 보장 문제**를 해결하기 위해 적용했습니다. 주문 데이터를 커밋할 때 Outbox 테이블에도 이벤트 발행 대기 상태를 함께 저장한 뒤, 이를 안전하게 Kafka로 발행하는 구조를 통해 장애 시에도 데이터 불일치를 방지하고 중복 주문 0건을 달성할 수 있었습니다.", "coaching_comment": "단순히 '잘 해결했다'고 넘어가지 말고, 멱등 키가 막는 중복 요청과 Outbox 패턴이 해결하는 Dual Write(원자성) 문제를 각각 명확히 구분하여 구조적으로 설명해야 합니다."}, "latency_sec": 3.058, "in_tokens": 1382, "out_tokens": 586} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 7, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC 환경에서 오래 지속되는 트랜잭션은 `xmin_horizon`을 현재 시점으로 전진시키지 못하게 막는 주요 원인이 됩니다. 이로 인해 VACUUM 작업이 수행되더라도, 해당 트랜잭션이 시작된 시점 이후에 생성된 dead tuple들은 가비지 컬렉션의 대상에서 제외되어 회수되지 않고 유지됩니다. 결과적으로 디스크 공간이 낭비되고 테이블 Bloat 현상이 발생하여, 전체적인 인덱스 및 테이블 스캔 성능 저하로 이어질 수 있습니다.", "answer_rewrite": "오래 열린 트랜잭션이 존재하면 PostgreSQL의 MVCC에서 VACUUM이 dead tuple을 제대로 회수하지 못하게 됩니다. 트랜잭션이 유지되는 동안 그 시작 시점의 xmin이 기준점으로 잡혀 있어, 그 이후 발생한 dead tuple들이 '아직 누군가 볼 수 있는 데이터'로 간주되기 때문입니다. 이로 인해 디스크 공간이 낭비되는 테이블 Bloat 현상이 발생할 수 있다는 점을 인지하고 있습니다.", "coaching_comment": "모르는 기술 개념이라도 VACUUM과 dead tuple이라는 키워드를 활용해 MVCC의 기본 원리와 연관지어 유추하는 답변을 시도하는 것이 좋습니다."}, "latency_sec": 2.422, "in_tokens": 915, "out_tokens": 297} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 8, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 직전 2주가 지연되는 갈등이 있었습니다. 저는 이 문제를 해결하기 위해 OpenAPI 명세를 선행 작성하고 Mock 서버를 띄워 프론트엔드 팀이 API 대기 없이 병렬 개발을 할 수 있도록 구조를 개선했습니다. 그 결과 다음 스프린트에서는 API 통합 관련 이슈가 3건에서 0건으로 줄어들며 일정을 맞출 수 있었습니다. 이 경험을 통해 기술적 해결책뿐만 아니라, 갈등 상황에서 상대방의 작업 블로커를 먼저 해소하고 대안을 제안하는 소통의 중요성을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트를 진행할 때, 프론트엔드 팀원과 API 스펙 해석에 대한 이견이 생겨 통합 직전 2주 동안 일정이 지연된 경험이 있습니다. 처음에는 제 주장을 고집하다가 감정이 상하기도 했지만, 문제를 해결하기 위해 OpenAPI 명세를 먼저 작성하고 Mock 서버를 구축하여 프론트엔드 팀이 독립적으로 병렬 개발을 할 수 있도록 제안했습니다. 그 결과 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 감소하며 무사히 프로젝트를 마칠 수 있었습니다. 이 경험을 통해 의견이 충돌할 때는 단순히 대화로 끝내는 것이 아니라, 객관적인 명세를 바탕으로 대안을 비교하고 상대방의 작업 흐름을 배려하는 방식으로 협업하는 법을 배웠습니다.", "coaching_comment": "추상적인 소통 찬양보다는 캡스톤 프로젝트의 API 스펙 갈등 사례와 구체적인 해결 행동(OpenAPI 명세, Mock 서버), 그리고 정량적 결과(이슈 3건->0건)를 STAR 구조로 명확히 드러내야 합니다."}, "latency_sec": 3.057, "in_tokens": 1250, "out_tokens": 420} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 9, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 네트워크 재시도와 비동기 메시징 환경에서의 원자성 결여가 원인이었습니다. 이를 해결하기 위해 두 가지 패턴을 결합해 적용했습니다.\n\n첫째, **멱등 키(Idempotency Key)**는 API 호출이나 외부 결제 게이트웨이의 콜백이 중복으로 들어올 때 동일한 요청임을 식별하여, 비즈니스 로직이 단 한 번만 수행되도록 보장합니다. 즉, 동일한 결제 건에 대해 여러 번 승인 요청이 와도 최초 1회만 처리하고 이후는 기존 결과를 반환합니다.\n\n둘째, **Transactional Outbox 패턴**은 주문 DB에 데이터를 저장하는 트랜잭션과 메시지 브로커(Kafka)에벤트를 발행하는 행위를 하나의 트랜잭션 경계 내에서 원자적으로 처리합니다. 만약 DB 저장 후 Kafka 발행 직전에 애플리케이션이 다운되거나 네트워크가 끊기면 이벤트 유실이 발생하는데, Outbox 테이블을 두어 DB 트랜잭션 내에 발행할 이벤트를 함께 저장한 뒤 별도 폴링이나 Debezium 등으로 안정적으로 메시지를 발행하여 **'At-least-once' 전달과 유실 방지**를 보장합니다. 결과적으로 중복 요청 방지는 멱등 키가, DB와 메시지 간의 데이터 일관성은 Outbox 패턴이 담당하도록 설계했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 인한 중복 주문은 멱등 키와 Transactional Outbox 패턴을 함께 사용하여 해결했습니다.\n\n결제 게이트웨이의 콜백이 지연되면서 클라이언트나 외부 시스템에서 동일한 요청을 중복으로 재시도하는 문제가 발생했습니다. 이를 막기 위해 **주문 테이블에 멱등 키(Idempotency Key) 제약조건**을 두어, 동일한 결제 고유 번호로는 중복 주문 데이터가 생성되지 않고 기존 결과를 반환하도록 처리했습니다.\n\n동시에 주문 생성 트랜잭션과 Kafka 이벤트 발행 간의 원자성을 보장하기 위해 **Transactional Outbox 패턴**을 도입했습니다. 비즈니스 로직 수행 시 Outbox 테이블에 발행할 이벤트를 함께 저장하여, DB 저장 성공 후 메시지 브로커 장애로 인한 이벤트 유실이나 불일치 케이스를 방지했습니다. 이로 인해 결제 지연 및 재시도 환경에서도 중복 주문 0건을 달성할 수 있었습니다.", "coaching_comment": "모호한 표현 대신 멱등 키가 막는 중복 요청과 Outbox 패턴이 해결하는 메시지 유실/원자성 문제를 각각 명확히 구분하여 설명해야 합니다."}, "latency_sec": 3.707, "in_tokens": 1382, "out_tokens": 617} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 10, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC 환경에서 오래 열린 트랜잭션(Long-running Transaction)은 VACUUM의 dead tuple 회수를 심각하게 지연시킵니다. VACUUM은 현재 실행 중인 가장 오래된 트랜잭션의 ID(xmin horizon)보다 이전의 xmin을 가진 dead tuple만 물리적으로 제거할 수 있기 때문입니다. 따라서 특정 트랜잭션이 오래 유지되면, 그 시점 이후에 발생한 수많은 dead tuple들이 회수되지 못하고 유지되어 디스크 공간 낭비와 Sequential Scan 성능 저하를 유발하는 테이블 블로트(Table Bloat) 현상으로 이어지게 됩니다.", "answer_rewrite": "잘 모르는 기술 개념 질문이라도 '모른다'고 바로 넘어가기보다는, 알고 있는 MVCC의 기본 개념(Dead tuple과 트랜잭션 ID 관리)을 바탕으로 유추해 답변하는 태도가 좋습니다. 예를 들어 다음과 같이 시도할 수 있습니다: \"정확한 VACUUM 내부 메커니즘까지는 기억나지 않지만, MVCC 특성상 오래 열린 트랜잭션이 존재하면 데이터의 유효성을 판단하는 기준점(xmin)이 과거에 머물러, 그 사이에 발생한 dead tuple들을 가비지 컬렉션(VACUUM)이 안전하게 지우지 못하고 쌓아두게 되는 것으로 이해하고 있습니다. 이로 인해 디스크 공간 낭비나 블로트 현상이 발생할 수 있을 것 같습니다.\"", "coaching_comment": "모르는 기술 질문이라도 완전히 포기하기보다는 MVCC의 핵심 원리(시점 유지 및 트랜잭션 ID)를 엮어서 아는 범위까지 논리적으로 유추해 답변하는 모습을 보여주세요."}, "latency_sec": 2.788, "in_tokens": 915, "out_tokens": 396} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 11, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 직전 2주가 지연되는 갈등이 있었습니다. 저는 서로의 주관적 해석을 맞추기보다 **OpenAPI 명세를 먼저 정의하고 Mock 서버를 구축**해 프론트엔드가 병렬로 개발할 수 있는 환경을 만들자고 제안했습니다. 그 결과, 이후 스프린트에서 통합 이슈가 3건에서 0건으로 줄어들며 일정을 맞출 수 있었습니다. 이 경험을 통해 기술적 해결책뿐만 아니라, 내 주장을 고집하기보다 **객관적인 도구와 대안을 제시해 팀원과 감정적 소모 없이 문제를 해결하는 법**을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트 진행 중 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주 동안 일정이 지연된 갈등 상황이 있었습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트엔드 팀이 병렬로 개발할 수 있도록 구조적인 해결책을 제안했습니다. 이 과정에서 제 방식을 너무 고집해 초반에 감정이 상하기도 했지만, 이후에는 대안 두 가지를 함께 비교하며 조율하는 방식으로 소통 방식을 개선했습니다. 결과적으로 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄어들며 성공적으로 프로젝트를 마무리할 수 있었습니다.", "coaching_comment": "추상적인 소통 예찬 대신 이력서에 있는 캡스톤 프로젝트의 구체적인 갈등 상황과 해결 과정을 STAR 구조로 담아내야 합니다."}, "latency_sec": 2.409, "in_tokens": 1250, "out_tokens": 378} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 12, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 발생한 중복 주문 문제는 네트워크 재시도와 비동기 메시징 환경에서의 원자성 결여가 원인이었습니다. 이를 해결하기 위해 두 가지 방어선을 구축했습니다.\n\n첫째, **멱등 키(Idempotency Key)**를 도입하여 결제 요청 및 주문 생성 시 고유 키(주문 번호 또는 결제 트랜잭션 ID)를 기반으로 DB 유니크 제약 조건을 걸어 동일한 요청이 여러 번 들어와도 최초 1회만 처리되도록 막았습니다. 이는 **네트워크 타임아웃으로 인한 클라이언트의 중복 요청(Retry) 시나리오**를 방어합니다.\n\n둘째, **Transactional Outbox 패턴**을 적용하여 주문 DB 저장과 Kafka 이벤트 발행 간의 원자성(Dual Write 문제)을 보장했습니다. 주문 데이터가 DB에 커밋될 때 Outbox 테이블에도 동일 트랜잭션으로 이벤트를 기록하고, 별도 릴레이 프로세스가 이를 읽어 Kafka로 발행하도록 했습니다. 이는 **DB 저장은 성공했으나 이벤트 발행 직전 애플리케이션이 죽거나 네트워크가 끊기는 실패 케이스**에서 메시지 유실이나 불일치를 방지합니다.", "answer_rewrite": "결제 승인 콜백이 지연될 때 클라이언트가 중복 요청을 보내거나 메시지 유실이 발생하는 문제를 막기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다.\n\n먼저 **멱등 키**를 통해 주문/결제 요청에 고유한 키를 부여하고 DB 유니크 제약 조건을 설정함으로써, 동일한 결제 승인 콜백이 중복으로 들어오더라도 1회만 처리되도록 중복 주문을 원천 차단했습니다.\n\n동시에 **Transactional Outbox 패턴**을 적용해, 주문 정보가 DB에 저장될 때 발행할 이벤트도 동일한 로컬 트랜잭션 내 Outbox 테이블에 함께 저장했습니다. 이후 폴링 릴레이를 통해 안전하게 Kafka로 이벤트를 발행함으로써, DB 트랜잭션과 메시지 발행 간의 불일치나 유실 문제를 해결했습니다.", "coaching_comment": "단순히 잘 처리했다는 답변 대신 멱등 키가 막는 중복 요청과 Outbox 패턴이 해결하는 분산 트랜잭션(Dual Write)의 실패 케이스를 각각 명확히 구분하여 설명해야 합니다."}, "latency_sec": 3.381, "in_tokens": 1382, "out_tokens": 547} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 13, "ok": true, "coaching": {"model_answer": "PostgreSQL은 MVCC를 구현하기 위해 각 튜플에 `xmin`, `xmax` 등의 트랜잭션 ID 시스템을 사용합니다. 이때 오래 열린 트랜잭션(Long-running transaction)이 존재하면, 해당 트랜잭션의 `xmin`이 전체 시스템의 `xmin horizon`을 결정하게 됩니다. VACUUM은 이 horizon보다 이전의 트랜잭션에서 생성된 dead tuple만 안전하게 회수할 수 있으므로, 오래 열린 트랜잭션 때문에 horizon이 전진하지 못하면 dead tuple이 쌓이게 됩니다. 이는 결국 디스크 공간 낭비와 Sequential Scan 성능 저하를 유발하는 Table Bloat 현상으로 이어집니다.", "answer_rewrite": "모르는 기술 개념 질문이라 하더라도 솔직하게 모른다고 넘어가기보다는, MVCC의 기본 개념(xmin/xmax)과 VACUUM의 목적을 엮어 유추한 내용을 답변하는 것이 좋습니다. 예를 들어 \"오래 열린 트랜잭션이 존재하면 VACUUM이 삭제된 dead tuple을 정리하는 기준 시점(xmin horizon)을 뒤로 밀어내어, 결과적으로 dead tuple이 회수되지 못하고 Table Bloat을 유발하는 원인이 된다고 이해하고 있습니다\"와 같이 핵심 키워드를 포함해 답변할 수 있습니다.", "coaching_comment": "모르는 기술 질문이라도 핵심 키워드인 xmin horizon, dead tuple, table bloat 개념을 엮어 아는 만큼 논리적으로 유추해 답변하는 태도가 필요합니다."}, "latency_sec": 2.506, "in_tokens": 915, "out_tokens": 351} +{"label": "gw-gemini-3.5-flash-lite", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 14, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 직전 2주간 일정이 지연된 갈등 상황이 있었습니다. 저는 서로의 주장을 고집하기보다 객관적인 명세를 먼저 맞추는 것이 중요하다고 판단하여, OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트엔드 팀원이 병렬로 개발할 수 있도록 환경을 개선했습니다. 그 결과 다음 스프린트에서는 통합 이슈가 3건에서 0건으로 줄어들며 일정을 맞출 수 있었습니다. 이 경험을 통해 기술적 해결책뿐만 아니라, 갈등 상황에서 감정을 배제하고 프로세스를 개선하는 방식으로 소통하는 법을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트를 진행할 때 프론트엔드 팀원과 API 스펙 해석 차이로 인해 통합 직전 2주 동안 일정이 지연된 적이 있습니다. 당시 제 방식이 옳다고 고집하다가 팀원과 감정이 상하기도 했습니다. 이를 해결하기 위해 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트엔드 팀원이 병렬로 개발을 진행할 수 있도록 제안했습니다. 이 과정에서 내 주장을 강요하기보다는 대안을 비교해 제시하는 방식으로 소통 방식을 바꿨고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄어들며 성공적으로 프로젝트를 마칠 수 있었습니다.", "coaching_comment": "추상적인 소통 찬양보다는 이력서에 있는 캡스톤 프로젝트의 구체적인 갈등 사례와 해결 프로세스, 정량적 결과(이슈 3건->0건)를 STAR 구조로 명확히 드러내야 합니다."}, "latency_sec": 2.494, "in_tokens": 1250, "out_tokens": 395} +{"label": "gw-gemini-3.5-flash-lite", "suite": "followup:during-fanout", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "유니크 제약만으로 동시 요청이 몰릴 때 발생할 수 있는 race condition을 완벽히 막지 못할 수도 있는데, 멱등 키 검증 시 동시성 제어는 어떻게 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 2.077, "ttft_sec": 1.621, "in_tokens": 9054, "out_tokens": 325} +{"label": "gw-gemini-3.5-flash-lite", "suite": "fanout_wall", "wall_sec": 10.826, "ok": true} diff --git a/docs/research/llm-eval-2026-09/raw/gw-gemma-4-31b.jsonl b/docs/research/llm-eval-2026-09/raw/gw-gemma-4-31b.jsonl new file mode 100644 index 0000000..7923fa4 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/gw-gemma-4-31b.jsonl @@ -0,0 +1,61 @@ +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "Outbox 테이블의 데이터를 릴레이가 폴링해 발행할 때, 메시지가 중복 발행될 가능성은 어떻게 해결하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 5.79, "ttft_sec": 3.524, "in_tokens": 3050, "out_tokens": 152} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "'중복이 안 생기게 처리했다'고 하셨는데, 멱등 키가 구체적으로 어떤 시점에 어떻게 검증되어 중복을 막았는지 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 16.038, "ttft_sec": 5.326, "in_tokens": 2790, "out_tokens": 168} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "괜찮습니다. 그럼 MVCC의 기본 개념이나, PostgreSQL에서 데이터 업데이트 시 내부적으로 어떻게 동작하는지 아는 범위 내에서 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 114.016, "ttft_sec": null, "in_tokens": 2698, "out_tokens": 164} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "괜찮습니다. 그럼 혹시 React에서 상태 업데이트를 여러 번 호출했을 때 성능을 최적화하기 위해 React가 내부적으로 어떻게 동작하는지 아시는 대로 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 14.069, "ttft_sec": null, "in_tokens": 2696, "out_tokens": 178} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA의 CPU 임계값을 70%로 설정하신 이유와, 자동 확장 외에 수동으로 미리 서버를 늘리는 사전 스케일아웃을 함께 사용하신 이유가 궁금합니다.", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 192.494, "ttft_sec": 132.339, "in_tokens": 2768, "out_tokens": 176} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "폴링 주기를 어느 정도로 설정하셨으며, 그 기준은 무엇이었나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 18.506, "ttft_sec": 7.463, "in_tokens": 2740, "out_tokens": 120} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "이력서에는 CPU 70% 기준과 CronJob을 통한 사전 스케일아웃을 운영하셨다고 적혀 있는데, 답변하신 내용과 차이가 있는 이유가 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "NONE", "correctness": 1.0}, "latency_sec": 114.173, "ttft_sec": 20.446, "in_tokens": 3332, "out_tokens": 176} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "autovacuum의 scale_factor를 0.05로 낮춘 것이 쿼리 성능 개선에 구체적으로 어떤 영향을 주었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 33.655, "ttft_sec": 8.145, "in_tokens": 3570, "out_tokens": 158} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "내용에 따라 다른 항목 높이를 관리하기 위해 구현하신 높이 캐시의 구체적인 갱신 전략은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 25.886, "ttft_sec": 6.621, "in_tokens": 3514, "out_tokens": 154} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "결정 전 대안 두 개를 비교하셨다고 했는데, 실제 사례에서 어떤 대안들을 비교해 결정하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 74.106, "ttft_sec": 13.274, "in_tokens": 2898, "out_tokens": 148} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "\"대화를 많이 하는 게 중요하다\"고 하셨는데, 실제로 의견 차이를 대화로 해결해 성과를 냈던 구체적인 사례가 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 46.484, "ttft_sec": 11.731, "in_tokens": 2780, "out_tokens": 158} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "재시도 횟수를 제한하거나 대기 시간을 조절하는 등의 전략 대신 분산 락을 선택하신 구체적인 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 31.478, "ttft_sec": 3.134, "in_tokens": 2846, "out_tokens": 158} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "Outbox 패턴을 사용하셨다고 했는데, DB에 저장된 이벤트를 Kafka로 발행하는 구체적인 메커니즘은 무엇이었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 5.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 18.719, "ttft_sec": 3.142, "in_tokens": 3462, "out_tokens": 158} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "화면별로 staleTime을 다르게 설정하셨다고 했는데, 어떤 기준으로 구분해 설정하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 25.163, "ttft_sec": 4.748, "in_tokens": 2808, "out_tokens": 142} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "Outbox 테이블의 데이터를 릴레이가 폴링할 때, 메시지 발행 후 처리 완료 상태를 어떻게 관리하시나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 44.064, "ttft_sec": 9.414, "in_tokens": 3050, "out_tokens": 146} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "중복 방지를 위해 멱등 키를 구체적으로 어디에 저장하고 어떻게 검증하셨는지 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 54.285, "ttft_sec": 10.87, "in_tokens": 2790, "out_tokens": 142} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "괜찮습니다. 그럼 MVCC의 기본 개념이나, PostgreSQL에서 데이터 업데이트 시 내부적으로 어떤 일이 일어나는지 아시는 대로 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 19.998, "ttft_sec": null, "in_tokens": 2698, "out_tokens": 164} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "괜찮습니다. 그럼 혹시 React에서 상태 업데이트를 효율적으로 처리하기 위해 여러 개의 setState를 하나로 묶어 처리하는 '배칭(Batching)'의 기본 개념에 대해 아시는 대로 설명해 주실 수 있을까요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 14.093, "ttft_sec": null, "in_tokens": 2696, "out_tokens": 196} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "HPA의 CPU 70% 설정 근거와, HPA가 있음에도 트래픽 피크 때 수동으로 미리 서버를 늘리신 이유를 각각 나누어 설명해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 16.124, "ttft_sec": 5.246, "in_tokens": 2768, "out_tokens": 178} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "폴링 주기와 DB 부하 사이의 트레이드오프는 어떻게 고려하여 설정하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 8.811, "ttft_sec": 4.859, "in_tokens": 2740, "out_tokens": 130} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "이력서에는 CPU 70% 기준과 CronJob을 통한 사전 스케일아웃을 운영하셨다고 적혀 있는데, 답변하신 내용과 차이가 있는 이유가 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": 1.0}, "latency_sec": 15.391, "ttft_sec": 5.653, "in_tokens": 3332, "out_tokens": 176} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "autovacuum의 scale_factor를 0.05로 낮춘 것이 쿼리 성능 개선에 구체적으로 어떤 영향을 주었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 8.663, "ttft_sec": 3.216, "in_tokens": 3570, "out_tokens": 158} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "내용에 따라 다른 항목 높이를 관리하기 위해 구축하신 높이 캐시의 구체적인 동작 방식은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 9.514, "ttft_sec": 3.152, "in_tokens": 3514, "out_tokens": 150} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "결정 전 대안 두 개를 비교하셨다고 했는데, 최근에 실제로 그렇게 적용해 합의를 이끌어낸 사례가 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 8.793, "ttft_sec": 3.594, "in_tokens": 2898, "out_tokens": 156} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "구체적으로 대화를 통해 의견 차이를 좁혀서 프로젝트 결과나 팀 분위기가 개선되었던 사례가 있을까요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 50.75, "ttft_sec": 7.513, "in_tokens": 2780, "out_tokens": 142} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "재시도 횟수를 제한하는 방식 대신 분산 락을 선택하신 구체적인 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 4.368, "ttft_sec": 1.793, "in_tokens": 2846, "out_tokens": 144} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "보상 이벤트 유실 시 스위퍼 배치가 상태를 재조회한다고 하셨는데, 이때 재조회 대상 서비스의 API 호출 결과가 '실패'라면 어떤 방식으로 최종 상태를 확정하시나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 5.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 5.531, "ttft_sec": 1.907, "in_tokens": 3462, "out_tokens": 186} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "화면별로 staleTime을 다르게 설정하셨다고 했는데, 어떤 기준으로 기준 시간을 차등 적용하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 5.001, "ttft_sec": 1.902, "in_tokens": 2808, "out_tokens": 146} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "Outbox 테이블의 데이터를 릴레이가 폴링할 때, 메시지 발행 후 처리 완료 상태를 어떻게 업데이트하시나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 5.598, "ttft_sec": 1.814, "in_tokens": 3050, "out_tokens": 146} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "'중복이 안 생기게' 처리하셨다고 했는데, 멱등 키를 구체적으로 어떤 시점에 검증하고 어떻게 저장하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.809, "ttft_sec": 1.814, "in_tokens": 2790, "out_tokens": 156} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "괜찮습니다. 그럼 MVCC의 기본 개념이나, PostgreSQL에서 데이터 업데이트 시 내부적으로 어떤 일이 일어나는지 아시는 대로 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.147, "ttft_sec": null, "in_tokens": 2698, "out_tokens": 164} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "괜찮습니다. 그럼 혹시 React에서 상태 업데이트를 효율적으로 처리하기 위해 기본적으로 제공하는 '배칭(Batching)'의 개념에 대해 아시는 대로 설명해 주실 수 있을까요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.376, "ttft_sec": null, "in_tokens": 2696, "out_tokens": 180} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA의 CPU 70% 설정 근거와, 자동 확장 외에 수동으로 미리 서버를 늘려주신 이유를 각각 나누어 설명해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 5.997, "ttft_sec": 2.955, "in_tokens": 2768, "out_tokens": 166} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "폴링 주기를 어느 정도로 설정하셨으며, 그 주기를 결정하신 기준은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.885, "ttft_sec": 1.804, "in_tokens": 2740, "out_tokens": 128} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "이력서에는 CPU 70% 설정과 CronJob을 통한 사전 스케일아웃을 운영하셨다고 적혀 있는데, 답변하신 내용과 다른 이유가 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": 1.0}, "latency_sec": 5.217, "ttft_sec": 1.826, "in_tokens": 3332, "out_tokens": 172} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "autovacuum의 scale_factor를 0.05로 낮춘 것이 쿼리 성능 개선에 구체적으로 어떤 영향을 주었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 4.545, "ttft_sec": 1.84, "in_tokens": 3570, "out_tokens": 158} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "내용에 따라 다른 항목 높이를 관리하기 위해 사용하신 높이 캐시의 구체적인 갱신 시점과 방식은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 5.541, "ttft_sec": 1.864, "in_tokens": 3514, "out_tokens": 160} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "\"대안 두 개를 비교하는 방식\"으로 바꾼 후, 실제로 의견 충돌을 해결했던 구체적인 사례가 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 4.489, "ttft_sec": 1.901, "in_tokens": 2898, "out_tokens": 150} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "\"대화를 많이 하는 게 중요하다\"고 하셨는데, 실제로 의견 차이가 있었던 구체적인 사례와 당시 어떤 대화를 통해 합의점을 찾으셨는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.69, "ttft_sec": 1.773, "in_tokens": 2780, "out_tokens": 166} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "재시도 부하를 줄이기 위해 분산 락을 도입하셨는데, 락 획득 대기 시간이 길어질 때의 처리 방식은 어떻게 구현하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 4.948, "ttft_sec": 1.781, "in_tokens": 2846, "out_tokens": 176} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "보상 이벤트 유실 시 스위퍼 배치가 상태를 재조회한다고 하셨는데, 재조회 후 상태를 업데이트하는 과정에서 발생할 수 있는 동시성 문제는 어떻게 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 5.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 5.738, "ttft_sec": 2.498, "in_tokens": 3462, "out_tokens": 182} +{"label": "gw-gemma-4-31b", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "화면별로 staleTime을 다르게 설정하셨다고 했는데, 어떤 기준으로 기준점을 나누셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 4.554, "ttft_sec": 1.741, "in_tokens": 2808, "out_tokens": 140} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연으로 인해 동일한 요청이 여러 번 들어오는 상황에서 **데이터 정합성**과 **이벤트 발행의 보장**이라는 두 가지 문제를 해결해야 했습니다.\n\n먼저 **멱등 키(Idempotency Key)**는 '중복 처리 방지'를 위해 도입했습니다. 결제 요청 시 생성한 고유 키를 DB의 멱등성 테이블에 저장하고, 동일한 키로 요청이 다시 들어오면 이미 처리된 요청으로 판단해 즉시 반환함으로써 중복 주문 생성을 막았습니다.\n\n하지만 주문 생성 후 Kafka로 주문 완료 이벤트를 발행할 때, DB 업데이트는 성공했지만 네트워크 장애로 이벤트 발행에 실패하는 **분산 트랜잭션 문제**가 발생할 수 있었습니다. 이를 해결하기 위해 **Transactional Outbox 패턴**을 적용했습니다. 주문 정보와 이벤트 데이터를 동일한 로컬 DB 트랜잭션 내에서 함께 저장하고, 별도의 Message Relay가 Outbox 테이블을 읽어 Kafka로 발행하게 함으로써 '최소 한 번(At-least-once) 전달'을 보장했습니다.\n\n결과적으로 멱등 키로 **중복 주문을 0건**으로 만들고, Outbox 패턴으로 **주문-결제 간 데이터 불일치**를 완전히 해결할 수 있었습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 인해 동일한 요청이 중복으로 들어오는 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 적용했습니다.\n\n첫째로, **멱등 키**를 통해 동일한 결제 요청이 여러 번 들어와도 주문이 중복 생성되지 않도록 처리했습니다. 요청마다 고유한 키를 부여해 DB에서 체크함으로써 중복 주문 발생을 원천적으로 차단했습니다.\n\n둘째로, 주문 생성 후 Kafka로 이벤트를 발행하는 과정에서 발생할 수 있는 유실 문제를 **Outbox 패턴**으로 해결했습니다. DB 트랜잭션 내에 이벤트 저장 로직을 포함시켜, 주문 저장과 이벤트 기록이 원자적으로 이루어지게 했습니다. 이후 별도 프로세스가 이 이벤트를 읽어 Kafka로 발행함으로써 시스템 간 정합성을 맞췄습니다.\n\n이러한 구조를 통해 중복 주문 0건을 달성하고, 안정적인 이벤트 기반 아키텍처를 구축할 수 있었습니다.", "coaching_comment": "추상적인 표현 대신 멱등 키는 '중복 요청 방지', Outbox 패턴은 '이벤트 발행 보장'이라는 구체적인 기술적 목적과 실패 케이스를 연결해 답변해야 합니다."}, "latency_sec": 26.135, "in_tokens": 1399, "out_tokens": 582} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC는 데이터 업데이트 시 기존 튜플을 삭제하지 않고 새로운 버전을 생성합니다. 이때 `VACUUM`은 더 이상 어떤 트랜잭션에서도 참조하지 않는 **dead tuple**을 회수하여 공간을 재사용 가능하게 만듭니다.\n\n만약 오래 열려 있는 트랜잭션(Long-running Transaction)이 있다면, 해당 트랜잭션의 `xmin`(가장 오래된 활성 트랜잭션 ID)이 **horizon** 역할을 하여 그 이후에 생성된 dead tuple들을 삭제하지 못하게 막습니다. 결과적으로 `VACUUM`이 수행되어도 실제 데이터 회수가 일어나지 않아 테이블 크기가 비정상적으로 커지는 **Table Bloat** 현상이 발생하며, 이는 I/O 성능 저하와 인덱스 효율 감소로 이어집니다.", "answer_rewrite": "죄송합니다. 해당 부분에 대해 정확히 숙지하지 못했습니다. 다만 제가 아는 범위 내에서 말씀드리면, PostgreSQL은 MVCC를 통해 데이터 버전을 관리하며 VACUUM이 불필요한 데이터를 정리하는 것으로 알고 있습니다. 오래된 트랜잭션이 이 정리 과정에 영향을 주어 성능 저하를 일으킬 수 있다고 생각하는데, 정확한 메커니즘에 대해서는 추가로 학습하여 보완하겠습니다.", "coaching_comment": "모르는 질문에도 완전히 포기하기보다, 아는 키워드(MVCC, VACUUM)를 활용해 논리적으로 추론하려는 시도를 보여주는 것이 중요합니다."}, "latency_sec": 14.372, "in_tokens": 932, "out_tokens": 345} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시, API 스펙 해석 차이로 인해 통합 작업이 2주나 지연되는 갈등 상황이 있었습니다. 저는 효율성을 위해 OpenAPI 명세 작성과 Mock 서버 도입을 제안했지만, 초기에는 제 방식만을 고집하여 팀원과 감정적인 충돌이 발생했습니다.\n\n이를 해결하기 위해 제가 먼저 다가가 소통 방식을 수정했습니다. 일방적인 제안 대신 **'대안 두 가지를 함께 제시하고 장단점을 비교'**하는 방식으로 의사결정 과정을 바꿨습니다. 결과적으로 프론트엔드와 백엔드가 병렬 개발이 가능해졌고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄어드는 성과를 거두었습니다. 이 경험을 통해 기술적 정답보다 팀원이 납득할 수 있는 합의 과정이 프로젝트의 속도를 높인다는 것을 배웠습니다.", "answer_rewrite": "사실 저는 원만한 성격이라 큰 갈등은 없었지만, 캡스톤 프로젝트 당시 API 스펙 해석 차이로 팀원과 의견 충돌이 있었던 경험이 있습니다. 당시 저는 OpenAPI 명세와 Mock 서버 도입을 제안하며 제 방식이 옳다고 고집해 팀원과 감정이 상하기도 했습니다.\n\n하지만 소통 방식의 문제임을 깨닫고, 이후에는 결정 전 항상 두 가지 이상의 대안을 준비해 팀원과 함께 장단점을 비교하는 방식으로 접근했습니다. 덕분에 팀원들의 동의를 얻어 효율적인 개발 환경을 구축할 수 있었고, 통합 이슈를 3건에서 0건으로 줄이며 프로젝트를 성공적으로 마칠 수 있었습니다.", "coaching_comment": "추상적인 '소통' 강조보다는 자소서에 기재된 API 스펙 갈등과 해결 과정(대안 비교 방식)이라는 구체적인 STAR 사례를 제시해야 합니다."}, "latency_sec": 20.196, "in_tokens": 1267, "out_tokens": 423} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": true, "coaching": {"model_answer": "결제 승인 콜백은 네트워크 지연이나 재시도 메커니즘으로 인해 동일한 요청이 여러 번 들어올 수 있습니다. 이때 **멱등 키(Idempotency Key)**는 '중복 요청'을 막기 위해 사용했습니다. 결제 요청 시 생성한 고유 키를 DB의 멱등성 테이블에 저장하고, 동일 키로 요청이 오면 이미 처리된 응답을 반환함으로써 중복 주문 생성을 원천 차단했습니다.\n\n하지만 멱등성 처리 후 주문 상태를 변경하고 Kafka로 이벤트를 발행하는 과정에서, DB 업데이트는 성공했지만 네트워크 장애로 이벤트 발행에 실패하는 '원자성 결여' 문제가 발생할 수 있습니다. 이를 해결하기 위해 **Transactional Outbox 패턴**을 도입했습니다. 이벤트 발행 내용을 DB의 Outbox 테이블에 주문 상태 변경과 하나의 트랜잭션으로 묶어 저장하고, 별도의 Relay 프로세스가 이를 읽어 Kafka로 발행하게 함으로써 '최소 한 번 전송(At-least-once delivery)'을 보장했습니다. 결과적으로 멱등 키는 **중복 처리를**, Outbox 패턴은 **데이터 일관성과 메시지 발행 보장**을 책임지게 하여 중복 주문 0건을 달성했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 인해 동일한 요청이 중복으로 들어오는 상황에서, 데이터 정합성을 보장하기 위해 두 가지 전략을 함께 사용했습니다.\n\n먼저 **멱등 키**를 도입하여 중복 요청을 방지했습니다. 요청마다 고유한 키를 부여해 DB에서 처리 여부를 확인하게 함으로써, 동일한 결제 건에 대해 주문이 여러 번 생성되는 케이스를 막았습니다.\n\n이후 주문 완료 후 타 서비스로 이벤트를 보내야 하는데, DB 저장과 Kafka 메시지 발행이 분리되어 있어 발생하는 '부분 실패' 문제를 해결하고자 **Outbox 패턴**을 적용했습니다. 주문 정보와 이벤트 메시지를 하나의 로컬 트랜잭션으로 묶어 Outbox 테이블에 저장함으로써, 시스템 장애가 발생하더라도 반드시 이벤트가 발행되도록 설계했습니다. 이를 통해 중복 주문을 완전히 제거하고 서비스 간 데이터 일관성을 확보할 수 있었습니다.", "coaching_comment": "추상적인 표현 대신 각 기술이 해결하려는 구체적인 실패 시나리오(중복 요청 vs 메시지 발행 실패)를 명확히 구분하여 답변해야 합니다."}, "latency_sec": 26.879, "in_tokens": 1399, "out_tokens": 543} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC는 데이터 변경 시 기존 튜플을 유지하고 새로운 버전을 생성하는 방식을 사용합니다. 이때 `VACUUM`은 더 이상 어떤 트랜잭션에서도 참조하지 않는 **Dead Tuple**을 찾아 회수하는 역할을 합니다.\n\n만약 오래 열려 있는 트랜잭션(Long-running Transaction)이 있다면, 해당 트랜잭션의 `xmin`(트랜잭션 ID)이 **xmin horizon**을 뒤로 밀어내게 됩니다. `VACUUM`은 이 horizon보다 오래된 데이터만 삭제할 수 있는데, 오래된 트랜잭션이 살아있으면 그 시점 이후에 생성된 Dead Tuple들을 '여전히 필요할 수 있는 데이터'로 판단하여 삭제하지 못합니다. 결과적으로 Dead Tuple이 계속 쌓여 테이블 크기가 비정상적으로 커지는 **Table Bloat** 현상이 발생하며, 이는 I/O 성능 저하와 인덱스 효율 감소로 이어집니다.", "answer_rewrite": "죄송합니다. 해당 부분에 대해 정확히 숙지하지 못했습니다. 다만 제가 이해하고 있는 MVCC의 기본 개념으로는, PostgreSQL이 데이터 변경 시 이전 버전을 남겨두기 때문에 이를 정리하는 VACUUM 과정이 필수적이라고 알고 있습니다. 오래 열린 트랜잭션이 이 정리 작업을 방해하여 성능 저하를 일으키는 메커니즘에 대해 더 학습하여 보완하겠습니다.", "coaching_comment": "기술 면접에서 모르는 질문이 나왔을 때는 단순히 넘기기보다, 아는 범위 내의 기본 개념(MVCC, VACUUM)을 먼저 언급하며 논리적으로 접근하려는 시도를 보여주는 것이 중요합니다."}, "latency_sec": 15.973, "in_tokens": 932, "out_tokens": 377} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시, API 스펙 해석 차이로 인해 통합 작업이 2주나 지연되는 갈등 상황이 있었습니다. 저는 효율적인 해결을 위해 **OpenAPI 명세 작성과 Mock 서버 구축**을 제안하여 프론트엔드와 백엔드가 병렬로 개발할 수 있는 환경을 만들었습니다. 그 결과, 이후 스프린트에서 통합 이슈가 **3건에서 0건으로 감소**하는 성과를 거두었습니다.\n\n다만, 이 과정에서 제 방식만을 고집해 팀원과 감정적인 충돌이 있었던 점을 반성했습니다. 이를 계기로 단순히 정답을 제시하는 것보다 **'두 가지 이상의 대안을 제시하고 함께 비교하여 결정'**하는 소통 방식을 도입했고, 팀원들의 심리적 안전감을 높이면서도 기술적 합의를 빠르게 이끌어내는 법을 배웠습니다.", "answer_rewrite": "저는 갈등 상황에서 단순한 대화보다는 '객관적인 기준'을 세워 해결하려 노력합니다. 캡스톤 프로젝트 당시 API 스펙 해석 차이로 통합이 2주 지연되었을 때, 저는 **OpenAPI 명세서 작성과 Mock 서버 도입**을 제안해 개발 병목을 해결했습니다. 덕분에 통합 이슈를 3건에서 0건으로 줄일 수 있었습니다.\n\n하지만 초반에 제 의견을 강하게 밀어붙여 팀원과 마찰이 있었던 경험이 있습니다. 이를 통해 기술적 정답보다 중요한 것은 팀원의 공감이라는 것을 깨달았고, 이후에는 **두 가지 이상의 선택지를 준비해 팀원과 함께 장단점을 비교하며 결정**하는 방식으로 소통 방식을 개선했습니다.", "coaching_comment": "추상적인 '소통' 강조보다는 자소서에 기재된 API 명세서 도입 사례와 소통 방식의 개선 과정을 STAR 구조로 구체화하세요."}, "latency_sec": 24.012, "in_tokens": 1267, "out_tokens": 434} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": true, "coaching": {"model_answer": "결제 승인 콜백은 네트워크 지연이나 재시도 메커니즘으로 인해 동일한 요청이 여러 번 들어올 수 있으며, 이를 처리하는 과정에서 DB 업데이트와 이벤트 발행이 원자적으로 이루어지지 않을 위험이 있습니다.\n\n먼저 **멱등 키(Idempotency Key)**는 '중복 요청'을 막기 위해 사용했습니다. 결제 요청 시 생성한 고유 키를 DB의 멱등성 테이블에 저장하고, 동일한 키로 요청이 오면 이미 처리된 요청으로 판단해 즉시 반환함으로써 중복 주문 생성을 원천 차단했습니다.\n\n하지만 멱등성 처리 후 주문 상태를 변경하고 Kafka로 이벤트를 발행할 때, DB 반영은 성공했지만 네트워크 장애로 이벤트 발행에 실패하는 '분산 트랜잭션' 문제가 발생할 수 있습니다. 이를 해결하기 위해 **Transactional Outbox 패턴**을 도입했습니다. 이벤트 발행 내용을 DB의 Outbox 테이블에 주문 상태 변경과 같은 트랜잭션으로 묶어 저장하고, 별도의 Relay 프로세스가 이를 읽어 Kafka로 발행하게 함으로써 '최소 한 번은 발행(At-least-once delivery)'됨을 보장했습니다.\n\n결과적으로 멱등 키로 **입력의 중복**을, Outbox 패턴으로 **출력의 유실**을 해결하여 중복 주문 0건을 달성할 수 있었습니다.", "answer_rewrite": "결제 승인 콜백 지연 시 발생하는 중복 요청과 데이터 불일치 문제를 해결하기 위해 두 가지 전략을 함께 사용했습니다.\n\n첫째, **멱등 키**를 도입하여 동일한 결제 요청이 여러 번 들어오더라도 실제 주문 생성 로직은 한 번만 실행되도록 처리했습니다. 이를 통해 네트워크 재시도로 인한 중복 주문 발생 케이스를 막았습니다.\n\n둘째, **Outbox 패턴**을 통해 주문 DB 업데이트와 Kafka 이벤트 발행 사이의 원자성을 보장했습니다. 주문 상태를 변경하는 트랜잭션 내에 이벤트 데이터를 Outbox 테이블에 함께 저장함으로써, DB는 업데이트되었는데 이벤트 발행만 실패하여 후속 서비스와 데이터가 불일치하는 케이스를 방지했습니다.\n\n이러한 구조를 통해 요청의 중복 처리와 이벤트 유실 문제를 모두 해결하여 중복 주문 0건이라는 결과를 얻었습니다.", "coaching_comment": "추상적인 답변 대신 멱등 키는 '중복 요청 방지', Outbox 패턴은 '트랜잭션 원자성 보장'이라는 각각의 명확한 역할과 실패 케이스를 기술적으로 설명해야 합니다."}, "latency_sec": 33.668, "in_tokens": 1399, "out_tokens": 583} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC는 데이터 변경 시 기존 튜플을 삭제하지 않고 새로운 버전을 생성하며, 더 이상 참조되지 않는 오래된 버전(Dead Tuple)을 **VACUUM**이 회수하는 구조입니다. 이때 VACUUM은 현재 실행 중인 모든 트랜잭션 중 가장 오래된 트랜잭션의 ID인 **xmin horizon**을 기준으로, 이보다 최신인 튜플들은 다른 트랜잭션에서 참조할 가능성이 있다고 판단하여 삭제하지 않습니다.\n\n만약 특정 트랜잭션이 매우 오래 열려 있다면, xmin horizon이 뒤로 밀리게 되어 VACUUM이 Dead Tuple을 정리하지 못하고 계속 누적시키게 됩니다. 결과적으로 물리적인 저장 공간이 낭비되는 **Table Bloat** 현상이 발생하며, 이는 인덱스 효율 저하와 전체적인 쿼리 성능 하락으로 이어집니다.", "answer_rewrite": "죄송합니다. 해당 부분에 대해 정확히 숙지하지 못했습니다. 다만 제가 이해하고 있는 MVCC의 기본 개념으로는, PostgreSQL이 데이터 업데이트 시 이전 버전을 남겨두고 이를 VACUUM이 정리하는 것으로 알고 있습니다. 트랜잭션이 오래 유지되면 이 정리 작업에 제약이 생겨 성능에 영향을 줄 수 있을 것 같은데, 이 부분은 면접 종료 후 반드시 다시 학습하여 보완하겠습니다.", "coaching_comment": "모르는 질문에도 단순히 넘기기보다, 아는 범위 내의 기본 개념(MVCC, VACUUM)을 언급하며 논리적으로 추론하려는 태도를 보이는 것이 중요합니다."}, "latency_sec": 13.678, "in_tokens": 932, "out_tokens": 359} +{"label": "gw-gemma-4-31b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트 당시 프론트엔드 팀원과 API 스펙 해석 차이로 통합 일정이 2주 지연되는 갈등을 겪었습니다. 초기에는 제 방식이 맞다고 고집하며 설득하려 했으나, 이는 오히려 팀원과의 감정적 갈등으로 이어졌습니다.\n\n이를 해결하기 위해 주관적인 주장이 아닌 **객관적인 기준**을 도입했습니다. **OpenAPI 명세**를 먼저 작성하고 **Mock 서버**를 구축하여 서로가 생각하는 스펙을 시각화하고 검증하는 방식을 제안했습니다. 그 결과, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄어들며 효율적으로 개발을 마칠 수 있었습니다. 이 경험을 통해 내 의견을 관철시키는 것보다, 팀원이 납득할 수 있는 객관적 근거와 대안을 제시하는 것이 협업의 핵심임을 배웠습니다.", "answer_rewrite": "사실 저는 원만한 관계를 지향하는 편이지만, 캡스톤 프로젝트 당시 API 스펙 해석 차이로 프론트엔드 팀원과 의견 충돌이 있었고 통합 일정이 2주 정도 지연된 적이 있습니다.\n\n처음에는 제 의견을 고집해 팀원과 감정이 상하기도 했지만, 소통 방식의 문제를 깨닫고 **OpenAPI 명세 작성과 Mock 서버 구축**이라는 구체적인 해결책을 제안했습니다. 서로의 해석을 명문화하여 확인하니 오해가 풀렸고, 이후 스프린트에서는 통합 이슈를 0건으로 줄일 수 있었습니다. 이 일을 계기로 무조건적인 대화보다는 **객관적인 데이터와 대안을 함께 비교**하며 의사결정 하는 습관을 갖게 되었습니다.", "coaching_comment": "추상적인 '소통' 강조보다는 자소서에 기재된 API 스펙 갈등 사례를 STAR 구조로 구체화하여 갈등 해결 능력과 성장 가능성을 증명하세요."}, "latency_sec": 22.56, "in_tokens": 1267, "out_tokens": 445} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연 시 멱등 키와 Outbox 패턴을 어떻게 조합해 중복 주문을 막으셨나요?", "job_category": "BACKEND", "target_evidence": "결제 콜백 지연으로 생긴 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결한 경험", "expected_signal": "멱등 키를 통한 요청 식별과 Outbox 패턴을 이용한 이벤트 발행의 원자성 보장 메커니즘을 구체적으로 설명할 수 있는가"}, {"category": "TECH_CHOICE", "question": "재고 동기화 구현 시 낙관적 락에서 분산 락으로 전환하신 구체적인 이유와 기준은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "충돌 빈도에 따른 락 전략의 트레이드오프를 이해하고, 분산 환경에서의 정합성 보장 방안을 선택한 근거가 명확한가"}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능을 5시간에서 40분으로 단축할 때 QueryDSL 튜닝의 핵심 포인트는 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "실행 계획 분석을 통한 쿼리 최적화 경험과 대량 데이터 처리 시 메모리 효율을 고려한 청크 처리 전략을 설명할 수 있는가"}, {"category": "CS_FUNDAMENTAL", "question": "주문 서비스를 분리하며 도입한 Kafka 이벤트 구조에서 메시지 발행 순서 보장을 위해 어떻게 설계하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "Kafka의 Partition 키 설계 등 분산 메시징 환경에서 이벤트 순서 보장과 정합성 유지 방법을 알고 있는가"}, {"category": "BEHAVIORAL", "question": "MSA 전환 과정에서 DB 분리로 인해 발생한 데이터 정합성 이슈를 해결하기 위해 노력한 경험이 있나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL)", "expected_signal": "분산 트랜잭션 환경의 어려움을 인지하고, 이를 해결하기 위한 본인의 구체적인 행동과 기술적 시도(Saga, TCC 등)가 드러나는가"}], "latency_sec": 38.486, "in_tokens": 2874, "out_tokens": 712} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "react-window 도입 후 INP를 480ms에서 120ms로 개선하셨는데, 구체적으로 어떤 렌더링 병목이 해결된 것인가요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "DOM 요소 수 증가에 따른 브라우저의 Layout/Paint 비용 증가와 가상화의 작동 원리를 연결해 설명할 수 있는가."}, {"category": "TECH_CHOICE", "question": "오프라인 편집을 위해 Dexie를 선택하셨는데, LocalStorage나 SessionStorage 대신 IndexedDB를 사용한 이유는 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화.", "expected_signal": "저장 용량, 비동기 처리, 구조화된 데이터 저장 등 IndexedDB의 기술적 이점을 정확히 인지하고 있는가."}, {"category": "PROJECT_DEEP_DIVE", "question": "낙관적 업데이트 충돌 해결 시 last-write-wins 방식을 쓰셨는데, 데이터 유실 가능성을 어떻게 판단하고 CRDT 검토를 생각하셨나요?", "job_category": "FRONTEND", "target_evidence": "충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "분산 데이터 동기화 시 발생하는 충돌 문제의 한계를 이해하고, 더 정교한 해결책(CRDT)의 필요성을 논리적으로 설명하는가."}, {"category": "CS_FUNDAMENTAL", "question": "Kakao Map SDK 마커 500개를 렌더링할 때 useMemo로 좌표 변환을 캐싱하셨는데, 이 과정에서 메모리 사용량과 연산 비용 사이의 트레이드오프는 어떠했나요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "Memoization이 무조건적인 성능 향상이 아니며, 메모리 점유와 CPU 연산 비용 사이의 균형을 고려해 적용했는지 확인."}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 클라이언트에서 WebP 변환을 수행하셨는데, 서버가 아닌 클라이언트에서 변환을 처리함으로써 얻은 이점은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "네트워크 전송량 감소(Bandwidth 절약)와 서버 리소스 부하 분산이라는 관점에서 답변할 수 있는가."}], "latency_sec": 42.684, "in_tokens": 2676, "out_tokens": 779} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "거래내역 테이블을 월 단위로 파티셔닝할 때, 파티션 키 선정 기준과 쿼리 성능 개선 수치는 어떻게 확인하셨나요?", "job_category": "DBA", "target_evidence": "파티셔닝으로 거래내역 테이블 월 단위 분할, 슬로우 쿼리 p95 2.3초 → 180ms", "expected_signal": "파티션 프루닝(Partition Pruning)의 원리를 이해하고, 실행 계획(Explain)을 통해 실제 성능 개선을 정량적으로 검증했는지 확인."}, {"category": "TECH_CHOICE", "question": "Terraform workspace를 사용하여 환경을 분리하셨는데, state 파일 관리와 보안 측면에서 어떤 이점이 있었나요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "환경별 격리 전략과 Backend state locking, 민감 정보 관리 방안에 대한 기술적 근거를 제시하는지 확인."}, {"category": "CS_FUNDAMENTAL", "question": "PostgreSQL의 autovacuum 튜닝을 진행하셨는데, Vacuum이 수행되지 않았을 때 발생하는 Bloat 현상이 성능에 어떤 영향을 주나요?", "job_category": "DBA", "target_evidence": "autovacuum 튜닝", "expected_signal": "MVCC 모델에서 Dead Tuple이 쌓였을 때 인덱스 스캔 및 테이블 풀 스캔 성능이 저하되는 메커니즘을 설명할 수 있는지 확인."}, {"category": "PROJECT_DEEP_DIVE", "question": "트래픽 피크 대비 CronJob으로 사전 스케일아웃을 운영하셨는데, HPA의 반응 속도만으로는 부족했던 구체적인 이유는 무엇인가요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "Pod의 Cold Start 시간이나 HPA의 메트릭 수집 주기(Cooldown/Delay)로 인한 급격한 트래픽 대응 한계를 인지하고 있는지 확인."}, {"category": "BEHAVIORAL", "question": "RDS 스토리지 풀 장애 당시 40분간 쓰기가 중단되었는데, 장애 복구 후 재발 방지를 위해 팀 내에서 어떤 프로세스를 개선하셨나요?", "job_category": "DBA", "target_evidence": "2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 상황을 STAR 방식으로 설명하고, 단순 기술 적용을 넘어 모니터링 체계 구축이라는 시스템적 해결책을 도출했는지 확인."}, {"category": "TECH_CHOICE", "question": "ArgoCD를 도입해 배포 리드타임을 획기적으로 줄이셨는데, 기존 배포 방식과 비교해 GitOps 모델이 가져다준 가장 큰 운영상 이점은 무엇인가요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "선언적 인프라 관리의 장점과 Drift Detection을 통한 상태 일치 유지, 롤백 편의성 등 운영 효율화 관점의 답변을 기대함."}], "latency_sec": 46.548, "in_tokens": 2668, "out_tokens": 902} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "팀원과 의견 충돌 후 대안을 비교하는 방식으로 바꾸셨는데, 최근에 이 방식을 적용해 갈등을 해결한 구체적인 사례가 있나요?", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "자신의 단점을 인지하고 개선한 행동이 실제 상황에서 어떻게 발현되었는지 STAR 방식으로 설명하는지 확인."}, {"category": "BEHAVIORAL", "question": "크롤러 중단으로 인한 사용자 항의를 처리하며 멈추지 않는 서비스의 중요성을 느끼셨는데, 당시 상황을 어떻게 수습하고 대응하셨나요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "예기치 못한 장애 상황에서의 책임감 있는 대응 태도와 사용자 관점의 문제 해결 능력을 확인."}, {"category": "PROJECT_DEEP_DIVE", "question": "OpenAPI 명세와 Mock 서버 도입 후 통합 이슈가 0건으로 줄었는데, 구체적으로 어떤 항목들을 명세화하여 소통 비용을 줄이셨나요?", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "API 설계 시 고려한 구체적인 요소(Request/Response 구조, 에러 코드 등)와 협업 프로세스 개선 능력을 확인."}, {"category": "TECH_CHOICE", "question": "SQLite의 동시 쓰기 락 문제를 해결하기 위해 PostgreSQL로 이전하셨는데, 이전 후 트랜잭션 격리 수준을 어떻게 설정하여 중복 발송을 막으셨나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "단순한 DB 교체를 넘어, 발생했던 동시성 문제의 원인과 선택한 격리 수준의 기술적 근거를 정확히 설명하는지 확인."}, {"category": "BEHAVIORAL", "question": "800명이 사용하는 서비스를 운영하며 가장 몰입했던 순간은 언제이며, 그 과정에서 본인이 기여한 가장 핵심적인 역할은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다.", "expected_signal": "서비스 운영 경험을 통해 얻은 성취감과 본인의 주도적인 기여도 및 성장 가능성을 확인."}], "latency_sec": 41.595, "in_tokens": 2659, "out_tokens": 797} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "주문 서비스 분리 후 Kafka 도입 시, 이벤트 발행의 원자성을 보장하기 위해 Outbox 패턴을 어떻게 구현하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "DB 트랜잭션 내에 Outbox 테이블에 이벤트를 저장하고, 별도 릴레이 프로세스가 이를 읽어 Kafka로 발행하는 메커니즘을 정확히 설명하는지 확인"}, {"category": "TECH_CHOICE", "question": "재고 동기화 프로젝트에서 낙관적 락을 분산 락으로 전환하신 구체적인 이유와 판단 기준은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "동시성 제어(낙관적 락 → 분산 락 전환) / 재고 불일치 건수 월 200건 → 3건", "expected_signal": "충돌 빈도가 높은 상황에서 낙관적 락의 재시도 비용 문제와 분산 락(Redis 등)을 통한 정합성 보장 이점을 비교 분석할 수 있는지 확인"}, {"category": "CS_FUNDAMENTAL", "question": "SQLite에서 PostgreSQL로 이전하며 공부하신 트랜잭션 격리 수준 중, 중복 발송 문제를 막기 위해 가장 중요했던 수준은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "Read Committed나 Repeatable Read 등 격리 수준에 따른 Phantom Read나 Non-repeatable Read 현상이 실제 중복 발송과 어떻게 연결되는지 이해하고 있는지 확인"}, {"category": "PROJECT_DEEP_DIVE", "question": "Redis 기반 재고 캐시와 DB write-behind 구조에서, 캐시 장애 시 데이터 유실을 방지하기 위해 어떤 전략을 세우셨나요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind", "expected_signal": "Write-behind의 특성상 발생할 수 있는 데이터 유실 가능성을 인지하고, 이를 보완하기 위한 백업 전략이나 체크포인트 메커니즘을 고민했는지 확인"}, {"category": "BEHAVIORAL", "question": "API 명세 작성 과정에서 팀원과 의견 충돌이 있었을 때, 대안을 비교하는 방식으로 소통 방식을 바꾸신 후 실제 협업 효율이 어떻게 달라졌나요?", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "자신의 고집을 인지하고 소통 방식을 수정한 구체적인 행동(Action)과 그로 인해 개선된 팀 분위기 및 결과(Result)를 STAR 방식으로 답변하는지 확인"}], "latency_sec": 40.572, "in_tokens": 4012, "out_tokens": 806} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연 시 멱등 키와 Outbox 패턴을 어떻게 조합해 중복 주문을 막으셨나요?", "job_category": "BACKEND", "target_evidence": "결제 콜백 지연으로 생긴 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결한 경험", "expected_signal": "멱등 키를 통한 요청 식별과 Outbox 패턴을 이용한 이벤트 발행의 원자성 보장 메커니즘을 설명할 수 있는가"}, {"category": "TECH_CHOICE", "question": "재고 동기화 구현 시 낙관적 락에서 분산 락으로 전환하신 구체적인 이유는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "충돌 빈도 증가에 따른 낙관적 락의 재시도 비용 문제와 분산 락의 필요성을 기술적으로 비교 분석할 수 있는가"}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능을 5시간에서 40분으로 단축할 때 QueryDSL 튜닝의 핵심 포인트는 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "실제 쿼리 실행 계획 분석을 통해 병목을 찾아내고 인덱스 최적화나 쿼리 구조를 개선한 구체적 사례를 제시하는가"}, {"category": "CS_FUNDAMENTAL", "question": "Kafka 기반 이벤트 구조에서 메시지 발행 순서가 보장되지 않을 때 데이터 정합성을 어떻게 유지하셨나요?", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입. 대용량 트래픽에서도 데이터 정합성을 지키는 서버를 만드는 데 관심", "expected_signal": "Kafka의 파티션 키 전략이나 컨슈머 측의 순서 보장 처리 방안 등 분산 시스템의 정합성 해결 능력이 있는가"}, {"category": "BEHAVIORAL", "question": "모놀리식을 MSA로 전환하며 주문 서비스를 분리할 때, 가장 갈등이 컸던 지점과 해결 과정은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "모놀리식을 MSA로 전환하면서 주문 서비스를 분리했고", "expected_signal": "서비스 경계 설정(Bounded Context) 과정에서의 의견 조율 능력과 논리적인 설득 과정을 STAR 방식으로 설명하는가"}], "latency_sec": 38.713, "in_tokens": 2874, "out_tokens": 694} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "react-window 도입 후 INP를 480ms에서 120ms로 개선하셨는데, 구체적으로 어떤 렌더링 병목이 해결된 것인가요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "DOM 요소 수 증가에 따른 브라우저의 Layout/Paint 비용 증가와 가상화의 동작 원리를 연결해 설명할 수 있는가."}, {"category": "TECH_CHOICE", "question": "오프라인 편집을 위해 Dexie를 선택하셨는데, LocalStorage나 SessionStorage 대신 IndexedDB를 사용한 이유는 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화.", "expected_signal": "저장 용량, 비동기 처리, 구조화된 데이터 저장 등 IndexedDB의 특성과 프로젝트 요구사항을 매칭해 설명하는가."}, {"category": "PROJECT_DEEP_DIVE", "question": "낙관적 업데이트 충돌 해결 시 last-write-wins 방식을 쓰셨는데, 이 방식의 한계와 CRDT 검토 이유를 설명해주세요.", "job_category": "FRONTEND", "target_evidence": "충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "데이터 덮어쓰기 문제(Data Loss)를 인지하고, 분산 시스템에서의 일관성 유지 전략인 CRDT의 필요성을 이해하고 있는가."}, {"category": "CS_FUNDAMENTAL", "question": "Kakao Map SDK 마커 렌더링 시 useMemo로 좌표 변환을 캐싱하셨는데, React의 메모이제이션이 성능에 기여하는 원리는 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "불필요한 재계산 방지와 참조 동일성 유지를 통한 리렌더링 최적화 개념을 정확히 설명하는가."}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 S3 직접 업로드와 WebP 변환을 클라이언트에서 처리한 이유는 무엇이며, 어떤 이점이 있었나요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "서버 부하 감소(Presigned URL)와 네트워크 전송량 최적화(WebP)라는 아키텍처적 선택 근거를 제시하는가."}], "latency_sec": 48.74, "in_tokens": 2676, "out_tokens": 760} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "거래내역 테이블을 월 단위로 파티셔닝할 때, 파티션 키 선정 기준과 쿼리 성능 변화는 어떠했나요?", "job_category": "DBA", "target_evidence": "파티셔닝으로 거래내역 테이블 월 단위 분할", "expected_signal": "파티션 프루닝(Partition Pruning)의 원리를 이해하고, 실제 쿼리 실행 계획의 변화를 정량적으로 설명할 수 있는가"}, {"category": "TECH_CHOICE", "question": "HPA 외에 CronJob을 이용한 사전 스케일아웃을 병행하신 구체적인 이유는 무엇인가요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "HPA의 반응형 스케일링이 가진 지연 시간(Lag) 문제를 인지하고, 예측 가능한 트래픽에 대응하는 전략적 선택을 했는가"}, {"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 슬로우 쿼리를 개선하며 복합 인덱스를 재설계할 때, 컬럼 순서를 결정한 기준은 무엇이었나요?", "job_category": "DBA", "target_evidence": "슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계)", "expected_signal": "카디널리티(Cardinality)와 쿼리 조건절의 일치 여부를 고려하여 인덱스 효율을 최적화하는 능력이 있는가"}, {"category": "CS_FUNDAMENTAL", "question": "Terraform workspace를 통해 환경을 분리하셨는데, state 파일의 정합성 관리와 락킹은 어떻게 처리하셨나요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "Remote Backend(S3, DynamoDB 등)를 통한 상태 관리와 동시성 제어 메커니즘을 정확히 이해하고 있는가"}, {"category": "BEHAVIORAL", "question": "RDS 스토리지 풀 장애 당시, 재발 방지를 위해 오토스케일링 외에 모니터링 관점에서 개선한 점이 있나요?", "job_category": "DBA", "target_evidence": "2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 발생 후 단순 조치를 넘어, 임계치 설정 및 알람 체계 고도화라는 근본적인 해결책을 도출하는 태도를 갖췄는가"}, {"category": "BEHAVIORAL", "question": "ArgoCD 도입으로 배포 리드타임을 대폭 단축하셨는데, 이 과정에서 팀원들을 어떻게 설득하고 적응시키셨나요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "새로운 기술 도입 시 발생하는 팀 내 저항이나 학습 곡선을 관리하고, 협업을 통해 성과를 낸 경험(STAR)이 있는가"}], "latency_sec": 58.718, "in_tokens": 2668, "out_tokens": 878} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "초반에 본인의 방식을 고집해 팀원과 갈등이 있었을 때, 구체적으로 어떤 상황이었으며 이를 어떻게 풀어나갔나요?", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "갈등 상황에서 본인의 잘못을 인정하는 태도와 이를 해결하기 위해 도입한 구체적인 소통 방식(대안 비교)의 실천 여부"}, {"category": "BEHAVIORAL", "question": "크롤러 중단으로 인한 사용자 항의를 받았을 때, 당시 가장 먼저 취한 행동과 최종적으로 어떻게 신뢰를 회복하셨나요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "장애 발생 시 대응 프로세스(상황 파악-조치-소통)와 서비스 안정성에 대한 책임감"}, {"category": "PROJECT_DEEP_DIVE", "question": "OpenAPI 명세와 Mock 서버 도입 후 통합 이슈가 0건으로 줄었다고 하셨는데, 구체적으로 어떤 프로세스로 협업하셨나요?", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "API First Design의 이해도와 프론트엔드와의 효율적인 인터페이스 합의 과정"}, {"category": "TECH_CHOICE", "question": "SQLite에서 PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하셨는데, 당시 발생한 중복 발송 문제를 해결하기 위해 어떤 격리 수준을 선택하셨나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "동시성 제어 문제의 원인 분석 능력과 DB 엔진 특성에 따른 적절한 격리 수준 선택 근거"}, {"category": "BEHAVIORAL", "question": "800명이 사용하는 서비스를 운영하며 가장 몰입했던 순간은 언제였으며, 그 경험이 본인의 성장과 어떤 연결이 되었나요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다.", "expected_signal": "실제 사용자 피드백을 기반으로 서비스를 개선하려는 주도성과 성취감의 원천"}], "latency_sec": 50.061, "in_tokens": 2659, "out_tokens": 775} +{"label": "gw-gemma-4-31b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "Outbox 패턴 도입 시, Outbox 테이블의 데이터를 Kafka로 발행하는 릴레이 프로세스는 어떻게 구현하셨나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "Polling Publisher나 CDC(Change Data Capture) 등 구체적인 구현 방식과 메시지 발행 보장 전략을 설명할 수 있는가"}, {"category": "TECH_CHOICE", "question": "재고 동기화 프로젝트에서 낙관적 락을 분산 락으로 전환하신 구체적인 이유와 전환 후 성능 변화는 어떠했나요?", "job_category": "BACKEND", "target_evidence": "동시성 제어(낙관적 락 → 분산 락 전환) / 재고 불일치 건수 월 200건 → 3건", "expected_signal": "충돌 빈도가 높은 환경에서 낙관적 락의 재시도 비용 문제를 인지하고, 분산 락의 트레이드오프를 이해하고 선택했는가"}, {"category": "CS_FUNDAMENTAL", "question": "알림 봇의 SQLite 동시 쓰기 락 문제를 PostgreSQL로 해결하며 배운 트랜잭션 격리 수준의 차이는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "SQLite의 파일 기반 락과 PostgreSQL의 MVCC 기반 동시성 제어 차이 및 격리 수준(Isolation Level)에 대한 이해도가 있는가"}, {"category": "PROJECT_DEEP_DIVE", "question": "모놀리식에서 MSA로 전환하며 주문 서비스를 분리할 때, DB 분리로 인한 데이터 정합성 문제는 어떻게 해결하셨나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "분산 트랜잭션 환경에서 Saga 패턴이나 Eventual Consistency를 통해 정합성을 유지한 구체적인 설계 능력이 있는가"}, {"category": "BEHAVIORAL", "question": "API 스펙 갈등 당시 본인의 고집으로 팀원과 감정이 상했던 상황을 어떻게 인지했고, 이후 대안 비교 방식으로 어떻게 개선하셨나요?", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "자신의 커뮤니케이션 과오를 객관적으로 성찰하고, 이를 시스템적인 협업 방식(대안 비교)으로 개선한 경험이 있는가 (STAR)"}], "latency_sec": 44.674, "in_tokens": 4012, "out_tokens": 776} diff --git a/docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b-mt2048.jsonl b/docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b-mt2048.jsonl new file mode 100644 index 0000000..a1c3943 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b-mt2048.jsonl @@ -0,0 +1,42 @@ +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "Outbox 패턴을 도입했을 때, 실제로 어떤 상황에서 이벤트가 누락될 위험이 있었고, 그 상황을 어떻게 해결했는지 구체적인 예를 들어 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.006, "ttft_sec": 3.995, "in_tokens": 1619, "out_tokens": 424} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 각각 어떤 실패 상황을 방지하도록 설계했는지 구체적인 예시를 들어 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.114, "ttft_sec": 3.686, "in_tokens": 1479, "out_tokens": 333} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "PostgreSQL MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 구체적 영향을 설명해 주시겠습니까?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.403, "ttft_sec": null, "in_tokens": 1429, "out_tokens": 590} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18의 automatic batching이 기존 버전과 달라지는 구체적인 상황을 예시와 함께 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.413, "ttft_sec": null, "in_tokens": 1428, "out_tokens": 352} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA를 CPU 사용량 70%에 맞춰 설정한 이유와, 트래픽 급증 시 미리 파드를 추가한 이유를 간단히 말씀해 주세요.", "answer_intent": "CLARIFICATION", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.439, "ttft_sec": 4.08, "in_tokens": 1464, "out_tokens": 512} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "폴링 주기를 어떻게 설정하셨으며, 그 기준은 무엇이었는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 3.283, "ttft_sec": 2.995, "in_tokens": 1450, "out_tokens": 432} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "그럼 트래픽 피크 시 사전 스케일아웃을 위한 CronJob을 운영하지 않으신 건가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": 0.0}, "latency_sec": 6.71, "ttft_sec": 6.098, "in_tokens": 1752, "out_tokens": 584} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "autovacuum scale_factor를 0.05로 낮춘 것이 p95 감소에 얼마나 기여했는지 구체적인 수치를 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 3.956, "ttft_sec": 3.652, "in_tokens": 1871, "out_tokens": 640} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "react-window 가상화를 적용하면서 발생한 접근성(스크린리더 등) 이슈는 어떻게 해결하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 5.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 3.136, "ttft_sec": 2.802, "in_tokens": 1837, "out_tokens": 448} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "결정 전에 팀원과 비교한 두 가지 대안은 구체적으로 무엇이었는지 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 4.008, "ttft_sec": 3.682, "in_tokens": 1544, "out_tokens": 538} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "그때 실제로 어떤 프로젝트에서 의견 충돌이 있었고, 어떤 구체적인 행동을 취했는지, 결과를 수치로 어떻게 확인했는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.27, "ttft_sec": 1.878, "in_tokens": 1472, "out_tokens": 246} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "버전 충돌이 발생한 구체적인 비율이나 재시도 평균 횟수를 알려주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 5.083, "ttft_sec": 4.614, "in_tokens": 1512, "out_tokens": 539} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "스위퍼 배치를 구현할 때 사용한 스케줄링 방식과 배치 로직을 구체적으로 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 5.545, "ttft_sec": 4.862, "in_tokens": 1825, "out_tokens": 546} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "각 화면에서 설정한 staleTime 값은 구체적으로 얼마였으며, 그 값을 선택한 근거는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.601, "ttft_sec": 3.283, "in_tokens": 1489, "out_tokens": 541} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "Outbox 테이블에 기록한 뒤 폴링 프로세스가 중간에 실패하면 어떻게 복구하고 중복 전송을 방지하나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.272, "ttft_sec": 3.901, "in_tokens": 1619, "out_tokens": 478} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키가 방지하는 중복 상황과 Outbox가 해결하는 트랜잭션 경계 문제를 각각 예시로 들어 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.235, "ttft_sec": 4.897, "in_tokens": 1479, "out_tokens": 590} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "오래 열린 트랜잭션이 있을 때 vacuum이 회수하지 못하는 dead tuple이 왜 발생하는지 구체적으로 말씀해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.848, "ttft_sec": null, "in_tokens": 1429, "out_tokens": 519} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "React 18의 automatic batching이 이전 버전과 어떻게 다르고, setTimeout·Promise 등 비동기 콜백에서도 배칭이 적용되는 구체적인 예시를 들어 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.827, "ttft_sec": null, "in_tokens": 1428, "out_tokens": 461} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "HPA 임계값을 CPU 70%로 정한 이유와 트래픽 피크 시 사전 스케일아웃을 한 배경을 알려 주세요.", "answer_intent": "CLARIFICATION", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.029, "ttft_sec": 2.673, "in_tokens": 1464, "out_tokens": 384} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "폴링 주기를 어떻게 설정하셨고, 구현에 사용한 기술 스택은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.35, "ttft_sec": 4.012, "in_tokens": 1450, "out_tokens": 453} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "이력서에선 CPU 70%와 사전 스케일아웃 CronJob을 사용했다고 했는데, 실제로는 메모리 50%만 사용하셨다고요? 이유를 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 1.0, "structure": "NONE", "correctness": 0.0}, "latency_sec": 4.226, "ttft_sec": 3.751, "in_tokens": 1752, "out_tokens": 598} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "인덱스 적용 후 p95가 900ms가 된 구체적인 쿼리 플랜 변화를 알려 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 4.442, "ttft_sec": 4.137, "in_tokens": 1871, "out_tokens": 724} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "가상화 적용 시 접근성(예: 스크린리더 지원) 문제와 해결 방안을 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 5.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 7.359, "ttft_sec": 5.954, "in_tokens": 1837, "out_tokens": 845} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "그때 제시한 두 가지 대안은 구체적으로 어떤 것이었는지 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 3.184, "ttft_sec": 2.874, "in_tokens": 1544, "out_tokens": 436} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "그때 구체적으로 어떤 상황에서 어떤 행동을 하셨고, 결과가 어떻게 되었는지 숫자로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 0.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.93, "ttft_sec": 3.519, "in_tokens": 1472, "out_tokens": 295} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "재시도 때문에 발생한 DB 부하가 구체적으로 어느 정도였는지 수치로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 5.254, "ttft_sec": 4.946, "in_tokens": 1512, "out_tokens": 478} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "스위퍼 배치를 어떤 주기로 실행했고, 구현에 사용한 기술 스택은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 4.814, "ttft_sec": 4.449, "in_tokens": 1825, "out_tokens": 532} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "TanStack Query를 도입하면서 겪은 단점이나 트레이드오프가 있었다면 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 8.238, "ttft_sec": 7.438, "in_tokens": 1489, "out_tokens": 572} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "Outbox 테이블에 이벤트를 기록한 뒤 릴레이가 폴링할 때, 동일 이벤트가 중복 전송되는 것을 어떻게 방지했는지 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.399, "ttft_sec": 2.988, "in_tokens": 1619, "out_tokens": 432} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "멱등 키와 Outbox 패턴 각각이 방지하는 구체적인 실패 시나리오를 예시와 함께 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.411, "ttft_sec": 2.549, "in_tokens": 1479, "out_tokens": 390} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "PostgreSQL MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 구체적인 영향을 설명해 보실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.386, "ttft_sec": null, "in_tokens": 1429, "out_tokens": 497} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "React 18의 automatic batching이 이전 버전과 다른 점을 구체적인 예시와 함께 설명해 보실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.356, "ttft_sec": null, "in_tokens": 1428, "out_tokens": 421} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA를 CPU 70% 기준으로 잡은 이유와 피크 시 미리 스케일아웃을 하는 이유를 알려 주세요.", "answer_intent": "CLARIFICATION", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.468, "ttft_sec": 3.15, "in_tokens": 1464, "out_tokens": 462} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "outbox 릴레이를 폴링하는 주기와 사용한 기술 스택(언어·프레임워크·배포 방식)을 구체적으로 알려 주세요.", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.448, "ttft_sec": 3.904, "in_tokens": 1450, "out_tokens": 401} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "HPA 기준을 메모리 50%로 잡으셨다고 했는데, 이력서엔 CPU 70%라고 적혀 있습니다. 실제 적용한 메트릭을 알려 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 1.0, "structure": "NONE", "correctness": 0.0}, "latency_sec": 7.847, "ttft_sec": 7.37, "in_tokens": 1752, "out_tokens": 952} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "인덱스만 적용했을 때 p95가 900 ms가 된 근거를 구체적인 측정 방법과 수치로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 4.567, "ttft_sec": 4.199, "in_tokens": 1871, "out_tokens": 651} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "이 가상화를 적용하면서 설정한 구체적인 목표와 기대 성과는 무엇이었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.782, "ttft_sec": 4.495, "in_tokens": 1837, "out_tokens": 683} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "통합 일정 지연 2주를 어떻게 회복했는지, 실제 회복된 일수나 비율을 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 4.862, "ttft_sec": 4.345, "in_tokens": 1544, "out_tokens": 606} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "그때 구체적으로 어떤 대화를 진행하셨고, 그 결과 팀 성과에 어떤 변화가 있었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.287, "ttft_sec": 3.909, "in_tokens": 1472, "out_tokens": 482} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "레디스 분산 락을 도입하면서 발생한 추가적인 레이턴시나 운영 복잡도는 어떻게 관리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.971, "ttft_sec": 3.596, "in_tokens": 1512, "out_tokens": 583} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "30분 이상 PENDING 상태인 주문을 처리하기 위해 만든 스위퍼 배치의 동작 방식과 배치 주기를 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 5.434, "ttft_sec": 5.039, "in_tokens": 1825, "out_tokens": 660} +{"label": "gw-gpt-oss-120b-mt2048", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "staleTime을 화면별로 어떻게 설정했는지 구체적인 기준을 알려 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.472, "ttft_sec": 3.216, "in_tokens": 1489, "out_tokens": 513} diff --git a/docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b.jsonl b/docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b.jsonl new file mode 100644 index 0000000..e22514f --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/gw-gpt-oss-120b.jsonl @@ -0,0 +1,61 @@ +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 5.17, "ttft_sec": null, "in_tokens": 1619, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "멱등 키를 어떻게 생성했고, 어떤 경우에 중복 주문이 발생했는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.371, "ttft_sec": 3.958, "in_tokens": 1479, "out_tokens": 439} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "PostgreSQL MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 구체적인 영향을 말씀해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 4.928, "ttft_sec": null, "in_tokens": 1429, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18에서 자동 배칭이 적용되는 구체적인 예시를 하나 들어보실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 4.835, "ttft_sec": null, "in_tokens": 1428, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA를 CPU 사용량 70%로 설정한 이유와, 트래픽이 급증하기 전에 미리 스케일아웃을 진행한 판단 근거를 간단히 설명해 주세요.", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 3.518, "ttft_sec": 3.121, "in_tokens": 1464, "out_tokens": 415} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "폴링 주기를 어떻게 정하셨으며, 지연 발생 시 재시도 로직은 어떻게 구현하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.311, "ttft_sec": 3.798, "in_tokens": 1450, "out_tokens": 370} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 5.286, "ttft_sec": null, "in_tokens": 1752, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.613, "ttft_sec": null, "in_tokens": 1871, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.393, "ttft_sec": null, "in_tokens": 1837, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 8.703, "ttft_sec": null, "in_tokens": 1544, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "최근 의견 충돌이 있었던 구체적인 상황과 그때 직접 취한 행동을 자세히 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 0.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.199, "ttft_sec": 3.898, "in_tokens": 1472, "out_tokens": 323} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 5.533, "ttft_sec": null, "in_tokens": 1512, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "전환 전에는 정합성 오류가 얼마나 발생했고, 전환 후 실제 감소한 건수는 정확히 몇 건인지 알려주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 3.331, "ttft_sec": 2.68, "in_tokens": 1825, "out_tokens": 350} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "네트워크 요청이 40% 감소했다고 하셨는데, 이를 어떤 방식으로 측정했는지 구체적인 방법과 수치를 알려 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.816, "ttft_sec": 3.463, "in_tokens": 1489, "out_tokens": 484} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 동시에 적용했을 때, 예를 들어 주문 저장은 성공했지만 이벤트 전송이 실패하는 상황에서 두 가지가 어떻게 상호 보완되는지 구체적인 시나리오와 그때 방지되는 복합 실패 케이스를 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.52, "ttft_sec": 3.852, "in_tokens": 1619, "out_tokens": 493} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키가 방지하는 구체적인 실패 상황과 Outbox 패턴이 해결하는 트랜잭션 경계 문제를 각각 예시로 들어 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.452, "ttft_sec": 3.704, "in_tokens": 1479, "out_tokens": 379} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "오래 열린 트랜잭션이 있을 때 vacuum이 회수하지 못하는 튜플이 왜 발생하는지 구체적인 예시와 함께 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 4.584, "ttft_sec": null, "in_tokens": 1429, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "React 18의 automatic batching이 이전 버전과 어떻게 다른지 구체적인 예시와 함께 설명해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 8.315, "ttft_sec": null, "in_tokens": 1428, "out_tokens": 349} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "HPA를 CPU 사용량 70%로 설정", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 4.965, "ttft_sec": 4.635, "in_tokens": 1464, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "폴링 주기를 어느 정도로 설정하셨고, 그 기준은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 5.648, "ttft_sec": 5.268, "in_tokens": 1450, "out_tokens": 330} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.904, "ttft_sec": null, "in_tokens": 1752, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.475, "ttft_sec": null, "in_tokens": 1871, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "커스텀 검색 박스를 도입하면서 접근성은 어떻게", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 4.923, "ttft_sec": 4.73, "in_tokens": 1837, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "그때 제시한 두 대안은 구체적으로 어떤 것이었는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 5.076, "ttft_sec": 4.633, "in_tokens": 1544, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "의견 충돌이 있었던 구체적인 프로젝트와, 직접 취한 행동 및 그 결과를 상세히 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.604, "ttft_sec": 4.276, "in_tokens": 1472, "out_tokens": 376} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.771, "ttft_sec": null, "in_tokens": 1512, "out_tokens": 512} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "이벤트 ID 로 멱등성을 보장하기 위해 어떤 로직이나 저장 방식을 사용했는지 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 3.684, "ttft_sec": 3.304, "in_tokens": 1825, "out_tokens": 453} +{"label": "gw-gpt-oss-120b", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "NORMAL 120ms)", "expected_signal": "성능 병목 파악, 가상화 적용 방법, 결과 측정"}, {"category": "TECH_CHOICE", "question": "클라이언트 상태 관리에 Zustand을 선택한 이유와 Redux와 비교했을 때 장점을 말씀해 주세요.", "job_category": "FRONTEND", "target_evidence": "상태 관리는 Zustand", "expected_signal": "선택 근거, 간결성, 타입 안전성, 퍼포먼스"}, {"category": "PROJECT_DEEP_DIVE", "question": "IndexedDB(Dexie)를 활용한 오프라인 편집과 낙관적 업데이트, 충돌 해결 전략을 상세히 설명해 주세요.", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) ... 충돌은 last-write-wins", "expected_signal": "오프라인 데이터 저장, 동기화 로직, 충돌 정책"}, {"category": "TECH_CHOICE", "question": "서버 상태 관리에 TanStack Query v5를 사용한 이유와 주요 기능 활용 사례를 알려 주세요.", "job_category": "FRONTEND", "target_evidence": "서버 상태는 TanStack Query v5", "expected_signal": "데이터 페칭, 캐싱, 자동 리패치 등 장점"}, {"category": "CS_FUNDAMENTAL", "question": "presigned URL를 이용해 클라이언트에서 직접 S3에 이미지 업로드하고 WebP 변환을 수행한 흐름을 설명해 주세요.", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "보안, 인증, 변환 단계, 업로드 절차"}], "latency_sec": 15.635, "in_tokens": 2763, "out_tokens": 1606} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "ArgoCD 도입으로 배포 리드타임을 1일에서 30분으로 단축한 과정과 롤백 전략을 설명해 주세요.", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "엔드‑투‑엔드 GitOps 파이프라인 구축 경험과 롤백 절차에 대한 이해를 보여준다."}, {"category": "TECH_CHOICE", "question": "Terraform을 사용해 VPC·RDS·EKS를 모듈화하고 workspace를 분리한 이유와 상태 관리 방식을 알려 주세요.", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "IaC의 장점, 모듈 설계, 환경 격리 및 상태 파일 관리에 대한 깊은 이해를 보여준다."}, {"category": "CS_FUNDAMENTAL", "question": "PostgreSQL에서 autovacuum 튜닝과 파티셔닝을 적용해 p95 쿼리 시간을 2.3초→180ms로 개선한 핵심 원리를 설명해 주세요.", "job_category": "DBA", "target_evidence": "복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할", "expected_signal": "데이터베이스 내부 메커니즘과 성능 최적화 기법을 정확히 설명한다."}, {"category": "PROJECT_DEEP_DIVE", "question": "2024년 3월 RDS 스토리지 부족으로 쓰기 중단이 발생했을 때 원인 파악과 복구 절차, 이후 오토스케일링 적용 방식을 말씀해 주세요.", "job_category": "DBA", "target_evidence": "2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "인시던트 대응 과정, 원인 분석, 재발 방지를 위한 자동화 설계 능력을 보여준다."}, {"category": "BEHAVIORAL", "question": "월급날 트래픽 피크를 대비해 HPA와 사전 스케일아웃 CronJob을 도입한 팀 내 역할과 협업 방식을 이야기해 주세요.", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "용량 계획과 자동화 구현에서 자신의 구체적 행동과 팀 협업 결과를 제시한다."}, {"category": "TECH_CHOICE", "question": "EKS 기반 3개 클러스터(≈400 파드) 운영을 선택한 이유와 자체 K8s 대비 장·단점을 설명해 주세요.", "job_category": "INFRA", "target_evidence": "EKS 기반 쿠버네티스 클러스터 3개 운영 (파드 약 400개)", "expected_signal": "관리형 서비스 선택 근거와 비용·보안·운용 측면의 비교 분석을 제시한다."}], "latency_sec": 14.82, "in_tokens": 2752, "out_tokens": 2001} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "서비스가 중단돼 사용자 불만이 들어왔을 때 어떻게 문제를 파악하고 해결했나요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "체계적인 문제 분석과 신속한 복구 조치를 통해 서비스 신뢰성을 확보한 경험을 설명한다."}, {"category": "BEHAVIORAL", "question": "팀원과 의견 충돌 후 의사결정 방식을 어떻게 바꾸었는지 구체적으로 말씀해주세요.", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "갈등을 인식하고, 대안 비교와 협업을 통해 의사결정 프로세스를 개선한 사례를 제시한다."}, {"category": "PROJECT_DEEP_DIVE", "question": "SQLite에서 PostgreSQL로 마이그레이션할 때 어떤 절차와 고려사항을 적용했나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "데이터 이전, 스키마 변환, 트랜잭션 설정 등 구체적인 마이그레이션 단계와 성능·안정성 개선 효과를 설명한다."}, {"category": "TECH_CHOICE", "question": "API 통합 전 OpenAPI 명세와 Mock 서버를 도입한 이유와 기대 효과는 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했습니다.", "expected_signal": "명세‑우선 접근으로 인터페이스 명확화, 병렬 개발 촉진, 통합 이슈 감소 효과를 강조한다."}, {"category": "BEHAVIORAL", "question": "백엔드 개발에서 ‘멈추지 않는 서비스’를 구현하기 위해 가장 중시하는 점은?", "job_category": "BACKEND", "target_evidence": "‘멈추지 않는 서비스’가 신뢰를 만든다.", "expected_signal": "가용성, 모니터링, 장애 복구 전략 등 신뢰성 확보를 위한 핵심 원칙을 제시한다."}], "latency_sec": 17.647, "in_tokens": 2760, "out_tokens": 1799} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 시 주문 서비스 DB 분리와 Kafka 이벤트 설계에서 가장 고민한 점은?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입.", "expected_signal": "데이터 정합성, 이벤트 스키마 설계, 서비스 경계 정의 등 트레이드오프를 명확히 설명한다."}, {"category": "TECH_CHOICE", "question": "Kotlin과 Spring Boot 3를 선택한 이유와 Java 17 대비 장점은?", "job_category": "BACKEND", "target_evidence": "Kotlin, Java 17, Spring Boot 3", "expected_signal": "Kotlin의 널 안전성·코루틴·DSL, Spring Boot 3의 Jakarta EE 전환·성능 개선 등을 구체적으로 제시한다."}, {"category": "CS_FUNDAMENTAL", "question": "결제 콜백 지연 시 멱등성을 보장하기 위해 어떤 트랜잭션 격리 수준을 사용했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "READ COMMITTED·SERIALIZABLE 등 선택 이유와 격리 수준이 멱등성에 미치는 영향을 설명한다."}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화에서 낙관적 락을 분산 락으로 바꾼 구체적 이유와 구현은?", "job_category": "BACKEND", "target_evidence": "실시간 재고 동기화 ... 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "고가용성·다중 인스턴스 환경에서 레디스 기반 RedLock 등 구현 방식을 상세히 설명한다."}, {"category": "BEHAVIORAL", "question": "중복 주문 문제 해결 과정에서 팀 의견 충돌이 있었나요? 본인의 역할은?", "job_category": "BACKEND", "target_evidence": "결제 콜백 지연으로 생긴 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결한 경험이 가장 기억에 남습니다.", "expected_signal": "STAR 구조로 상황·과제·행동·결과를 제시하며 갈등 조정 및 협업 성과를 강조한다."}], "latency_sec": 15.13, "in_tokens": 4111, "out_tokens": 2071} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연으로 발생한 중복 주문을 해결하기 위해 Transactional Outbox를 어떻게 구현했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "트랜잭션 내에서 Outbox 테이블에 이벤트를 저장하고 별도 프로듀서가 Kafka에 전송하는 흐름과 정확히‑한번 전송을 보장하는 메커니즘을 설명"}, {"category": "TECH_CHOICE", "question": "주문 서비스 MSA 전환 시 Kafka를 선택한 이유와 기대 효과는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "내구성, 순서 보장, 확장성 등 Kafka가 다른 메시징 솔루션보다 적합한 이유를 구체적으로 제시"}, {"category": "CS_FUNDAMENTAL", "question": "중복 주문 방지를 위한 멱등 키 테이블 설계와 적용 방법을 설명해주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "키 생성 전략, 유니크 제약, 트랜잭션 연계 방식 등을 포함한 설계 원리를 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 시간을 5시간에서 40분으로 단축한 QueryDSL 튜닝과 청크 처리 방식을 구체적으로 말씀해주세요.", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "쿼리 최적화, 인덱스 재구성, 청크 사이즈 조정 등 실제 적용한 기술적 조치를 상세히 기술"}, {"category": "BEHAVIORAL", "question": "결제 승인 지연 장애 발생 시 현장에서 어떤 조치를 취했고 결과는 어땠나요?", "job_category": "BACKEND", "target_evidence": "장애 대응: 결제 승인 지연으로 인한 중복 주문 이슈를 멱등 키 + Outbox 패턴으로 해결", "expected_signal": "상황·과제·행동·결과(STAR) 구조로 문제 인식, 즉각적인 대응, 해결 방안 적용, 결과 및 교훈을 제시"}], "latency_sec": 17.683, "in_tokens": 2966, "out_tokens": 1574} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "타임라인 가상화 구현 시 react-window 선택 이유와 성능 개선 결과를 설명해주세요.", "job_category": "FRONTEND", "target_evidence": "react-window 가상화 도입 (INP 480ms -> 120ms)", "expected_signal": "가상화 필요성, 구현 방식, 측정된 성능 향상"}, {"category": "TECH_CHOICE", "question": "상태 관리에 Zustand을 선택한 근거와 Redux와 차별점은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "상태 관리는 Zustand", "expected_signal": "Zustand 장점, 간결함, React와의 결합"}, {"category": "TECH_CHOICE", "question": "TanStack Query v5를 사용해 서버 데이터 캐싱을 어떻게 설계했는지 알려주세요.", "job_category": "FRONTEND", "target_evidence": "서버 상태는 TanStack Query v5", "expected_signal": "쿼리 키, 자동 재패치, 캐시 무효화 전략"}, {"category": "PROJECT_DEEP_DIVE", "question": "오프라인 편집을 Dexie와 낙관적 업데이트로 구현한 흐름과 충돌 해결 방식을 설명해주세요.", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) ... 충돌은 last-write-wins", "expected_signal": "오프라인 저장, 동기화 로직, LWW 충돌 처리"}, {"category": "CS_FUNDAMENTAL", "question": "presigned URL를 이용한 S3 직접 업로드와 클라이언트 WebP 변환의 보안·성능 이점을 설명해주세요.", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "서명된 URL 보안, 서버 부하 감소, 이미지 최적화"}], "latency_sec": 9.386, "in_tokens": 2763, "out_tokens": 1560} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "EKS 클러스터에서 월급날 피크 트래픽을 대비해 설정한 HPA와 CronJob 스케일아웃 전략을 구체적으로 설명해 주세요.", "job_category": "INFRA", "target_evidence": "EKS 기반 쿠버네티스 클러스터 3개 운영 (파드 약 400개)·HPA 기준 CPU 70%·트래픽 피크 대비 CronJob 스케일아웃", "expected_signal": "HPA 임계값·메트릭·CronJob 스케줄링·운영 효과를 명확히 설명한다."}, {"category": "TECH_CHOICE", "question": "여러 환경(dev/stg/prod)에서 Terraform workspace를 분리한 이유와 관리 방식을 설명해 주세요.", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "환경 격리·상태 파일 관리·CI 파이프라인 연동 이유를 논리적으로 제시한다."}, {"category": "PROJECT_DEEP_DIVE", "question": "거래내역 테이블에 복합 인덱스 재설계와 파티셔닝을 적용해 p95 응답 시간을 2.3초에서 180ms로 개선한 과정을 상세히 말씀해 주세요.", "job_category": "DBA", "target_evidence": "PostgreSQL 14 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝)", "expected_signal": "인덱스 설계·파티션 전략·autovacuum 튜닝·측정 결과를 구체적으로 서술한다."}, {"category": "TECH_CHOICE", "question": "RDS 쓰기 중단 장애 후 도입한 스토리지 오토스케일링 설정과 알람 정책을 어떻게 설계했는지 설명해 주세요.", "job_category": "DBA", "target_evidence": "2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "알람 임계값·스케일링 정책·테스트·운영 적용 방식을 체계적으로 제시한다."}, {"category": "CS_FUNDAMENTAL", "question": "Prometheus와 Grafana를 활용해 쿠버네티스 클러스터 주요 지표를 모니터링할 때 선택한 Exporter와 대시보드 설계 기준은 무엇이었나요?", "job_category": "INFRA", "target_evidence": "Prometheus, Grafana 사용 경험", "expected_signal": "Exporter 선택 이유·핵심 메트릭·대시보드 가독성·알림 기준을 설명한다."}, {"category": "BEHAVIORAL", "question": "ArgoCD GitOps 도입 프로젝트에서 팀 저항을 어떻게 극복했고, 배포 리드타임 감소를 어떻게 측정했나요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "변화 관리·소통·교육·정량적 성과 측정 방식을 STAR 형식으로 제시한다."}], "latency_sec": 17.268, "in_tokens": 2752, "out_tokens": 2270} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "팀원과 의견 충돌 후 갈등을 어떻게 해결했는지 구체적으로 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후 대안 두 가지를 비교하는 방식으로 바꿈.", "expected_signal": "갈등 해결 과정과 자기 반성, 협업 개선 의지를 보여줌."}, {"category": "PROJECT_DEEP_DIVE", "question": "알림 봇 서비스가 중단될 때 신뢰를 유지하기 위해 어떤 대비책을 마련했나요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때, '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "장애 대비 설계, 모니터링, 자동 복구 방안 등을 제시함."}, {"category": "TECH_CHOICE", "question": "SQLite에서 PostgreSQL로 마이그레이션을 결정한 핵심 이유와 기대 효과는?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. PostgreSQL 로 이전.", "expected_signal": "데이터 일관성, 동시성 처리, 확장성 향상 등 선택 근거를 명확히 설명함."}, {"category": "CS_FUNDAMENTAL", "question": "트랜잭션 격리 수준을 학습한 뒤 실제 적용 사례와 결과를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "격리 수준 선택 이유와 실제 트랜잭션 충돌 방지 효과를 제시함."}, {"category": "BEHAVIORAL", "question": "OpenAPI 명세와 Mock 서버 도입으로 통합 이슈를 줄인 과정과 본인의 역할은?", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "프로세스 주도, 커뮤니케이션, 결과적인 이슈 감소를 강조함."}], "latency_sec": 13.696, "in_tokens": 2760, "out_tokens": 1820} +{"label": "gw-gpt-oss-120b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 시 주문 서비스와 기존 서비스 간 데이터 정합성을 어떻게 보장했나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "이벤트 기반 싱크·비동기 처리, Saga 패턴·Idempotent 설계 등으로 일관성을 유지한 방법을 설명"}, {"category": "TECH_CHOICE", "question": "Kafka를 이벤트 파이프라인으로 선택한 이유와 고려한 대안은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "처리량·내구성·순서 보장 등 선택 근거와 RabbitMQ·gRPC·Kinesis 등 대안 비교를 제시"}, {"category": "CS_FUNDAMENTAL", "question": "Transactional Outbox를 구현할 때 어떤 트랜잭션 경계와 테이블 설계를 사용했나요?", "job_category": "BACKEND", "target_evidence": "멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "동일 DB 트랜잭션 내에 Outbox 테이블 삽입·커밋·별도 프로듀서가 읽어 Kafka 전송하는 흐름을 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화에서 낙관적 락에서 분산 락으로 전환한 구체적 이유와 구현 방식을 알려주세요.", "job_category": "BACKEND", "target_evidence": "동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "재고 경쟁 상황·락 충돌 사례와 Redis 기반 RedLock·키 만료 설계 등을 상세히 설명"}, {"category": "BEHAVIORAL", "question": "API 스펙 충돌 상황에서 팀원과 갈등을 어떻게 해결했는지 구체적으로 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 초기 고집으로 감정이 상한 경험을 언급", "expected_signal": "STAR 구조로 상황·과제·행동·결과를 제시, 갈등 해결·협업 개선 효과를 강조"}], "latency_sec": 13.134, "in_tokens": 4111, "out_tokens": 1509} diff --git a/docs/research/llm-eval-2026-09/raw/gw-llama-4-maverick.jsonl b/docs/research/llm-eval-2026-09/raw/gw-llama-4-maverick.jsonl new file mode 100644 index 0000000..4e57d04 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/gw-llama-4-maverick.jsonl @@ -0,0 +1,61 @@ +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "Outbox 패턴 도입 시 릴레이 서비스의 장애나 지연이 발생하면 결제 시스템에 어떤 영향을 미칠까요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.036, "ttft_sec": 1.518, "in_tokens": 2796, "out_tokens": 138} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 사용한 구체적인 구현 방식과, 각각이 어떻게 중복 주문 문제를 해결하는 데 기여했는지 설명해 주시겠습니까?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.965, "ttft_sec": null, "in_tokens": 2550, "out_tokens": 158} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "MVCC 의 기본 원리는 이해하고 계신가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.805, "ttft_sec": null, "in_tokens": 2468, "out_tokens": 106} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18의 automatic batching 기능에 대해 전혀 모르겠다고 하셨는데, 혹시 React 18 이전 버전에서 배칭이 어떻게 동작하는지에 대해서 아는 게 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.171, "ttft_sec": null, "in_tokens": 2472, "out_tokens": 164} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA 를 사용하셨다고 하셨는데, 갑자기 트래픽이 증가할 때 HPA 가 즉각적으로 대응하지 못하는 이유가 무엇이라고 생각하시나요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 2.441, "ttft_sec": 1.695, "in_tokens": 2528, "out_tokens": 154} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "아웃박스 릴레이는 어떤 주기로 폴링했나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 2.754, "ttft_sec": 1.609, "in_tokens": 2496, "out_tokens": 108} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "서비스 특성상 메모리를 많이 쓴다고 했는데, 어떤 부분에서 메모리를 많이 사용하나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.065, "ttft_sec": 1.54, "in_tokens": 3054, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "거래내역 테이블에 복합 인덱스를 적용했을 때, 인덱스 스캔 방식은 index scan이었나요, index-only scan이었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.853, "ttft_sec": 1.265, "in_tokens": 3256, "out_tokens": 148} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "항목 높이가 동적으로 변할 때, 높이 캐시를 어떻게 관리했는지 구체적으로 설명해 주세요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.025, "ttft_sec": 1.467, "in_tokens": 3192, "out_tokens": 138} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "당시에 API 스펙 해석 차이로 인해 2주 지연된 상황에, 구체적으로 어떤 대안을 비교해 보았나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.986, "ttft_sec": 2.514, "in_tokens": 2656, "out_tokens": 142} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "그럼 의견 충돌 상황에서 구체적으로 어떻게 대화를 시작하고 진행하신 건가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.919, "ttft_sec": 1.235, "in_tokens": 2544, "out_tokens": 122} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "분산 락 도입 후 불일치 건수가 200건에서 3건으로 감소했다고 했는데, 이 수치만으로 분산 락의 효과가 있다고 판단할 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.137, "ttft_sec": 1.513, "in_tokens": 2610, "out_tokens": 170} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "보상 이벤트가 유실되는 상황을 대비해 보완하는 방법은 따로 없었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.612, "ttft_sec": 1.235, "in_tokens": 3172, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "staleTime을 화면별로 다르게 준다고 했는데, 어떤 화면에서 staleTime을 길게 또는 짧게 설정했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.817, "ttft_sec": 1.31, "in_tokens": 2570, "out_tokens": 144} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "Outbox 패턴 도입 시 릴레이 서비스의 장애나 지연으로 인해 outbox 테이블에 쌓인 데이터가 처리되지 않고 쌓이게 되는 경우에 대한 대책은 세우셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.113, "ttft_sec": 1.53, "in_tokens": 2796, "out_tokens": 168} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 사용한 구체적인 구현 방식과 그로 인해 해결된 실패 케이스에 대해 설명해 주시겠습니까?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.926, "ttft_sec": null, "in_tokens": 2550, "out_tokens": 150} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "MVCC 의 기본 동작 원리나 vacuum 의 역할에 대해서는 어떻게 생각하시나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.591, "ttft_sec": null, "in_tokens": 2468, "out_tokens": 122} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "React 18의 automatic batching 개념에 대해 전혀 모르시나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.687, "ttft_sec": null, "in_tokens": 2472, "out_tokens": 116} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "HPA 기준을 CPU 사용률 70%로 설정한 이유와, 서비스 트래픽이 많이 몰리는 시점을 미리 파악해 스케일아웃을 함께 수행한 이유를 설명해 주세요.", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 2.087, "ttft_sec": 1.578, "in_tokens": 2528, "out_tokens": 166} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "Outbox 테이블을 읽을 때 트랜잭션 충돌을 방지하기 위한 특별한 조치를 하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 2.756, "ttft_sec": 1.327, "in_tokens": 2496, "out_tokens": 126} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "서비스 특성상 메모리를 많이 쓴다고 하셨는데, 어떤 부분이 메모리를 많이 차지하나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.98, "ttft_sec": 1.405, "in_tokens": 3054, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "EXPLAIN ANALYZE 결과에서 seq scan 외에 다른 병목 요인은 없었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.528, "ttft_sec": 1.137, "in_tokens": 3256, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "항목 높이가 동적으로 변할 때, 높이 캐시를 어떻게 관리했는지 구체적으로 설명해 주세요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 1.641, "ttft_sec": 1.244, "in_tokens": 3192, "out_tokens": 138} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "당시에 API 명세를 작성하면서 의사소통 과정에서 어려웠던 점이나 보완한 부분이 있을까요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.412, "ttft_sec": 1.305, "in_tokens": 2656, "out_tokens": 132} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "팀원과 갈등이 생겼을 때, 구체적으로 어떤 방식으로 대화를 시작하고 진행했는지 예를 들어 설명해 주시겠어요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.903, "ttft_sec": 1.413, "in_tokens": 2544, "out_tokens": 146} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "분산 락 도입 후 불일치가 200건에서 3건으로 줄어든 구체적인 메커니즘을 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.853, "ttft_sec": 1.322, "in_tokens": 2610, "out_tokens": 150} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "보상 이벤트가 유실되는 경우를 대비해 이벤트 이력을 별도로 저장하거나, 메시지 브로커의 재시도 기능을 활용하는 등의 추가적인 방법을 고려해 보셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.156, "ttft_sec": 1.608, "in_tokens": 3172, "out_tokens": 168} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "staleTime을 화면별로 다르게 준 기준이 따로 있을까요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.795, "ttft_sec": 1.361, "in_tokens": 2570, "out_tokens": 120} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "Outbox 패턴 도입 시, 릴레이 서비스의 폴링 주기와 실패 시 재시도 로직은 어떻게 설계하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.712, "ttft_sec": 1.309, "in_tokens": 2796, "out_tokens": 146} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 사용한 구체적인 방법과 그로 인해 해결된 실패 케이스에 대해 더 자세히 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.008, "ttft_sec": null, "in_tokens": 2550, "out_tokens": 156} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "MVCC 의 기본 동작 원리에 대해서 알고 계신 부분이 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.843, "ttft_sec": null, "in_tokens": 2468, "out_tokens": 114} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "React 18의 automatic batching 기능에 대해 전혀 모르겠다고 하셨는데, 혹시 이전 버전에서 배칭이 어떻게 동작하는지는 알고 계신가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.747, "ttft_sec": null, "in_tokens": 2472, "out_tokens": 154} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA 기준을 CPU 사용률 70%로 설정한 이유와, 서비스 트래픽이 많이 몰리는 시점을 미리 파악해 스케일아웃을 함께 수행한 이유를 알고 싶습니다.", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 1.735, "ttft_sec": 1.208, "in_tokens": 2528, "out_tokens": 164} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "Outbox 테이블을 폴링할 때 트랜잭션 처리나 락을 어떻게 관리했는지 궁금합니다.", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.658, "ttft_sec": 1.271, "in_tokens": 2496, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "서비스 특성상 메모리를 많이 쓴다고 했는데, 어떤 부분에서 메모리를 많이 사용하나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.762, "ttft_sec": 1.32, "in_tokens": 3054, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "EXPLAIN ANALYZE 결과에서 seq scan 외에 다른 병목 요인은 없었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.525, "ttft_sec": 1.156, "in_tokens": 3256, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "항목 높이가 동적으로 변할 때, 높이 캐시를 어떻게 관리했는지 구체적으로 설명해 주세요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 1.679, "ttft_sec": 1.29, "in_tokens": 3192, "out_tokens": 138} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "당시에 API 스펙 해석이 달랐던 구체적인 이유가 있었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 1.586, "ttft_sec": 1.296, "in_tokens": 2656, "out_tokens": 120} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "팀원과 갈등을 겪었을 때, 구체적으로 어떤 행동을 통해 문제를 해결하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.467, "ttft_sec": 1.154, "in_tokens": 2544, "out_tokens": 124} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "분산 락 도입 후 불일치가 3건 남은 구체적인 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.658, "ttft_sec": 1.206, "in_tokens": 2610, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "보상 이벤트가 유실되는 경우를 대비해 보완한 다른 방법은 없었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.586, "ttft_sec": 1.195, "in_tokens": 3172, "out_tokens": 128} +{"label": "gw-llama-4-maverick", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "staleTime을 화면별로 다르게 준다고 했는데, 어떤 화면에서 staleTime을 길게 또는 짧게 설정했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.898, "ttft_sec": 1.455, "in_tokens": 2570, "out_tokens": 144} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다. 멱등 키는 동일한 요청을 여러 번 받아도 한 번 처리된 것으로 간주하여 중복 처리를 방지합니다. 예를 들어, 결제 승인 요청에 고유한 멱등 키를 부여하고 데이터베이스에 저장하여 동일한 키의 요청이 여러 번 들어오더라도 한 번만 처리하도록 했습니다. Outbox 패턴은 트랜잭션 경계 내에서 이벤트를 안전하게 발행하기 위해 사용되었습니다. 주문 처리 트랜잭션 내에서 Outbox 테이블에 이벤트를 저장하고, 이후 별도의 프로세스가 Outbox 테이블의 이벤트를 Kafka로 발행합니다. 이를 통해 트랜잭션이 커밋된 경우에만 이벤트가 발행되도록 보장하여 데이터의 일관성을 유지했습니다. 멱등 키는 결제 승인 요청의 중복 처리를 막았고, Outbox 패턴은 트랜잭션과 이벤트 발행의 일관성을 보장하여 주문 데이터의 불일치를 방지했습니다.", "answer_rewrite": "중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결했습니다. 멱등 키를 통해 동일한 결제 승인 요청이 여러 번 들어와도 한 번만 처리되도록 했습니다. 예를 들어, 결제 승인 요청에 고유한 멱등 키를 부여하고 데이터베이스에 저장하여 중복 처리를 방지했습니다. Outbox 패턴은 주문 처리 트랜잭션 내에서 이벤트를 안전하게 발행하기 위해 사용되었습니다. 이를 통해 트랜잭션이 커밋된 경우에만 이벤트가 발행되도록 보장하여 데이터의 일관성을 유지했습니다. 결과적으로 중복 주문 0건을 달성했습니다.", "coaching_comment": "멱등 키와 Outbox 패턴을 사용한 구체적인 방법과 각각이 어떤 실패 케이스를 막는지 명확히 설명해야 합니다."}, "latency_sec": 4.826, "in_tokens": 1286, "out_tokens": 402} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum 프로세스에 부정적인 영향을 미칠 수 있습니다. MVCC에서 각 트랜잭션은 고유한 트랜잭션 ID(xid)를 가지며, xmin과 xmax라는 두 개의 시스템 열을 통해 tuple의 가시성을 관리합니다. 오래 열린 트랜잭션은 xmin horizon을 뒤로 밀어내어, 그 이전의 트랜잭션에서 삭제된 tuple이 dead tuple임에도 불구하고 회수되지 못하고 남아있게 만듭니다. 이는 vacuum이 dead tuple을 효과적으로 회수하지 못하게 하여 테이블의 bloat을 초래하고, 결과적으로 성능 저하를 유발할 수 있습니다. 따라서 오래 실행되는 트랜잭션을 주의 깊게 모니터링하고 관리하는 것이 중요합니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum에 영향을 줄 수 있습니다. 구체적으로 xmin horizon을 변경하여 dead tuple의 회수를 지연시키고, 이는 테이블 bloat으로 이어질 수 있습니다. 오래 실행되는 트랜잭션을 모니터링하고 관리하는 것이 중요함을 알 수 있습니다.", "coaching_comment": "질문에 대한 기본적인 개념 이해와 함께 구체적인 설명이 필요하며, 지원자가 PostgreSQL의 MVCC와 vacuum에 대해 더 공부하고 이를 설명할 수 있도록 준비하는 것이 중요합니다."}, "latency_sec": 3.761, "in_tokens": 862, "out_tokens": 302} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": true, "coaching": {"model_answer": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 지연된 적이 있습니다. 당시 저는 API 명세를 먼저 작성하자고 제안했으나 팀원이 동의하지 않아 프로젝트가 2주나 지연되었습니다. 이 문제를 해결하기 위해 저는 우선 OpenAPI 명세를 작성하고 Mock 서버를 구축해 병렬 개발이 가능하도록 환경을 마련했습니다. 그 결과, 이후 스프린트에서 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 저는 의견 충돌 시 상대방의 관점을 존중하며 대화를 통해 해결책을 찾는 것이 중요하다는 것을 배웠습니다. 이후에는 제 방식이 옳다고 고집하기보다 대안을 함께 비교하며 결정하는 방식으로 협업 방식을 개선했습니다.", "answer_rewrite": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 대화와 협업 방식의 개선이 중요함을 깨달았고, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "coaching_comment": "구체적인 상황 설명과 본인의 행동, 결과를 포함하여 STAR 형식에 맞게 답변을 구성해야 합니다."}, "latency_sec": 3.823, "in_tokens": 1181, "out_tokens": 319} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다. 멱등 키는 동일한 요청을 여러 번 받아도 한 번 처리된 것처럼 동작하게 하여, 결제 승인 콜백이 여러 번 호출되어도 중복 주문이 발생하지 않도록 했습니다. 예를 들어, 주문 서비스에서 결제 승인 콜백을 받을 때 `payment_id`를 멱등 키로 사용하여, 이미 처리된 결제 건에 대해서는 주문 생성 로직을 실행하지 않도록 했습니다. 한편, Outbox 패턴은 트랜잭션 경계 내에서 이벤트를 안정적으로 발행하기 위해 사용했습니다. 주문 생성 트랜잭션과 함께 Outbox에 이벤트를 저장하고, 별도의 프로세스가 이를 Kafka로 발행하도록 설계하여 트랜잭션 내 이벤트 발행 실패 문제를 해결했습니다. 이를 통해 결제 승인 콜백 지연으로 인한 중복 주문을 효과적으로 차단할 수 있었습니다.", "answer_rewrite": "중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결했습니다. 멱등 키를 통해 동일한 결제 승인 콜백을 여러 번 받아도 한 번만 처리하도록 했고요, Outbox 패턴으로 트랜잭션 내에서 이벤트 발행의 안정성을 높였습니다. 예를 들어, `payment_id`를 멱등 키로 사용하여 중복 처리를 막았고, Outbox 테이블에 이벤트를 저장 후 Kafka로 발행하는 구조로 이벤트 유실을 방지했습니다.", "coaching_comment": "중복 주문 문제를 해결한 구체적인 방법과 그 이유를 설명하고, 멱등 키와 Outbox 패턴이 각각 어떤 실패 케이스를 막는지 명확히 구분하여 설명해야 합니다."}, "latency_sec": 4.08, "in_tokens": 1286, "out_tokens": 359} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum 프로세스에 영향을 미칩니다. MVCC는 여러 버전의 데이터를 관리하며, 트랜잭션이 오래 열려 있으면 xmin horizon이 낮아집니다. xmin horizon은 현재 실행 중인 가장 오래된 트랜잭션의 ID를 의미하며, 이로 인해 vacuum이 회수할 수 있는 dead tuple이 제한됩니다. 결과적으로, 오래된 트랜잭션으로 인해 dead tuple이 회수되지 못하고, 이는 테이블 bloat을 유발할 수 있습니다. 테이블 bloat은 불필요한 데이터로 인해 테이블 크기가 커지는 현상으로, 성능 저하를 일으킬 수 있습니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum에 영향을 미칩니다. 구체적으로 xmin horizon에 영향을 주는데, 이는 현재 실행 중인 가장 오래된 트랜잭션의 ID를 의미합니다. 이로 인해 dead tuple의 회수가 지연되고, 결과적으로 테이블 bloat이 발생할 수 있습니다. 테이블 bloat은 성능 저하를 일으킬 수 있으므로, 트랜잭션을 적절히 관리하는 것이 중요합니다.", "coaching_comment": "질문에 대한 기본적인 이해와 개념을 설명할 수 있어야 합니다."}, "latency_sec": 3.494, "in_tokens": 862, "out_tokens": 279} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": true, "coaching": {"model_answer": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 지연된 적이 있습니다. 처음에는 제가 생각한 방식이 옳다고 주장하며 OpenAPI 명세 작성과 Mock 서버를 제안했지만, 팀원이 동의하지 않아 감정이 상하기도 했습니다. 하지만 통합 지연이 계속될 수 없어 대화를 통해 서로의 입장을 공유했습니다. 그 결과, 제가 OpenAPI 명세를 작성하고 Mock 서버를 구축하는 것을 팀원이 받아들이면서 2주간의 지연을 만회할 수 있었습니다. 이후 통합 이슈도 3건에서 0건으로 줄었습니다. 이 경험을 통해 상대방의 의견을 경청하고 대안을 함께 비교하는 것이 중요함을 배웠습니다.", "answer_rewrite": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 지연된 적이 있습니다. 처음에는 제가 생각한 방식이 옳다고 주장했지만, 팀원이 동의하지 않아 감정이 상했습니다. 그래서 서로의 입장을 공유했고, 제가 OpenAPI 명세를 작성하고 Mock 서버를 구축하는 걸 받아들여 2주간의 지연을 만회했습니다. 이후 통합 이슈도 3건에서 0건으로 줄었고, 상대방의 의견을 경청하는 것의 중요성을 배웠습니다.", "coaching_comment": "구체적인 경험과 그때 취한 행동, 결과를 중심으로 답하고, 배운 점을 연결하면 더 설득력 있는 답변이 됩니다."}, "latency_sec": 4.073, "in_tokens": 1181, "out_tokens": 320} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다. 멱등 키는 동일한 요청에 대해 시스템이 여러 번 처리하더라도 결과가 동일하도록 보장합니다. 예를 들어, 결제 승인 요청에 대해 고유한 멱등 키를 생성하여 데이터베이스에 저장하고, 동일한 키의 요청이 들어오면 이미 처리된 것으로 간주하여 중복 처리를 방지했습니다. 한편, Outbox 패턴은 트랜잭션 경계 내에서 이벤트를 저장하고, 이후 비동기적으로 이벤트를 발행하여 메시지 누락을 방지합니다. 이를 통해 결제 승인 이벤트가 신뢰성 있게 발행되고, 주문 서비스가 이를 안전하게 처리할 수 있었습니다. 결과적으로, 두 패턴을 함께 사용하여 중복 주문을 효과적으로 차단하고, 메시지 유실을 방지할 수 있었습니다.", "answer_rewrite": "중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결했습니다. 멱등 키는 동일한 결제 승인 요청이 여러 번 들어오더라도 한 번만 처리되도록 하여 중복 주문을 막았습니다. Outbox 패턴은 트랜잭션 내에서 이벤트를 저장하고 비동기적으로 발행하여, 결제 승인 이벤트가 누락되지 않도록 했습니다. 이를 통해 중복 주문 0건을 달성할 수 있었습니다.", "coaching_comment": "중복 주문 문제를 해결한 구체적인 방법과 그 이유를 설명하고, 멱등 키와 Outbox 패턴이 각각 어떤 실패 케이스를 막는지 명확히 구분해야 합니다."}, "latency_sec": 4.448, "in_tokens": 1286, "out_tokens": 328} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum 프로세스에 부정적인 영향을 미칠 수 있습니다. MVCC에서 각 트랜잭션은 고유한 트랜잭션 ID(xid)를 가지며, xmin과 xmax라는 두 개의 시스템 열을 통해 row의 가시성을 관리합니다. 오래 살아있는 트랜잭션은 xmin horizon을 뒤로 밀어내어, vacuum이 dead tuple을 회수하는 것을 지연시킵니다. 이는 테이블 bloat을 유발하고, 결과적으로 성능 저하를 초래할 수 있습니다. 예를 들어, 대량 데이터 변경 작업 후 오래 실행되는 트랜잭션이 남아있으면, vacuum이 dead tuple을 제거하지 못해 디스크 사용량이 증가하고 쿼리 성능이 저하될 수 있습니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum에 영향을 줄 수 있습니다. 구체적으로, 오래 실행되는 트랜잭션은 xmin horizon을 변경하여 dead tuple의 회수를 지연시키고, 이는 테이블 bloat을 유발할 수 있습니다. 따라서 주기적으로 트랜잭션을 커밋하거나, 오래 실행되는 트랜잭션을 모니터링하여 조기에 문제를 발견하는 것이 중요합니다.", "coaching_comment": "질문에 대한 기본 개념을 이해하고 구체적인 예를 들어 설명할 수 있어야 합니다."}, "latency_sec": 3.746, "in_tokens": 862, "out_tokens": 304} +{"label": "gw-llama-4-maverick", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 지연된 적이 있습니다. 당시 저는 API 우선 접근법을 제안했습니다. 우선 OpenAPI 명세를 작성하고, Mock 서버를 띄워 프론트엔드가 백엔드와 병렬로 개발할 수 있게 한 것입니다. 이 접근법 덕분에 이후 스프린트에서 통합 이슈가 3건에서 0건으로 줄었습니다. 다만, 초반에 제 방식이 옳다고 고집했던 점은 반성합니다. 이후에는 결정 전에 대안 두 가지를 함께 비교하고 토론하는 시간을 가지며 팀원과의 의사소통 방식을 개선했습니다.", "answer_rewrite": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 이 문제를 해결하기 위해 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트엔드가 병렬로 개발하도록 제안했고, 이후 통합 이슈가 3건에서 0건으로 줄었습니다. 처음에는 제 방식이 옳다고 고집해 팀원과 감정이 상했지만, 이후 결정 전에 대안을 비교하며 토론하는 방식으로 개선했습니다.", "coaching_comment": "구체적인 경험과 그때 취한 행동, 결과를 중심으로 답하고, 교훈을 얻은 점도 구체적으로 말해 보세요."}, "latency_sec": 3.603, "in_tokens": 1181, "out_tokens": 303} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 시 주문 서비스 분리 과정에서 어떤 문제를 겪었고, 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "구체적인 문제 상황과 해결책을 설명해야 합니다."}, {"category": "TECH_CHOICE", "question": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 멱등 키와 Outbox 패턴으로 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키와 Outbox 패턴의 구체적인 구현 방식과 효과를 설명해야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능을 5시간에서 40분으로 개선한 방법에 대해 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "성능 개선을 위해 적용한 구체적인 기술과 그 효과를 설명해야 합니다."}, {"category": "TECH_CHOICE", "question": "Redis 기반 재고 캐시와 DB write-behind 전략을 사용하면서 동시성 제어에 어떤 이슈가 있었고, 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "동시성 제어 이슈와 그 해결책으로 분산 락 전환 과정을 설명해야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "Kafka 이벤트 파이프라인 설계 시 고려한 사항과 장애 대응 경험에 대해 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "Kafka 설계 시 고려 사항과 실제 장애 대응 경험을 설명해야 합니다."}], "latency_sec": 6.714, "in_tokens": 2665, "out_tokens": 549} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "타임라인 항목 2천 개 이상일 때 react-window 도입으로 INP가 480ms에서 120ms로 개선된 구체적 이유는?", "job_category": "FRONTEND", "target_evidence": "커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\"", "expected_signal": "react-window 도입으로 가상화된 리스트 렌더링이 성능에 끼친 영향을 설명할 수 있다."}, {"category": "TECH_CHOICE", "question": "Kakao Map SDK 마커 500개를 렌더링할 때 useMemo로 좌표 변환을 캐싱한 이유는?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "useMemo를 사용해 불필요한 계산을 줄인 이유를 설명할 수 있다."}, {"category": "PROJECT_DEEP_DIVE", "question": "IndexedDB에 낙관적 업데이트를 저장하고 온라인 복귀 시 동기화하는 로직에서 충돌 해결 전략은?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins", "expected_signal": "현재 last-write-wins 전략을 사용 중이며, CRDT 검토 필요성을 이해하고 있다."}, {"category": "CS_FUNDAMENTAL", "question": "presigned URL을 사용해 클라이언트에서 S3로 직접 업로드할 때 보안 고려 사항은?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "presigned URL 사용 시 보안 위험을 이해하고 적절한 조치를 설명할 수 있다."}, {"category": "PROJECT_DEEP_DIVE", "question": "Lighthouse 성능 점수를 68에서 91로 개선한 구체적 방법은?", "job_category": "FRONTEND", "target_evidence": "Lighthouse 성능 점수 68 → 91 (PR #57 설명)", "expected_signal": "성능 개선을 위해 어떤 최적화 작업을 수행했는지 구체적으로 설명할 수 있다."}], "latency_sec": 6.167, "in_tokens": 2485, "out_tokens": 560} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "EKS 클러스터 운영 시 HPA 설정과 CronJob을 통한 사전 스케일아웃 전략의 효과는?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "HPA와 CronJob의 구체적 설정 내용과 그로 인한 시스템 안정성 향상 효과를 설명할 수 있다."}, {"category": "TECH_CHOICE", "question": "ArgoCD를 도입한 이유와 그로 인한 배포 리드타임 개선 효과는?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "ArgoCD 선택 이유와 도입 전후의 배포 프로세스 차이 및 개선 효과를 설명할 수 있다."}, {"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 성능 최적화를 위해 수행한 작업들과 그 효과는?", "job_category": "DBA", "target_evidence": "복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할", "expected_signal": "수행한 최적화 작업들의 구체적 내용과 그로 인한 성능 개선 효과를 설명할 수 있다."}, {"category": "BEHAVIORAL", "question": "RDS 스토리지 풀 문제 발생 시 어떻게 대응했고, 이후 어떤 조치를 취했는가?", "job_category": "DBA", "target_evidence": "2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 발생 시의 구체적 대응 과정과 이후 예방을 위한 조치 내용을 설명할 수 있다."}, {"category": "TECH_CHOICE", "question": "Terraform을 사용해 VPC·RDS·EKS를 모듈화한 배경과 그 장점은?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "Terraform 모듈화의 이유와 그로 인한 인프라 관리의 효율성 향상을 설명할 수 있다."}, {"category": "CS_FUNDAMENTAL", "question": "쿠버네티스 클러스터에서 파드 약 400개를 운영할 때 고려한 리소스 관리 및 스케일링 전략은?", "job_category": "INFRA", "target_evidence": "EKS 기반 쿠버네티스 클러스터 3개 운영 (파드 약 400개)", "expected_signal": "대규모 파드 운영 시 리소스 관리와 스케일링을 어떻게 고려했는지 설명할 수 있다."}], "latency_sec": 8.214, "in_tokens": 2472, "out_tokens": 682} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 API 스펙 해석 문제로 통합이 지연됐을 때, 본인의 제안과 그에 따른 결과는?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "본인의 구체적 행동(제안)과 그로 인한 결과(통합 이슈 감소)를 STAR 형식으로 설명해야 합니다."}, {"category": "TECH_CHOICE", "question": "알림 봇 DB를 SQLite에서 PostgreSQL로 이전한 이유는?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "SQLite의 한계와 PostgreSQL로의 이전 이유를 명확히 설명해야 합니다."}, {"category": "BEHAVIORAL", "question": "팀원과 감정이 상했던 경험과 그 이후 본인의 의사소결정 방식 변화는?", "job_category": "BACKEND", "target_evidence": "다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "갈등 상황에서의 본인 행동 변화와 그 이유를 설명해야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "학사 공지 알림 봇에서 '멈추지 않는 서비스'를 운영하기 위해 어떤 노력을 했나요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "서비스 안정성을 높이기 위한 구체적 노력을 설명해야 합니다."}, {"category": "BEHAVIORAL", "question": "본인이 백엔드 개발자로서 '신뢰받는 서비스'를 만든다는 것이 어떤 의미인지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "본인의 가치관과 그에 따른 행동 기준을 설명해야 합니다."}], "latency_sec": 7.234, "in_tokens": 2479, "out_tokens": 674} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 시 주문 서비스 분리 과정에서 Kafka 이벤트 파이프라인 설계 시 고려 사항은?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입.", "expected_signal": "Kafka 도입 배경, 이벤트 설계 시 고려 사항, 장애 대응 전략 등"}, {"category": "TECH_CHOICE", "question": "재고 동기화 프로젝트에서 Redis 기반 재고 캐시와 DB write-behind 전략을 선택한 이유는?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "Redis 도입 이유, write-behind 전략의 장단점, 동시성 제어 방식 변경 배경 등"}, {"category": "CS_FUNDAMENTAL", "question": "정산 배치 성능 개선 시 QueryDSL 튜닝과 인덱스 재설계 과정에서 데이터베이스 락 경합을 어떻게 관리했나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "QueryDSL 튜닝 방법, 인덱스 재설계 시 고려 사항, 락 경합 관리 전략 등"}, {"category": "BEHAVIORAL", "question": "API 스펙 해석 문제로 통합이 지연된 경험에서, 본인의 구체적 행동과 결과는?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "STAR(상황, 과제, 행동, 결과)로 설명하며, 구체적 행동과 정량적 결과 강조"}, {"category": "TECH_CHOICE", "question": "주문 관리 어드민에서 react-window 도입으로 INP가 480ms에서 120ms로 개선된 구체적 방법은?", "job_category": "BACKEND", "target_evidence": "react-window 가상화 도입 (커밋 메시지: virtualize timeline, INP 480ms -> 120ms)", "expected_signal": "react-window 도입 배경, 가상화 구현 방법, 성능 개선 효과 등"}], "latency_sec": 8.034, "in_tokens": 3710, "out_tokens": 624} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 시 주문 서비스 분리 과정에서 어떤 문제를 겪었고 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "MSA 전환 과정에서 발생한 구체적 문제와 그 해결책을 설명해야 합니다."}, {"category": "TECH_CHOICE", "question": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 멱등 키와 Outbox 패턴으로 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키와 Outbox 패턴의 구체적 구현 방식과 그 효과를 설명해야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능 개선 과정에서 어떤 튜닝을 했고, 그 결과는 어땠나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "정산 배치 성능 개선을 위해 수행한 구체적 튜닝 작업과 그 결과를 설명해야 합니다."}, {"category": "TECH_CHOICE", "question": "Redis 기반 재고 캐시와 DB write-behind 전략을 사용한 이유와 그 장단점은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "Redis 기반 재고 캐시와 DB write-behind 전략을 선택한 이유와 그에 따른 장단점을 설명해야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "Kafka 이벤트 파이프라인 설계 시 고려한 데이터 정합성 및 장애 복구 전략은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "Kafka를 사용하면서 데이터 정합성과 장애 복구를 위해 고려한 전략을 설명해야 합니다."}], "latency_sec": 6.346, "in_tokens": 2665, "out_tokens": 566} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "타임라인 항목 2천 개 이상일 때 react-window 도입으로 INP가 480ms에서 120ms로 개선된 구체적 이유는?", "job_category": "FRONTEND", "target_evidence": "react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "react-window 도입으로 인한 렌더링 최적화 효과를 구체적으로 설명할 수 있어야 함"}, {"category": "TECH_CHOICE", "question": "Kakao Map SDK 마커 500개를 렌더링할 때 useMemo를 사용해 좌표 변환을 캐싱한 이유는?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "useMemo를 사용한 성능 최적화 이유와 그 효과를 설명할 수 있어야 함"}, {"category": "PROJECT_DEEP_DIVE", "question": "오프라인 편집 시 IndexedDB에 낙관적 업데이트를 저장하고 온라인 복귀 시 동기화하는 로직에서 발생할 수 있는 충돌 해결 방안은?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "현재 last-write-wins 전략의 한계를 이해하고 CRDT와 같은 대안을 고려할 수 있어야 함"}, {"category": "CS_FUNDAMENTAL", "question": "TanStack Query v5를 사용한 서버 상태 관리에서 캐시 무효화 전략은 어떻게 구현했는지?", "job_category": "FRONTEND", "target_evidence": "상태 관리는 Zustand, 서버 상태는 TanStack Query v5", "expected_signal": "TanStack Query의 캐시 무효화 전략을 이해하고 이를 프로젝트에 적용한 경험을 설명할 수 있어야 함"}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 presigned URL을 사용해 S3에 직접 업로드하는 방식을 선택한 이유는?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "presigned URL을 사용한 보안 및 성능상의 이점을 이해하고 이를 프로젝트에 적용한 경험을 설명할 수 있어야 함"}], "latency_sec": 7.303, "in_tokens": 2485, "out_tokens": 605} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "EKS 기반 쿠버네티스 클러스터 3개를 운영하며 HPA와 CronJob을 통해 트래픽 피크에 대비한 사전 스케일아웃을 어떻게 구현했는지 설명해 주세요?", "job_category": "INFRA", "target_evidence": "EKS 기반 쿠버네티스 클러스터 3개 운영, HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "HPA 설정과 CronJob을 통한 사전 스케일아웃 전략을 구체적으로 설명할 수 있어야 함"}, {"category": "TECH_CHOICE", "question": "ArgoCD를 도입하여 배포 리드타임을 1일에서 30분으로 단축한 구체적인 방법은 무엇인가요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "ArgoCD 도입 과정과 그로 인한 배포 리드타임 단축 효과를 설명할 수 있어야 함"}, {"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 14 (RDS) 운영 중 슬로우 쿼리를 최적화한 방법(복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝)을 설명해 주세요.", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "슬로우 쿼리 최적화를 위한 구체적인 기술적 조치와 그 효과를 설명할 수 있어야 함"}, {"category": "BEHAVIORAL", "question": "2024년 3월 RDS 스토리지 풀 문제 발생 시 어떻게 대응했고, 이후 어떤 예방 조치를 취했는지 설명해 주세요.", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 발생 시의 대응 과정과 이후의 예방 조치를 구체적으로 설명할 수 있어야 함"}, {"category": "TECH_CHOICE", "question": "Terraform을 사용해 VPC, RDS, EKS를 모듈화하고 환경별 workspace를 분리한 이유와 그 장점은 무엇인가요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "Terraform을 사용한 인프라 코드화의 이유와 그로 인한 운영상의 장점을 설명할 수 있어야 함"}, {"category": "BEHAVIORAL", "question": "인프라/DBA로서의 경력 중 가장 도전적이었던 프로젝트나 문제를 해결한 경험에 대해 설명해 주세요.", "job_category": "INFRA", "target_evidence": "", "expected_signal": "도전적인 프로젝트나 문제 해결 경험, 그리고 그 과정에서 본인의 역할을 구체적으로 설명할 수 있어야 함"}], "latency_sec": 8.475, "in_tokens": 2472, "out_tokens": 781} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "동아리 공지 알림 봇 운영 중 크롤러가 멈췄을 때 어떻게 대응했나요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "본인의 구체적 대응과 그 과정에서 배운 점을 설명해야 합니다."}, {"category": "TECH_CHOICE", "question": "SQLite에서 PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하게 된 계기는?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "SQLite의 한계를 설명하고 PostgreSQL의 어떤 장점을 고려했는지 명확히 해야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "OpenAPI 명세와 Mock 서버 도입으로 통합 이슈가 줄어든 구체적 이유는?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "OpenAPI 명세와 Mock 서버가 어떻게 협업을 개선했는지 구체적으로 설명해야 합니다."}, {"category": "BEHAVIORAL", "question": "팀원과 감정이 상했던 경험과 이후 어떻게 개선했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "갈등 상황에서의 본인 행동 변화와 그 결과를 설명해야 합니다."}, {"category": "BEHAVIORAL", "question": "백엔드 개발자로서 '멈추지 않는 서비스'의 중요성을 어떻게 이해하고 있나요?", "job_category": "BACKEND", "target_evidence": "기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "본인의 경험과 '멈추지 않는 서비스'에 대한 이해를 연결 지어 설명해야 합니다."}], "latency_sec": 6.638, "in_tokens": 2479, "out_tokens": 671} +{"label": "gw-llama-4-maverick", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 시 주문 서비스 분리 과정에서 Kafka 이벤트 파이프라인 설계 시 고려한 사항은?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입.", "expected_signal": "Kafka 도입 배경, 이벤트 설계 시 고려사항, 장애 대응 전략을 구체적으로 설명할 수 있어야 함."}, {"category": "TECH_CHOICE", "question": "재고 동기화 프로젝트에서 Redis 기반 재고 캐시와 DB write-behind 전략을 선택한 이유는?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "Redis 도입 이유, write-behind 전략의 장단점, 동시성 제어 방식 변경 사유를 명확히 설명할 수 있어야 함."}, {"category": "CS_FUNDAMENTAL", "question": "정산 배치 성능 개선 시 QueryDSL 튜닝과 인덱스 재설계 과정에서 어떤 분석을 했나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "성능 병목 지점 분석 방법, QueryDSL 튜닝과 인덱스 재설계의 구체적 내용을 설명할 수 있어야 함."}, {"category": "BEHAVIORAL", "question": "협업 중 API 스펙 해석 차이로 통합이 지연된 경험이 있나요? 어떻게 해결했는지 구체적으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "구체적 상황, 본인의 행동, 결과 및 배운 점을 STAR 형식으로 설명할 수 있어야 함."}, {"category": "TECH_CHOICE", "question": "주문 관리 어드민에서 react-window 도입 전후의 성능 차이를 수치로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "react-window 가상화 도입 (커밋 메시지: virtualize timeline, INP 480ms -> 120ms)", "expected_signal": "react-window 도입 배경, 성능 지표 변화(INP 480ms → 120ms)를 설명하고, 가상화의 이점을 이해하고 있음을 보여줘야 함."}], "latency_sec": 7.773, "in_tokens": 3710, "out_tokens": 660} diff --git a/docs/research/llm-eval-2026-09/raw/gw-solar-pro4.jsonl b/docs/research/llm-eval-2026-09/raw/gw-solar-pro4.jsonl new file mode 100644 index 0000000..c619a94 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/gw-solar-pro4.jsonl @@ -0,0 +1,61 @@ +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "Outbox 릴레이가 폴링 중 실패하거나 중복 발행했을 때, 멱등 키만으로는 막을 수 없는 케이스가 생기는데 그 경계는 어떻게 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.641, "ttft_sec": 1.716, "in_tokens": 1197, "out_tokens": 88} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 쓴 이유를, 각각이 막은 구체적인 실패 케이스(예: 콜백 중복 전달 vs. 트랜잭션 커밋 후 메시지 유실)와 함께 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.832, "ttft_sec": null, "in_tokens": 1105, "out_tokens": 92} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "PostgreSQL MVCC 에서 오래 열린 트랜잭션이 vacuum 에 미치는 영향, 특히 xmin horizon 과 dead tuple 회수 지연, 그리고 테이블 bloat 으로 이어지는 흐름을 다시 설명해 드릴까요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.37, "ttft_sec": null, "in_tokens": 1079, "out_tokens": 87} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18 의 automatic batching 이 이전 버전과 어떻게 다른지, 특히 setTimeout 이나 Promise 같은 비동기 콜백 내부에서도 상태 업데이트가 배칭되는지 설명해 보세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.884, "ttft_sec": null, "in_tokens": 1083, "out_tokens": 85} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA 가 CPU 70% 에 반응하기까지 메트릭 수집·파드 기동 시간이 걸리는데, 트래픽 피크처럼 그 지연을 기다릴 수 없는 상황에서는 미리 스케일아웃을 해두는 이유를 설명해 달라는 질문입니다.", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 2.303, "ttft_sec": 1.223, "in_tokens": 1104, "out_tokens": 93} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "폴링 간격과 배치 크기는 어떻게 정하셨고, 아웃박스 레코드 처리 중 장애·중복 발행은 어떻게 방지하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.987, "ttft_sec": 3.23, "in_tokens": 1090, "out_tokens": 77} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "이력서에 적힌 CPU 70% 기준과 월급날 피크 대비 CronJob 사전 스케일아웃은 어떤 근거로 선택하셨고, 그 사전 스케일아웃이 없었다면 피크 때 어떤 문제가 생겼을 거라고 보시나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": 1.0}, "latency_sec": 1.869, "ttft_sec": 1.113, "in_tokens": 1332, "out_tokens": 92} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "인덱스 변경만으로 p95가 900ms까지 내려간 시점과 파티셔닝 후 180ms가 된 시점을 각각 어떻게 측정·비교하셨나요? EXPLAIN ANALYZE에서 seq scan이 사라진 뒤 실제 실행 계획에 파티션 프루닝이 적용된 걸 어떻게 확인하셨는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 7.688, "ttft_sec": 2.267, "in_tokens": 1429, "out_tokens": 120} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "VariableSizeList 의 높이 캐시를 직접 구현하셨다고 했는데, 실제 콘텐츠 높이가 바뀌거나 초기 추정치가 틀렸을 때 캐시를 어떻게 갱신·보정했는지 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.967, "ttft_sec": 2.002, "in_tokens": 1422, "out_tokens": 89} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "처음에 제 방식만 고집해서 감정이 상했다고 하셨는데, 구체적으로 어떤 결정이나 발언에서 그런 상황이 생겼는지, 그리고 그걸 인지한 뒤 어떻게 풀었는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 6.793, "ttft_sec": 1.765, "in_tokens": 1150, "out_tokens": 90} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "구체적으로 어떤 프로젝트나 상황에서 의견 차이가 있었는지, 그리고 그 차이를 좁히기 위해 본인이 실제로 취한 행동 한 가지는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.34, "ttft_sec": 1.844, "in_tokens": 1104, "out_tokens": 74} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "타임세일 때 버전 충돌이 얼마나 자주 발생했는지, 재시도 비용과 분산 락 도입으로 인한 대기/병목 비용을 어떻게 비교해서 트레이드오프를 판단하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.987, "ttft_sec": 1.236, "in_tokens": 1127, "out_tokens": 85} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "주문 상태 재조회 스위퍼 배치가 PENDING 상태를 해소할 때, 결제·재고 서비스의 실제 최종 상태와 불일치하는 보상 중복 실행은 어떻게 방지했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.414, "ttft_sec": 1.604, "in_tokens": 1356, "out_tokens": 86} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "invalidateQueries 로 목록만 갱신했다고 하셨는데, 목록 외에 상세 페이지나 다른 컴포넌트에서 같은 데이터를 쓰고 있었다면 그 stale 데이터는 어떻게 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 5.269, "ttft_sec": 1.846, "in_tokens": 1127, "out_tokens": 85} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "Outbox 릴레이가 폴링 중 실패하거나 장애로 재시작될 때, 동일 이벤트가 중복 발행되지 않도록 멱등성을 어떻게 보장했는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.066, "ttft_sec": 0.886, "in_tokens": 1197, "out_tokens": 88} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키가 막은 실패 케이스와 Outbox 패턴이 막은 실패 케이스를 각각 구체적으로 나눠 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.178, "ttft_sec": 1.62, "in_tokens": 1105, "out_tokens": 76} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "PostgreSQL MVCC 에서 오래 열린 트랜잭션이 vacuum 의 dead tuple 회수를 어떻게 막는지, xmin horizon 관점에서 설명해 주실 수 있을까요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.501, "ttft_sec": null, "in_tokens": 1079, "out_tokens": 79} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "React 18 의 automatic batching 이 이전 버전과 어떻게 다른지, 특히 setTimeout 이나 Promise 같은 비동기 콜백 내부에서도 상태 업데이트가 배칭되는지 설명해 보세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.851, "ttft_sec": null, "in_tokens": 1083, "out_tokens": 85} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "제가 드린 질문은 두 가지입니다. 첫째, HPA CPU 임계값을 70% 로 정하신 근거가 무엇인지, 둘째, 트래픽 피크가 예상될 때 HPA 만 기다리지 않고 미리 스케일아웃을 병행하신 이유를 여쭤본 것입니다. 이 두 가지를 각각 설명해 주시면 됩니다.", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 3.931, "ttft_sec": 1.274, "in_tokens": 1104, "out_tokens": 106} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "폴링 간격과 outbox 테이블 읽는 방식(단일/배치), 그리고 멱등 키와 outbox 상태를 어떻게 연동했는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.889, "ttft_sec": 1.31, "in_tokens": 1090, "out_tokens": 81} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "이력서에는 HPA 기준을 CPU 70% 로 설정하고 월급날 10시 피크 대비 사전 스케일아웃 CronJob을 운영했다고 되어 있는데, 면접에서는 메모리 50% 기준과 사전 대응 없이 HPA에만 의존했다고 하셨어요. 실제 운영 기준은 CPU 70% 와 사전 스케일아웃 중 어느 쪽이었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": 1.0}, "latency_sec": 4.429, "ttft_sec": 2.736, "in_tokens": 1332, "out_tokens": 118} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "autovacuum scale_factor 를 0.2에서 0.05로 낮춘 뒤 dead tuple 정리로 인한 쓰기 증폭이나 vacuum 충돌 같은 부작용은 없었는지, 그리고 인덱스·파티셔닝·vacuum 각각의 기여가 p95 2.3초→180ms 개선에 얼마나 나뉘었다고 보시는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.739, "ttft_sec": 1.282, "in_tokens": 1429, "out_tokens": 123} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "VariableSizeList 의 높이 캐시를 직접 구현하셨다고 했는데, 항목 높이가 실제보다 작게 추정됐을 때 스크롤 위치가 어긋나는 문제를 어떻게 보정했는지 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.643, "ttft_sec": 1.254, "in_tokens": 1422, "out_tokens": 88} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "감정이 상한 팀원과 구체적으로 어떤 대화를 나눴고, 그 뒤 대안 두 개를 비교한 첫 결정 사례는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.546, "ttft_sec": 1.633, "in_tokens": 1150, "out_tokens": 77} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "구체적으로 어떤 상황에서 누구의 어떤 의견과 충돌했고, 그 대화를 통해 실제로 어떤 결정을 내렸는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.263, "ttft_sec": 1.871, "in_tokens": 1104, "out_tokens": 73} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "분산 락으로 바꾼 뒤 재시도 비용은 실제로 어떻게 줄었고, 락 획득 대기나 데드락 같은 새 문제는 없었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.34, "ttft_sec": 1.847, "in_tokens": 1127, "out_tokens": 79} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "보상 이벤트 유실 시 PENDING 상태가 남는 문제를 스위퍼 배치로 해결하셨다고 했는데, 스위퍼가 재조회해서 상태를 확정할 때 결제·재고 서비스의 최종 상태와 이벤트 순서가 불일치할 수 있는 경우는 어떻게 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 1.88, "ttft_sec": 1.121, "in_tokens": 1356, "out_tokens": 99} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "staleTime 을 화면별로 다르게 준 구체적인 기준과, invalidateQueries 로 목록만 갱신했을 때 발생할 수 있는 캐시 불일치 문제는 어떻게 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.799, "ttft_sec": 1.127, "in_tokens": 1127, "out_tokens": 84} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "멱등 키의 유니크 제약이 걸린 테이블과 Outbox 테이블이 같은 트랜잭션 경계 안에 함께 묶여 있나요? 만약 별도 트랜잭션이라면, 주문 저장 성공 후 Outbox INSERT 가 실패해 이벤트가 유실되는 케이스는 어떻게 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.501, "ttft_sec": 1.009, "in_tokens": 1197, "out_tokens": 102} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "멱등 키가 막은 실패 케이스와 Outbox 패턴이 막은 실패 케이스를 각각 구체적으로 말씀해 주실 수 있을까요? 그리고 두 패턴을 함께 쓴 이유가 트랜잭션 경계와 어떤 관련이 있었는지 설명해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.607, "ttft_sec": null, "in_tokens": 1105, "out_tokens": 93} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "PostgreSQL MVCC 에서 오래 열린 트랜잭션이 vacuum 의 dead tuple 회수를 어떻게 막는지, xmin horizon 과 테이블 bloat 관점에서 다시 설명해 보시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.637, "ttft_sec": null, "in_tokens": 1079, "out_tokens": 82} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "React 18 의 automatic batching 이 이전 버전과 어떻게 다른지 설명해 주세요. 특히 setTimeout 이나 Promise 같은 비동기 콜백 내부에서의 상태 업데이트도 배칭되는지 중심으로 말씀해 보세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.917, "ttft_sec": null, "in_tokens": 1083, "out_tokens": 90} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA 가 CPU 70% 에 도달해서 파드를 늘리는 데까지 시간이 걸리는데, 트래픽 피크가 미리 예측될 때는 그 반응 지연 때문에 미리 스케일아웃을 해두는 이유를 설명해 달라는 질문입니다.", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 1.619, "ttft_sec": 1.169, "in_tokens": 1104, "out_tokens": 93} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "폴링 간격과 배치 크기는 어떻게 정했고, outbox 레코드 잠금/중복 처리로 경합은 어떻게 막았나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 1.479, "ttft_sec": 0.937, "in_tokens": 1090, "out_tokens": 76} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "HPA 를 메모리 50% 기준으로만 두고 피크 대응을 HPA 에만 맡기셨다면, 월급날 10시 같은 급격한 트래픽 증가 시 파드가 새로 뜨는 데 걸리는 시간 때문에 요청이 밀릴 수 있는데, 이 지연을 어떻게 보완하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": 0.0}, "latency_sec": 1.592, "ttft_sec": 0.9, "in_tokens": 1332, "out_tokens": 105} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "인덱스 변경만으로 p95가 900ms까지 내려왔다고 하셨는데, EXPLAIN ANALYZE에서 seq scan이 사라진 뒤 실제 실행 계획에서 인덱스 스캔의 cost와 실제 소요 시간이 어떻게 달라졌는지 수치로 확인해 보셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.718, "ttft_sec": 1.102, "in_tokens": 1429, "out_tokens": 105} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "VariableSizeList 에서 항목 높이가 달라질 때 높이 캐시를 어떻게 갱신·검증하셨는지, 그리고 자체 검색 박스 도입 시 접근성(스크린 리더·키보드 포커스)과 검색 정확도 측면에서 어떤 트레이드오프가 있었는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.126, "ttft_sec": 1.206, "in_tokens": 1422, "out_tokens": 101} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "처음에 제 방식만 고집해서 팀원과 감정이 상했다고 하셨는데, 그 상황에서 구체적으로 어떤 말이나 행동으로 관계가 틀어졌고, 이후 ‘대안 두 개를 같이 비교하는 방식’을 실제 회의에서 어떻게 운영하셨는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 1.667, "ttft_sec": 1.256, "in_tokens": 1150, "out_tokens": 99} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "구체적으로 어떤 상황에서 어떤 의견 차이가 있었는지, 그리고 그 대화를 통해 실제로 어떤 결정을 내렸는지 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.082, "ttft_sec": 1.593, "in_tokens": 1104, "out_tokens": 76} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "레디스 분산 락으로 바꾼 뒤 재시도 로직은 어떻게 달라졌나요? 락 획득 실패 시 바로 실패 처리했는지, 아니면 재시도나 대기 큐 같은 보완책을 함께 뒀는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 8.745, "ttft_sec": 1.278, "in_tokens": 1127, "out_tokens": 94} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "코레오그래피 Saga 로 가신 이유가 각 서비스의 자율성을 높이기 위해서였나요, 아니면 운영 복잡도 때문이었나요? 그리고 보상 이벤트 유실 시 PENDING 상태를 스위퍼 배치로만 해결하셨다면, 보상 이벤트 자체가 발행조차 안 된 경우는 어떻게 감지하고 처리하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "FULL_STAR", "correctness": null}, "latency_sec": 3.483, "ttft_sec": 2.899, "in_tokens": 1356, "out_tokens": 107} +{"label": "gw-solar-pro4", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "invalidateQueries 로 목록만 갱신하셨다고 했는데, mutation 후 목록 외에 상세 화면이나 다른 탭에 남아 있던 stale 데이터는 어떻게 처리했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.607, "ttft_sec": 1.385, "in_tokens": 1127, "out_tokens": 84} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "멱등 키와 Outbox 패턴을 함께 쓴 이유는 두 패턴이 방어하는 실패 케이스가 서로 다르기 때문입니다. 멱등 키는 네트워크 타임아웃, 클라이언트 재시도, 콜백 중복 전달 등으로 인해 같은 결제 승인 요청이 여러 번 들어오는 문제를 막습니다. 주문 생성 전에 멱등 키 테이블에서 이미 처리된 키인지 확인하고, 처음이면 처리 후 키를 저장해 중복 요청을 걸러냈습니다. 반면 Outbox 패턴은 결제 승인 처리와 주문 상태 변경·Kafka 이벤트 발행을 하나의 트랜잭션으로 묶어서, 트랜잭션 커밋은 성공했는데 이벤트 발행이나 콜백 응답이 실패해 주문이 실제보다 늦게 처리되거나 유실되는 문제를 막습니다. 즉 멱등 키는 ‘같은 요청이 여러 번 들어오는’ 중복을, Outbox는 ‘트랜잭션 경계 밖에서 발생하는 상태 불일치·이벤트 유실’을 각각 막습니다. 두 가지를 함께 써야 결제 승인 콜백 지연 상황에서도 중복 주문 0건을 달성할 수 있었습니다.", "answer_rewrite": "중복 주문을 막기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다. 멱등 키는 결제 승인 콜백이 지연되거나 클라이언트가 재시도할 때 같은 요청이 여러 번 들어와 중복 주문이 생기는 문제를 막습니다. 주문 처리 전에 멱등 키 테이블에서 해당 키의 처리 여부를 확인하고, 처음이면 처리 후 키를 저장해 중복 요청을 걸러냈습니다. Outbox 패턴은 결제 승인 처리와 주문 상태 변경, Kafka 이벤트 발행을 하나의 트랜잭션으로 묶어서, 트랜잭션은 커밋됐지만 이벤트 발행이나 콜백 응답이 실패해 주문 상태가 불일치하거나 이벤트가 유실되는 문제를 막습니다. 멱등 키는 ‘동일 요청 중복’을, Outbox는 ‘트랜잭션 경계 밖 상태 불일치·이벤트 유실’을 각각 방어하기 때문에 두 패턴을 함께 써서 결제 승인 콜백 지연 상황에서도 중복 주문 0건을 달성했습니다.", "coaching_comment": "두 기법이 각각 어떤 실패 케이스를 막는지 구체적으로 구분해서 말하면, 멱등성과 트랜잭션 경계에 대한 이해를 훨씬 설득력 있게 전달할 수 있습니다."}, "latency_sec": 10.058, "in_tokens": 1150, "out_tokens": 385} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서는 각 행에 xmin(생성 트랜잭션 ID)과 xmax(삭제/갱신 트랜잭션 ID)가 기록됩니다. VACUUM은 현재 활성 트랜잭션의 가장 오래된 xmin, 즉 'xmin horizon'보다 오래된 dead tuple만 안전하게 제거할 수 있습니다. 오래 열린 트랜잭션이 있으면 그 트랜잭션의 xmin이 horizon을 낮추므로, 실제로 삭제·갱신된 튜플들이 horizon 아래에 머물게 되어 VACUUM이 회수하지 못합니다. 그 결과 dead tuple이 쌓여 테이블 bloat이 발생하고, 디스크 사용량과 순차 스캔 비용이 증가하며, autovacuum이 더 자주/오래 돌거나 임계치를 넘겨 성능 저하로 이어질 수 있습니다. 대응으로는 긴 트랜잭션의 수명 관리, idle 트랜잭션 모니터링, autovacuum 설정 점검, 필요하면 수동으로 vacuum을 고려하되 근본적으로는 열린 트랜잭션 자체를 줄이는 것이 핵심입니다.", "answer_rewrite": "이 질문은 제가 완전히 숙지하지 못한 부분이라 지금은 정확히 말씀드리기 어렵습니다. 다만 제가 이해한 범위에서는, PostgreSQL MVCC에서 각 행에 xmin/xmax가 남고 VACUUM은 활성 트랜잭션 중 가장 오래된 xmin(horizon)보다 오래된 dead tuple만 제거할 수 있다고 알고 있습니다. 오래 열린 트랜잭션이 있으면 horizon이 낮아져 dead tuple 회수가 지연되고, 그 결과 테이블 bloat이 생길 수 있다는 방향까지는 연결됩니다. 정확한 메커니즘과 대응 방식은 이후에 정리해서 다시 설명드리겠습니다.", "coaching_comment": "모르는 질문에서 바로 포기하기보다, 아는 범위(xmin/xmax, horizon 개념)까지 두괄식으로 말하고 모르는 부분은 솔직히 구분한 뒤 후속 학습 의사를 덧붙이면 훨씬 좋은 인상을 줍니다."}, "latency_sec": 5.32, "in_tokens": 781, "out_tokens": 317} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발할 수 있도록 제안했습니다. 다만 초반에는 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있었습니다. 이후 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨고, 그 결과 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 의견 충돌은 '누가 맞느냐'보다 '대안을 함께 비교하며 합의점을 찾는 과정'이 중요하다는 것을 배웠고, 지금은 결정 전에 항상 대안과 근거를 함께 제시하는 습관이 생겼습니다.", "answer_rewrite": "저는 팀원과 의견이 충돌했던 경험이 있습니다. 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있는데요. 저는 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발할 수 있도록 제안했습니다. 다만 초반에는 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있었습니다. 그래서 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨고, 그 결과 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 의견 충돌은 '누가 맞느냐'보다 '대안을 함께 비교하며 합의점을 찾는 과정'이 중요하다는 것을 배웠고, 지금은 결정 전에 항상 대안과 근거를 함께 제시하는 습관이 생겼습니다.", "coaching_comment": "추상적인 '소통이 중요하다'는 말 대신, 실제 프로젝트에서 의견이 달랐던 지점·본인이 취한 구체적 행동·그 결과(통합 이슈 3건→0건)·이후 바뀐 의사결정 방식까지 STAR로 말하면 훨씬 설득력 있는 답변이 됩니다."}, "latency_sec": 5.98, "in_tokens": 1012, "out_tokens": 343} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": true, "coaching": {"model_answer": "멱등 키와 Outbox 패턴을 함께 쓴 이유는 각각이 담당하는 실패 케이스와 트랜잭션 경계가 다르기 때문입니다. 멱등 키는 결제 승인 콜백이 네트워크 지연·재시도로 여러 번 도착했을 때, 같은 키면 중복 주문을 막는 역할을 합니다. 구체적으로는 콜백 요청마다 고유 키를 부여하고, 처리 전에 멱등 키 테이블에 이미 처리됐는지 확인해 중복 실행을 차단했습니다. 반면 Outbox 패턴은 주문 생성과 이벤트 발행을 하나의 로컬 트랜잭션으로 묶어, 주문은 저장됐는데 Kafka 발행이 실패하거나 서비스 재시작으로 이벤트가 유실되는 문제를 막습니다. 주문 트랜잭션과 같은 DB 트랜잭션 안에서 outbox 테이블에 이벤트를 기록하고, 별도 퍼블리셔가 이를 Kafka로 전송한 뒤 확인·삭제하는 구조로 처리했습니다. 두 가지를 함께 쓴 이유는 멱등 키만으로는 이벤트 발행 실패·유실까지 막을 수 없고, Outbox만으로는 콜백 중복 호출 자체를 막을 수 없기 때문입니다. 멱등 키로 ‘동일 콜백 중복 처리’를 막고, Outbox로 ‘주문 저장과 이벤트 발행의 원자성’을 보장해 중복 주문 0건을 달성했습니다.", "answer_rewrite": "중복 주문은 결제 승인 콜백이 지연되거나 네트워크 문제로 여러 번 도착하면서 발생했습니다. 이 문제를 멱등 키와 Outbox 패턴으로 함께 해결한 이유는 두 기법이 막는 실패 케이스와 담당하는 트랜잭션 경계가 다르기 때문입니다.\n\n멱등 키는 콜백 재시도로 인한 중복 요청을 막습니다. 콜백이 들어올 때마다 고유 멱등 키를 부여하고, 처리 전에 멱등 키 테이블에 이미 처리됐는지 확인해 같은 키면 중복으로 처리하지 않도록 했습니다. 이를 통해 네트워크 타임아웃 후 재전송된 콜백이 여러 번 들어와도 주문이 중복 생성되지 않게 막았습니다.\n\nOutbox 패턴은 주문 저장과 이벤트 발행의 원자성을 보장합니다. 주문 서비스에서는 주문 생성과 함께 outbox 테이블에 이벤트 기록을 같은 로컬 트랜잭션으로 처리하고, 별도 퍼블리셔가 outbox 레코드를 읽어 Kafka로 발행한 뒤 확인·삭제하는 구조로 만들었습니다. 이렇게 하면 주문은 저장됐는데 Kafka 발행이 실패하거나, 발행 전 서비스가 다운돼 이벤트가 유실되는 문제를 막을 수 있습니다.\n\n두 가지를 함께 쓴 이유는 멱등 키만으로는 이벤트 발행 실패·유실까지 막을 수 없고, Outbox만으로는 콜백 중복 호출 자체를 막을 수 없기 때문입니다. 멱등 키로 ‘동일 콜백 중복 처리’를 막고, Outbox로 ‘주문 저장과 이벤트 발행의 원자성’을 함께 보장해 중복 주문 0건을 달성했습니다.", "coaching_comment": "해결 사실만 말하지 말고, 멱등 키가 막는 실패(콜백 중복 호출)와 Outbox가 막는 실패(이벤트 발행 실패·유실)를 각각 구체적으로 구분해 설명하면 훨씬 강한 답변이 됩니다."}, "latency_sec": 12.795, "in_tokens": 1150, "out_tokens": 529} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL MVCC에서는 UPDATE/DELETE 시 기존 튜플을 바로 지우지 않고 dead tuple로 표시한 뒤, xmin(트랜잭션 ID) 기반으로 가시성을 판단합니다. VACUUM은 다른 트랜잭션이 아직 보지 못할 수 있는 dead tuple을 회수하는데, 오래 열린 트랜잭션이 있으면 그 트랜잭션의 xmin보다 앞선 커밋된 dead tuple도 '아직 필요할 수 있다'고 간주되어 회수가 지연됩니다. 이것이 xmin horizon이 뒤로 밀리는 현상이며, 결과적으로 dead tuple이 쌓여 테이블 bloat이 발생하고, 인덱스까지 커지며 쿼리 성능 저하와 디스크 사용량 증가로 이어집니다. 이를 완화하려면 장기 트랜잭션을 최소화하고, autovacuum 임계치/동시성 설정을 업무 특성에 맞게 조정하며, 필요하면 수동 VACUUM FULL이나 테이블 재구성을 고려합니다.", "answer_rewrite": "PostgreSQL MVCC에서는 UPDATE나 DELETE를 해도 기존 튜플을 즉시 제거하지 않고 dead tuple로 남겨둡니다. 실제 회수는 VACUUM이 담당하는데, 이때 각 트랜잭션의 xmin을 기준으로 '다른 트랜잭션이 아직 볼 수 있는 튜플인지'를 판단합니다. 오래 열린 트랜잭션이 하나라도 있으면 그 트랜잭션의 xmin보다 앞선 시점에 생성된 dead tuple도 아직 필요할 수 있다고 간주되어 VACUUM이 회수하지 못합니다. 그래서 xmin horizon이 뒤로 밀리고, dead tuple이 계속 쌓여 테이블 bloat이 생깁니다. bloat이 커지면 테이블과 인덱스 크기가 불필요하게 증가하고, 순차 스캔이나 인덱스 스캔 성능에도 영향을 줍니다. 실무에서는 장기 트랜잭션을 가능한 한 짧게 유지하고, autovacuum의 임계치나 동시성 설정을 트래픽 패턴에 맞게 조정하며, bloat이 심하면 수동 VACUUM이나 테이블 재구성으로 대응하는 식으로 관리합니다.", "coaching_comment": "모른다고 바로 넘기기보다, MVCC의 dead tuple과 xmin 기반 가시성, 그리고 오래 열린 트랜잭션이 vacuum의 회수 시점을 뒤로 밀어 bloat으로 이어진다는 핵심 연결고리만이라도 두괄식으로 말하면 기술 면접에서 충분히 부분 점수를 받을 수 있습니다."}, "latency_sec": 3.07, "in_tokens": 781, "out_tokens": 394} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발할 수 있도록 제안했습니다. 다만 초반에는 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있었습니다. 이후 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨고, 그 결과 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 의견 충돌은 ‘누가 맞느냐’보다 ‘어떤 기준으로 결정할지’를 먼저 합의하는 것이 중요하다는 것을 배웠고, 지금은 기술적 판단 근거를 문서화해 팀원과 함께 검토하는 습관을 갖고 있습니다.", "answer_rewrite": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 경험이 있습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발할 수 있도록 제안했습니다. 다만 초반에는 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있었습니다. 그래서 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨고, 그 결과 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 의견 충돌은 서로의 기준을 먼저 맞추고, 판단 근거를 문서화해 함께 검토하는 것이 중요하다는 것을 배웠습니다.", "coaching_comment": "충돌 경험이 거의 없다는 식의 답변은 설득력이 약하므로, 실제 협업 지연 사례와 본인의 구체적 행동·결과·변화(STAR)를 중심으로 다시 구성하세요."}, "latency_sec": 3.491, "in_tokens": 1012, "out_tokens": 298} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": true, "coaching": {"model_answer": "멱등 키와 Outbox 패턴을 함께 쓴 이유는 두 기법이 방어하는 실패 케이스가 다르기 때문입니다. 멱등 키는 결제 승인 콜백이 지연·재시도되어 같은 요청이 여러 번 들어올 때, 중복 주문을 막는 역할입니다. 예를 들어 결제사 콜백이 타임아웃으로 재전송되거나, 우리 서버가 처리 응답을 늦게 보내 결제사가 다시 콜백을 보내는 경우, 멱등 키(예: order_id + 결제사 트랜잭션 ID)로 이미 처리된 요청임을 확인해 두 번째 주문을 생성하지 않습니다. 반면 Outbox 패턴은 주문 생성과 ‘주문 확정 이벤트 발행’이라는 두 작업을 하나의 로컬 트랜잭션으로 묶어, 주문은 저장됐는데 Kafka 발행이 실패하거나 서버가 중간에 죽는 경우 이벤트 누락을 막습니다. 즉 멱등 키는 ‘외부에서 들어오는 중복 요청’에 대한 방어이고, Outbox는 ‘우리 시스템이 이벤트를 확실히 한 번만 발행’하도록 보장하는 장치입니다. 둘을 함께 쓰면 콜백 중복으로 인한 중복 주문 방지와, 주문 상태 변화에 따른 이벤트 신뢰성 확보를 동시에 해결할 수 있습니다. 실제 구현에서는 주문 테이블에 멱등 키를 유니크 제약으로 두고, Outbox 테이블에 이벤트 레코드를 함께 저장한 뒤 별도 퍼블리셔가 Kafka로 전송하며, 이미 전송된 아웃박스 레코드는 중복 발행하지 않도록 처리했습니다.", "answer_rewrite": "중복 주문을 막기 위해 멱등 키와 Outbox 패턴을 함께 도입한 이유는, 두 기법이 각각 다른 실패 케이스를 방어하기 때문입니다. 먼저 멱등 키는 결제 승인 콜백이 지연되거나 결제사가 재시도할 때 발생하는 중복 요청을 막습니다. 결제사 콜백이 우리 응답을 받지 못해 타임아웃 후 다시 콜백을 보내거나, 네트워크 문제로 같은 콜백이 여러 번 들어오는 상황에서, 주문 생성 요청마다 결제사 트랜잭션 ID나 order_id 기반 멱등 키를 부여하고 DB 유니크 제약으로 중복 처리를 차단했습니다. 다음으로 Outbox 패턴은 주문 저장과 이벤트 발행이 원자적으로 함께 수행되도록 보장합니다. 주문은 PostgreSQL에 저장됐는데 Kafka 이벤트 발행이 실패하거나, 발행 직전 서버가 장애로 내려가면 주문 상태와 이벤트 간 불일치가 생깁니다. 이를 막기 위해 주문 트랜잭션 안에서 Outbox 테이블에 이벤트 레코드를 함께 저장하고, 별도 프로세스/스레드에서 Outbox를 읽어 Kafka로 발행하며 이미 발행된 레코드는 다시 보내지 않도록 처리했습니다. 정리하면 멱등 키는 ‘외부 콜백 중복’이라는 입력 측 중복을, Outbox는 ‘이벤트 발행 신뢰성’이라는 출력 측 보장을 담당하며, 둘을 함께 써서 중복 주문 0건을 달성할 수 있었습니다.", "coaching_comment": "멱등 키와 Outbox가 각각 어떤 실패 케이스를 막는지 구체적으로 구분해서 말하면, 트랜잭션 경계와 멱등성에 대한 이해를 훨씬 설득력 있게 전달할 수 있습니다."}, "latency_sec": 4.875, "in_tokens": 1150, "out_tokens": 523} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": true, "coaching": {"model_answer": "PostgreSQL MVCC에서 UPDATE나 DELETE가 일어나면 기존 행은 바로 지워지지 않고 dead tuple로 남습니다. Vacuum은 이 dead tuple을 회수하는데, 이때 각 튜플의 xmin(생성 트랜잭션 ID)과 xmax(삭제 트랜잭션 ID)를 기준으로 '아직 커밋되지 않았거나, 현재 트랜잭션이 볼 수 있는' 튜플은 건드리지 않습니다. 오래 열린 트랜잭션이 있으면 그 트랜잭션의 시작 시점보다 나중에 생성된 dead tuple, 혹은 그 트랜잭션이 아직 읽을 수 있다고 판단되는 튜플이 vacuum에서 회수되지 못하고 남습니다. 이것이 xmin horizon이 뒤로 밀리는 현상이고, 결과적으로 dead tuple이 쌓여 테이블 blooming(bloat)이 생깁니다. 특히 autovacuum은 트랜잭션 ID wraparound 방지 차원에서 oldest active transaction을 기준으로 작동하므로, 오래 열린 트랜잭션 하나가 vacuum을 지연시키고 테이블 크기와 디스크 사용량, 순차 스캔 비용까지 악화시킬 수 있습니다. 따라서 장기 트랜잭션은 최소화하고, 불가피한 경우 vacuum 설정이나 모니터링으로 bloat을 관리해야 합니다.", "answer_rewrite": "이 질문은 제가 아직 충분히 정리하지 못한 부분이라 지금 바로 정확히 답하기는 어렵습니다. 다만 제가 이해한 범위에서는, PostgreSQL MVCC에서 UPDATE/DELETE 시 기존 행이 dead tuple로 남고, vacuum이 이를 정리할 때 트랜잭션의 xmin/xmax와 활성 트랜잭션의 시점을 기준으로 회수 가능 여부를 판단한다고 알고 있습니다. 오래 열린 트랜잭션이 있으면 그 트랜잭션이 아직 볼 수 있는 튜플이 회수되지 못해 xmin horizon이 뒤로 밀리고, 그 결과 dead tuple이 쌓여 테이블 bloat으로 이어질 수 있다는 점이 핵심이라고 생각합니다. 이 부분은 제가 더 정확히 정리해서 다음 기회에 보완하겠습니다.", "coaching_comment": null}, "latency_sec": 3.329, "in_tokens": 781, "out_tokens": 364} +{"label": "gw-solar-pro4", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발할 수 있도록 제안했습니다. 다만 초반에는 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있었습니다. 이후 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨고, 그 결과 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 의견 충돌은 '누가 맞느냐'보다 '어떻게 함께 검증할 것인가'로 풀어야 한다는 것을 배웠고, 지금은 결정 전에 항상 대안과 근거를 함께 제시하는 습관을 갖고 있습니다.", "answer_rewrite": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 경험이 있습니다. 당시 저는 먼저 OpenAPI 명세를 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발할 수 있도록 제안했습니다. 다만 초반에는 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있었습니다. 그래서 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨고, 그 결과 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 의견 충돌은 '누가 맞느냐'보다 '어떻게 함께 검증할 것인가'로 풀어야 한다는 것을 배웠고, 지금은 결정 전에 항상 대안과 근거를 함께 제시하는 습관을 갖고 있습니다.", "coaching_comment": "의견 충돌이 거의 없었다는 답변보다, 실제 있었던 협업 갈등 사례(API 스펙 해석 차이로 인한 2주 지연)를 STAR 구조로 구체적으로 말하는 것이 훨씬 설득력 있습니다."}, "latency_sec": 5.356, "in_tokens": 1012, "out_tokens": 311} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연으로 중복 주문이 발생했던 상황에서, 멱등 키와 Transactional Outbox를 함께 도입한 이유와 두 메커니즘이 각각 어떤 실패 시나리오를 막는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키가 동일 요청의 재처리/중복 실행을 막는 원리와 Outbox가 트랜잭션 내 이벤트 발행과 DB 커밋을 원자적으로 묶어 이벤트 누락·중복 발행을 방지하는 구조를 구분해 설명하는지 확인."}, {"category": "TECH_CHOICE", "question": "모놀리식에서 주문 서비스를 분리할 때 DB까지 PostgreSQL로 별도 분리했는데, 서비스 분리와 DB 분리를 함께 진행한 판단 근거와 그 과정에서 가장 크게 달라진 운영·데이터 정합성 측면의 trade-off는 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "서비스 분리만으로 충분하지 않아 DB 분리를 함께 선택한 이유(예: 결합도·독립 배포·데이터 소유권)와, 분산 환경에서 트랜잭션 범위 축소·최종 정합성 수용 등 trade-off를 구체적으로 말하는지 확인."}, {"category": "CS_FUNDAMENTAL", "question": "실시간 재고 동기화에서 낙관적 락에서 분산 락으로 전환했다고 했는데, 두 동시성 제어 방식이 각각 어떤 충돌 상황을 가정하고 있으며, 전환 전후로 재고 불일치가 줄어든 이유를 락의 동작 방식 관점에서 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환), 재고 불일치 건수 월 200건 → 3건", "expected_signal": "낙관적 락(버전/조건 기반 업데이트, 충돌 시 재시도)과 분산 락(공유 자원 선점, 동시 접근 직렬화)의 차이와, 고동시성 재고 차감에서 각 방식이 불일치를 유발하는 지점을 정확히 짚어내는지 확인."}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능을 5시간에서 40분으로 줄일 때 QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계를 함께 적용했는데, 세 가지 개선 중 실제 병목 원인을 어떻게 진단했고 각 기법이 어떤 단계의 병목을 해결했는지 순서대로 말해 주세요.", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "실행 계획·로그·메트릭 등으로 실제 병목(I/O, 메모리, N+1, 풀 스캔 등)을 특정하고, 인덱스 재설계·QueryDSL 최적화·청크 처리가 각각 어떤 비용 구간을 줄였는지 인과적으로 설명하는지 확인."}, {"category": "TECH_CHOICE", "question": "주문·결제 이벤트 파이프라인에 Kafka를 도입했는데, 결제 승인처럼 데이터 정합성이 중요한 도메인에서 Kafka를 선택한 이유와, 이벤트 순서 보장·재처리·실패 핸들링을 어떻게 설계했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입 / 결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "Kafka의 처리량·내구성·재생성 같은 특성이 주문·결제 이벤트에 왜 적합했는지, 파티션 키·컨슈머 그룹·오프셋 커밋·DLQ/재시도 등으로 순서성과 재처리를 어떻게 통제했는지 구체적으로 설명하는지 확인."}], "latency_sec": 10.1, "in_tokens": 2281, "out_tokens": 812} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "일정 타임라인에서 react-window 가상화를 도입하기 전, 스크롤 끊김의 원인을 어떻게 진단했고 가상화 적용 후 INP가 480ms에서 120ms로 개선된 것을 어떻게 측정했나요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "성능 저하 원인을 프로파일링으로 특정하고, 가상화 전후 지표를 동일 조건에서 측정해 개선 효과를 정량적으로 설명한 답변이 드러나야 함."}, {"category": "TECH_CHOICE", "question": "오프라인 편집에서 IndexedDB(Dexie)에 낙관적 업데이트를 저장하고 온라인 복귀 시 동기화할 때 last-write-wins로 충돌을 해결했는데, 이 방식을 선택한 이유와 CRDT 검토가 필요하다고 남긴 배경은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "낙관적 업데이트와 충돌 해결 전략의 트레이드오프를 이해하고, last-write-wins의 한계와 CRDT가 필요한 상황을 구체적으로 설명할 수 있어야 함."}, {"category": "CS_FUNDAMENTAL", "question": "이미지 업로드에서 presigned URL로 S3에 직접 업로드하고 클라이언트에서 WebP 변환을 수행했는데, 이 구조에서 CORS·인증·파일 크기 제한을 어떻게 처리했고 서버 부하 측면에서 어떤 이점이 있었나요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "presigned URL의 동작 원리와 클라이언트 직접 업로드가 서버 부하·보안·대역폭에 미치는 영향을 정확히 설명할 수 있어야 함."}, {"category": "PROJECT_DEEP_DIVE", "question": "Lighthouse 성능 점수를 68에서 91로 올린 PR #57에서 어떤 항목을 우선 개선했고, 각 개선이 Core Web Vitals 중 어떤 지표에 영향을 줬다고 판단했나요?", "job_category": "FRONTEND", "target_evidence": "Lighthouse 성능 점수 68 → 91 (PR #57 설명)", "expected_signal": "성능 개선 항목을 구체적으로 짚고, 각 변경이 LCP·INP·CLS 등 실제 사용자 지표와 어떻게 연결되는지 논리적으로 설명한 답변이 드러나야 함."}, {"category": "TECH_CHOICE", "question": "상태 관리에 Zustand, 서버 상태에 TanStack Query v5를 함께 쓴 이유와 두 라이브러리의 책임 경계를 어떻게 나눴는지, 실제 코드에서 경계가 모호했던 사례가 있었다면 어떻게 정리했나요?", "job_category": "FRONTEND", "target_evidence": "상태 관리는 Zustand, 서버 상태는 TanStack Query v5", "expected_signal": "클라이언트 로컬 상태와 서버 상태의 차이를 이해하고, 두 도구를 선택한 근거와 실제 사용 중 경계 충돌 사례를 해결한 경험을 구체적으로 설명할 수 있어야 함."}], "latency_sec": 25.827, "in_tokens": 2144, "out_tokens": 705} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 슬로우 쿼리 p95를 2.3초에서 180ms로 줄인 과정에서, 복합 인덱스 재설계 시 어떤 컬럼 순서와 포함 컬럼을 선택했고, 그 판단이 실제 쿼리 패턴에 어떻게 부합했는지 설명해 주세요.", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "실제 쿼리 패턴을 근거로 인덱스 컬럼 순서와 포함 컬럼을 선택한 이유와 그 효과를 구체적으로 설명한다."}, {"category": "TECH_CHOICE", "question": "EKS에서 HPA 기준을 CPU 70%로 잡고 월급날 10시 트래픽 피크 대비 사전 스케일아웃 CronJob을 운영했는데, 왜 반응형 HPA만으로는 부족하다고 판단했는지, 그리고 CronJob 기반 사전 스케일아웃의 한계나 리스크는 무엇이라고 보는지 말해 주세요.", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "트래픽 패턴의 예측 가능성과 HPA의 반응 지연을 근거로 사전 스케일아웃 선택 이유를 설명하고, 과잉 프로비저닝·패턴 편차 등 리스크도 함께 짚는다."}, {"category": "PROJECT_DEEP_DIVE", "question": "2024년 3월 RDS 스토리지 풀 쓰기 중단 40분 장애 당시, CloudWatch 알람과 스토리지 오토스케일링을 적용했다고 했는데, 장애 발생 직후 원인 파악과 복구 과정에서 본인이 직접 수행한 조치와 의사결정, 그리고 이후 재발 방지를 위해 바꾼 운영 절차를 구체적으로 설명해 주세요.", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "STAR 구조로 당시 본인의 구체적 행동, 판단 근거, 복구 결과, 그리고 재발 방지 측면의 운영 변경점을 명확히 제시한다."}, {"category": "TECH_CHOICE", "question": "Terraform으로 VPC·RDS·EKS를 모듈화하고 환경별 dev/stg/prod workspace를 분리했다고 했는데, workspace 방식과 별도 상태 파일(state file) 방식 중 왜 workspace를 선택했는지, 그리고 그 선택으로 인해 협업·롤백·상태 충돌 측면에서 어떤 trade-off를 감수했는지 말해 주세요.", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "workspace 선택의 이유와 함께 상태 관리·협업·롤백 관점에서의 trade-off를 구체적으로 인식하고 설명한다."}, {"category": "CS_FUNDAMENTAL", "question": "ArgoCD GitOps 도입으로 배포 리드타임을 1일에서 30분으로 줄였다고 했는데, GitOps 방식에서 애플리케이션 배포 시 실제 동기화(sync) 흐름과 롤백이 어떻게 동작하는지, 그리고 이전 배포 방식과 비교해 어떤 실패 모드가 줄어들었다고 보는지 설명해 주세요.", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "GitOps 동기화·롤백의 실제 동작과 이전 방식 대비 줄어든 실패 모드를 배포 경험 맥락에서 설명한다."}, {"category": "BEHAVIORAL", "question": "인프라와 DBA 역할을 함께 수행하면서 EKS 운영과 PostgreSQL 튜닝을 병행했는데, 두 영역의 우선순위가 충돌한 상황이 있었다면 당시 상황, 본인의 판단 기준, 실제 행동과 결과를 STAR 구조로 설명해 주세요.", "job_category": "INFRA", "target_evidence": "", "expected_signal": "상황·과제·행동·결과가 드러나며, 우선순위 판단의 기준과 실제 행동, 그로 인한 결과가 구체적으로 제시된다."}], "latency_sec": 15.116, "in_tokens": 2121, "out_tokens": 862} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "학사 공지 알림 봇을 운영하며 새벽 크롤러 중단으로 공지가 누락됐을 때, 사용자 항의를 직접 받은 경험이 있다고 했습니다. 당시 상황을 구체적으로 설명해 주시고, 그 경험을 통해 '멈추지 않는 서비스'에 대해 어떤 기준을 갖게 됐는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "STAR 구조로 당시 상황·본인의 구체적 대응(모니터링·복구·소통 등)·정량/정성적 결과를 설명하고, 이후 운영 관점에서 신뢰성 확보를 위해 어떤 습관이나 설계를 적용하게 됐는지 성찰이 드러나야 함."}, {"category": "PROJECT_DEEP_DIVE", "question": "알림 봇 DB를 SQLite로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송됐고, 원인 파악에 3일이 걸렸다고 했습니다. 당시 어떤 증상으로 문제를 인지했고, 락 경합 원인을 추적하는 과정에서 어떤 로그나 관측 지점을 확인했는지, PostgreSQL로 이전하며 트랜잭션 격리 수준을 어떻게 적용했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "중복 발송 증상을 구체적으로 기술하고, SQLite 동시 쓰기 한계(WAL/락)와 원인 추적 과정, PostgreSQL 전환 시 선택한 격리 수준과 그 근거를 자신의 이해로 설명해야 함."}, {"category": "TECH_CHOICE", "question": "캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2주가 지연됐고, 이를 해결하기 위해 OpenAPI 명세 작성 후 Mock 서버를 띄워 프론트 병렬 개발을 제안했다고 했습니다. 왜 다른 방식(예: 구두 합의, 문서만 공유)이 아니라 OpenAPI+Mock 서버를 선택했는지, 그 선택으로 얻은 이점과 한계는 무엇이었는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "OpenAPI와 Mock 서버를 선택한 이유를 계약 기반 개발·병렬화·피드백 루프 관점에서 설명하고, 실제 효과(통합 이슈 감소)와 함께 유지보수 부담·명세 드리프트 같은 한계도 함께 인지했는지 확인."}, {"category": "BEHAVIORAL", "question": "초반에 자신의 방식이 옳다고 고집해 팀원과 감정이 상한 적이 있고, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨다고 했습니다. 그 변화 이후 실제로 대안을 비교하며 의사결정한 사례를 하나 들어, 당시 두 대안의 비교 기준과 최종 선택 이유, 그리고 그 과정에서 팀원과의 관계가 어떻게 달라졌는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "STAR 구조로 구체적 상황·비교한 두 대안과 비교 기준·본인의 행동과 결과·팀원 반응 및 관계 변화를 설명하고, 고집에서 협업적 의사결정으로 바뀐 계기가 진정성 있게 드러나야 함."}, {"category": "CS_FUNDAMENTAL", "question": "SQLite에서 PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하게 됐다고 했습니다. 백엔드 개발에서 트랜잭션 격리 수준이 왜 중요한지, 특히 알림 발송처럼 중복을 피해야 하는 작업에서 격리 수준이 어떤 영향을 주는지, 자신이 이해한 수준으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "", "expected_signal": "격리 수준이 해결하는 문제(더티 읽기·비반복 읽기·팬텀 읽기 등)를 개념적으로 설명하고, 알림 중복 방지 맥락에서 적절한 격리 수준 선택과 그 trade-off를 자신의 언어로 서술해야 함."}], "latency_sec": 7.887, "in_tokens": 2078, "out_tokens": 890} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "주문 서비스를 모놀리식에서 MSA로 분리할 때 DB를 PostgreSQL로 분리한 뒤 Kafka 이벤트 파이프라인을 설계했다고 했는데, 주문 생성 시 다른 서비스로 전파해야 하는 이벤트는 무엇이고, 이벤트 순서 보장이나 중복 처리를 위해 어떤 설계를 적용했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입. 결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "주문 상태 변경 이벤트를 식별하고, Outbox 테이블과 Kafka 발행의 원자성, 컨슈머 측 멱등 처리·재시도·순서 보장 전략을 구체적으로 설명해야 함."}, {"category": "TECH_CHOICE", "question": "실시간 재고 동기화에서 동시성 제어를 낙관적 락에서 분산 락으로 전환했다고 했는데, Redis 분산 락을 선택한 이유와 락 획득·해제 시 데드락이나 장애 상황을 어떻게 처리했는지, 그리고 전환 전후로 재고 불일치가 줄어든 근거를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환), 재고 불일치 건수 월 200건 → 3건", "expected_signal": "낙관적 락의 한계(충돌·롤백 비용)를 설명하고, Redis 분산 락의 TTL·락 소유자 식별·장애 시 해제 전략, write-behind와 정합성 유지 방식을 구체적으로 제시해야 함."}, {"category": "CS_FUNDAMENTAL", "question": "결제 승인 콜백 지연으로 중복 주문이 발생했을 때 멱등 키와 Transactional Outbox로 해결했다고 했는데, 멱등 키가 중복을 막는 원리와 Outbox 패턴이 DB 트랜잭션과 메시지 발행의 원자성을 어떻게 보장하는지, 그리고 실제 운영에서 멱등 키 충돌·만료 처리는 어떻게 했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키의 중복 감지 원리, Outbox 테이블의 트랜잭션 내 기록 후 별도 발행 구조, 컨슈머 재처리 시 멱등성 유지, 키 만료·정리 전략을 구체적으로 설명해야 함."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2주가 지연됐을 때 OpenAPI 명세와 Mock 서버를 먼저 작성해 병렬 개발을 제안했다고 했는데, 그 과정에서 본인이 구체적으로 어떤 역할을 했고, 초반에 고집이 세다는 피드백을 받은 뒤 의사결정 방식을 어떻게 바꿨는지, 이후 통합 이슈가 3건에서 0건으로 줄어든 결과를 어떻게 확인했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "STAR 구조로 본인의 구체적 행동(명세서 작성·Mock 서버·협업 방식 변경)과 정량적 결과, 실패/갈등 상황에서의 성찰과 개선 행동을 명확히 드러내야 함."}, {"category": "CS_FUNDAMENTAL", "question": "알림 봇 DB를 SQLite에서 PostgreSQL로 이전하면서 트랜잭션 격리 수준을 공부하게 됐다고 했는데, 결제·주문 도메인에서 중복 주문이나 재고 정합성 문제를 다룰 때 어떤 격리 수준이 적절한지, 그리고 실제 서비스에서 격리 수준만 높이는 것만으로 해결되지 않는 동시성 문제(예: 팬텀 리드, 분산 환경)를 어떻게 보완했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "SQLite 동시 쓰기 락 문제와 격리 수준 개념을 연결하고, PostgreSQL에서 선택한 격리 수준과 그 한계, 분산 락·멱등 키·Outbox 등 애플리케이션 수준 보완을 함께 설명해야 함."}], "latency_sec": 17.335, "in_tokens": 3174, "out_tokens": 940} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연으로 중복 주문이 발생했을 때 멱등 키와 Transactional Outbox로 해결했다고 했는데, 멱등 키 테이블을 어떤 키로 구성하고 Outbox 테이블과 실제 주문 테이블의 정합성을 어떻게 보장했는지 구체적으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키 설계(어떤 키, TTL/정리 전략), Outbox 발행과 실제 처리의 정합성 보장 방식(트랜잭션 범위, 재시도/중복 처리), 중복 주문 0건을 검증한 방법을 STAR로 설명."}, {"category": "TECH_CHOICE", "question": "모놀리식에서 주문 서비스를 분리할 때 DB를 PostgreSQL로 분리하고 Kafka 이벤트 파이프라인을 도입했는데, 주문 서비스 분리에 Kafka를 선택한 이유와 이벤트 설계 시 고려한 점(메시지 순서, 중복, 실패 처리)을 말해 주세요.", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일", "expected_signal": "Kafka 선택 근거(큐 대비 이벤트 파이프라인 적합성), 주문 이벤트 설계에서 순서 보장·파티셔닝·멱등 소비·실패/재처리 전략을 구체적으로 설명."}, {"category": "CS_FUNDAMENTAL", "question": "실시간 재고 동기화에서 낙관적 락에서 분산 락으로 전환했다고 했는데, 두 방식의 차이와 분산 락 도입 시 Redis로 어떤 락 메커니즘을 썼는지, 그리고 락 경합이나 데드락 같은 문제를 어떻게 다뤘는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환), 재고 불일치 건수 월 200건 → 3건", "expected_signal": "낙관적 락과 분산 락의 트레이드오프, Redis 기반 분산 락 구현 방식(키·TTL·원자성), 경합/데드락/실패 시 처리, 재고 불일치 감소의 인과 설명."}, {"category": "PROJECT_DEEP_DIVE", "question": "정산 배치 성능을 5시간에서 40분으로 줄였다고 했는데, QueryDSL 튜닝과 청크 단위 처리, 인덱스 재설계 중 실제로 병목이 어디였는지와 각 개선이 성능에 미친 영향을 구체적으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "병목 지점 식별 근거, QueryDSL/인덱스/청크 처리 각각의 효과와 trade-off, 개선 후 정합성·장애 여부 검증 방법을 구체적으로 설명."}, {"category": "BEHAVIORAL", "question": "대용량 트래픽에서도 데이터 정합성을 지키는 서버에 관심이 많다고 했는데, 실제 주문·결제 도메인에서 정합성 위험을 감지하거나 예방한 경험 중 가장 기억에 남는 사례를 상황·본인의 행동·결과 중심으로 말해 주세요.", "job_category": "BACKEND", "target_evidence": "대용량 트래픽에서도 데이터 정합성을 지키는 서버를 만드는 데 관심이 많습니다.", "expected_signal": "정합성 위험 상황, 본인이 취한 구체적 조치(설계/모니터링/대응), 정량적 결과와 배운 점을 STAR로 설명."}], "latency_sec": 17.639, "in_tokens": 2281, "out_tokens": 766} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "타임라인 가상화 도입 전 스크롤 끊김의 원인을 어떻게 진단했고, react-window 적용 후 INP가 480ms에서 120ms로 줄어든 것을 어떤 지표로 확인했나요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "렌더링 병목 진단 과정(프로파일링/측정)과 가상화 적용 후 실제 측정 지표(INP 등)를 구체적으로 설명한다."}, {"category": "TECH_CHOICE", "question": "오프라인 편집에서 IndexedDB(Dexie)에 낙관적 업데이트를 저장한 뒤 온라인 복귀 시 동기화하는 흐름과, last-write-wins 충돌 해결의 한계를 어떻게 판단했는지 설명해 주세요.", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "낙관적 업데이트→동기화 흐름과 last-write-wins의 한계, CRDT 등 대안 검토 여부를 자신의 판단으로 설명한다."}, {"category": "CS_FUNDAMENTAL", "question": "지도 마커 500개를 useMemo로 좌표 변환 캐싱한 결정에서, 어떤 값이 메모이제이션 대상이 되었고 참조 동일성·의존성 설계에서 주의한 점은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "메모이제이션 대상 값, 의존성 배열 설계, 참조 동일성이 리렌더/마커 렌더링에 미치는 영향을 구체적으로 설명한다."}, {"category": "PROJECT_DEEP_DIVE", "question": "이미지 업로드에서 presigned URL로 S3 직접 업로드를 선택한 이유와, 클라이언트에서 WebP 변환 시 브라우저 호환성·실패 케이스를 어떻게 처리했는지 말해 주세요.", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "직접 업로드 선택의 이유(서버 부하/보안 등)와 WebP 변환의 호환성 처리, 실패 시 폴백/재시도 방안을 설명한다."}, {"category": "TECH_CHOICE", "question": "Lighthouse 성능 점수를 68에서 91로 올린 PR #57에서 어떤 항목을 우선 개선했고, 그 개선이 실제 사용자 경험(INP/FCP 등)과 어떻게 연결된다고 봤나요?", "job_category": "FRONTEND", "target_evidence": "Lighthouse 성능 점수 68 → 91 (PR #57 설명)", "expected_signal": "개선 항목과 측정 지표 간 연결, 점수 상승이 실제 사용자 경험에 미친 영향을 구체적으로 설명한다."}], "latency_sec": 11.671, "in_tokens": 2144, "out_tokens": 673} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 슬로우 쿼리 p95를 2.3초에서 180ms로 줄인 과정에서, 어떤 쿼리를 먼저 프로파일링했고 복합 인덱스 재설계 시 어떤 컬럼 순서와 포함 컬럼을 선택했는지 설명해 주세요.", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "실제 슬로우 쿼리 식별 방법(EXPLAIN/로그/메트릭)과 인덱스 설계 판단 근거, 개선 효과를 구체적으로 설명한다."}, {"category": "TECH_CHOICE", "question": "EKS에서 HPA 기준을 CPU 70%로 잡고 월급날 10시 피크 대비 사전 스케일아웃 CronJob을 병행한 이유는 무엇이며, 두 방식의 장단점과 한계를 어떻게 평가했나요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "반응형 HPA와 예측형 CronJob을 함께 쓴 이유, 각 방식의 트레이드오프와 실제 운영상 한계를 자신의 관점으로 설명한다."}, {"category": "PROJECT_DEEP_DIVE", "question": "2024년 3월 RDS 스토리지 풀 쓰기 중단 40분 장애 당시 감지·대응 흐름과, 이후 CloudWatch 알람과 스토리지 오토스케일링을 어떻게 설계해 재발 방지했는지 말해 주세요.", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 탐지부터 복구, 사후 개선까지의 자신의 역할과 구체적 조치, 재발 방지 설계 근거를 STAR 구조로 설명한다."}, {"category": "TECH_CHOICE", "question": "Terraform으로 VPC·RDS·EKS를 모듈화하고 환경별 workspace를 분리했는데, 상태 파일 관리와 환경 간 차이(예: prod-only 리소스)는 어떻게 처리했나요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "모듈화 구조와 workspace 활용 방식, 상태 격리·공유 전략, 환경별 예외 처리 방법을 구체적으로 설명한다."}, {"category": "CS_FUNDAMENTAL", "question": "PostgreSQL에서 autovacuum 튜닝과 월 단위 파티셔닝을 함께 적용했을 때, 각각 어떤 문제(디스크 팽창, 동시성, 쿼리 성능 등)를 해결하려 했는지 원리 중심으로 설명해 주세요.", "job_category": "DBA", "target_evidence": "autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할", "expected_signal": "autovacuum의 역할과 튜닝 지점, 파티셔닝이 쿼리·유지보수에 주는 효과를 원리 수준에서 정확히 설명한다."}, {"category": "BEHAVIORAL", "question": "ArgoCD GitOps 도입으로 배포 리드타임을 1일에서 30분으로 줄였다고 했는데, 그 과정에서 팀 내 저항이나 운영 습관 변화는 어떻게 다뤘고, 본인에게 가장 크게 남은 교훈은 무엇인가요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "도입 배경·본인의 역할·팀 설득/적응 과정·결과를 STAR로 설명하고, 경험을 통해 얻은 운영 관점의 배움을 제시한다."}], "latency_sec": 8.303, "in_tokens": 2121, "out_tokens": 809} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "알림 봇을 SQLite에서 PostgreSQL로 이전할 때 트랜잭션 격리 수준을 공부했다고 했는데, 구체적으로 어떤 격리 수준을 선택했고 그 이유는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "SQLite의 동시 쓰기 락 문제와 PostgreSQL의 트랜잭션 격리 수준(예: Read Committed, Repeatable Read)을 연결해 설명하고, 중복 발송을 막기 위해 선택한 격리 수준과 그 근거를 구체적으로 제시해야 함."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 API 스펙 해석 차이로 통합이 2주 지연됐을 때, OpenAPI 명세와 Mock 서버를 먼저 작성하자고 제안한 구체적인 상황과 그 과정에서 팀원과 감정이 상한 경험을 STAR로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "상황(스펙 해석 차이, 2주 지연)·과제(병렬 개발 유도)·행동(OpenAPI·Mock 서버 제안, 고집으로 인한 갈등)·결과(통합 이슈 3건→0건, 이후 대안 비교 방식 도입)를 구체적으로 서술하고, 갈등 상황에서의 자기 인식과 개선 행동을 드러내야 함."}, {"category": "TECH_CHOICE", "question": "알림 봇을 SQLite로 시작한 이유와 PostgreSQL로 이전한 판단 기준을 설명해 주세요. 당시 서비스 규모와 운영 상황을 고려할 때 그 선택이 적절했다고 보나요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. ... 알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "초기에는 빠른 프로토타이핑·간편성 때문에 SQLite를 선택했을 개연성을 인정하고, 사용자 800명·일일 운영·동시 쓰기 락 문제를 겪은 뒤 PostgreSQL로 이전한 판단 기준(트랜잭션, 동시성, 운영 안정성)을 논리적으로 설명해야 함."}, {"category": "BEHAVIORAL", "question": "새벽에 크롤러가 멈춰 공지 누락이 발생했을 때 동아리원들의 항의를 직접 받았다고 했는데, 그 상황에서 본인이 취한 조치와 이후 '멈추지 않는 서비스'를 위해 어떤 운영적 개선을 했는지 말해 주세요.", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "크롤러 중단 직후의 대응(사용자 안내, 수동 복구 등)과 재발 방지를 위한 모니터링·알림·자동 재시작 등 운영 개선 행동을 STAR로 설명하고, '멈추지 않는 서비스'라는 통찰을 실제 운영 관행으로 어떻게 연결했는지 드러내야 함."}, {"category": "CS_FUNDAMENTAL", "question": "알림 봇에서 동시 쓰기 락으로 중복 발송이 발생했다고 했는데, 데이터베이스 락과 트랜잭션 격리 수준이 어떻게 다른 개념인지, 그리고 그 문제를 해결하는 데 각각 어떤 역할을 하는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "락(동시에 같은 데이터에 접근하는 것을 막는 메커니즘)과 트랜잭션 격리 수준(트랜잭션 간 가시성·일관성 보장 수준)의 차이를 구분하고, SQLite의 동시 쓰기 락 문제와 PostgreSQL의 격리 수준이 중복 발송 방지에 어떻게 기여하는지 자신의 경험과 연결해 설명해야 함."}], "latency_sec": 17.371, "in_tokens": 2078, "out_tokens": 934} +{"label": "gw-solar-pro4", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화에서 낙관적 락에서 분산 락으로 전환한 구체적인 계기와, 분산 락 도입 후 동시성 제어의 동작 방식과 트레이드오프를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환), 재고 불일치 건수 월 200건 → 3건", "expected_signal": "낙관적 락 충돌/재시도 비용 등 전환 사유를 구체적으로 짚고, 분산 락의 획득·해제 흐름과 Redis 기반 구현 시 장애·타임아웃 처리, 성능/정합성 트레이드오프를 설명할 수 있어야 함."}, {"category": "TECH_CHOICE", "question": "MSA 전환 시 주문 서비스 분리와 Kafka 이벤트 파이프라인을 도입하면서, 서비스 간 데이터 정합성을 어떻게 설계했는지와 Outbox 패턴을 선택한 이유를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입. 결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "DB 분리 후 즉시 일관성 포기, 이벤트 기반 최종 정합성 설계 의도를 설명하고, Outbox가 로컬 트랜잭션과 이벤트 발행의 원자성을 보장하는 원리와 Kafka 발행 실패/재시도 처리 방안을 언급해야 함."}, {"category": "CS_FUNDAMENTAL", "question": "결제 승인 콜백 지연 상황에서 멱등 키를 적용할 때, 동시 요청이 들어왔을 때 중복 실행을 막기 위해 DB 레벨에서 어떤 제약이나 조회·삽입 순서를 사용했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키의 고유성 보장 방식(예: 유니크 제약, INSERT 시 충돌 처리)과 동시 요청 시 레이스컨디션을 막는 처리 순서, 실패/재시도 시 멱등성 유지 방법을 구체적으로 설명해야 함."}, {"category": "CS_FUNDAMENTAL", "question": "알림 봇 DB를 SQLite에서 PostgreSQL로 이전하면서 트랜잭션 격리 수준을 공부했다고 했는데, 결제/주문 도메인에서 중복 주문이나 재고 불일치와 관련해 어떤 격리 수준이 왜 중요한지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "SQLite 동시 쓰기 한계와 PostgreSQL 전환 배경을 연결하고, Read Committed/Repeatable Read/Serializable 등 격리 수준이 팬텀·손실 갱신 등에 미치는 영향을 주문·결제 정합성 맥락으로 설명할 수 있어야 함."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 API 스펙 해석 차이로 통합이 2주 지연됐을 때, OpenAPI 명세 작성 후 Mock 서버를 띄워 병렬 개발을 제안한 구체적인 과정과 그 결과, 그리고 초반에 고집이 세다는 피드백을 이후 어떻게 개선했는지 말해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다. 다만 초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "STAR 구조로 상황·과제·행동·결과를 설명하고, Mock 서버 도입으로 병렬 개발이 가능해진 지점과 정량적 결과(통합 이슈 3건→0건)를 제시하며, 고집 문제를 인지한 뒤 대안 비교 방식으로 협업 태도를 바꾼 성찰을 포함해야 함."}], "latency_sec": 21.145, "in_tokens": 3174, "out_tokens": 866} diff --git a/docs/research/llm-eval-2026-09/raw/local-ax4-light.jsonl b/docs/research/llm-eval-2026-09/raw/local-ax4-light.jsonl new file mode 100644 index 0000000..25b1be7 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/local-ax4-light.jsonl @@ -0,0 +1,80 @@ +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "멱등 키를 사용한 이유와 그로 인해 방지한 실패 케이스가 정확히 어떤 것인지 구체적으로 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.71, "ttft_sec": 0.762, "in_tokens": 1235, "out_tokens": 71} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용한 이유를 구체적으로 설명해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.628, "ttft_sec": null, "in_tokens": 1140, "out_tokens": 68} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "PostgreSQL의 MVCC에서 xmin horizon이 무엇인지, 그리고 오래 열린 트랜잭션이 vacuum에 미치는 영향에 대해 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.849, "ttft_sec": null, "in_tokens": 1115, "out_tokens": 78} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18의 자동 배치 기능이 이전 버전과 어떻게 다른지, 특히 비동기 콜백 내부에서의 업데이트 처리에 대해 설명해 보세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.858, "ttft_sec": null, "in_tokens": 1115, "out_tokens": 76} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA 기준 CPU 70%를 설정한 구체적인 이유와 트래픽 피크에 사전 스케일아웃을 병행한 이유를 간단히 설명해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 3.815, "ttft_sec": 1.924, "in_tokens": 1130, "out_tokens": 71} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "Outbox 릴레이는 어떤 방식으로 동작하며, 그 설계의 주요 이점은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.688, "ttft_sec": 1.868, "in_tokens": 1126, "out_tokens": 67} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "HPA 기준 설정에 대해 구체적으로 설명해 주세요. 메모리 50%를 선택하신 이유가 무엇인지, 그리고 사전 스케일아웃을 CronJob으로 운영한 이유도 함께 말씀해 주시겠어요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 6.077, "ttft_sec": 3.616, "in_tokens": 1375, "out_tokens": 86} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "복합 인덱스 변경과 파티셔닝 적용 후 p95 성능이 각각 어떻게 변했는지 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 12.365, "ttft_sec": 3.91, "in_tokens": 1475, "out_tokens": 260} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "react-window의 VariableSizeList를 사용함으로써 렌더링 성능이 어떻게 개선되었는지 구체적으로 설명해 주세요. 특히 항목 높이가 동적으로 변할 때 성능 저하를 방지하기 위한 캐싱 전략을 어떻게 구현했는지 궁금합니다.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 6.566, "ttft_sec": 3.907, "in_tokens": 1475, "out_tokens": 90} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "API 스펙 해석 충돌 시, OpenAPI 명세와 Mock 서버 제안을 통해 통합 이슈를 3건에서 0건으로 줄인 구체적인 과정과 그 결과를 좀 더 자세히 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 4.487, "ttft_sec": 2.059, "in_tokens": 1180, "out_tokens": 85} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "구체적인 사례를 들어주실 수 있나요? 예를 들어, 어떤 상황에서 의견 충돌이 있었고 어떻게 해결했는지 말씀해 주시겠어요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.925, "ttft_sec": 0.903, "in_tokens": 1130, "out_tokens": 71} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "분산 락으로 변경한 후, 불일치 건수가 구체적으로 어떻게 감소했는지 수치적으로 설명해 주시겠어요? 특히 '월 200건'과 '3건' 사이의 관계와 그 원인에 대해 좀 더 자세히 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 4.822, "ttft_sec": 2.059, "in_tokens": 1158, "out_tokens": 95} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "주문 서비스의 DB 분리 시 Saga 패턴을 적용한 이유와, 보상 처리 흐름을 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 5.463, "ttft_sec": 3.649, "in_tokens": 1399, "out_tokens": 66} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "TanStack Query를 선택한 구체적인 이점과, 이전 Zustand 방식에서의 문제점을 더 자세히 설명해 주실 수 있나요? 특히 stale data 문제와 cache invalidation의 어려움이 어떻게 해결되었는지 알고 싶습니다.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.648, "ttft_sec": 2.093, "in_tokens": 1161, "out_tokens": 89} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "멱등 키를 사용한 이유와 Outbox 패턴을 도입한 이유를 각각 구체적으로 설명해 주실 수 있나요? 특히, 두 패턴이 어떤 실패 케이스를 방지하는지에 대해 명확히 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.86, "ttft_sec": 2.563, "in_tokens": 1235, "out_tokens": 82} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 사용한 구체적인 이유와 각각의 실패 케이스를 설명해 보세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.675, "ttft_sec": null, "in_tokens": 1140, "out_tokens": 67} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "PostgreSQL의 MVCC에서 xmin horizon이 무엇인지, 그리고 오래 열린 트랜잭션이 vacuum에 미치는 영향에 대해 설명해 보세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.807, "ttft_sec": null, "in_tokens": 1115, "out_tokens": 76} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "React 18의 자동 배치 기능이 이전 버전과 어떻게 다른지 구체적으로 설명해 보세요. 특히 setTimeout이나 Promise와 같은 비동기 콜백 내부에서의 업데이트가 어떻게 처리되는지 알려주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.087, "ttft_sec": null, "in_tokens": 1115, "out_tokens": 84} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정한 구체적인 이유와 트래픽 피크 시 사전 스케일아웃을 병행한 이유를 간단히 설명해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 3.929, "ttft_sec": 1.936, "in_tokens": 1130, "out_tokens": 71} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "Outbox 릴레이를 별도 프로세스로 운영하신 구체적인 이유나 장점은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.473, "ttft_sec": 1.878, "in_tokens": 1126, "out_tokens": 60} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "HPA 기준에서 메모리 50%를 선택하신 이유가 구체적으로 무엇인지 설명해 주실 수 있나요? 또한 사전 스케일아웃을 CronJob으로 운영하셨다고 하셨는데, 그 구체적인 스케줄과 실행 방식을 좀 더 자세히 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 6.348, "ttft_sec": 3.638, "in_tokens": 1375, "out_tokens": 93} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "복합 인덱스 변경으로 p95가 900ms까지 감소했다고 하셨는데, 구체적으로 어떤 컬럼에 인덱스를 추가했으며 이 선택이 성능 향상에 어떻게 기여했는지 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 6.411, "ttft_sec": 3.93, "in_tokens": 1475, "out_tokens": 86} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "react-window의 VariableSizeList를 사용함으로써 항목 높이가 동적으로 변할 때 어떻게 성능 문제를 해결했는지 구체적으로 설명해 주세요. 특히 높이 캐싱과 브라우저 검색 기능 대체에 대한 기술적 구현 방식을 알려주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 6.733, "ttft_sec": 3.941, "in_tokens": 1475, "out_tokens": 92} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "구체적으로 어떻게 OpenAPI 명세를 작성하고 Mock 서버를 구축했는지 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.82, "ttft_sec": 2.063, "in_tokens": 1180, "out_tokens": 65} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "구체적인 사례를 들어주실 수 있나요? 예를 들어, 의견 충돌이 있었던 특정 프로젝트와 그 해결 과정을 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.926, "ttft_sec": 0.896, "in_tokens": 1130, "out_tokens": 71} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "낙관적 락을 사용했을 때 버전 충돌로 인한 재시도 횟수가 얼마나 증가했나요? 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 4.096, "ttft_sec": 2.062, "in_tokens": 1158, "out_tokens": 72} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "주문 서비스의 DB 분리 시 Saga 방식을 선택한 구체적인 이유와, 보상 이벤트 유실 문제를 해결하기 위해 도입한 스위퍼 배치의 작동 원리를 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "FULL_STAR", "correctness": 5.0}, "latency_sec": 5.832, "ttft_sec": 3.656, "in_tokens": 1399, "out_tokens": 77} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "TanStack Query를 선택한 구체적인 이점과, staleTime 설정 및 invalidateQueries 사용에 대한 추가 설명을 부탁드립니다. 특히 '네트워크 요청이 40% 줄었다'는 주장에 대해 어떻게 달성했는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.736, "ttft_sec": 2.071, "in_tokens": 1161, "out_tokens": 91} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 사용한 이유에 대해, 각각이 방지하는 실패 케이스를 구체적으로 다시 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.632, "ttft_sec": 2.565, "in_tokens": 1235, "out_tokens": 75} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 사용한 구체적인 이유와 각각의 실패 케이스를 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.703, "ttft_sec": null, "in_tokens": 1140, "out_tokens": 69} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "MVCC의 xmin horizon과 dead tuple 회수 지연에 대해 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.554, "ttft_sec": null, "in_tokens": 1115, "out_tokens": 67} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "React 18의 자동 배치 기능이 이전 버전과 어떻게 다른지, 특히 비동기 콜백 내부에서의 업데이트 처리에 대해 설명해 보세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.834, "ttft_sec": null, "in_tokens": 1115, "out_tokens": 76} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정한 구체적인 이유와 트래픽 피크 시 사전 스케일아웃을 선택한 근거를 다시 설명해 주시겠어요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 3.812, "ttft_sec": 1.935, "in_tokens": 1130, "out_tokens": 70} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "그럼 outbox 릴레이는 정확히 어떤 방식으로 동작하나요? 예를 들어, 몇 초마다 폴링하는지, 에러 발생 시 어떻게 처리하는지 구체적으로 설명해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 4.211, "ttft_sec": null, "in_tokens": 1126, "out_tokens": 81} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "HPA 기준 설정을 메모리 50%로 한 구체적인 이유가 무엇인가요? 해당 수치가 어떻게 도출되었는지 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 5.638, "ttft_sec": 3.639, "in_tokens": 1375, "out_tokens": 72} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "복합 인덱스 변경만으로 p95가 900ms까지 감소했다고 하셨는데, 구체적으로 어떤 인덱스 구조를 적용하셨는지 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 6.112, "ttft_sec": 3.938, "in_tokens": 1475, "out_tokens": 77} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "react-window의 VariableSizeList를 사용함으로써 렌더링 성능이 어떻게 개선되었는지 구체적으로 설명해 주실 수 있나요? 특히 INP(Input Performance)가 480ms에서 120ms로 줄어든 이유와 그 과정에서 발생한 트레이드오프에 대해 더 자세히 알려주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 7.011, "ttft_sec": 3.936, "in_tokens": 1475, "out_tokens": 101} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "API 스펙 해석 차이로 인한 2주 지연 상황에서, 어떻게 통합 일정을 되돌리기 위해 OpenAPI 명세와 Mock 서버를 활용했는지 구체적으로 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 4.309, "ttft_sec": 2.118, "in_tokens": 1180, "out_tokens": 78} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "구체적인 사례를 들어주실 수 있나요? 예를 들어, 어떤 상황에서 의견 충돌이 있었고, 그때 어떻게 해결했는지 말씀해 주시겠어요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 1.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.984, "ttft_sec": 0.901, "in_tokens": 1130, "out_tokens": 73} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "분산 락으로 변경한 후, 충돌 빈도가 얼마나 감소했는지 구체적으로 말씀해 주시겠어요? 예를 들어, 월 몇 건에서 몇 건으로 줄었는지 명확히 설명해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.562, "ttft_sec": 2.057, "in_tokens": 1158, "out_tokens": 83} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "주문-결제-재고 서비스 간 데이터 정합성을 위해 Saga 패턴을 사용하셨다고 했는데, 구체적으로 어떤 이벤트들이 발행되고 처리되는지 예시를 들어 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 6.157, "ttft_sec": 3.658, "in_tokens": 1399, "out_tokens": 85} +{"label": "local-ax4-light", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "TanStack Query를 선택한 구체적인 이유가 '네트워크 요청 감소'라는 점인가요? 예를 들어, 얼마나 감소했는지 수치적으로 설명해 주시겠어요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.314, "ttft_sec": 2.058, "in_tokens": 1161, "out_tokens": 78} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 **멱등 키(Idempotent Key)**와 **Outbox 패턴**을 결합했습니다. 멱등 키는 동일한 주문 요청이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 보장합니다. 예를 들어, 결제 시스템에서 네트워크 오류로 인해 콜백이 지연되면, 클라이언트는 같은 주문을 다시 시도할 수 있지만, 멱등 키가 이미 존재한다면 중복 처리를 방지합니다.\n\nOutbox 패턴은 비동기 메시징에서 트랜잭션 경계를 명확히 하기 위해 사용했습니다. 주문 생성 시 즉시 데이터베이스에 반영하지 않고, Outbox 큐에 메시지를 저장하고, 별도의 워커가 이 메시지를 처리하여 결제 시스템에 요청을 보냅니다. 이렇게 하면 **결제 실패 시 주문 데이터가 불완전하게 남아있지 않도록** 하며, 트랜잭션이 완료되기 전까지 DB에 최종 상태를 기록하지 않아 데이터 일관성을 유지합니다.\n\n결과적으로, 멱등 키는 동일한 요청의 중복 실행을 방지하고, Outbox 패턴은 비동기 처리의 신뢰성을 확보하여 결제 승인 지연으로 인한 중복 주문 문제를 효과적으로 해결했습니다. 이 접근법으로 중복 주문 0건을 달성했으며, 시스템 안정성과 트랜잭션 무결성을 동시에 강화했습니다.", "answer_rewrite": "결제 승인 콜백 지연이 발생했을 때, **멱등 키**와 **Outbox 패턴**을 활용해 문제를 해결했습니다. 멱등 키는 동일한 주문이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 하여 중복을 방지합니다. 예를 들어, 결제 시스템에서 네트워크 문제로 콜백이 지연되면, 클라이언트가 같은 주문을 다시 시도해도 멱등 키가 이미 존재하면 중복 처리가 되지 않습니다.\n\nOutbox 패턴은 주문 생성 시 즉시 DB에 저장하지 않고, **비동기 메시지 큐**(Kafka 등)를 통해 결제 시스템에 요청을 전송합니다. 이 방식은 트랜잭션 경계를 명확히 하여, 결제 실패 시에도 주문 데이터가 불완전하게 남지 않도록 보장합니다. 결과적으로, 이 두 패턴을 결합해 중복 주문을 완전히 해결했으며, 시스템의 안정성과 데이터 일관성을 크게 향상시켰습니다.", "coaching_comment": "구체적인 사례와 정량적 결과를 포함해 답변의 신뢰성을 높이세요."}, "latency_sec": 22.168, "in_tokens": 1167, "out_tokens": 439} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시켜 `dead tuple` 회수를 지연시킵니다. 이로 인해 테이블의 **bloat**가 발생할 수 있습니다.\n\n* **상황**: 트랜잭션이 오랜 시간 열려 있으면, 해당 트랜잭션이 생성한 `xmin` 값이 계속 유지됩니다.\n* **과제**: 시스템은 이 오래된 `xmin`을 기준으로 더 이상 회수할 필요가 없는 튜플들을 식별하지 못합니다.\n* **행동**: `VACUUM` 명령이 실행되면, PostgreSQL은 `xmin horizon` 내의 모든 튜플을 검사하고, `dead tuple`을 회수하려고 시도합니다. 하지만 오래 열린 트랜잭션이 많으면 이 과정이 지연됩니다.\n* **결과**: 결과적으로 테이블의 크기가 증가하고, 쿼리 성능이 저하될 수 있습니다. 이는 특히 대량의 데이터 처리 시 심각한 성능 문제로 이어질 수 있습니다.", "answer_rewrite": "오래 열린 트랜잭션은 PostgreSQL의 MVCC에서 `xmin horizon`을 확장시켜 `dead tuple` 회수를 지연시킵니다. 이로 인해 **테이블 bloat**가 발생할 수 있습니다.\n\n* **상황**: 예를 들어, 장시간 실행되는 트랜잭션이 있을 때 이 트랜잭션이 생성한 `xmin` 값이 계속 유지됩니다.\n* **행동**: `VACUUM`이 실행되면 시스템은 오래된 `xmin`을 기준으로 불필요한 튜플들을 회수하지 못해, `dead tuple`의 수가 증가합니다.\n* **결과**: 이로 인해 테이블 크기가 커지고 쿼리 성능이 저하되며, 장기적으로는 데이터베이스의 효율성이 떨어집니다.", "coaching_comment": "구체적인 예시와 함께 xmin horizon과 bloat의 관계를 명확히 설명하세요."}, "latency_sec": 15.257, "in_tokens": 789, "out_tokens": 383} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": true, "coaching": {"model_answer": "제가 이전에 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석으로 갈등이 있었던 경험이 있습니다. 당시 우리는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 통해 병렬 개발을 제안했습니다. 하지만 초기에는 제 의견을 고집해 팀원의 반감을 샀습니다. 이후, 결정 전에 두 가지 대안을 비교하는 방식을 도입했고, 그 결과 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정 방식의 필요성을 깨달았습니다.", "answer_rewrite": "저는 이전에 캡스톤 프로젝트에서 프론트엔드 팀원과의 의견 충돌을 경험한 적이 있습니다. 당시 API 스펙 해석 차이로 인해 통합이 2주 지연되었는데, 저는 OpenAPI 명세를 작성하고 Mock 서버를 제안하여 병렬 개발을 가능하게 했습니다. 그러나 처음에는 제 의견을 고집해 팀원의 반감을 샀습니다. 이후, 의사결정 전에 두 가지 대안을 비교하는 방식으로 접근법을 수정했고, 그 결과 스프린트 중 통합 이슈가 3건에서 0건으로 감소했습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정의 필요성을 깊이 깨달았습니다.", "coaching_comment": "구체적인 수치(이슈 감소)와 행동 변화(대안 비교 방식 도입)를 명확히 언급하여 STAR 구조를 강화하세요."}, "latency_sec": 12.366, "in_tokens": 1020, "out_tokens": 252} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 결합한 이유는 각각의 패턴이 다른 실패 케이스를 방지하기 때문입니다. **멱등 키**는 동일한 요청이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 보장합니다. 예를 들어, 결제 시스템에서 네트워크 오류로 인해 동일한 주문 요청이 여러 번 서버에 도달했을 때, 멱등 키를 통해 중복된 주문이 저장되는 것을 막았습니다. **Outbox 패턴**은 비동기 메시징 환경에서 트랜잭션 경계를 명확히 하여, 메시지 발행 후 실제 데이터베이스 업데이트가 완료되기 전까지 메시지가 손실되지 않도록 합니다. 이 패턴을 사용하면 결제 승인 콜백이 지연되더라도, 주문 정보가 이미 데이터베이스에 안전하게 저장되어 있어 중복 주문 발생을 방지할 수 있습니다. 결과적으로 두 패턴의 조합은 네트워크 장애나 시스템 오류로 인한 데이터 불일치 문제를 효과적으로 해결했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 해결하기 위해 **멱등 키**와 **Outbox 패턴**을 사용했습니다. 멱등 키는 동일한 주문이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 하여, 네트워크 장애로 인한 중복 저장 문제를 방지합니다. Outbox 패턴은 비동기 메시징 환경에서 트랜잭션 경계를 명확히 해, 결제 승인 콜백이 지연되더라도 주문 정보가 안전하게 데이터베이스에 기록되도록 보장합니다. 이 두 가지 접근법을 결합함으로써, 중복 주문 0건이라는 성과를 달성했습니다.", "coaching_comment": "구체적인 실패 사례와 각 패턴의 역할을 더 명확하게 설명하면 설득력이 높아집니다."}, "latency_sec": 15.307, "in_tokens": 1167, "out_tokens": 311} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: ```json\n{\n \"model_answer\": \"PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시킵니다. 이는 오래된 트랜잭션이 종료되지 않으면, 해당 트랜잭션이 삭제한 튜플이 '죽은' 상태로 남아 있게 되고, 이로 인해 VACUUM이 dead tuple을 회수하는 데 시간이 더 걸립니다.\\n\\n**구체적인 영향:**\n1. **XMIN Horizon 확장**: 오래 열린 트랜잭션은 xmin 값을 증가시키고, 이는 MVCC가 관리하는 오래된 버전들의 범위를 넓힙니다.\n2. **Dead Tuple 회수 지연**: VACUUM은 xmin보다 작은 시퀀스 번호를 가진 튜플을 회수합니다. 오래 열린 트랜잭션이 많으면 dead tuple이 계속 쌓여 VACUUM의 효율이 떨어집니다.\n3. **테이블 Bloat 발생**: 죽은 튜플이 제거되지 않으면, ", "latency_sec": 16.055, "in_tokens": 789, "out_tokens": 408} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 개발 과정에서 흔히 발생하는 문제입니다. 제가 참여했던 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 인해 통합이 지연된 경험이 있습니다. **상황(Situation)**: 우리는 서로 다른 해석을 가지고 있었고, 이로 인해 스프린트 마지막 2주 동안 통합 작업이 중단되었습니다. **과제(Task)**: 이 문제를 해결하기 위해 저는 OpenAPI 명세를 작성하고 Mock 서버를 구축하여 병렬 개발을 제안했습니다. **행동(Action)**: 처음에는 제 방식이 옳다고 고집했으나, 팀원의 반발을 수용하고 대안 두 가지를 비교하는 방식으로 접근법을 수정했습니다. **결과(Result)**: 그 결과 통합 이슈는 3건에서 0건으로 줄었고, 이후 팀원들과의 소통도 개선되었습니다. 이 경험을 통해 저는 의견 충돌이 발생했을 때, 자신의 입장만 고수하지 않고 대안을 모색하는 것이 중요하다는 것을 배웠습니다.", "answer_rewrite": "저는 과거에 프론트엔드 팀원과 API 해석 차이로 인해 프로젝트 통합이 지연된 경험이 있습니다. **상황**: 서로 다른 견해로 인해 스프린트 마지막 2주 동안 작업이 정체되었습니다. **과제**: 이 문제를 해결하기 위해 OpenAPI 명세를 작성하고 Mock 서버를 제안했습니다. **행동**: 처음에는 제 의견을 고집했으나, 팀원과의 감정 충돌을 피하기 위해 대안을 함께 비교하는 방식으로 접근법을 수정했습니다. **결과**: 그 결과 통합 이슈는 3건에서 0건으로 줄었고, 팀 내 소통도 개선되었습니다. 이 경험을 통해 의견 충돌이 있을 때, 유연한 태도로 다양한 해결책을 모색하는 것이 중요하다는 것을 배웠습니다.", "coaching_comment": "STAR 구조를 활용해 구체적인 상황과 행동, 결과를 명확히 제시하세요."}, "latency_sec": 15.501, "in_tokens": 1020, "out_tokens": 344} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 결합한 이유는 다음과 같습니다. **상황**: 결제 시스템에서 콜백이 지연되면 동일한 주문이 여러 번 처리될 수 있습니다. **과제**: 이 중복을 방지하고 트랜잭션 경계를 명확히 해야 했습니다. **행동**: 먼저, *멱등 키*를 도입해 주문 ID가 중복으로 생성되지 않도록 했습니다. 이는 데이터베이스에 주문 시 고유 키를 강제해 동일 주문의 재처리를 방지합니다. 동시에 *Outbox 패턴*을 적용해 결제 승인 콜백이 지연되더라도 실제 주문 데이터 변경은 트랜잭션 내에서 처리되도록 했습니다. 이로 인해, 결제 실패나 네트워크 문제로 인한 중복 주문이 0건으로 감소했습니다. **결과**: 이러한 접근으로 시스템 안정성과 사용자 신뢰성을 크게 향상시켰습니다.", "answer_rewrite": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 사용했습니다. **먼저**, 멱등 키를 도입해 동일한 주문 ID가 중복 생성되지 않도록 데이터베이스에서 고유성 제약을 적용했습니다. **다음으로**, Outbox 패턴을 활용해 결제 승인 콜백이 지연되더라도 실제 주문 데이터는 트랜잭션 내에서 처리되도록 했습니다. 이로 인해 결제 실패나 네트워크 문제로 인한 중복 주문이 발생하지 않게 되었고, 결과적으로 시스템 안정성이 향상되었습니다.", "coaching_comment": "구체적인 실패 케이스와 해결 효과를 더 명확히 설명하면 설득력이 높아집니다."}, "latency_sec": 14.468, "in_tokens": 1167, "out_tokens": 287} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시킵니다. 이는 오래된 트랜잭션이 완료되지 않은 상태에서 새로운 트랜잭션이 실행될 때, 더 많은 이전 버전의 데이터가 'dead tuple'로 간주되게 만듭니다. 결과적으로 VACUUM이 이러한 dead tuple을 회수하는 데 시간이 더 걸리게 됩니다.\n\n또한, 오래 열린 트랜잭션은 테이블의 **bloat**를 유발합니다. 이는 불필요한 중복 데이터와 인덱스 조각화로 이어지며, 성능 저하를 초래합니다. 예를 들어, 트랜잭션이 종료되지 않으면 `xmin` 값이 계속 증가하여 VACUUM이 실행될 때 더 많은 페이지를 스캔해야 하므로, 전체 데이터베이스 크기가 증가하고 쿼리 응답 시간이 느려집니다.\n\n따라서, **적절한 트랜잭션 관리**가 중요합니다. 예를 들어, 트랜잭션을 가능한 짧게 유지하고, 정기적으로 VACUUM을 실행하거나 ANALYZE를 통해 테이블을 최적화하는 것이 필요합니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 VACUUM에 미치는 영향은 다음과 같습니다: 먼저, 오래된 트랜잭션이 종료되지 않으면 `xmin horizon`이 확장되어 더 많은 'dead tuple'이 발생합니다. 이로 인해 VACUUM 작업이 지연되고 테이블 **bloat**가 발생하게 됩니다.\n\n즉, 트랜잭션 관리가 중요하며, 예를 들어 **트랜잭션을 짧게 유지**하고 주기적으로 VACUUM을 실행함으로써 성능 저하를 방지할 수 있습니다.", "coaching_comment": "구체적인 예시와 함께 MVCC의 작동 원리와 xmin horizon의 영향을 명확히 설명해야 합니다."}, "latency_sec": 14.386, "in_tokens": 789, "out_tokens": 360} +{"label": "local-ax4-light", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "저는 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 인해 통합이 지연된 경험이 있습니다. **상황:** 프론트엔드와 백엔드 간의 소통이 원활하지 않아, 2주 동안 스프린트 일정이 위협받았습니다. **과제:** 이 문제를 해결하기 위해 OpenAPI 명세를 작성하고 Mock 서버를 구축했습니다. 이를 통해 양측이 병렬로 개발할 수 있도록 했습니다. **행동:** 초기에는 제 방식을 고집했으나, 팀원의 반발을 경험한 후 대안 두 가지를 비교하는 방식으로 접근법을 수정했습니다. **결과:** 이후 통합 이슈가 3건에서 0건으로 줄었으며, 팀워크가 크게 개선되었습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정의 필요성을 배웠습니다.", "answer_rewrite": "제 경험 중 하나로 캡스톤 프로젝트에서의 의견 충돌을 들 수 있습니다. **상황**으로, 프론트엔드 팀원과의 API 해석 차이로 인해 통합이 지연된 적이 있었습니다. **과제**는 이를 해결하는 것이었고, 저는 OpenAPI 명세를 작성하고 Mock 서버를 구축하여 양측이 병렬로 개발하도록 제안했습니다. **행동**에서는 처음에 제 방식이 옳다고 고집했으나, 팀원의 반발을 경험한 후 대안 두 가지를 비교하는 방식으로 접근법을 수정했습니다. **결과**로 통합 이슈가 3건에서 0건으로 줄었으며, 팀워크도 크게 개선되었습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정의 필요성을 깊이 깨달았습니다.", "coaching_comment": "STAR 구조를 활용해 구체적인 상황과 행동, 결과를 명확히 제시하세요."}, "latency_sec": 14.194, "in_tokens": 1020, "out_tokens": 308} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "주문 서비스 MSA 전환 프로젝트에서, 주문 서비스를 분리하고 Kafka 이벤트 파이프라인을 설계한 구체적인 과정과 그 효과를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일", "expected_signal": "Kafka 파이프라인 설계의 필요성과 구현 방식, 그리고 이로 인한 배포 효율성 향상 효과를 명확히 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "결제 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 선택한 이유와 그 기술적 구현 방식을 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키와 Outbox 패턴의 선택 이유 및 실제 구현 방식(예: Spring Boot에서의 적용 코드 구조)을 구체적으로 설명할 수 있어야 합니다."}, {"category": "CS_FUNDAMENTAL", "question": "Kafka 이벤트 기반 아키텍처에서 메시지 중복 처리 문제를 해결하기 위한 일반적인 접근 방식과, 귀하가 적용한 Outbox 패턴의 장점을 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "Kafka의 메시지 중복 처리 접근 방식과 Outbox 패턴의 장점(예: 트랜잭션 보장, 시스템 확장성)을 명확히 설명할 수 있어야 합니다."}, {"category": "BEHAVIORAL", "question": "주문 서비스 분리 프로젝트에서 본인의 구체적인 역할과 기여도를 설명하고, 이 경험이 향후 커리어에 어떤 영향을 미칠 것으로 예상하는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "주문/결제 도메인 담당. 일 평균 주문 12만 건 처리", "expected_signal": "프로젝트 내 본인의 구체적 역할(예: 설계, 구현, 테스트)과 기여도, 그리고 이를 통해 얻은 기술적 통찰이나 성장 가능성을 STAR 방식으로 설명할 수 있어야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 Redis와 DB write-behind를 적용한 이유와 그 결과를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "재고 동기화 방식 선택과 그 기술적 구현(예: Redis 캐싱, write-behind), 그리고 이로 인한 재고 불일치 감소 효과를 명확히 설명할 수 있어야 합니다."}], "latency_sec": 38.428, "in_tokens": 2384, "out_tokens": 672} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "여행 일정 공유 웹앱에서 react-window를 도입해 스크롤 성능을 개선한 경험을 설명해 주세요. 구체적으로 어떤 문제를 해결했으며, 그 과정에서 어떤 기술적 결정을 내렸는지 말씀해 주세요.", "job_category": "FRONTEND", "target_evidence": "커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\"", "expected_signal": "구체적인 성능 개선 전후 수치, react-window 도입 이유 및 구현 방식 설명"}, {"category": "TECH_CHOICE", "question": "Kakao Map SDK 마커 클러스터링과 useMemo를 사용한 좌표 변환 캐싱의 장단점을 설명하고, 이 선택이 프로젝트의 성능에 어떤 영향을 미쳤는지 구체적으로 말씀해 주세요.", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "기술 선택의 장단점 분석 및 성능 개선 효과 수치 제시"}, {"category": "CS_FUNDAMENTAL", "question": "IndexedDB를 활용한 낙관적 업데이트와 충돌 해결 방식(last-write-wins)에 대해 설명해 주세요. 이 접근 방식의 한계나 개선할 점이 있다면 무엇인지 말씀해 주세요.", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "IndexedDB의 작동 원리, last-write-wins 방식의 구현 방식 및 한계점 설명"}, {"category": "BEHAVIORAL", "question": "여행 일정 공유 웹앱 개발 과정에서 팀 내 의견 충돌이 발생했을 때 어떻게 해결했는지 구체적인 사례를 들어 설명해 주세요. 본인의 역할과 기여도, 그리고 그 경험에서 배운 점을 말씀해 주세요.", "job_category": "FRONTEND", "target_evidence": "팀 프로젝트 경험 (레포 및 자기소개서 기반)", "expected_signal": "STAR 방식으로 상황 설명, 본인의 구체적 행동 및 결과, 갈등 해결 과정 및 배운 점 제시"}, {"category": "PROJECT_DEEP_DIVE", "question": "Vitest와 Playwright를 활용한 테스트 자동화 과정에서 가장 도전적이었던 부분은 무엇이었고, 어떻게 극복했는지 설명해 주세요. 성능 점수 개선(68→91)에 기여한 구체적인 테스트 케이스를 언급해 주세요.", "job_category": "FRONTEND", "target_evidence": "Lighthouse 성능 점수 68 → 91 (PR #57 설명)", "expected_signal": "테스트 자동화 도전 과제, 극복 방법 및 성능 개선에 기여한 특정 테스트 케이스 설명"}], "latency_sec": 32.26, "in_tokens": 2255, "out_tokens": 654} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"EKS 클러스터 운영 시 HPA를 CPU 70%로 설정한 이유와 그 효과를 설명해 주세요. 트래픽 피크 시간대에 어떤 조치를 취했는지 구체적으로 말씀해 주세요.\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영\", \"expectedSignal\": \"HPA 설정의 이유와 실제 효과를 정량적으로 설명할 수 있어야 함.\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"ArgoCD를 GitOps 도입으로 활용하여 배포 리드타임을 1일에서 30분으로 단축한 구체적인 과정과 그 기술적 선택 이유를 설명해 주세요.\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분\", \"expectedSignal\": \"GitOps 구현 과정과 기술적 선택의 근거를 명확히 설명할 수 있어야 함.\"}, {\"category\": \"BEHAVIORAL\", \"question\": \"RDS 스토리지 풀로 인한 장애 발생 시 어떻게 문제를 해결했는지, 그 과정에서 본인의 역할과 구체적인 행동을 설명해 주세요.\", \"jobCategory\": \"DBA\", \"targetEvidence\": \"202", "latency_sec": 31.58, "in_tokens": 2222, "out_tokens": 647} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "알림 봇 프로젝트에서 DB 문제로 인해 알림이 중복 발송된 경험이 있었습니다. 그 상황에서 본인의 구체적 역할과 행동은 무엇이었나요? 그리고 그 문제를 해결하기 위해 어떤 과정을 거쳤으며, 결과적으로 배운 점은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "구체적인 문제 해결 과정과 그 과정에서 나타난 리더십, 문제 분석 능력, 그리고 배운 점을 명확히 설명할 수 있어야 합니다."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 통합 문제로 갈등이 발생했을 때, 어떻게 상황을 개선했나요? 본인의 구체적인 행동과 그 결과를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 2주 지연된 적이 있었습니다. 저는 OpenAPI 명세를 작성하고 Mock 서버를 제안해 문제를 해결했습니다.", "expected_signal": "갈등 상황에서 본인의 구체적인 행동, 문제 해결을 위한 대안 제시, 그리고 그 결과로 통합 이슈가 줄어든 점을 명확히 설명할 수 있어야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "알림 봇 프로젝트에서 사용한 SQLite와 PostgreSQL의 트랜잭션 격리 수준에 대해 설명해 주세요. 두 데이터베이스 선택 시 고려한 주요 차이점은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "트랜잭션 격리 수준의 개념과 두 데이터베이스의 차이점에 대해 명확히 설명하고, 실제 프로젝트에서 어떤 고려사항이 있었는지 구체적으로 답변할 수 있어야 합니다."}, {"category": "BEHAVIORAL", "question": "동아리에서 운영한 알림 봇 서비스가 사용자 800명의 신뢰를 얻는 데 중요한 역할을 했다고 언급하셨습니다. 이 경험을 통해 배운 점과 이를 향후 프로젝트에 어떻게 적용할 계획인지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "서비스의 지속성과 신뢰 구축의 중요성을 이해하고 있으며, 이를 바탕으로 향후 프로젝트에서 어떻게 안정성을 강화할 계획인지 구체적으로 설명할 수 있어야 합니다."}, {"category": "TECH_CHOICE", "question": "알림 봇 프로젝트에서 SQLite를 PostgreSQL로 변경한 이유와 그 과정에서 학습한 기술적 내용은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "데이터베이스 선택 시 고려한 기술적 요소와 그 과정에서 습득한 새로운 기술 지식을 명확히 설명할 수 있어야 합니다."}], "latency_sec": 35.077, "in_tokens": 2176, "out_tokens": 761} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"주문 서비스 MSA 전환 시 Kafka 이벤트 파이프라인을 어떻게 설계했는지 구체적으로 설명해 주세요.\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"Kafka 기반 이벤트 발행/구독 구조 도입, 배포 단위 축소로 배포 주기 2주 → 2일\", \"expectedSignal\": \"Kafka의 Producer와 Consumer 패턴 설명 및 실제 구현 방식, 장애 대응 방안 포함\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 선택한 이유와 그 기술적 구현 방식은 무엇인가요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"결제 승인 콜백 지연으로 인한 중복 주문 이슈를 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성\", \"expectedSignal\": \"멱등성과 Outbox 패턴의 개념 설명 및 실제 코드 구현 예시 제시\"}, {\"category\": \"CS_FUNDAMENTAL\", \"question\": \"Spring Boot에서 트랜잭션 관리와 관련된 주요 개념과, 주문 서비스에서의 적용 사례는 무엇인가요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"정산", "latency_sec": 37.512, "in_tokens": 3326, "out_tokens": 595} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "주문 서비스 MSA 전환 프로젝트에서 Kafka 이벤트 파이프라인을 설계했다고 했는데, 구체적으로 어떤 방식으로 구현했는지 설명해 주세요. 특히 장애 대응 측면에서 어떻게 데이터 정합성을 유지했는지 구체적인 예시를 들어주세요.", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "Kafka의 Producer와 Consumer 설계, 이벤트 흐름 제어 방식, 장애 시 멱등 키 및 Outbox 패턴 적용 사례 설명"}, {"category": "TECH_CHOICE", "question": "결제 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 선택했는데, 이 두 기술의 장단점과 해당 문제 해결에 어떻게 적합했는지 구체적으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "멱등 키의 유일성 보장, Outbox 패턴의 비동기 처리 방식 설명 및 실제 적용 사례"}, {"category": "CS_FUNDAMENTAL", "question": "Spring Boot에서 JPA와 QueryDSL을 활용해 주문 도메인 쿼리를 최적화했다고 했는데, 구체적으로 어떤 성능 개선 작업을 했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "QueryDSL을 통한 쿼리 최적화 기법, 청크 단위 처리의 이점, 인덱스 설계 변경의 효과 설명"}, {"category": "BEHAVIORAL", "question": "중복 주문 문제를 해결한 경험을 통해 얻은 교훈과 이를 향후 프로젝트에 어떻게 적용할 계획인지 구체적으로 설명해 주세요. (STAR 방식으로 답변)", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 멱등 키 + Outbox 패턴으로 해결", "expected_signal": "상황(문제 발생), 과제(해결 방안 모색), 행동(패턴 적용), 결과(중복 주문 0건 달성) 및 향후 적용 계획 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 Redis와 DB write-behind를 구현했는데, 동시성 제어 문제를 어떻게 해결했는지 구체적인 기술적 접근법을 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "동시성 문제 발생 원인, 낙관적 락과 분산 락의 차이 및 적용 방식 설명"}], "latency_sec": 29.382, "in_tokens": 2384, "out_tokens": 649} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "React 18의 가상화(react-window)를 도입하면서 성능 개선을 이룬 구체적인 사례를 설명해 주세요. 특히 타임라인 항목 수가 2천 개 이상일 때 스크롤 끊김 문제를 어떻게 해결했는지, 그 과정에서 어떤 기술적 도전과제를 겪었는지 말씀해 주세요.", "job_category": "FRONTEND", "target_evidence": "커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\"", "expected_signal": "구체적인 성능 개선 수치(예: INP 480ms → 120ms)와 함께 가상화 도입의 필요성, 구현 과정에서의 기술적 도전과 해결 방법을 명확히 설명."}, {"category": "TECH_CHOICE", "question": "Kakao Map SDK에서 마커 클러스터링을 구현할 때 useMemo를 활용해 좌표 변환을 캐싱한 이유와 그 효과를 설명해 주세요. 이 선택이 성능에 미친 영향을 구체적으로 수치화해 볼 수 있나요?", "job_category": "FRONTEND", "target_evidence": "useMemo 로 좌표 변환 캐싱", "expected_signal": "useMemo 활용의 이유(성능 최적화), 좌표 변환 계산 비용 절감 효과, 구체적인 수치적 개선(예: 렌더링 시간 단축)을 설명."}, {"category": "CS_FUNDAMENTAL", "question": "IndexedDB를 활용한 낙관적 업데이트와 충돌 해결 방식(last-write-wins)에 대해 설명해 주세요. 이 접근 방식의 장단점과 실제 구현 시 고려해야 할 주요 기술적 요소는 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화, 충돌은 last-write-wins", "expected_signal": "낙관적 업데이트의 원리, last-write-wins 방식의 장단점, 구현 시 고려해야 할 기술적 요소(예: 트랜잭션 관리, 데이터 일관성 유지 방법)를 명확히 설명."}, {"category": "BEHAVIORAL", "question": "여행 일정 공유 웹앱 개발 과정에서 팀 내 협업이나 문제 해결 경험이 있었다면 구체적으로 설명해 주세요. 특히 본인의 역할과 행동, 그리고 그 결과가 프로젝트에 어떤 영향을 미쳤는지 STAR 방식으로 답변해 주세요.", "job_category": "FRONTEND", "target_evidence": "팀 프로젝트 경험", "expected_signal": "상황(Situation), 과제(Task), 행동(Action), 결과(Result)를 명확히 제시하여 팀 내 협업 또는 문제 해결 과정에서의 본인의 기여와 그 효과를 구체적으로 설명."}, {"category": "PROJECT_DEEP_DIVE", "question": "S3에 WebP 형식으로 이미지를 업로드하는 과정에서 presigned URL을 사용한 이유와, 이 방식이 클라이언트 측 성능에 미친 영향을 설명해 주세요. 또한, WebP 변환이 실제로 얼마나 효과적인지 구체적인 수치를 제시해 볼 수 있나요?", "job_category": "FRONTEND", "target_evidence": "presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "presigned URL 사용의 이유(보안/성능), WebP 변환이 이미지 파일 크기 및 로딩 시간에 미친 구체적인 수치적 개선 효과(예: 30% 압축률)를 설명."}], "latency_sec": 35.68, "in_tokens": 2255, "out_tokens": 753} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"EKS 클러스터 운영 시 HPA를 CPU 70%로 설정한 이유와 그 효과를 설명해 보세요.\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영\", \"expectedSignal\": \"트래픽 패턴 분석과 HPA 설정의 정량적 효과(스케일 아웃 빈도, 비용 절감 등)를 설명해야 함.\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"ArgoCD 도입으로 배포 리드타임을 1일에서 30분으로 단축한 구체적인 과정을 설명해 주세요.\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분\", \"expectedSignal\": \"GitOps 구현 방식, CI/CD 파이프라인 개선, 자동화 도구 선택 이유를 명확히 설명해야 함.\"}, {\"category\": \"BEHAVIORAL\", \"question\": \"RDS 스토리지 풀로 인한 장애 발생 시 어떻게 문제를 해결했는지 구체적인 사례를 들어 설명해 주세요.\", \"jobCategory\": \"DBA\", \"targetEvidence\": \"2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리", "latency_sec": 32.454, "in_tokens": 2222, "out_tokens": 671} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "BEHAVIORAL", "question": "알림 봇 프로젝트에서 DB 문제로 인해 알림이 중복 발송된 경험이 있었습니다. 그 상황에서 본인의 구체적 역할과 행동, 그리고 이를 해결하기 위해 어떤 노력을 기울였는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "구체적인 문제 해결 과정과 팀 내 소통 방식, 그리고 배운 점을 명확히 설명할 수 있어야 합니다."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 프론트엔드 팀원과의 갈등 상황을 어떻게 극복했는지 구체적인 사례를 들어 설명해 주세요. 특히 본인의 행동과 그 결과를 중심으로 이야기해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 통합이 지연된 적이 있었습니다. 저는 OpenAPI 명세를 작성하고 Mock 서버를 제안했습니다.", "expected_signal": "갈등 상황에서의 구체적 행동, 문제 해결 과정, 그리고 그 결과로 팀워크가 어떻게 개선되었는지 설명할 수 있어야 합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "알림 봇 프로젝트에서 사용한 SQLite와 PostgreSQL의 트랜잭션 격리 수준에 대해 구체적으로 설명하고, 이 경험이 향후 백엔드 개발에 어떤 영향을 미쳤는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "트랜잭션 격리 수준의 차이와 그 영향에 대해 명확히 설명하고, 실제 적용 사례를 통해 배운 점을 구체적으로 제시할 수 있어야 합니다."}, {"category": "BEHAVIORAL", "question": "지원동기로 언급한 '멈추지 않는 서비스'의 중요성을 실제로 어떻게 구현했는지 구체적인 프로젝트 경험을 바탕으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영했습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받았습니다.", "expected_signal": "서비스의 지속성을 보장하기 위한 구체적 조치와 그 결과, 그리고 이를 통해 얻은 교훈을 명확히 설명할 수 있어야 합니다."}, {"category": "BEHAVIORAL", "question": "리더십 발휘 경험을 한 사례를 들어 설명해 주세요. 특히 팀 내 갈등 상황에서 어떻게 리더십을 보여줬는지 구체적인 상황을 중심으로 이야기해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과의 API 스펙 해석 차이로 통합이 지연된 적이 있었습니다. 저는 OpenAPI 명세를 작성하고 Mock 서버를 제안했습니다.", "expected_signal": "갈등 상황에서 리더십을 발휘한 구체적인 행동과 그 결과, 그리고 팀워크 개선에 대한 통찰을 명확히 설명할 수 있어야 합니다."}], "latency_sec": 33.117, "in_tokens": 2176, "out_tokens": 701} +{"label": "local-ax4-light", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "주문 서비스 분리 및 Kafka 이벤트 파이프라인 설계 과정에서 어떤 기술적 도전이 있었고, 이를 어떻게 해결했는지 구체적으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입.", "expected_signal": "Kafka 파이프라인 설계의 도전과 해결 방안을 구체적으로 설명하며, 기술적 세부사항(예: 메시지 브로커 선택 이유, 데이터 일관성 유지 방법 등)을 포함해야 함."}, {"category": "TECH_CHOICE", "question": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 선택한 이유와 그 구현 방식에 대해 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연으로 인한 중복 주문 이슈를 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성.", "expected_signal": "멱등 키와 Outbox 패턴의 선택 이유(성능/신뢰성 측면)와 실제 구현 방식(예: 데이터베이스 설계, 트랜잭션 처리 흐름 등)을 명확히 설명해야 함."}, {"category": "CS_FUNDAMENTAL", "question": "Kafka 이벤트 기반 아키텍처에서 메시지 중복 처리를 방지하기 위한 일반적인 패턴과 그 한계는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Kafka 기반 이벤트 발행/구독 구조 도입.", "expected_signal": "메시지 중복 방지 패턴의 종류(예: 멱등성, Outbox 등)와 각 패턴의 장단점 및 Kafka 환경에서의 적용 한계를 설명해야 함."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 프론트엔드 팀과의 협업 과정에서 발생한 갈등을 어떻게 해결했는지 구체적인 사례를 들어 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 지연, OpenAPI 명세 작성 및 Mock 서버 제안으로 문제 해결.", "expected_signal": "갈등 상황(상황), 해결 과정(과제/행동), 결과(결과)를 STAR 방식으로 설명하며, 갈등 해결 전략과 팀워크 개선 방안을 포함해야 함."}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 Redis와 DB write-behind 방식을 적용한 이유와 그 구현 방식에 대해 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환).", "expected_signal": "Redis와 write-behind 방식의 선택 이유(성능/확장성 측면)와 실제 구현 방식(예: Redis 설정, write-behind 로직 등)을 명확히 설명해야 함."}], "latency_sec": 40.613, "in_tokens": 3326, "out_tokens": 680} +{"label": "local-ax4-light", "suite": "followup:cold", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "멱등 키를 사용함으로써 어떤 실패 케이스를 방지했다고 설명하셨는지, 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 12.152, "ttft_sec": 10.117, "in_tokens": 1235, "out_tokens": 69} +{"label": "local-ax4-light", "suite": "followup:after-cold", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용한 구체적인 이유와 각각의 실패 케이스가 무엇인지 설명해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.745, "ttft_sec": null, "in_tokens": 1140, "out_tokens": 72} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 결합한 이유는 각각의 패턴이 특정 실패 케이스를 방지하기 때문입니다. **멱등 키**는 동일한 요청이 여러 번 처리되더라도 결과가 한 번만 반영되도록 보장합니다. 예를 들어, 결제 시스템에서 네트워크 문제로 인해 콜백이 두 번 호출되면, 멱등 키를 통해 이미 처리된 주문임을 식별하고 중복 처리를 방지할 수 있습니다. **Outbox 패턴**은 비동기 메시지 발행 시 트랜잭션 경계를 명확히 하여, 메시지 전송 실패 시 데이터 불일치(예: 주문이 데이터베이스에 저장되었으나 결제 메시지가 발송되지 않은 경우)를 방지합니다. 이 두 패턴을 함께 사용함으로써, 네트워크 지연으로 인한 콜백 실패와 시스템 장애 상황에서도 주문 처리의 일관성과 신뢰성을 유지할 수 있었습니다. 결과적으로 중복 주문 0건을 달성하며 시스템의 안정성을 크게 향상시켰습니다.", "answer_rewrite": "결제 승인 콜백 지연 문제를 해결하기 위해 **멱등 키**와 **Outbox 패턴**을 결합한 이유는 각각의 패턴이 특정 실패 케이스를 방지하기 때문입니다. 멱등 키는 동일한 요청이 여러 번 처리되더라도 결과가 한 번만 반영되도록 보장합니다. 예를 들어, 결제 시스템에서 네트워크 문제로 인해 콜백이 두 번 호출되면, 멱등 키를 통해 이미 처리된 주문임을 식별하고 중복 처리를 방지했습니다. Outbox 패턴은 비동기 메시지 발행 시 트랜잭션 경계를 명확히 하여, 메시지 전송 실패 시 데이터 불일치를 예방합니다. 이 두 패턴을 결합하여 네트워크 지연 및 시스템 장애로 인한 중복 주문을 효과적으로 해결했고, 결과적으로 **중복 주문 0건**을 달성하며 시스템의 신뢰성을 높였습니다.", "coaching_comment": "구체적인 실패 사례와 각 패턴의 역할을 명확히 설명하여, 문제 해결의 논리적 흐름을 잘 전달했습니다. 다만, 실제 구현에서의 코드 구조나 성능 개선 수치(예: 처리 속도 향상)를 추가하면 더 설득력 있는 답변이 될 것입니다."}, "latency_sec": 62.855, "in_tokens": 1167, "out_tokens": 385} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC(다중 버전 동시성 제어)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시켜 `dead tuple` 회수를 지연시킵니다. 이는 다음과 같이 작동합니다:\n\n- **상황**: 오래된 트랜잭션이 열려 있으면, 해당 트랜잭션이 작성한 데이터는 `xmin`(가장 작은 커밋된 트랜잭션 ID)에 영향을 받습니다.\n- **과제**: 데이터베이스는 주기적으로 VACUUM을 실행해 dead tuple을 회수하고 테이블을 정리해야 합니다.\n- **행동**: 그러나 오래 열린 트랜잭션은 `xmin horizon`을 넓히게 되어, VACUUM이 dead tuple을 제거하는 데 필요한 범위를 증가시킵니다. 이로 인해:\n - Dead tuple 회수가 지연되어 테이블의 bloat(팽창)이 발생할 수 있습니다.\n - 성능 저하가 발생하며, 특히 대량의 트랜잭션이 동시에 실행되는 환경에서 더 두드러집니다.\n\n- **결과**: 따라서 VACUUM 실행 주기를 조정하거나, 트랜잭션 관리를 통해 오래된 트랜잭션을 최소화하는 것이 중요합니다. 예를 들어, 명시적으로 트랜잭션을 종료하거나, 자동화된 정리 스크립트를 사용하는 방법이 있습니다.", "answer_rewrite": "오래 열린 트랜잭션이 PostgreSQL의 MVCC에 미치는 영향을 설명하자면:\n\n- **상황**: 오래 실행되는 트랜잭션은 `xmin horizon`을 확장시킵니다.\n- **과제**: 이로 인해 VACUUM이 dead tuple을 회수하는 데 시간이 더 걸립니다.\n- **행동**: 구체적으로, 오래된 트랜잭션이 열려 있을 때 해당 트랜잭션이 작성한 데이터는 `xmin`에 영향을 주어 VACUUM의 범위를 넓히게 됩니다. 이는:\n - Dead tuple 회수의 지연을 초래해 테이블 bloat(불필요한 공간 증가)를 유발합니다.\n - 결과적으로 쿼리 성능 저하로 이어질 수 있습니다.\n\n- **결과**: 따라서 트랜잭션 관리 전략을 개선하거나, 정기적인 VACUUM 실행을 통해 이러한 문제를 완화할 필요가 있습니다.", "coaching_comment": "구체적인 예시와 함께 xmin horizon과 dead tuple 회수의 지연이 테이블 bloat에 미치는 영향을 명확히 설명하세요."}, "latency_sec": 31.289, "in_tokens": 789, "out_tokens": 461} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 백엔드 개발에서 흔히 발생하는 문제입니다. 제가 경험한 사례로는 캡스톤 프로젝트에서의 API 통합 지연이 있습니다. 당시 프론트엔드 팀원과 API 스펙 해석 차이로 인해 통합이 2주 지연되었습니다. 저는 먼저 OpenAPI 명세를 작성하고, Mock 서버를 통해 병렬 개발을 제안했습니다. 이 과정에서 제 의견을 고집하기보다는 두 가지 대안을 비교하며 조율하는 방식으로 접근해 갈등을 해결했습니다. 결과적으로 스프린트 중 통합 이슈가 3건에서 0건으로 줄었고, 팀워크가 개선되었습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정 방식의 필요성을 배웠습니다.", "answer_rewrite": "저는 이전 캡스톤 프로젝트에서 프론트엔드 팀원과의 의견 충돌로 인해 API 통합이 지연된 경험이 있습니다. 당시 우리는 서로 다른 해석으로 인해 2주 동안 통합을 하지 못했습니다. 저는 OpenAPI 명세를 작성하고 Mock 서버를 제안하여 병렬 개발을 가능하게 했습니다. 하지만 초기에는 제 방식만 옳다고 주장해 팀원과 감정이 상하기도 했습니다. 이후, 두 가지 대안을 비교하며 결정하는 방식으로 접근법을 수정했고, 그 결과 스프린트 중 통합 이슈가 3건에서 0건으로 감소했습니다. 이 경험을 통해 소통의 중요성과 유연한 협업의 가치를 깨달았습니다.", "coaching_comment": "구체적인 사례와 수치적 결과를 포함하여 STAR 구조를 명확히 활용한 점이 좋습니다. 다만, 감정 상했던 부분을 더 솔직하게 언급해 개선 의지를 보여주는 것이 중요합니다."}, "latency_sec": 45.13, "in_tokens": 1020, "out_tokens": 297} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 3, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 **멱등 키(Idempotent Key)**와 **Outbox 패턴**을 결합한 것은 매우 효과적인 접근이었습니다. 멱등 키는 동일한 요청이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 보장합니다. 예를 들어, 결제 시스템에서 '주문 ID'를 멱등 키로 사용하면, 결제 승인 콜백이 지연되어 같은 주문이 두 번 처리되는 상황을 방지할 수 있습니다.\n\n반면 Outbox 패턴은 비동기 메시징에서 트랜잭션 경계를 명확히 하여, 메시지 발행이 완료되기 전까지 데이터베이스 작업이 롤백되지 않도록 합니다. 이 조합은 다음과 같은 실패 케이스를 방지합니다: 1) 결제 승인 콜백 지연으로 인한 중복 주문(멱등 키로 해결), 2) 메시지 큐 장애 시 데이터 손실(Outbox로 보장). 실제로 이 두 패턴을 적용한 후, 중복 주문이 완전히 제거되어 시스템 안정성이 크게 향상되었습니다.", "answer_rewrite": "결제 승인 콜백 지연 문제를 해결하기 위해 **멱등 키**와 **Outbox 패턴**을 사용했습니다. 멱등 키는 동일한 요청이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 하여, 결제 승인 지연 시 발생할 수 있는 **중복 주문 문제**를 방지했습니다. Outbox 패턴은 비동기 메시징에서 트랜잭션 경계를 명확히 하여, 메시지 큐 장애 시에도 데이터 손실을 막아줍니다. 이 두 가지 패턴을 결합함으로써, 중복 주문이 0건으로 줄어드는 성과를 달성했습니다.", "coaching_comment": "구체적인 실패 사례와 해결 과정을 STAR 구조로 명확히 설명하면 더 설득력 있는 답변이 됩니다."}, "latency_sec": 74.012, "in_tokens": 1167, "out_tokens": 328} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 4, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시켜 `dead tuple` 회수를 지연시킵니다. 이는 `vacuum`이 실행될 때, 오래된 트랜잭션이 남긴 비활성 튜플들을 회수하지 못하게 하여 테이블의 **bloat**를 유발합니다. 예를 들어, 장시간 실행된 트랜잭션이 많은 데이터를 변경하고 롤백되지 않으면, 해당 트랜잭션의 `xmin` 값이 계속 유지되어 새로운 `vacuum`이 필요 이상의 시간을 소모하게 됩니다. 결과적으로 데이터베이스의 성능 저하와 저장 공간 낭비를 초래하며, 이는 정기적인 `vacuum` 및 `analyze` 작업의 필요성을 증가시킵니다.", "answer_rewrite": "오래 열린 트랜잭션은 PostgreSQL의 MVCC에서 **xmin horizon**을 확장시켜 `dead tuple` 회수를 지연시킵니다. 이로 인해 `vacuum` 작업이 비효율적으로 변하며, 테이블의 **bloat**가 발생합니다. 예를 들어, 장시간 실행된 트랜잭션이 많은 데이터를 변경하고 롤백되지 않으면, 해당 트랜잭션의 `xmin` 값이 계속 유지되어 새로운 `vacuum`이 필요 이상의 시간을 소모하게 됩니다. 결과적으로 데이터베이스 성능 저하와 저장 공간 낭비가 발생하며, 정기적인 `vacuum` 및 `analyze` 작업이 필수적이 됩니다.", "coaching_comment": "구체적인 예시와 함께 xmin horizon과 dead tuple 회수의 지연 효과를 명확히 설명해야 합니다."}, "latency_sec": 15.678, "in_tokens": 789, "out_tokens": 320} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 5, "ok": true, "coaching": {"model_answer": "**상황:** 캡스톤 프로젝트 중 프론트엔드 팀원과 API 스펙 해석 차이로 통합이 지연된 경험이 있습니다. **과제:** 두 팀 간의 의견 차이를 해결하고 프로젝트를 기한 내에 완료해야 했습니다. **행동:** 먼저 OpenAPI 명세를 작성하고, Mock 서버를 통해 병렬 개발을 제안했습니다. 이 과정에서 제 방식이 옳다고 고집하지 않고, 대안을 함께 검토하는 협업 방식을 도입했습니다. **결과:** 이후 스프린트에서 통합 이슈가 3건에서 0건으로 줄었으며, 팀워크가 개선되었습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정 과정의 가치를 배웠습니다.", "answer_rewrite": "**상황:** 캡스톤 프로젝트에서 프론트엔드 팀원과의 의견 충돌로 인해 API 통합이 지연된 경험이 있습니다. **과제:** 두 팀 간의 해석 차이를 해결하고 프로젝트를 기한 내에 마치기 위해 노력했습니다. **행동:** 먼저 OpenAPI 명세를 작성하고, Mock 서버를 구축하여 양 팀이 병렬로 개발할 수 있도록 했습니다. 초기에는 제 방식이 옳다고 주장했으나, 이후 대안 두 가지를 함께 검토하는 방식으로 변경해 팀원과의 감정을 개선했습니다. **결과:** 통합 이슈가 3건에서 0건으로 줄었고, 팀워크가 강화되었습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정 과정을 배웠습니다.", "coaching_comment": "STAR 구조를 활용해 구체적인 상황과 행동, 결과를 명확히 제시하세요."}, "latency_sec": 84.037, "in_tokens": 1020, "out_tokens": 280} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 6, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 결합한 이유는 각각의 패턴이 특정 실패 케이스를 방지하기 때문입니다. **멱등 키**는 동일한 요청이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 보장합니다. 예를 들어, 결제 시스템에서 '주문 ID'를 멱등 키로 사용하면, 동일한 주문 ID로 다시 호출이 오더라도 이미 처리된 주문으로 인식되어 중복 처리를 방지합니다. **Outbox 패턴**은 비동기 메시징 환경에서 트랜잭션 경계를 명확히 하여, 메시지 발행과 데이터베이스 업데이트가 동시에 완료되지 않는 상황에서도 데이터 일관성을 유지합니다. 결제 승인 콜백이 지연될 경우, Outbox는 주문이 실제로 처리되었음을 보장하지 않은 상태에서 메시지가 손실되지 않도록 합니다. 이 두 패턴을 함께 사용함으로써 **중복 주문 0건**이라는 성과를 달성했습니다.", "answer_rewrite": "결제 승인 콜백 지연이 발생했을 때 중복 주문을 방지하기 위해 멱등 키와 Outbox 패턴을 사용했습니다. **멱등 키는** 동일한 주문이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 하여, 예를 들어 결제 시스템에서 '주문 ID'를 키로 사용해 중복을 방지합니다. **Outbox 패턴은** 비동기 처리 환경에서 트랜잭션 경계를 명확히 해 메시지 발행 후 데이터베이스 업데이트가 완료되지 않더라도 데이터 일관성을 유지합니다. 이 두 접근법을 결합하여, 결제 승인 콜백 지연으로 인한 중복 주문 문제를 효과적으로 해결했고, 결과적으로 중복 주문이 0건으로 감소했습니다.", "coaching_comment": "실패 케이스를 구체적으로 설명하고, 각 패턴의 역할을 실제 상황에 맞춰 명확히 연결하세요."}, "latency_sec": 84.092, "in_tokens": 1167, "out_tokens": 325} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 7, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시켜 `dead tuple` 회수를 지연시킵니다. 이로 인해 테이블의 **bloating**이 발생할 수 있습니다. 구체적으로, 오래된 트랜잭션이 락을 유지하며 `xmin` 값이 계속 증가하면, `vacuum`이 불필요하게 많은 튜플을 검사해야 하므로 성능이 저하됩니다. 결과적으로, 정기적으로 `vacuum`과 `analyze`를 실행하지 않으면 테이블이 점점 커지고 쿼리 성능도 떨어집니다.", "answer_rewrite": "오래 열린 트랜잭션은 PostgreSQL의 MVCC에서 **xmin horizon**을 확장시켜 **dead tuple** 회수를 지연시킵니다. 이로 인해 테이블의 **bloat(팽창)**이 발생하며, `vacuum` 작업이 비효율적으로 수행됩니다. 예를 들어, 특정 트랜잭션이 장시간 열려 있으면, 해당 트랜잭션이 처리한 데이터의 `xmin` 값이 계속 증가하여, 이후 실행되는 `vacuum`은 더 많은 튜플을 검사해야 하므로 성능이 저하되고 테이블 크기가 증가합니다. 따라서 정기적인 **vacuum**과 **analyze**가 필수적입니다.", "coaching_comment": "구체적인 예시와 성능 저하의 영향을 명확히 설명하여 이해를 돕는 것이 중요합니다."}, "latency_sec": 81.908, "in_tokens": 789, "out_tokens": 280} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 8, "ok": true, "coaching": {"model_answer": "저는 이전 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 인해 통합이 지연된 경험이 있습니다. **상황**으로, 우리는 OpenAPI 명세를 명확히 하고 Mock 서버를 구축하여 병렬 개발을 제안했습니다. **행동**으로는, 초기에 제 의견을 고집했으나 이후 대안 두 가지를 함께 검토하는 방식으로 전환했습니다. **결과**로, 스프린트 중 통합 이슈가 3건에서 0건으로 감소했고, 팀 내 소통도 개선되었습니다. 이 경험을 통해 의견 충돌 시 유연한 접근과 소통의 중요성을 배웠습니다.", "answer_rewrite": "이전 캡스톤 프로젝트에서 프론트엔드 팀원과의 API 해석 차이로 인해 통합이 지연된 적이 있습니다. **상황**: 우리는 OpenAPI 명세를 명확히 하고 Mock 서버를 구축하여 병렬 개발을 제안했습니다. **행동**: 처음에는 제 의견을 고집했으나, 이후 대안 두 가지를 함께 검토하는 방식으로 접근법을 수정했습니다. **결과**: 이 변경으로 스프린트 중 통합 이슈가 3건에서 0건으로 줄었고, 팀 내 소통이 개선되었습니다. 이를 통해 의견 충돌 시 유연한 소통과 협업의 중요성을 깨달았습니다.", "coaching_comment": "STAR 구조를 활용해 구체적인 상황, 행동, 결과를 명확히 제시하세요."}, "latency_sec": 76.653, "in_tokens": 1020, "out_tokens": 258} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 9, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 결합한 이유는 각각의 패턴이 다른 실패 케이스를 방지하기 때문입니다. **멱등 키**는 동일한 요청이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 보장합니다. 예를 들어, 결제 시스템에서 네트워크 문제로 결제 승인이 지연되어 동일한 주문이 두 번 처리되는 상황을 막습니다. **Outbox 패턴**은 비동기 메시징 환경에서 메시지를 발행하고 실제로 전달되었는지 확인하는 메커니즘으로, 메시지 손실이나 중복 처리를 방지합니다. 이 둘을 함께 사용함으로써, 결제 승인 지연이 발생해도 주문 데이터가 중복 저장되지 않도록 하고, Kafka와 같은 이벤트 기반 시스템에서 메시지가 제대로 처리됐는지 확인할 수 있습니다. 결과적으로, 이러한 접근법은 중복 주문 0건을 달성하는 데 기여했습니다.", "answer_rewrite": "결제 승인 지연으로 인한 중복 주문 문제를 해결하기 위해 **멱등 키**와 **Outbox 패턴**을 사용했습니다. 멱등 키는 동일한 요청이 여러 번 전송되더라도 데이터베이스에 한 번만 반영되도록 하여, 결제 승인 지연이 발생해도 주문이 중복 처리되는 것을 방지합니다. Outbox 패턴은 비동기 메시징 환경에서 메시지가 제대로 전달되었는지 확인하는 역할을 하며, 메시지 손실이나 중복 처리를 막아줍니다. 이 두 가지 패턴을 결합함으로써, 결제 시스템의 신뢰성을 높이고 중복 주문 문제를 효과적으로 해결했습니다. 결과적으로, 이러한 접근법을 통해 중복 주문을 0건으로 줄일 수 있었습니다.", "coaching_comment": "실패 케이스를 구체적으로 예시와 함께 설명하여 패턴의 필요성을 명확히 전달하세요."}, "latency_sec": 80.712, "in_tokens": 1167, "out_tokens": 312} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 10, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시킵니다. 이는 오래된 트랜잭션이 종료되지 않으면, 해당 트랜잭션이 생성한 죽은 튜플(dead tuple)이 회수되지 않고 계속해서 테이블 공간을 차지하게 됩니다. 결과적으로 **테이블 부loat**가 발생하고, `VACUUM` 명령이 실행될 때 불필요한 시간 지연이 발생합니다. 구체적으로, 오래 열린 트랜잭션은 `xmin` 값을 증가시켜 더 많은 튜플을 `live`로 간주하게 만들고, 이로 인해 `VACUUM`이 실제로 회수해야 할 죽은 튜플의 수가 증가합니다. 이는 성능 저하와 디스크 공간 낭비로 이어집니다.", "answer_rewrite": "오래 열린 트랜잭션이 PostgreSQL의 MVCC에 미치는 영향은 다음과 같습니다: 오래된 트랜잭션은 `xmin horizon`을 확장시켜, 해당 트랜잭션이 생성한 **죽은 튜플(dead tuple)**이 회수되지 않고 테이블 공간을 차지하게 만듭니다. 이로 인해 **테이블 부loat**가 발생하며, `VACUUM` 실행 시 불필요한 시간 지연이 발생합니다. 예를 들어, 트랜잭션이 장시간 열려 있으면 `xmin` 값이 증가하여 더 많은 튜플이 살아있는 것으로 간주되고, 결과적으로 `VACUUM`이 처리해야 할 죽은 튜플의 수가 많아져 성능이 저하됩니다.", "coaching_comment": "구체적인 예시와 함께 `xmin horizon`과 테이블 부loat의 연관성을 명확히 설명하세요."}, "latency_sec": 68.192, "in_tokens": 789, "out_tokens": 323} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 11, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 개발 과정에서 흔히 발생하는 문제입니다. 제가 참여했던 캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 인해 통합이 지연된 경험이 있습니다. 당시 저는 OpenAPI 명세를 작성하고 Mock 서버를 제안하여 병렬 개발을 유도했습니다. 하지만 초기에는 제 방식이 옳다고 고집해 팀원의 감정을 상하게 했습니다. 이후, 결정 전에 대안 두 가지를 함께 비교하는 방식으로 접근법을 수정했고, 그 결과 스프린트 중 통합 이슈가 3건에서 0건으로 감소했습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정의 필요성을 배웠습니다.", "answer_rewrite": "저는 이전에 캡스톤 프로젝트에서 프론트엔드 팀원과 API 해석 차이로 인해 통합이 지연된 경험이 있습니다. 당시 저는 OpenAPI 명세를 작성하고 Mock 서버를 제안해 병렬 개발을 시도했으나, 제 의견을 고집하여 팀원과의 감정이 상하는 상황이 발생했습니다. 이후, 대안 두 가지를 함께 비교하는 방식으로 접근법을 수정했고, 그 결과 스프린트 중 통합 이슈가 3건에서 0건으로 줄었습니다. 이 경험을 통해 소통의 중요성과 유연한 의사결정의 필요성을 깨달았습니다.", "coaching_comment": "STAR 구조를 활용해 구체적인 상황, 행동, 결과를 명확히 제시하세요."}, "latency_sec": 64.773, "in_tokens": 1020, "out_tokens": 254} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 12, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 결합한 이유는 각각의 패턴이 특정 실패 케이스를 효과적으로 막기 때문입니다. **멱등 키**는 동일한 요청이 여러 번 발생하더라도 시스템이 이를 하나의 요청으로 인식하게 하여, 중복 주문과 같은 오류를 방지합니다. 예를 들어, 결제 시스템에서 네트워크 문제로 인해 콜백이 지연되더라도, 이미 처리된 주문에 대해 멱등 키를 통해 중복 처리를 차단할 수 있습니다.\n\n반면 **Outbox 패턴**은 비동기 메시징 환경에서 트랜잭션 경계를 명확히 하여, 메시지 발행이 실패했을 때 데이터 불일치가 발생하지 않도록 합니다. 예를 들어, 결제 승인 요청이 Kafka로 전송 중 실패할 경우, Outbox는 해당 주문이 실제로 처리되지 않았음을 보장하여, 후속 시스템에서 중복 처리를 방지합니다.\n\n결과적으로 이 두 패턴의 조합은 **네트워크 지연**으로 인한 콜백 실패(멱등 키)와 **메시지 전송 실패**(Outbox)에 모두 대응할 수 있어, 결제 시스템의 신뢰성을 크게 향상시켰습니다. 실제 구현에서는 주문 ID를 멱등 키로 사용하고, Kafka 메시지의 발행 상태를 Outbox로 관리하여 중복 주문 0건을 달성했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 해결하기 위해 **멱등 키**와 **Outbox 패턴**을 사용했습니다. 멱등 키는 동일한 요청이 여러 번 발생해도 하나의 요청으로 처리되도록 하여, 네트워크 지연이나 재시도 과정에서 발생하는 중복을 방지합니다. 예를 들어, 결제 승인 콜백이 지연되더라도 이미 처리된 주문에 대해 멱등 키를 통해 중복 처리를 차단할 수 있었습니다.\n\n한편 Outbox 패턴은 비동기 메시징 환경에서 트랜잭션 경계를 명확히 하여, 메시지 발행 실패 시 데이터 불일치를 예방합니다. Kafka로 결제 승인 요청을 전송하는 도중 문제가 발생해도, Outbox는 해당 주문이 실제로 처리되지 않았음을 보장하여 후속 시스템에서 중복을 방지했습니다. 이 두 패턴의 결합으로 네트워크 지연과 메시지 전송 실패 모두에 대응할 수 있었고, 결과적으로 중복 주문 0건을 달성했습니다.", "coaching_comment": "구체적인 사례와 정량적 결과를 포함하여 실패 케이스를 명확히 구분해야 합니다."}, "latency_sec": 72.852, "in_tokens": 1167, "out_tokens": 444} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 13, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 `xmin horizon`을 확장시켜 `dead tuple` 회수를 지연시킵니다. 이로 인해 테이블의 **bloat**가 발생할 수 있습니다.\n\n**상황:** 예를 들어, 오래된 트랜잭션이 계속 열려 있으면 해당 트랜잭션이 생성한 `xmin` 값이 증가합니다. 이 값이 높을수록 `vacuum`이 회수해야 할 죽은 행(dead tuple)의 기준이 높아집니다.\n\n**과제:** `vacuum`은 주기적으로 실행되어 테이블을 정리하지만, 오래 열린 트랜잭션으로 인해 `xmin horizon`이 커지면 `vacuum`이 효과적으로 작동하지 않습니다.\n\n**행동:** 이 경우, 개발자는 다음과 같은 조치를 취할 수 있습니다:\n - **트랜잭션 관리 최적화**: 불필요한 트랜잭션을 빠르게 종료하거나, 자동 커밋을 활용합니다.\n - **정기적인 Vacuum 실행**: 시스템 모니터링 도구를 활용해 `vacuum` 실행을 주기적으로 스케줄링합니다.\n - **테이블 재구성**: 심각한 bloat가 발생한 경우 `ANALYZE`와 함께 테이블 재구성을 고려합니다.\n\n**결과:** 이러한 조치를 통해 MVCC의 효율성을 유지하고, 성능 저하를 방지할 수 있습니다.", "answer_rewrite": "오래 열린 트랜잭션이 PostgreSQL의 MVCC에 미치는 영향을 설명하자면, 먼저 **xmin horizon**이 확장된다는 점이 중요합니다. 이는 `vacuum`이 회수해야 할 죽은 행(dead tuple)의 기준을 높이게 만듭니다.\n\n예를 들어, 오래된 트랜잭션이 열려 있으면 해당 트랜잭션에서 생성된 xmin 값이 증가합니다. 이로 인해 `vacuum`은 더 많은 데이터를 처리해야 하므로 **테이블 bloat**가 발생할 수 있습니다. 이는 결국 쿼리 성능 저하로 이어질 수 있죠.\n\n따라서, 이런 상황에서는 다음과 같은 접근이 필요합니다:\n - 트랜잭션을 효율적으로 관리하여 불필요한 장기 트랜잭션을 줄입니다.\n - 정기적으로 `vacuum`을 실행해 테이블을 최적화합니다.\n - 심각한 경우 테이블 재구성을 고려해볼 수 있습니다.", "coaching_comment": "구체적인 예시와 함께 xmin horizon과 bloat의 관계를 명확히 설명하는 것이 중요합니다."}, "latency_sec": 78.787, "in_tokens": 789, "out_tokens": 480} +{"label": "local-ax4-light", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 14, "ok": true, "coaching": {"model_answer": "팀원과 의견 충돌이 있었던 프로젝트에서, 저는 **구체적인 행동**으로 문제를 해결했습니다. 예를 들어, 캡스톤 프로젝트 중 API 스펙 해석 차이로 통합이 지연된 경험이 있습니다. 당시 저는 **OpenAPI 명세를 먼저 작성하고 Mock 서버를 구축**해 프론트엔드 팀과 병렬 개발을 제안했습니다. 이를 통해 **통합 이슈가 3건에서 0건으로 감소**하는 성과를 달성했습니다. 초기에는 제 방식을 고집했으나, 이후 **대안 두 가지를 함께 비교하는 의사결정 프로세스**로 전환하여 팀 내 갈등을 줄이고 협업을 강화했습니다. 이 경험을 통해 **소통과 유연한 의사결정의 중요성**을 깊이 깨달았습니다.", "answer_rewrite": "제가 이전에 참여했던 캡스톤 프로젝트에서 프론트엔드 팀원과의 의견 차이로 인해 통합이 지연된 경험이 있습니다. 이때 저는 **OpenAPI 명세를 작성하고 Mock 서버를 구축**하여 양 팀이 병렬로 작업할 수 있도록 제안했습니다. 그 결과, **통합 이슈가 3건에서 0건으로 줄어들었습니다**. 이 과정에서 처음에는 제 의견을 고집했으나, 이후 **대안 두 가지를 함께 검토하는 방식으로 접근법을 수정**해 팀 내 갈등을 줄이고 협업을 더 원활하게 만들었습니다. 이를 통해 **소통의 중요성과 유연한 의사결정**의 가치를 실감하게 되었습니다.", "coaching_comment": "STAR 구조를 활용해 구체적인 행동, 결과 및 배운 점을 명확히 제시하세요."}, "latency_sec": 76.632, "in_tokens": 1020, "out_tokens": 278} +{"label": "local-ax4-light", "suite": "followup:during-fanout", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "멱등 키를 사용함으로써 어떤 실패 케이스를 방지했다고 설명하셨나요? 구체적으로 예를 들어 설명해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 81.17, "ttft_sec": 78.919, "in_tokens": 1235, "out_tokens": 72} +{"label": "local-ax4-light", "suite": "fanout_wall", "wall_sec": 231.365, "ok": true} diff --git a/docs/research/llm-eval-2026-09/raw/local-kanana2-3b.jsonl b/docs/research/llm-eval-2026-09/raw/local-kanana2-3b.jsonl new file mode 100644 index 0000000..9c1f544 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/local-kanana2-3b.jsonl @@ -0,0 +1,63 @@ +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "븝 재 증 단 재 증 연 증 단 재 증 증 단 재 증 단 증 단 재 증 단 증 단 증 단 단 증 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.942, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.67, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.97, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.064, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.05, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "n 구 n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.078, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 credit", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 229.332, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "투 연 연 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 224.641, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "투 연 연 관 연 연 관 관 연 관 연 관 연 관 연 관 연 연 관 연 연 관 연 연 연 관 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 2.414, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "n 다 연 단 연 단 연 단 연 단 연 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 연 단 단 연 단 연 단 단 연 단 단 연 단 연 단 단 단 연 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 2.3, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.736, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.15, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "연 증 관 취 연 증 관 연 취 연 관 증 취 연 관 취 연 증 취 연 증 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 취 연 증 취 연 증 취 연 증 취 연 취 연 증 취 연 증 취 연 취 연 증 취 연 증 취 연 증 취 연 취 연 증 취 연 취 연 취 증 취 연 취 연 취 연 취 연 증 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 취 연 취 연 취 연 취 연 취 연 취 취 연 취 연 취 연 취 취 취 연 취 취 연 취 취 취 연 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 3.924, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.142, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "증 단 증 연 증 단 증 증 증 단 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.49, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.636, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.976, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.069, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.096, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.065, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "투 증 연 연 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 228.944, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "투 연 연 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 221.957, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 221.323, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "n 다 연 연 단 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.328, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.722, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.153, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "관 연 증 관 연 취 연 증 연 관 취 연 증 연 연 증 관 연 증 취 연 증 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 취 증 취 연 증 취 연 취 연 증 취 연 취 증 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 취 연 취 연 취 연 취 취 연 취 취 연 취 연 취 연 취 취 연 취 연 취 취 연 취 취 연 취 취 연 취 취 취 연 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 3.5, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.144, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "연 단 연 단 재 연 단 단 연 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.477, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.636, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.988, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.074, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.062, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "n 구 n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.093, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 229.354, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "투 증 연 연 관 연 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 222.658, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "재 연 관 연 관 연 관 연 관 연 연 증 연 연 관 연 연 연 관 연 연 연 연 연 관 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 2.405, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "n 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.272, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.72, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.145, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 증 취 연 취 연 증 취 연 취 연 취 연 취 증 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 취 연 취 연 취 연 취 취 연 취 연 취 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 연 취 취 연 취 연 취 취 연 취 취 취 취 취 연 취 취 연 취 취 취 취 연 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취 취", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 3.817, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 1.139, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": false, "error": "OutputParserException: Invalid json output: 뉴 늘 늘 구 늘 연 늘 구 증 관 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 243.608, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion \" \". Got: 1 validation error for CoachingResult\n Input should be a valid dictionary or instance of CoachingResult [type=model_type, input_value=' ', input_type=str]\n For further information visit https://errors.pydantic.dev/2.12/v/model_type\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 1.616, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": false, "error": "OutputParserException: Invalid json output: 번 연 증 연 연 증 연 연 증 연 연 증 연 연 연 증 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 2.577, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: 뉴 연 관 구 구 증 연 늘 증 신 증 증 연 늘 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 3.07, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion \" \". Got: 1 validation error for CoachingResult\n Input should be a valid dictionary or instance of CoachingResult [type=model_type, input_value=' ', input_type=str]\n For further information visit https://errors.pydantic.dev/2.12/v/model_type\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 1.607, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: 신 ㄴ 맡 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 2.43, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": false, "error": "OutputParserException: Invalid json output: 늘 늘 구 증 증 연 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 2.929, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion \" \". Got: 1 validation error for CoachingResult\n Input should be a valid dictionary or instance of CoachingResult [type=model_type, input_value=' ', input_type=str]\n For further information visit https://errors.pydantic.dev/2.12/v/model_type\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 1.603, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": false, "error": "OutputParserException: Invalid json output: 연 재 연 연 증 연 연 연 연 증 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연 연\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 2.492, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": false, "error": "OutputParserException: Invalid json output: 증 뉴 관 관 적 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 5.418, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": false, "error": "OutputParserException: Invalid json output: 관 구 구 구 구 구 구 구 관 관 구 관 관 관 구 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 5.02, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": false, "error": "OutputParserException: Invalid json output: 구 구 관 관 관 구 관 관 관 연 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 4.937, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": false, "error": "OutputParserException: Invalid json output: 재 구 구 증 구 구 증 구 관 구 관 구 증 구 관 구 구 증 증 관 증 증 관 증 증 증 증 연 증 증 관 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 4.943, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": false, "error": "OutputParserException: Invalid json output: 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 8.76, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: 뉴 관 뉴 관 관 구 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 3.739, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: 구 구 구 구 구 구 구 관 구 구 관 구 관 관 구 구 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 4.997, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: 구 구 구 관 관 구 구 관 관 관 연 관 연 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 5.002, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: 증 구 관 구 증 연 구 구 증 증 연 구 증 관 증 증 연 관 증 연 증 증 증 연 증 증 증 연 증 증 증 증 증 증 증 증 증 증 증 연 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증 증\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 5.068, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": false, "error": "OutputParserException: Invalid json output: 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관 관\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 8.726, "in_tokens": 0, "out_tokens": 0} +{"label": "local-kanana2-3b", "suite": "followup:cold", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "븝 연 증 단 연 증 단 연 증 단 증 연 단 증 연 단 증 단 증 단 연 증 단 증 단 연 증 단 증 단 증 단 단 증 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단 단", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 3.345, "ttft_sec": null, "in_tokens": null, "out_tokens": null} +{"label": "local-kanana2-3b", "suite": "followup:after-cold", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 0.628, "ttft_sec": null, "in_tokens": null, "out_tokens": null} diff --git a/docs/research/llm-eval-2026-09/raw/local-midm2-mini.jsonl b/docs/research/llm-eval-2026-09/raw/local-midm2-mini.jsonl new file mode 100644 index 0000000..8629894 --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/local-midm2-mini.jsonl @@ -0,0 +1,80 @@ +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "Outbox 패턴을 적용했을 때 구체적으로 어떤 트랜잭션 실패 케이스를 막으려고 했는지, 멱등 키와 함께 사용하신 이유는 무엇인지 좀 더 자세히 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.359, "ttft_sec": null, "in_tokens": 1723, "out_tokens": 80} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 사용한 구체적인 사례나 상황에 대해 좀 더 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.187, "ttft_sec": null, "in_tokens": 1613, "out_tokens": 60} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향을 구체적으로 어떤 방식으로 설명하셨는지 궁금합니다.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.578, "ttft_sec": null, "in_tokens": 1584, "out_tokens": 61} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18에서 자동 배칭이 이전 버전과 어떻게 다른지 구체적으로 설명해 주실 수 있나요? 특히 비동기 콜백 내부 업데이트도 배칭되는지 여부를 명확히 해주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.885, "ttft_sec": null, "in_tokens": 1588, "out_tokens": 75} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 잡으신 구체적인 이유나 근거에 대해 설명해주실 수 있나요? 특히 어떤 기술 선택이나 경험을 바탕으로 이 수치를 결정하셨는지 궁금합니다.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.899, "ttft_sec": null, "in_tokens": 1605, "out_tokens": 76} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "outbox 테이블을 읽는 릴레이 프로세스가 실제로 어떤 방식으로 구현되었는지 구체적인 기술 스택이나 언어를 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.665, "ttft_sec": null, "in_tokens": 1594, "out_tokens": 61} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정하신 구체적인 이유가 무엇인가요? 이전 답변에서는 서비스가 메모리를 많이 쓴다고만 언급하셨는데, 정확히 어떤 기술적/성능적 고려사항이 있었는지 설명해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.944, "ttft_sec": null, "in_tokens": 1840, "out_tokens": 86} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "그럼 거래내역 테이블의 월 단위 파티셔닝을 적용할 때, 구체적으로 어떤 컬럼들을 기준으로 분할하셨는지 설명해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 3.078, "ttft_sec": null, "in_tokens": 1933, "out_tokens": 76} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "react-window의 VariableSizeList를 사용한 가상화가 화면에 보이는 항목을 정확히 30개로 제한하셨다고 하셨는데, 그렇다면 실제 프로젝트에서는 이 숫자가 어떻게 결정되었는지 그 기준이나 방법론이 있었는지 궁금합니다.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 3.222, "ttft_sec": null, "in_tokens": 1925, "out_tokens": 87} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "통합 이슈가 3건에서 0건으로 줄었다고 하셨는데, 구체적으로 어떤 API 스펙 해석 차이였는지 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.946, "ttft_sec": null, "in_tokens": 1668, "out_tokens": 65} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "의견 충돌 시 구체적으로 어떤 방식의 '대화'를 시도하셨는지, 그리고 그 대화에서 상대방과 '서로 다른 의견'이 무엇이었는지 조금 더 자세히 말씀해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.469, "ttft_sec": null, "in_tokens": 1613, "out_tokens": 72} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "그럼 재고 동시성 제어를 위해 사용한 '레디스(Redis)'는 구체적으로 어떤 기술인가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.753, "ttft_sec": null, "in_tokens": 1636, "out_tokens": 61} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "주문 생성 시 OrderCreated 이벤트 발행 시점과 결제 승인 시 PaymentApproved 이벤트 발행 시점 사이에 구체적인 시간차를 어떻게 설정하셨나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.83, "ttft_sec": null, "in_tokens": 1890, "out_tokens": 67} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "네트워크 요청이 40% 감소했다고 하셨는데, 구체적으로 어떤 유형의 네트워크 요청들이 감소했는지 예시를 들어 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.813, "ttft_sec": null, "in_tokens": 1633, "out_tokens": 63} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "Outbox 패턴을 도입할 때 구체적으로 어떤 데이터베이스 트랜잭션과 Kafka 발행 사이의 폴링 방식을 사용하셨는지 설명해주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.146, "ttft_sec": null, "in_tokens": 1723, "out_tokens": 65} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 사용한 이유는 어떤 상황에서 중복 주문 문제를 방지할 수 있다고 말씀하셨는데, 구체적으로 어떤 실패 케이스들을 각각의 기술이 막을 수 있는지 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.5, "ttft_sec": null, "in_tokens": 1613, "out_tokens": 80} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "PostgreSQL에서 오래 열린 트랜잭션이 vacuum 작업 시 어떤 구체적인 영향을 주는지 수치적 예시를 들어 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.599, "ttft_sec": null, "in_tokens": 1584, "out_tokens": 62} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "React 18의 automatic batching이 이전 버전과 다른 점을 구체적으로 설명해 주실 수 있나요? 특히 비동기 콜백 내부 업데이트에서 어떻게 달라지는지 수치나 사례를 들어 말씀해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.908, "ttft_sec": null, "in_tokens": 1588, "out_tokens": 76} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정하신 구체적인 이유와 트래픽 피크에 사전 스케일아웃을 병행한 기술적 근거가 무엇인가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.714, "ttft_sec": null, "in_tokens": 1605, "out_tokens": 64} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "outbox 테이블을 읽는 릴레이 프로세스가 정확히 어떤 방식으로 동작하는지 구체적으로 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.829, "ttft_sec": null, "in_tokens": 1594, "out_tokens": 71} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정하신 이유와 사전 스케일아웃을 별도로 운영하지 않으신 구체적인 기술적 근거를 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.839, "ttft_sec": null, "in_tokens": 1840, "out_tokens": 80} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "그럼 구체적으로 어떤 복합 인덱스를 사용하셨는지 설명해 주시겠어요? (user_id, created_at) 외에 다른 컬럼도 포함되었는지 궁금합니다.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.973, "ttft_sec": null, "in_tokens": 1933, "out_tokens": 69} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "react-window로 타임라인 가상화 시 30개 항목만 렌더링한다고 하셨는데, 구체적으로 어떤 기준으로 30개를 선택하셨는지 수치나 사례를 들어 설명해주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 3.081, "ttft_sec": null, "in_tokens": 1925, "out_tokens": 79} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "API 통합 이슈가 3건에서 0건으로 줄었다는 수치를 구체적으로 어떤 방식으로 측정했는지 설명해주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.944, "ttft_sec": null, "in_tokens": 1668, "out_tokens": 65} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "그럼 '의견이 다를 때'라고 하셨는데, 구체적으로 어떤 상황에서 의견 충돌을 경험하셨나요? 단순히 '대화를 많이 한다'는 것 말고 실제 사례가 있는지 말씀해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.592, "ttft_sec": null, "in_tokens": 1613, "out_tokens": 81} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "그럼 낙관적 락을 사용할 때 구체적으로 어떤 버전 충돌이 발생했는지 예시를 들어 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.782, "ttft_sec": null, "in_tokens": 1636, "out_tokens": 63} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "주문 서비스와 결제 서비스 간의 Saga 흐름에서 'OrderCreated' 이벤트 발행 시점과 'PaymentApproved' 이벤트 소비 시점 사이에 트랜잭션 격리 시간이 얼마나 되는지 구체적으로 설명해주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.998, "ttft_sec": null, "in_tokens": 1890, "out_tokens": 77} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "네트워크 요청이 40% 줄었다는 부분에서 구체적으로 어떤 화면이나 상황에서 그런 효과를 경험하셨는지 수치적 예시로 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.991, "ttft_sec": null, "in_tokens": 1633, "out_tokens": 72} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "Outbox 패턴을 적용할 때 '주문 저장과 Kafka 발행이 한 트랜잭션이 아니어서'라는 설명 외에 구체적으로 어떤 상황에서 이벤트가 발행되지 않는지 더 자세히 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.31, "ttft_sec": null, "in_tokens": 1723, "out_tokens": 76} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 사용한 구체적인 사례가 결제 시스템에서 어떤 중복 주문 방지 실패 케이스를 막았는지 설명해주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.33, "ttft_sec": null, "in_tokens": 1613, "out_tokens": 68} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "그럼 PostgreSQL에서 MVCC가 오래 열린 트랜잭션이 vacuum에 미치는 영향을 구체적으로 어떻게 설명하시나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.533, "ttft_sec": null, "in_tokens": 1584, "out_tokens": 58} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "이전 버전과 비교하여 React 18의 자동 배칭이 비동기 콜백 내부 업데이트에 어떻게 영향을 미치는지 구체적인 예를 들어 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.862, "ttft_sec": null, "in_tokens": 1588, "out_tokens": 74} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정한 구체적인 기술적 근거가 무엇인가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.581, "ttft_sec": null, "in_tokens": 1605, "out_tokens": 55} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "아웃박스(outbox) 테이블을 읽을 때 별도 프로세스로 폴링하셨다고 하셨는데, 그 프로세스가 구체적으로 어떤 주기로 작동하는지 설명해주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.918, "ttft_sec": null, "in_tokens": 1594, "out_tokens": 74} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정한 구체적인 이유가 무엇인가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 3.193, "ttft_sec": null, "in_tokens": 1840, "out_tokens": 103} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "그럼 pg_stat_statements로 상위 쿼리를 뽑았을 때 구체적으로 어떤 SQL 문을 확인하셨나요? 특히 어떤 부분에서 seq scan이 발생했는지 상세히 말씀해 주세요.", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 3.144, "ttft_sec": null, "in_tokens": 1933, "out_tokens": 80} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "react-window에서 VariableSizeList를 사용하신 이유가 화면에 보이는 항목만 렌더링했기 때문이라고 하셨는데, 정확히 몇 개의 항목을 보여주는 것으로 설정하셨는지 구체적인 수치를 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 3.148, "ttft_sec": null, "in_tokens": 1925, "out_tokens": 82} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "통합 일정을 되돌리는 과정에서 OpenAPI 명세를 먼저 작성하셨다고 하셨는데, 구체적으로 어떤 API 엔드포인트와 메소드들을 정의하셨는지 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.213, "ttft_sec": null, "in_tokens": 1668, "out_tokens": 79} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "의견 충돌 시 '대화를 많이 한다'고 하셨는데, 구체적으로 어떤 방식의 대화를 시도했는지 말씀해 주세요. 예를 들어, 어떤 주제로, 몇 번이나 대화했는지 등 구체적인 사례가 있으신가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.635, "ttft_sec": null, "in_tokens": 1613, "out_tokens": 85} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "그럼 낙관적 락을 사용했을 때 정확히 몇 건의 버전 충돌이 발생했는지 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.754, "ttft_sec": null, "in_tokens": 1636, "out_tokens": 61} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "주문-결제-재고 흐름에서 결제 서비스가 'PaymentFailed' 이벤트를 발행한다고 하셨는데, 이 이벤트에 어떤 구체적인 필드들이 포함되나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.955, "ttft_sec": null, "in_tokens": 1890, "out_tokens": 74} +{"label": "local-midm2-mini", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "그럼 TanStack Query에서 staleTime을 화면별로 다르게 설정했다고 하셨는데, 구체적으로 몇 초 단위로 설정하셨는지 수치를 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 2.005, "ttft_sec": null, "in_tokens": 1633, "out_tokens": 75} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"멱등 키는 트랜잭션 내에서 동일한 주문에 대한 중복 연산을 방지하여 한 번의 결제 승인 콜백만 처리되도록 합니다.\", \"title\": \"멱등 키 설명\"}, {\"type\": \"string\", \"description\": \"Outbox 패턴은 각 트랜잭션이 독립적으로 실행되어 트랜잭션 간 충돌 없이 안전하게 데이터를 처리할 수 있도록 보장합니다.\", \"title\": \"Outbox 패턴 설명\"}], \"default\": null, \"title\": \"멱등 키와 Outbox 패턴의 역할\"}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"결제 승인 콜백 지연으로 인한 중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 ", "latency_sec": 9.36, "in_tokens": 1639, "out_tokens": 386} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"title\": \"Model Answer\", \"description\": \"PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum 작업에 여러 가지 영향을 미칩니다. 먼저, xmin horizon이 오래된 트랜잭션으로 인해 증가합니다. 이는 더 많은 dead tuples이 생성되어 vacuum 작업 시 회수해야 하는 대상이 많아지게 만듭니다. 또한, 오래된 트랜잭션이 메모리를 계속 점유함에 따라 테이블 bloat 현상이 발생할 수 있습니다. 이러한 상황은 데이터베이스 성능 저하로 이어질 수 있으며, 정기적인 vacuum 작업과 적절한 xmin horizon 설정이 필요합니다.\", \"type\": \"string\"}, \"answer_rewrite\": {\"title\": \"Answer Rewrite\", \"description\": \"PostgreSQL의 MVCC에서 오", "latency_sec": 5.467, "in_tokens": 1272, "out_tokens": 291} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"의견 충돌 상황에서의 구체적 행동과 결과를 명확히 제시\"}, {\"type\": \"null\", \"description\": \"구체적인 경험이 없는 경우 일반적인 접근 방식을 설명\"}], \"default\": null, \"title\": \"Model Answer\", \"description\": \"팀원과의 의견 충돌 상황에서 어떻게 행동했는지, 그 결과가 어떠했는지를 구체적으로 설명하고 배운 점을 강조하는 답변 구조\"}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"지원자의 실제 경험을 바탕으로 STAR 형식에 맞춰 개선한 답변\"}, {\"type\": \"null\", \"description\": \"구체적인 상황과 행동, 결과를 명확하게 서술", "latency_sec": 5.8, "in_tokens": 1530, "out_tokens": 249} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"title\": \"Model Answer\", \"content\": \"결제 시스템에서 중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용한 이유는 각각의 특성이 서로 다른 실패 케이스를 커버하기 때문입니다. 멱등 키는 트랜잭션 내에서 동일한 요청에 대해 여러 번 처리되더라도 일관된 결과를 보장하여, 예를 들어 결제 승인 콜백 지연으로 인한 재시도 상황에서 중복 주문을 방지합니다. 반면 Outbox 패턴은 외부 시스템과의 비동기 통신 시 발생할 수 있는 예외 상황(예: 네트워크 오류)으로 인한 데이터 손실이나 중복 발행을 처리하는 데 효과적입니다. 이 두 가지 접근 방식을 결합함으로써, 트랜잭션 내에서의 일관성 문제와 외부 시스템 간 통신 중 발생할 수 있는 다양한 실패 케이스를 모두 커버할 수 있었습니다.\"}, \"answer_rewrite\": {\"ti", "latency_sec": 8.018, "in_tokens": 1639, "out_tokens": 366} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 xmin horizon을 증가시켜 dead tuple 회수를 지연시키고, 결과적으로 테이블 bloat를 유발할 수 있습니다.\"}, {\"type\": \"null\"}], \"title\": \"Model Answer\", \"description\": \"PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 xmin horizon을 증가시켜 dead tuple 회수를 지연시키고, 이는 결국 테이블 bloat로 이어질 수 있습니다. 이러한 현상은 특히 트랜잭션이 장기간 열려 있을 때 발생하며, 데이터베이스 성능에 영향을 미칠 수 있습니다.\"}, \"answer_rewrite\": {\"anyOf\"", "latency_sec": 6.606, "in_tokens": 1272, "out_tokens": 365} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"의견 충돌 상황과 해결 과정을 구체적으로 설명\"}, {\"type\": \"null\", \"description\": \"구체적인 경험이 없을 경우 대체 가능한 일반적인 접근 방법 제시\"}], \"default\": null, \"title\": \"Model Answer\", \"properties\": {\"situation\": \"의견 충돌이 발생한 구체적인 상황 설명\", \"task\": \"해결해야 했던 과제 명확히 기술\", \"actions\": \"어떤 행동을 취했는지 구체적으로 서술\", \"result\": \"결과와 배운 점 명시\"}}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"구체적인 상황과 해결 과정을 두괄식으로 설명\"}, {\"type\": \"", "latency_sec": 7.421, "in_tokens": 1530, "out_tokens": 352} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"situation\": \"결제 승인 콜백 지연으로 인해 중복 주문이 발생하는 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다.\", \"task\": \"멱등성을 보장하는 트랜잭션 경계 설정과 동시성 제어를 통해 중복 주문을 방지하는 것이 주요 과제였습니다.\", \"action\": \"먼저, 결제 승인 테이블에 고유한 멱등 키를 설정하여 한 번의 결제 요청이 여러 번의 호출에도 동일한 결과를 보장하도록 했습니다. 또한, Outbox 패턴을 적용하여 결제 승인 콜백 메서드에서 발생할 수 있는 예외 상황을 트랜잭션 경계 안에서 처리함으로써 트랜잭션 내 모든 작업이 성공적으로 완료되거나 모두 취소되도록 설계했습니다.\", \"result\": \"이를 통해 중복 주문 문제를 완전히 해결하여 일 평균 12만 건의 주문을 처리하는 환경에서도 안정적인 서비스 운영이 가능해졌습", "latency_sec": 5.733, "in_tokens": 1639, "out_tokens": 216} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion null. Got: 1 validation error for CoachingResult\n Input should be a valid dictionary or instance of CoachingResult [type=model_type, input_value=None, input_type=NoneType]\n For further information visit https://errors.pydantic.dev/2.12/v/model_type\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langchain/errors/OUTPUT_PARSING_FAILURE ", "latency_sec": 8.119, "in_tokens": 1272, "out_tokens": 468} +{"label": "local-midm2-mini", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"title\": \"Model Answer\", \"description\": \"저는 과거 프로젝트에서 API 스펙 해석 차이로 인한 개발 지연 경험이 있습니다. 당시 프론트엔드와 백엔드 간의 통합 문제를 해결하기 위해 OpenAPI 명세를 먼저 작성하고 Mock 서버를 구축하여 병렬 개발을 제안했습니다. 이 과정에서 대안 두 가지를 함께 비교하는 방식으로 접근하여 초기 3건의 통합 이슈를 0건으로 줄였습니다. 이후에는 결정 전에 다양한 해결책을 검토하는 문화를 정착시켰습니다.\", \"type\": \"array\"}, \"answer_rewrite\": {\"title\": \"Answer Rewrite\", \"description\": \"과거 캡스톤 프로젝트에서 API 스펙 해석 차이로 개발이 지연된 경험이 있습니다. 프론트엔드와 백엔드 간의 통합 문제를 해결하기 위해 OpenAPI 명세를 ", "latency_sec": 6.288, "in_tokens": 1530, "out_tokens": 280} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "TECH_CHOICE", "question": "결제 콜백 지연 문제를 해결할 때 사용한 멱등 키와 Outbox 패턴의 구체적인 구현 방식은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키 설계 방식과 Outbox 패턴 적용 과정에서의 구체적 구현 방법을 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 프로젝트에서 Kafka 기반 이벤트 파이프라인을 설계할 때 직면했던 주요 기술적 도전과제는 무엇이었고 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일", "expected_signal": "Kafka 토픽 설계와 메시지 처리 로직의 구현 방식을 구체적으로 설명"}, {"category": "TECH_CHOICE", "question": "정산 배치 성능 개선에서 QueryDSL 튜닝과 인덱스 재설계를 통해 5시간에서 40분으로 단축한 구체적인 방법은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "쿼리 최적화 기법과 인덱스 설계 전략을 구체적으로 설명"}, {"category": "BEHAVIORAL", "question": "3년간 커머스 도메인에서 일하면서 가장 어려웠던 기술적 난관은 무엇이었고, 이를 극복하기 위해 어떤 리더십을 발휘했나요?", "job_category": "BACKEND", "target_evidence": "", "expected_signal": "기술적 난관 극복 과정에서의 구체적 행동과 리더십 발휘 사례를 STAR 형식으로 설명"}, {"category": "TECH_CHOICE", "question": "Kafka 기반 이벤트 파이프라인 설계 시 성능 최적화를 위해 고려한 주요 요소들은 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "", "expected_signal": "Kafka 토픽 구조, 메시지 처리량, 지연 시간 등의 기술적 고려사항을 구체적으로 설명"}], "latency_sec": 17.239, "in_tokens": 2851, "out_tokens": 531} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"React 18에서 virtualize timeline 구현 시 성능 개선을 위해 window 가상화를 도입했다고 했는데, 구체적으로 어떤 방식으로 스크롤 끊김 문제를 해결했는지 설명해 주세요.\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"react-window 가상화 도입, INP 480ms -> 120ms\"}, {\"question\": \"Kakao Map SDK에서 500개 마커를 클러스터링할 때 useMemo로 좌표 변환을 캐싱했다고 했는데, 이 최적화가 실제 성능에 어떤 영향을 미쳤는지 수치적으로 설명해 주실 수 있나요?\", \"category\": \"PROJECT_DEEP_DIVE\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"Kakao Map SDK 마커 500개를 클러스터링\"}, {\"question\": \"오프라인 편집 시 IndexedDB(Dexie)에 낙관적 업데이트를 저장한다고 했는데, 실제 서비스에서 충돌 상황이 발생했을 때 어떤 방식으로 해결했는지 말씀해 주세요.\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"IndexedDB(Dexie) 낙관적 업데이트\"}, {\"question\": \"Vitest 단위 테스트 42개와 Playwright", "latency_sec": 12.553, "in_tokens": 2711, "out_tokens": 436} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"Terraform으로 VPC와 RDS를 환경별로 분리하신 경험에서, 실제 개발환경과 운영환경 간의 보안 차이로 인해 발생한 이슈는 무엇이었고 어떻게 해결하셨나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리\"}, {\"question\": \"ArgoCD GitOps 도입으로 배포 리드타임을 1일에서 30분으로 단축한 경험에 대해 구체적으로 설명해주세요. 이 과정에서 팀원들과의 협업 방식은 어떻게 변화했나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분\"}, {\"question\": \"PostgreSQL 운영에서 복합 인덱스 재설계와 파티셔닝을 통해 쿼리 성능을 개선한 경험에 대해 설명해주세요. 구체적으로 어떤 테이블과 인덱스를 대상으로 하셨나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"DBA\", \"targetEvidence\": \"슬로우 쿼리 p95 2.3초 → 180ms\"}, {\"question\": \"장애 상황에서 CloudWatch 알람과 스토리지 오토스케일링을 적용한 경험에 대해 설명해주세", "latency_sec": 14.671, "in_tokens": 2688, "out_tokens": 559} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"알림 봇 개발 시 동시 쓰기 락 문제를 해결하기 위해 PostgreSQL로 전환하셨다고 하셨는데, 구체적으로 어떤 트랜잭션 격리 수준을 적용하셨고 그 결과는 어떠했나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다.\", \"expectedSignal\": \"PostgreSQL의 트랜잭션 격리 수준과 적용 결과에 대한 구체적 설명\"}, {\"question\": \"프론트엔드와 API 스펙 해석 차이로 2주간 지연된 프로젝트에서 OpenAPI 명세를 먼저 작성하셨다고 하셨는데, 이 과정에서 어떤 도구를 사용하셨고 팀 내 소통 방식은 어떻게 바꾸셨나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.\", \"expectedSignal\": \"사용한 도구와 소통 방식 변화에 대한 구체적 설명\"}, {\"question\": \"알림 봇 프로젝트에서 새벽 크롤러 오류 시 동아리원들의 항의를 직접 받으셨다고 하셨는데, 그 상황에서 본인이 취한 구체적인 행동과 배운 점은 무엇이었", "latency_sec": 15.301, "in_tokens": 2667, "out_tokens": 602} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"결제 승인 콜백 지연으로 인한 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결할 때 구체적으로 어떤 데이터 구조를 설계하셨나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성\", \"expectedSignal\": \"멱등 키 설계 방식과 Outbox 패턴 적용 방법을 구체적으로 설명\"}, {\"question\": \"MSA 전환 과정에서 Kafka 기반 이벤트 파이프라인을 설계할 때 어떤 아키텍처 패턴을 사용하셨고, 그 이유는 무엇인가요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입\", \"expectedSignal\": \"Kafka 패턴 선택의 기술적 근거와 구현 방식 설명\"}, {\"question\": \"정산 배치 성능을 5시간에서 40분으로 개선할 때 QueryDSL 튜닝 외에 어떤 최적화 기법을 적용하셨나요?\", \"category\": \"TECH_FUNDAMENTAL\", \"jobCategory\": \"BACKEND\", \"targetEvidence", "latency_sec": 20.253, "in_tokens": 3766, "out_tokens": 546} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"결제 콜백 지연 문제를 해결할 때 사용한 멱등 키와 Outbox 패턴의 구체적인 구현 방식은 무엇이었나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성\", \"expectedSignal\": \"멱등 키 설계 방식과 Outbox 패턴 적용 과정을 구체적으로 설명\"}, {\"question\": \"Kafka 기반 이벤트 파이프라인에서 트랜잭션성을 보장하기 위해 사용한 구체적인 전략은 무엇이었나요?\", \"category\": \"PROJECT_DEEP_DIVE\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일\", \"expectedSignal\": \"Kafka 트랜잭션성 보장을 위한 구체적인 설계 결정과 구현 방법 설명\"}, {\"question\": \"MSA 전환 과정에서 주문 서비스 분리를 위해 선택한 데이터베이스 기술(PostgreSQL)의 선택 근거는 무엇이었나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"BACKEND\", \"t", "latency_sec": 13.278, "in_tokens": 2851, "out_tokens": 534} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"React 18에서 virtualize timeline 구현 시 INP를 480ms에서 120ms로 단축한 경험에 대해 구체적으로 설명해 주세요. 당시 어떤 최적화 기법을 사용하셨나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"react-window 가상화 도입\"}, {\"question\": \"Kakao Map SDK 마커 500개를 클러스터링할 때 useMemo로 좌표 변환을 캐싱한 경험에 대해 말씀해 주세요. 성능 개선 효과는 어떻게 측정하셨나요?\", \"category\": \"PROJECT_DEEP_DIVE\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"Kakao Map SDK 마커 렌더링\"}, {\"question\": \"오프라인 편집 시 IndexedDB(Dexie)에 낙관적 업데이트를 저장했다가 온라인 복귀 시 동기화하는 방식을 선택한 이유는 무엇인가요? 실제 구현 과정에서 어떤 어려움이 있었나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"오프라인 편집 기능\"}, {\"question\": \"Vitest 단위 테스트 42개와 Playwright E2E 6개를 통해 성능을 개선한 경험에 대해 설명해 주세요. 특히 Lighthouse 점수가 68에", "latency_sec": 12.492, "in_tokens": 2711, "out_tokens": 433} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"question\": \"EKS 클러스터에서 파드 수가 400개일 때, 장애 발생 시 대응 프로세스를 어떻게 설계하셨나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"EKS 기반 쿠버네티스 클러스터 3개 운영 (파드 약 400개)\", \"expectedSignal\": \"장애 대응 프로세스의 구체적 단계와 정량적 성과를 설명\"}, {\"question\": \"Terraform을 사용해 VPC·RDS·EKS 모듈화를 설계하신 경험에서, 보안 측면에서 가장 중요하게 고려한 요소는 무엇이었나요?\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(workspace 분리)\", \"expectedSignal\": \"보안 고려사항과 실제 적용 사례를 구체적으로 설명\"}, {\"question\": \"ArgoCD GitOps 도입 후 배포 리드타임이 1일에서 30분으로 단축된 경험에 대해 자세히 설명해 주세요.\", \"category\": \"TECH_CHOICE\", \"jobCategory\": \"INFRA\", \"targetEvidence\": \"ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분\", \"expectedSignal\": \"도입 전후 변화와 구체적인 개선점을 수치로 설명\"}, {\"", "latency_sec": 15.852, "in_tokens": 2688, "out_tokens": 626} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": true, "questions": [{"category": "TECH_CHOICE", "question": "알림 봇 개발 시 동시 쓰기 락 문제를 해결하기 위해 PostgreSQL로 전환한 경험에 대해 구체적으로 설명해 주세요. 당시 어떤 기술적 결정을 내렸고, 그 결과는 어떠했나요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다.", "expected_signal": "PostgreSQL으로 전환 시 적용한 기술적 해결책과 그 효과에 대한 구체적 설명"}, {"category": "BEHAVIORAL", "question": "프론트엔드와 API 스펙 해석 차이로 인한 통합 지연 상황에서 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 병렬 개발을 제안한 경험이 있습니다. 이 과정에서 어떤 역할을 했고, 팀 내 갈등은 어떻게 해결하셨나요?", "job_category": "BACKEND", "target_evidence": "프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다.", "expected_signal": "갈등 상황에서의 구체적 행동과 해결 과정, 배운 점에 대한 성찰"}, {"category": "BEHAVIORAL", "question": "새벽에 크롤러가 멈춰 공지 누락 시 동아리원들의 항의를 받은 경험을 통해 '멈추지 않는 서비스'의 중요성을 깨달았다고 하셨습니다. 이 경험이 현재 백엔드 개발 철학에 어떤 영향을 미쳤나요?", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "해당 경험이 현재 업무 철학과 가치관에 미친 구체적 영향"}, {"category": "TECH_CHOICE", "question": "알림 봇 개발 중 3일 동안 원인을 찾지 못해 PostgreSQL로 이전한 경험이 있습니다. 당시 어떤 기술적 도전과제가 있었고, 이를 통해 새롭게 학습한 점은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다.", "expected_signal": "기술적 도전과제와 그 해결 과정에서 얻은 구체적 학습 내용"}, {"category": "BEHAVIORAL", "question": "프론트엔드 팀원과의 협업에서 결정 전 대안을 비교하는 방식으로 바꾼 경험이 있습니다. 이 변화를 통해 팀 내 소통에 어떤 긍정적 영향이 있었는지 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "협업 방식 변화가 팀 소통과 개발 프로세스에 미친 구체적 영향"}], "latency_sec": 15.524, "in_tokens": 2667, "out_tokens": 614} +{"label": "local-midm2-mini", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "TECH_CHOICE", "question": "결제 콜백 지연으로 인한 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결한 과정을 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키 설계 방식과 Outbox 패턴 적용 과정을 구체적으로 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "MSA 전환 프로젝트에서 주문 서비스를 별도로 분리하고 Kafka 기반 이벤트 파이프라인을 설계한 경험에 대해 자세히 말씀해 주세요.", "job_category": "BACKEND", "target_evidence": "주문/결제 도메인 담당. 모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, DB 분리(PostgreSQL) 및 Kafka 기반 이벤트 발행/구독 구조 도입.", "expected_signal": "Kafka 토픽 설계와 데이터 흐름을 구체적으로 설명"}, {"category": "TECH_CHOICE", "question": "정산 배치 성능을 5시간에서 40분으로 개선한 방법과 그 과정에서 사용한 기술에 대해 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "QueryDSL 튜닝과 인덱스 최적화 방법을 구체적으로 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "재고 동기화 프로젝트에서 Redis 기반 캐시와 동시성 제어를 적용한 과정에 대해 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "실시간 재고 동기화 (2024) - Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "분산 락으로 전환한 구체적 이유와 구현 방식 설명"}, {"category": "BEHAVIORAL", "question": "알림 봇 개발 경험에서 새벽에 크롤러가 멈췄을 때 동아리원들의 항의를 받은 상황에서 어떻게 문제를 해결했는지 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "문제 해결 과정에서 본인의 구체적 역할과 의사결정 방식 설명"}], "latency_sec": 20.799, "in_tokens": 3766, "out_tokens": 574} +{"label": "local-midm2-mini", "suite": "followup:cold", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "Outbox 패턴을 도입할 때 사용한 '같은 DB 트랜잭션'이라는 표현이 어떤 구체적인 상황을 의미하는지 좀 더 자세히 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 7.673, "ttft_sec": null, "in_tokens": 1723, "out_tokens": 73} +{"label": "local-midm2-mini", "suite": "followup:after-cold", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 사용한 구체적인 사례나 기술적 근거가 무엇인지 설명해주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 1.192, "ttft_sec": null, "in_tokens": 1613, "out_tokens": 60} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"title\": \"Model Answer\", \"description\": \"결제 승인 콜백 지연으로 인한 중복 주문 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용한 이유는 두 가지 중요한 기술적 이점 때문입니다. 먼저, 멱등 키(Idempotent Key)는 동일한 트랜잭션 내에서 동일한 데이터에 대한 중복 연산이 발생해도 결과가 동일하게 유지되도록 하여 트랜잭션의 일관성을 보장합니다. 이는 결제 승인 과정에서 동일한 주문이 여러 번 승인되는 상황을 방지합니다. 반면 Outbox 패턴은 트랜잭션이 실패하더라도 이미 발행된 메시지를 보존하여 최종 상태를 안정적으로 유지할 수 있게 합니다. 이 두 가지 접근 방식을 함께 사용함으로써, 결제 승인 지연 시 발생할 수 있는 중복 주문 문제와 서비스 중단에 따른 롤백으로 인한 데이터 손실 문제 모두를 효과적으로 방", "latency_sec": 31.341, "in_tokens": 1639, "out_tokens": 397} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"description\": \"PostgreSQL의 MVCC(Multi-Version Concurrency Control)에서 오래 열린 트랜잭션은 테이블 bloat와 vacuum 성능에 중대한 영향을 미칩니다. 먼저, 트랜잭션이 오래 지속될수록 데이터 페이지에 대한 락(lock)이 유지되어 다른 트랜잭션의 동시성(concurrency)을 방해합니다. 이로 인해 테이블의 물리적 공간이 비효율적으로 사용되며, 이는 결국 table bloat 현상을 가속화시킵니다. 또한, MVCC에서는 각 행에 대해 여러 버전의 데이터가 존재하므로 dead tuple(더 이상 참조되지 않는 레코드) 회수 과정이 지연되어 vacuum 작업 시 더 많은 시간과 리소스를 소모하게 됩니다. 따라서 트랜잭션 관리와 적절한 commit/rollback 전략이 중요합니다.\"}, \"answer_rewri", "latency_sec": 18.414, "in_tokens": 1272, "out_tokens": 305} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 2, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"situation\": \"캡스톤 프로젝트에서 프론트엔드와 백엔드 API 스펙 해석 차이로 통합이 지연된 상황\", \"task\": \"OpenAPI 명세를 먼저 작성하고 Mock 서버를 통해 병렬 개발을 제안하여 문제 해결\", \"action\": \"대안 두 가지를 함께 비교하는 방식으로 협업 프로세스 개선\", \"result\": \"통합 이슈 3건에서 0건으로 감소\", \"learning\": \"소통의 중요성과 다양한 해결책 모색의 필요성 인식\"}, \"answer_rewrite\": {\"situation\": \"캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합에 지연이 발생한 상황\", \"task\": \"OpenAPI 명세를 먼저 작성하고 Mock 서버를 통해 병렬 개발을 제안하여 문제 해결 시도\", \"action\": \"결정 전 대안 두 가지 비교 방식으로 협업 프로세스 ", "latency_sec": 7.134, "in_tokens": 1530, "out_tokens": 267} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 3, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"멱등 키와 Outbox 패턴의 결합은 트랜잭션 내에서 중복 작업을 방지하고, 트랜잭션 실패 시에도 일관된 결과를 보장하기 위해 설계되었습니다.\", \"title\": \"Model Answer\"}, {\"type\": \"null\", \"description\": \"각 패턴이 어떤 실패 케이스를 막는지에 대한 설명이 필요합니다.\"}], \"default\": null}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"결제 승인 콜백 지연 문제는 트랜잭션 내에서 중복 작업을 발생시키는 주요 원인이었습니다. 멱등 키를 사용하여 각 주문의 고유성을 보장함으로써, 동일한 주문이 여러 번 처리되는 것을 방지할 수 있었습니다.\", \"title\": \"A", "latency_sec": 25.17, "in_tokens": 1639, "out_tokens": 294} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 4, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 테이블 bloat와 vacuum 작업에 영향을 미칩니다. 오래된 트랜잭션이 오래 열려있을수록, 해당 트랜잭션과 관련된 dead tuples이 더 많이 생성되어 나중에 vacuum 작업 시 더 많은 데이터를 회수해야 하므로 성능 저하가 발생할 수 있습니다.\"}, {\"type\": \"null\", \"description\": \"PostgreSQL의 MVCC는 각 트랜잭션을 별도로 관리하므로, 오래 열린 트랜잭션은 xmin horizon을 통해 해당 시점 이후의 모든 dead tuples을 포함할 수 있어 vacuum 작업 시 더 많은 데이터를 회수해야 합니다. 이는 테이블 bloat와 성능 저하로 이어질 수 있습니다.\"}]}, \"answer_r", "latency_sec": 13.893, "in_tokens": 1272, "out_tokens": 384} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 5, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"프로젝트에서 API 스펙 해석 차이로 인한 개발 지연 상황을 설명하고, OpenAPI 명세와 Mock 서버를 활용한 해결책을 제시함\"}, {\"type\": \"null\", \"description\": \"의견 충돌 시 대안 비교 방식으로 전환한 경험을 공유함\"}], \"title\": \"Model Answer\", \"description\": \"프로젝트에서 발생한 API 스펙 해석 차이로 인한 개발 지연 상황과 이를 해결하기 위해 OpenAPI 명세와 Mock 서버를 활용한 방법, 그리고 의견 충돌 시 대안 비교 방식으로 전환한 경험을 구체적으로 설명함\"}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"캡스톤 프로젝트에서 프론트엔드 팀", "latency_sec": 36.652, "in_tokens": 1530, "out_tokens": 313} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 6, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"situation\": \"결제 승인 콜백 지연으로 인해 주문 시스템에서 중복 주문이 발생하는 상황을 해결하기 위해 멱등 키와 Outbox 패턴을 함께 적용했습니다.\", \"transformation\": \"멱등 키는 동일한 주문에 대해 여러 결제 요청이 동시에 발생해도 일관된 결과를 보장하여 중복 주문을 방지합니다. 반면, Outbox 패턴은 트랜잭션 내에서 발생한 모든 작업의 결과를 한 번에 처리하여 오류 시 롤백함으로써 데이터 일관성을 유지합니다.\", \"result\": \"두 방법을 함께 사용함으로써 중복 주문 0건 달성과 동시에 시스템 안정성 향상을 이루었습니다.\"}, \"coaching_comment\": \"멱등성과 트랜잭션 경계의 개념을 구체적 사례로 설명하여 기술적 이해도를 보여주세요.\"}. Got: 1 validation error for CoachingResult", "latency_sec": 34.756, "in_tokens": 1639, "out_tokens": 172} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 7, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 xmin horizon과 dead tuple 회수에 영향을 줍니다.\"}, {\"type\": \"null\"}], \"title\": \"Model Answer\", \"content\": \"PostgreSQL의 MVCC(Multi-Version Concurrency Control) 환경에서는 여러 트랜잭션이 동시에 실행될 때 각 트랜잭션마다 버전된 데이터를 사용합니다. 이때 오래 열린 트랜잭션은 xmin horizon을 확장시켜 더 많은 dead tuple(죽은 튜플)을 생성하게 됩니다. 이로 인해 데이터베이스 성능 저하와 테이블 bloat 현상이 발생할 수 있습니다. 따라서 주기적인 vacuum 작업을 통해 이러한 dead tuples을 회수하고, ", "latency_sec": 36.83, "in_tokens": 1272, "out_tokens": 373} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 8, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"상황 설명과 구체적인 행동, 그리고 결과를 명확히 제시\"}, {\"type\": \"null\", \"description\": \"경험이 없을 경우 일반적인 접근 방식을 제안\"}], \"title\": \"Model Answer\", \"default\": null}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"구체적인 상황, 갈등의 원인과 본인의 행동, 그리고 결과를 상세히 설명\"}, {\"type\": \"null\", \"description\": \"경험이 없을 경우 STAR 구조로 접근 방법을 제안\"}], \"title\": \"Answer Rewrite\", \"default\": null}, \"coaching_comment\": \"지원자의 실제 경험을 ", "latency_sec": 35.209, "in_tokens": 1530, "out_tokens": 214} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 9, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"description\": \"결제 승인 콜백 지연 문제를 해결하기 위해 멱등 키와 Outbox 패턴을 함께 사용한 이유는 각각의 실패 케이스를 효과적으로 방지하기 위함입니다. 멱등 키는 동일한 주문 ID에 대해 중복된 결제 승인 요청이 발생하지 않도록 하여 트랜잭션 내에서 한 번만 처리되도록 보장합니다. 반면, Outbox 패턴은 각 결제 승인 콜백을 독립적인 트랜잭션으로 처리하여 네트워크 오류나 서버 장애 시에도 하나의 콜백만 손실되고 다른 모든 트랜잭션은 정상적으로 완료되도록 합니다. 이 두 접근 방식을 결합함으로써 중복 주문과 결제 실패를 모두 방지할 수 있었습니다.\", \"title\": \"Model Answer\"}, \"answer_rewrite\": {\"description\": \"결제 승인 지연 문제 해결을 위해 멱등 키와 Outbox 패턴을 함께 사용한 이유는 각", "latency_sec": 37.579, "in_tokens": 1639, "out_tokens": 406} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 10, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 xmin horizon을 증가시켜 dead tuple 회수를 지연시키고, 이로 인해 테이블 bloat가 발생할 수 있다.\"}, {\"type\": \"null\"}], \"title\": \"Model Answer\", \"description\": \"PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 미치는 영향에 대해 설명한다.\"}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"PostgreSQL에서 오래 열린 트랜잭션은 xmin horizon을 증가시켜 dead tuple 회수를 지연시키고, 이는 테이블 bloat로 이어질 수 있다. 이러한 문제는 특히 데이터베이스 성능 모니", "latency_sec": 30.064, "in_tokens": 1272, "out_tokens": 266} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 11, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"situation\": \"캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석 차이로 인해 통합이 지연되었습니다.\", \"task\": \"API 명세를 먼저 작성하고 Mock 서버를 통해 프론트가 병렬로 개발하도록 제안했습니다.\", \"action\": \"대안 두 가지를 함께 비교하는 방식으로 결정 전에 충분한 논의를 진행했습니다.\", \"result\": \"통합 이슈가 3건에서 0건으로 감소했으며, 이후 프로젝트 완료율이 향상되었습니다.\", \"outcome\": \"팀원과의 갈등을 해결하고 협업 효율성이 증가했습니다.\"}, \"answer_rewrite\": {\"situation\": \"캡스톤 프로젝트 중 프론트엔드 팀원과 API 스펙 해석 차이로 통합 지연이 발생했습니다.\", \"task\": \"API 명세를 먼저 작성하고 Mock 서버를 통해 프론트 개발을 병렬화하도록 제안했습니다.\"", "latency_sec": 31.319, "in_tokens": 1530, "out_tokens": 277} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 12, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"title\": \"Model Answer\", \"description\": \"멱등 키와 Outbox 패턴을 함께 적용한 이유는 각각의 실패 케이스를 명확히 구분하기 위함입니다. 멱등 키는 동일한 주문 ID에 대해 중복된 트랜잭션이 발생하더라도 하나만 처리되도록 보장하여 데이터 일관성을 유지합니다. 반면, Outbox 패턴은 트랜잭션 내에서 발생하는 모든 작업이 완전히 완료되거나 모두 취소될 수 있도록 하여 트랜잭션 경계에서 발생할 수 있는 오류를 격리시킵니다. 이를 통해 결제 승인 콜백 지연과 같은 상황에서 중복 주문 문제가 발생하지 않도록 합니다.\", \"type\": \"string\"}, \"answer_rewrite\": {\"title\": \"Answer Rewrite\", \"description\": \"결제 시스템에서 중복 주문을 방지하기 위해 멱등 키와 Outbox 패턴을 함께", "latency_sec": 31.806, "in_tokens": 1639, "out_tokens": 314} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 13, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 테이블의 bloat를 유발하여 vacuum 작업을 지연시킬 수 있습니다. xmin horizon이 커짐에 따라 더 많은 dead tuples이 생성되어, 이들을 회수하기 위한 vacuum 작업 시 성능 저하가 발생합니다.\"}, {\"type\": \"null\", \"description\": \"PostgreSQL에서는 트랜잭션이 오래 열려 있을수록 테이블의 dead tuples이 증가하여 vacuum 작업의 효율성이 떨어집니다. 이는 xmin horizon 설정과 관련이 있으며, 적절한 모니터링과 관리가 필요합니다.\"}]}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"Pos", "latency_sec": 32.479, "in_tokens": 1272, "out_tokens": 322} +{"label": "local-midm2-mini", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 14, "ok": false, "error": "OutputParserException: Failed to parse CoachingResult from completion {\"model_answer\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"프로젝트에서 API 스펙 해석 차이로 인한 통합 지연 상황을 구체적으로 설명하고, OpenAPI 명세와 Mock 서버를 활용한 해결책을 제시함\"}, {\"type\": \"null\", \"description\": \"소통의 중요성을 강조하며 이후 대안 비교 방식으로 개선한 경험 공유\"}], \"title\": \"Model Answer\", \"default\": null}, \"answer_rewrite\": {\"anyOf\": [{\"type\": \"string\", \"description\": \"학부 동아리 프로젝트에서 학사 공지 알림 봇을 운영하며 새벽에 발생한 서비스 오류로 인한 갈등 상황과 해결 과정을 구체적으로 설명\"}, {\"type\": \"null\", \"description\": \"OpenAPI 명세를 먼저 작", "latency_sec": 30.224, "in_tokens": 1530, "out_tokens": 289} +{"label": "local-midm2-mini", "suite": "followup:during-fanout", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "결제 키에 유니크 제약을 걸어 두 번째 요청을 기존 주문으로 돌려보낸다는 설명에서, '유니크 제약'이 구체적으로 어떤 테이블 컬럼이나 데이터 타입을 의미하는지 더 자세히 설명해 주시겠어요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 33.094, "ttft_sec": null, "in_tokens": 1723, "out_tokens": 79} +{"label": "local-midm2-mini", "suite": "fanout_wall", "wall_sec": 99.15, "ok": true} diff --git a/docs/research/llm-eval-2026-09/raw/local-qwen3-4b-instruct.jsonl b/docs/research/llm-eval-2026-09/raw/local-qwen3-4b-instruct.jsonl new file mode 100644 index 0000000..48eb99e --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/local-qwen3-4b-instruct.jsonl @@ -0,0 +1,80 @@ +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "결제 키에 유니크 제약을 걸어 두 번째 요청을 돌려주는 부분에서, 그 키의 구체적인 형식은 무엇이었나요? (예: 결제 ID + 트랜잭션 ID 또는 결제 ID + 생성 시간 등)", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.071, "ttft_sec": 0.377, "in_tokens": 1708, "out_tokens": 108} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "트랜잭션 경계를 관리했고, 중복 주문을 막았다고 했는데, 멱등 키와 Outbox 패턴이 각각 어떤 실패 케이스를 막는지 구체적으로 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.241, "ttft_sec": 0.547, "in_tokens": 1535, "out_tokens": 108} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "그렇다면 PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향에 대해 잘 모르시는 이유가 무엇인가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.421, "ttft_sec": null, "in_tokens": 1475, "out_tokens": 81} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18의 automatic batching이 비동기 콜백(예: setTimeout 또는 Promise) 내부 업데이트를 포함하여 배칭한다는 점을 말씀하셨는데, 그 부분에 대해 좀 더 구체적으로 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.933, "ttft_sec": null, "in_tokens": 1478, "out_tokens": 102} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정하신 이유와, 트래픽 피크에 사전 스케일아웃을 병행하신 이유를, 좀 더 쉽게 설명해 주실 수 있나요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 2.907, "ttft_sec": 1.519, "in_tokens": 1508, "out_tokens": 93} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "네, 맞습니다. 그럼 outbox 릴레이가 별도 프로세스로 폴링하신 건가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.518, "ttft_sec": 1.459, "in_tokens": 1504, "out_tokens": 72} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "메모리 50% 기준을 선택한 이유가 무엇인가요? CPU 70% 기준이 더 일반적이지 않나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 4.184, "ttft_sec": 2.938, "in_tokens": 1850, "out_tokens": 81} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "인덱스 변경으로 p95가 900ms까지 내려간 부분에서, (user_id, created_at) 복합 인덱스의 선택 기준을 좀 더 구체적으로 말씀해 주세요. 예를 들어, 어떤 성능 측정 기준이나, 쿼리 패턴 분석 방법이 있었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 5.6, "ttft_sec": 3.562, "in_tokens": 1987, "out_tokens": 125} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "항목 높이가 내용에 따라 달라서 높이 캐시를 따로 뒀다고 했는데, 그 캐시를 구현한 방식은 어떤 것이었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.999, "ttft_sec": 3.442, "in_tokens": 1975, "out_tokens": 99} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "OpenAPI 명세를 쓰고 Mock 서버를 띄워 프론트가 병렬로 개발하게 제안하신 부분에서, 그 명세는 몇 가지 항목을 포함했고, 어떤 구체적인 예시로 프론트 팀이 개발을 시작했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 3.779, "ttft_sec": 1.956, "in_tokens": 1603, "out_tokens": 115} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "소통이 중요하다고 말씀하셨는데, 그 대화를 통해 어떤 구체적인 행동을 했고, 그 결과로 팀의 어떤 변화가 있었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.008, "ttft_sec": 0.733, "in_tokens": 1523, "out_tokens": 84} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "불일치가 200건에서 3건으로 줄었다는 점에서, 그 전 상태에서의 실제 충돌 빈도와 재시도 비용을 수치로 정확히 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.311, "ttft_sec": 1.71, "in_tokens": 1571, "out_tokens": 102} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "주문 생성 시 OrderCreated 이벤트를 outbox로 발행했고, 결제 실패 시 PaymentFailed를 발행했는데, 그때 재고 서비스가 StockReserveFailed를 내보내는 경우, 이벤트가 유실되면 주문 상태가 어떻게 되고, 그 상황에서 보상 흐름이 어떻게 작동하나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 5.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 5.387, "ttft_sec": 3.297, "in_tokens": 1945, "out_tokens": 127} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "화면별 staleTime 을 다르게 설정하신 예시나, 어떤 화면에서 얼마나 설정했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.778, "ttft_sec": 1.706, "in_tokens": 1548, "out_tokens": 72} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "결제 키에 유니크 제약을 걸어 두 번째 요청을 돌려주는 부분인데, 그 유니크 키의 구체적인 구조는 어떤 것이었나요? 예를 들어, 결제 ID와 어떤 식의 키 조합을 사용했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.19, "ttft_sec": 2.418, "in_tokens": 1708, "out_tokens": 111} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "트랜잭션 경계와 멱등 키가 각각 어떤 실패 케이스를 막는지, 예를 들어 중복 주문이 발생할 수 있는 상황을 구체적으로 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.141, "ttft_sec": 0.592, "in_tokens": 1535, "out_tokens": 99} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "그런데 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향에 대해 잘 모르겠다고 말씀하셨는데, 혹시 xmin horizon과 관련된 기본 개념을 알고 계신가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.652, "ttft_sec": null, "in_tokens": 1475, "out_tokens": 92} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "그렇게 말씀하셨는데, React 18의 automatic batching이 어떤 경우에 비동기 콜백(예: setTimeout 또는 Promise) 내에서 업데이트가 배칭되는지, 그 기능이 이전 버전과 어떻게 다를지 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.062, "ttft_sec": null, "in_tokens": 1478, "out_tokens": 109} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정하고, 트래픽 피크에 사전 스케일아웃을 병행하는 이유를 설명해 주실 수 있나요? 예를 들어, 어떤 메트릭 수집 주기와 파드 기동 시간이었는지, 그리고 피크 예측에 사용한 데이터는 무엇이었나요?", "answer_intent": "CLARIFICATION", "answer_evaluation": {"specificity": 3.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.542, "ttft_sec": 1.523, "in_tokens": 1508, "out_tokens": 127} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "네, 맞습니다. 그럼 outbox 릴레이가 별도 프로세스로 폴링하신 건가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.533, "ttft_sec": 1.472, "in_tokens": 1504, "out_tokens": 72} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "메모리 50% 기준을 선택한 이유가 무엇인가요? CPU 70% 기준이 더 일반적인 경우가 아닌가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 4.224, "ttft_sec": 2.954, "in_tokens": 1850, "out_tokens": 82} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "인덱스 변경으로 p95가 900ms까지 내려간 부분에서, (user_id, created_at) 복합 인덱스의 인덱스 선택 기준을 좀 더 구체적으로 말씀해 주실 수 있나요? 예를 들어, 어떤 조합이 더 빠르게 조회가 되었는지, 또는 어떤 조합이 쿼리 실행 계획에서 seq scan을 타고 있었는지 알려주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 6.124, "ttft_sec": 3.551, "in_tokens": 1987, "out_tokens": 153} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "항목 2천 개가 리렌더링되는 상황에서 INP가 480ms에서 120ms로 줄어든다고 했는데, 그 과정에서 동적 높이 캐시를 어떻게 구현했고, 캐시 갱신 시점은 언제였나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 5.472, "ttft_sec": 3.448, "in_tokens": 1975, "out_tokens": 123} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "OpenAPI 명세를 쓰고 Mock 서버를 띄워 프론트가 병렬로 개발하게 제안하신 부분에서, 그 Mock 서버의 구체적인 기술 스택과 성능 지표(예: 응답 시간, 요청 빈도)를 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.878, "ttft_sec": 1.92, "in_tokens": 1603, "out_tokens": 121} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "의견이 다를 때 소통을 많이 했던 구체적인 예를 들어주시겠어요? 예를 들어, 어떤 상황에서 어떤 주장이 있었고, 그에 대해 어떻게 대화를 나누었는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.282, "ttft_sec": 0.742, "in_tokens": 1523, "out_tokens": 98} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "불일치가 200건에서 3건으로 줄었다는 부분에서, 그 전과 후의 실제 충돌 빈도와 재시도 횟수를 정량적으로 비교한 사례가 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.287, "ttft_sec": 1.731, "in_tokens": 1571, "out_tokens": 99} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "주문 생성 후 OrderCreated 이벤트를 outbox로 발행했고, 결제 서비스가 PaymentApproved를 받은 경우 재고 서비스가 차감하는 흐름을 설명하셨는데, 그때의 이벤트 ID 기반 멱등 처리는 어떻게 구현했나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 5.149, "ttft_sec": 3.323, "in_tokens": 1945, "out_tokens": 111} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "화면별 staleTime 을 다르게 설정하신 경우, 어떤 화면에서 어떻게 설정했고, 그 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.878, "ttft_sec": 1.716, "in_tokens": 1548, "out_tokens": 77} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "결제 키에 유니크 제약을 걸어 두 번째 요청을 돌려주는 부분에서, 그 키의 구체적인 형식과 예를 들어 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 3.87, "ttft_sec": 2.438, "in_tokens": 1708, "out_tokens": 92} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "트랜잭션 경계와 멱등성 각각이 막던 실패 케이스를 구체적으로 말씀해 주실 수 있나요? 예를 들어, 멱등 키가 막아내는 상황과 Outbox 패턴이 막아내는 상황은 어떤 것인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.409, "ttft_sec": 0.532, "in_tokens": 1535, "out_tokens": 116} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "그런데 MVCC에서 오래 열린 트랜잭션의 xmin horizon이 vacuum에 어떤 영향을 주는지, 잘 모르시는 건가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.459, "ttft_sec": null, "in_tokens": 1475, "out_tokens": 80} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "React 18의 automatic batching이 비동기 콜백(예: setTimeout이나 Promise) 내부 업데이트를 포함해 배칭한다는 점을 말씀하셨는데, 그 예시로 어떤 상황을 말씀해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 1.0, "logic": 1.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.942, "ttft_sec": null, "in_tokens": 1478, "out_tokens": 101} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA 기준을 CPU 70%로 설정하고, 트래픽 피크에 사전 스케일아웃을 병행하는 데 있어, 어떤 메트릭을 기준으로 반응 지연을 평가했고, 그 기준이 피크 예측에 어떻게 연결되었는지 좀 더 구체적으로 설명해 주실 수 있나요?", "answer_intent": "CLARIFICATION", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 3.589, "ttft_sec": 1.534, "in_tokens": 1508, "out_tokens": 129} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "그럼 outbox 릴레이가 별도 프로세스로 폴링하신 건가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.483, "ttft_sec": 1.482, "in_tokens": 1504, "out_tokens": 68} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "메모리 50% 기준으로 HPA 설정하셨다고 하셨는데, 그 기준은 어떤 메트릭 기반으로 선택되었고, CPU 70%와 비교해 어떤 이유가 있었나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 2.0, "structure": "PARTIAL_STAR", "correctness": 4.0}, "latency_sec": 4.488, "ttft_sec": 2.975, "in_tokens": 1850, "out_tokens": 95} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "인덱스 변경으로 p95가 900ms까지 내려간 부분에서, (user_id, created_at) 복합 인덱스의 선택 기준을 말씀해 주실 수 있나요? 예를 들어, 왜 이 두 컬럼을 선택했고, 그 인덱스가 실제로 쿼리에 어떻게 적용되었는지 좀 더 구체적으로 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 5.923, "ttft_sec": 3.576, "in_tokens": 1987, "out_tokens": 140} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "항목 높이가 내용에 따라 달라서 높이 캐시를 따로 뒀다고 했는데, 그 캐시를 구체적으로 어떻게 구현했나요? 예를 들어, 높이 계산에 어떤 알고리즘을 사용했고, 캐시가 얼마나 오래 유지되는지 알려주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 5.679, "ttft_sec": 3.522, "in_tokens": 1975, "out_tokens": 130} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "OpenAPI 명세를 쓰고 Mock 서버를 띄워 프론트가 병렬로 개발하게 제안하신 부분에서, 그 과정에서 구체적으로 어떤 기준으로 스펙을 해석했고, 그 기준이 프론트 팀과 어떻게 다를 수 있었는지 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.02, "ttft_sec": 1.935, "in_tokens": 1603, "out_tokens": 128} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "소통이 중요하다고 말씀하셨는데, 그 소통 과정에서 구체적으로 어떤 행동을 했고, 그 결과로 팀의 어떤 변화가 있었는지 좀 더 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 2.254, "ttft_sec": 0.744, "in_tokens": 1523, "out_tokens": 96} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "불일치가 200건에서 3건으로 줄었다는 점에서, 그 전 상태의 충돌 빈도와 재시도 비용을 구체적으로 측정한 사례가 있나요? 예를 들어, 평균 재시도 횟수나 요청 처리 지연 시간을 들 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 3.779, "ttft_sec": 1.734, "in_tokens": 1571, "out_tokens": 126} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "주문이 생성되면 OrderCreated 이벤트를 outbox 로 발행하고, 결제 서비스가 승인하면 PaymentApproved 를 발행한다고 하셨는데, 그때의 outbox 구현 방식은 어떤 기술을 사용하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 4.986, "ttft_sec": 3.326, "in_tokens": 1945, "out_tokens": 103} +{"label": "local-qwen3-4b-instruct", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "화면별 staleTime 을 다르게 설정한 예시나, 어떤 화면에서 얼마나 설정했는지 구체적으로 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 2.986, "ttft_sec": 1.71, "in_tokens": 1548, "out_tokens": 83} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제는 두 가지 핵심 실패 케이스를 동시에 해결해야 합니다. 먼저, 멱등 키는 동일한 주문 요청이 여러 번 처리되지 않도록 보장합니다. 결제 승인 콜백이 지연되더라도, 주문 서비스가 이미 처리한 주문인지 확인하기 위해 주문 ID와 결제 ID를 기반으로 멱등 키를 생성하고, 이 키가 이미 존재하면 중복 처리를 방지합니다. 이는 주문 요청이 중복으로 들어오더라도, DB에 중복 저장되지 않도록 합니다. 반면, Outbox 패턴은 트랜잭션 경계를 명확히 하여, 결제 승인 이벤트가 DB에 정상적으로 반영되지 않았을 때도 주문 상태를 일관되게 유지합니다. 예를 들어, 결제 승인 콜백이 실패하거나 지연되면, 결제 서비스가 아직 처리되지 않은 주문을 완전히 무시하지 않고, Outbox에 임시로 저장하여 이후 재처리를 위해 기다리게 합니다. 이로써 결제 승인 이벤트가 완전히 도달하지 않았을 때도, 주문 서비스와 결제 서비스 사이의 상태가 안정적으로 유지됩니다. 따라서 멱등 키는 중복 주문을 막고, Outbox는 트랜잭션 실패 시의 상태 불일치를 막아, 두 가지 실패 케이스를 동시에 예방합니다.", "answer_rewrite": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제를 해결하기 위해, 저는 멱등 키와 Outbox 패턴을 함께 적용했습니다. 먼저, 멱등 키를 사용해 주문 요청이 중복되지 않도록 보장했습니다. 주문 서비스가 결제 승인 콜백을 기다리고 있을 때, 주문 ID와 결제 ID를 기반으로 멱등 키를 생성하고, 이미 처리된 주문인지 확인하는 로직을 구현했습니다. 이로 인해 결제 콜백이 지연되더라도, 동일한 주문이 두 번 처리되지 않도록 했습니다. 또한, Outbox 패턴을 통해 결제 승인 이벤트가 DB에 정상적으로 반영되지 않았을 경우도 처리했습니다. 주문이 생성되었지만 결제 승인 이벤트가 아직 도달하지 않았을 때, 주문 상태를 '결제 대기 중'으로 유지하고, 결제 승인 콜백이 도달하면 이후에 Outbox에서 이벤트를 처리하도록 했습니다. 이로써 결제 실패나 지연 시에도 주문 상태가 일관되게 유지되고, 중복 주문이 발생하지 않게 되었습니다. 실제로 이 방식을 적용한 결과, 중복 주문은 0건 발생했고, 주문 서비스의 안정성이 크게 향상되었습니다.", "coaching_comment": "멱등 키와 Outbox 패턴의 역할을 구체적인 실패 케이스(중복 주문 vs 상태 불일치)로 구분해서 설명해야 합니다."}, "latency_sec": 19.918, "in_tokens": 1561, "out_tokens": 750} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 주로 xmin horizon과 관련이 있습니다. MVCC에서는 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 보호하며, 트랜잭션이 종료되지 않은 경우 그 xmin은 'dead tuple'을 제거할 수 있는 조건을 만족하지 않습니다. 즉, 오래 열린 트랜잭션이 존재하면 그 xmin이 'horizon'으로 설정되어, 이후에 생성된 dead tuple들은 그 xmin보다 낮은 값이 아니면 제거되지 않게 됩니다. 이로 인해 vacuum이 dead tuple을 회수하지 못하고, 테이블 내에 'bloat'가 쌓이게 됩니다. 예를 들어, 한 트랜잭션이 1시간 동안 실행되고 있다면, 그 동안 생성된 삭제된 행들은 vacuum이 확인하지 못하고, 테이블의 물리적 크기가 커지게 됩니다. 이는 성능 저하와 저장 공간 낭비를 초래할 수 있습니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 xmin horizon과 관련이 있습니다. MVCC는 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 보호하며, 트랜잭션이 종료되지 않은 경우 그 xmin은 dead tuple 제거 조건을 만족하지 않습니다. 따라서 오래 열린 트랜잭션이 존재하면 그 xmin이 vacuum의 horizon으로 설정되어, 이후에 생성된 dead tuple들은 그 xmin보다 낮은 값이 아니면 제거되지 않습니다. 이로 인해 vacuum이 dead tuple을 회수하지 못하고, 테이블 내에 bloat가 쌓이게 됩니다. 예를 들어, 특정 쿼리가 오래 동안 실행되고 있는 경우, 그 동안 삭제된 데이터는 vacuum이 확인하지 못하고, 테이블의 물리적 크기가 커지게 됩니다. 이는 성능 저하와 저장 공간 낭비를 초래할 수 있습니다.", "coaching_comment": "오래 열린 트랜잭션의 xmin horizon이 vacuum의 제어 범위를 뒤로 밀어내는 메커니즘을 명확히 설명해야 합니다."}, "latency_sec": 11.172, "in_tokens": 997, "out_tokens": 539} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었어요. 당시 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했고, 이로 인해 스프린트 기간 동안 통합 이슈가 3건에서 0건으로 줄어들었습니다. 하지만 초기에 제 방식이 옳다고 고집해 팀원에게 감정적 반발을 받은 적이 있었어요. 그 경험을 바탕으로 이후에는 결정 전에 대안 두 가지를 함께 비교하고, 팀원들과 함께 논의하는 방식으로 전환했고, 현재는 팀 내 의견 충돌 시 모두의 입장을 반영한 합의를 도출하는 데 집중하고 있습니다. 이 과정에서 저는 단순한 소통보다는 '공감 기반의 협업'이 결과에 더 큰 영향을 미친다는 점을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었어요. 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했고, 이로 인해 스프린트 기간 동안 통합 이슈가 3건에서 0건으로 줄어들었습니다. 하지만 초기에 제 방식이 옳다고 고집해 팀원에게 감정적 반발을 받은 적이 있었어요. 이후 저는 결정 전에 대안 두 가지를 함께 비교하고, 팀원들과 함께 논의하는 방식으로 전환했고, 지금은 의견 충돌 시 모두의 입장을 반영한 합의를 도출하는 데 집중하고 있습니다. 이 경험을 통해 저는 단순한 소통보다는 '공감 기반의 협업'이 팀의 성과와 지속성에 더 큰 영향을 미친다는 점을 깨달았습니다.", "coaching_comment": "의견 충돌 시 감정적 반발이 있었음을 인정하고, 그 경험을 통해 구체적인 협업 방식의 변화를 보여주는 것이 중요합니다."}, "latency_sec": 13.445, "in_tokens": 1392, "out_tokens": 566} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제는 두 가지 핵심 실패 케이스를 동시에 막기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다. 먼저, 멱등 키는 동일한 주문 요청이 중복으로 처리되지 않도록 보장합니다. 결제 승인 콜백이 지연되더라도, 주문 서비스가 이미 처리한 주문인지 확인하기 위해 주문 ID와 결제 ID를 기반으로 멱등 키를 사용하여 중복 요청을 차단합니다. 이는 결제 승인 후 주문이 완료된 상태임에도 불구하고, 콜백이 도달 전에 주문이 다시 생성되는 경우를 방지합니다. 반면, Outbox 패턴은 결제 승인 이벤트가 성공적으로 처리되었는지를 DB 트랜잭션 내에서 명확히 분리하여, 결제 처리가 실패했을 경우에도 주문 상태가 일관되게 유지되도록 합니다. 예를 들어, 결제 승인 콜백이 실패했을 때, Outbox에서 저장된 이벤트는 배치에서 다시 처리되며, 이로 인해 주문 상태가 '결제 대기'로 유지되고, 중복 주문이 발생하지 않습니다. 따라서 멱등 키는 중복 요청을 막고, Outbox는 트랜잭션 경계를 보호하여 결제 지연 시 발생할 수 있는 두 가지 실패 케이스를 구체적으로 차단합니다.", "answer_rewrite": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제를 해결하기 위해, 멱등 키와 Outbox 패턴을 함께 적용했습니다. 먼저, 주문 서비스에서 결제 승인 콜백이 도달하기 전에 이미 처리된 주문인지 확인하기 위해, 주문 ID와 결제 ID를 기반으로 멱등 키 테이블을 사용했습니다. 이 키를 기반으로 동일한 주문 요청이 두 번 이상 처리되지 않도록 제어하여 중복 주문을 방지했습니다. 또한, 결제 승인 이벤트가 성공적으로 처리되었는지를 DB 트랜잭션 외부에서 분리하여, 결제 콜백이 지연되거나 실패했을 때도 주문 상태가 일관되게 유지되도록 Outbox 패턴을 도입했습니다. 예를 들어, 결제 승인 콜백이 도달하지 않았을 경우, Outbox에 저장된 이벤트는 배치에서 다시 처리되며, 이로 인해 주문이 중복되지 않고 '결제 대기' 상태로 유지됩니다. 이 두 패턴은 각각 '중복 요청'과 '트랜잭션 경계의 무너짐'이라는 실패 케이스를 구체적으로 막아, 실제로 주문 서비스에서 중복 주문 0건 발생을 달성했습니다.", "coaching_comment": "중복 주문과 트랜잭션 실패 케이스를 구분하고, 각 패턴이 어떤 상황에서 실패를 막는지를 명확히 설명해야 합니다."}, "latency_sec": 17.97, "in_tokens": 1561, "out_tokens": 754} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 주로 xmin horizon과 관련이 있습니다. MVCC는 트랜잭션의 일관성을 유지하기 위해 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리합니다. 오래 열린 트랜잭션은 그 xmin 값을 높은 수준으로 유지하게 되고, 이로 인해 vacuum이 그 트랜잭션의 끝을 기다려야 하므로, dead tuple의 회수를 지연시킵니다. 이는 특히 장기간 실행되는 트랜잭션(예: 대용량 업데이트 또는 long-running query)이 있을 때, 테이블에 bloat를 초래할 수 있습니다. vacuum이 이와 같은 경우에 대해 'dead tuple'을 제거하지 못하면, 테이블의 크기가 점점 커지게 되고, 성능 저하를 유발할 수 있습니다. 따라서, 이 문제는 DB 운영 시점에서 정기적인 vacuum을 수행하고, 필요 시 autovacuum 설정을 조정하는 것이 중요합니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum의 작동을 지연시킬 수 있습니다. MVCC는 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리하므로, 오래 열린 트랜잭션은 그 xmin 값을 유지하게 되고, vacuum은 그 트랜잭션이 종료될 때까지 dead tuple을 제거하지 못합니다. 이로 인해 dead tuple이 쌓이게 되고, 테이블에 bloat가 발생할 수 있습니다. 예를 들어, 대용량 업데이트나 장기간 실행되는 쿼리가 있다면, 이와 같은 상황이 더 자주 나타날 수 있습니다. 따라서, 자주 실행되는 트랜잭션을 최소화하고, autovacuum 설정을 적절히 조정하는 것이 관리 시점에서 중요합니다.", "coaching_comment": "오래 열린 트랜잭션의 xmin horizon과 vacuum의 지연 사이의 관계를 구체적으로 설명해야 합니다."}, "latency_sec": 10.658, "in_tokens": 997, "out_tokens": 508} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 이 과정에서 팀원들이 제 방식을 옳다고 생각하는 데 반발하며 감정적으로 반발했고, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 접근을 바꿨습니다. 이로 인해 다음 스프린트에서 통합 이슈가 3건에서 0건으로 줄어들었고, 팀 내 의사소통의 질이 개선되었습니다. 이 경험을 통해 저는 단순히 자신의 의견을 내는 것이 아니라, 팀원의 관점도 고려하고, 공감을 기반으로 한 협업이 결과에 더 큰 영향을 미친다는 점을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 그러나 이 과정에서 팀원들이 제 방식을 옳다고 생각하는 데 반발하며 감정적으로 반발했고, 이후 저는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 접근을 조정했습니다. 이 변화로 인해 다음 스프린트에서 통합 이슈가 3건에서 0건으로 줄었고, 팀 내 갈등이 사라지고 협업의 흐름이 더 원활해졌습니다. 이 경험을 통해 저는 단순한 의견 제시가 아니라, 팀원의 입장에 공감하고 함께 탐색하는 것이 협업의 핵심이라는 점을 깨달았습니다.", "coaching_comment": "감정적 반발이 있었음과 그 이후의 구체적 변화(이슈 수 감소, 접근 방식 개선)를 연결하는 것이 핵심입니다."}, "latency_sec": 12.826, "in_tokens": 1392, "out_tokens": 529} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제는 두 가지 핵심 실패 케이스를 동시에 해결해야 합니다. 먼저, 멱등 키는 동일한 주문 요청이 여러 번 처리되지 않도록 보장합니다. 결제 승인 후 주문 생성 시, 주문 ID와 결제 트랜잭션 ID를 기반으로 멱등 키 테이블에 기록하면, 동일한 결제가 왔을 때 이전 요청이 이미 처리되었음을 확인할 수 있습니다. 이는 중복 주문이 발생하지 않도록 하며, 특히 콜백이 지연되더라도 주문이 중복되는 것을 막습니다. 반면, Outbox 패턴은 주문 생성과 결제 승인 사이의 트랜잭션 경계를 명확히 하여, 주문이 성공적으로 생성되었지만 결제 승인에 실패했을 경우에도 주문 상태를 일관되게 유지합니다. 예를 들어, 결제 승인 콜백이 오지 않아도 주문이 DB에 저장되고, 이후 결제에 성공하면 결제 승인 이벤트를 Outbox를 통해 별도로 발행하여, 결제 상태를 일관되게 업데이트합니다. 이렇게 하면 결제 지연 시에도 주문이 중복되지 않으며, 트랜잭션의 완전성과 데이터 일관성이 보장됩니다.", "answer_rewrite": "결제 승인 콜백 지연으로 중복 주문이 발생하는 문제는 두 가지 실패 케이스를 동시에 막아야 합니다. 먼저, 멱등 키를 사용해 동일한 주문 요청이 중복으로 처리되지 않도록 합니다. 주문 생성 시, 결제 트랜잭션 ID와 주문 ID를 기반으로 멱등 키 테이블에 기록하고, 이후 콜백이 오기 전까지 해당 키가 이미 존재하면 주문을 중단합니다. 이로 인해 콜백 지연 시에도 중복 주문이 발생하지 않습니다. 또한, Outbox 패턴은 주문 생성과 결제 승인 사이의 트랜잭션 경계를 명확히 하여, 주문이 DB에 저장되었지만 결제 승인에 실패했을 경우에도 주문 상태를 일관되게 유지합니다. 예를 들어, 결제 승인 콜백이 오지 않아도 주문은 생성되고, 이후 결제에 성공하면 Outbox를 통해 결제 승인 이벤트를 발행해 상태를 업데이트합니다. 이 두 패턴을 함께 사용함으로써, 중복 주문과 트랜잭션 완전성 문제를 동시에 해결할 수 있습니다.", "coaching_comment": "무엇이 실패하는지 구체적으로 구분하고, 각 패턴이 어떤 상황에서 실패를 막는지 명확히 설명해야 합니다."}, "latency_sec": 17.009, "in_tokens": 1561, "out_tokens": 698} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 주로 xmin horizon과 관련이 있습니다. MVCC는 트랜잭션의 일관성을 유지하기 위해 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리합니다. 오래 열린 트랜잭션은 xmin 값을 높게 유지하고, 이 값이 vacuum 작업이 수행할 수 있는 'xmin horizon'을 뒤로 미칩니다. 따라서 vacuum은 그 이전의 xmin보다 작은 xmins만 처리할 수 있고, 그 이후에 생성된 'dead tuple'은 제거되지 않아 테이블에 bloat가 쌓입니다. 이로 인해, 테이블의 크기가 증가하고, 쿼리 성능에 부정적인 영향을 줄 수 있습니다. 이 문제는 특히 장기적으로 실행되는 트랜잭션(예: 대규모 데이터 처리, 로그 기록)이 있을 때 더욱 두드러집니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum 작업에 영향을 미칩니다. MVCC는 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리하며, vacuum은 xmin horizon 이하의 트랜잭션만 처리할 수 있습니다. 만약 오래 열린 트랜잭션이 계속 유지된다면, xmin horizon이 뒤로 미쳐 vacuum이 더 오래된 dead tuple을 제거하지 못하게 되고, 그 결과 dead tuple이 누적되어 테이블에 bloat가 생깁니다. 이는 특히 대량 데이터를 다루는 서비스에서 성능 저하를 초래할 수 있습니다. 예를 들어, 장기 동안 실행되는 로그 저장 트랜잭션은 이 현상을 악화시킬 수 있습니다.", "coaching_comment": "오래 열린 트랜잭션의 xmin horizon이 vacuum을 지연시키는 메커니즘을 명확히 설명하고, bloat와 성능에 연결하는 것이 핵심입니다."}, "latency_sec": 10.235, "in_tokens": 997, "out_tokens": 483} +{"label": "local-qwen3-4b-instruct", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연됐습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트팀이 병렬로 개발할 수 있도록 제안했습니다. 이 방식으로 팀의 개발 속도가 향상되었고, 스프린트 기간 동안 통합 이슈가 3건에서 0건으로 줄어들었습니다. 그러나 초기에 제 방식이 옳다고 고집해 팀원과 감정적 갈등이 생겼습니다. 이후 저는 결정 전에 대안 두 가지를 함께 비교하고, 팀원들과 함께 논의하는 방식으로 접근을 바꾸었습니다. 이 경험을 통해 저는 단순히 정답을 찾아내는 것이 아니라, 팀원들과의 공감과 협업을 통해 합의를 도출하는 것이 더 지속 가능한 협업이라는 점을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트팀이 병렬로 개발할 수 있도록 제안했습니다. 이 방식으로 통합 이슈가 3건에서 0건으로 줄어들었고, 개발 속도가 향상되었습니다. 그러나 초기에 제 방식이 옳다고 고집해 팀원의 감정이 상했고, 이후에는 결정 전에 대안 두 가지를 함께 비교하고, 팀원들과 함께 논의하는 방식으로 접근을 수정했습니다. 이 경험을 통해 저는 협업에서 '정답'보다는 '공감'과 '공동 결정'이 더 중요하다는 점을 깨달았습니다.", "coaching_comment": "감정적 갈등이 있었음을 인정하고, 그 이후에 구체적으로 어떻게 변화했는지를 보여주는 것이 중요합니다."}, "latency_sec": 12.261, "in_tokens": 1392, "out_tokens": 498} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연 시 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결했으나, 이 과정에서 멱등 키 테이블의 데이터 일관성 유지 방식은 어떻게 설계했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키 테이블의 생성/삭제 로직과 트랜잭션 범위 내에서의 일관성 보장 방식을 구체적으로 설명하며, 중복 주문 방지의 정량적 성과를 포함"}, {"category": "TECH_CHOICE", "question": "MSA 전환 시 Kafka를 이벤트 파이프라인으로 선택한 이유는 무엇이며, 이 선택이 주문 서비스의 배포 주기 단축에 어떤 기여를 했나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일", "expected_signal": "Kafka의 비동기성과 서비스 간 결합도 감소를 기반으로 한 선택 이유를 설명하고, 배포 주기 단축에 대한 구체적 기여를 정량화"}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 낙관적 락을 분산 락으로 전환한 과정에서 발생한 동시성 문제는 어떤 것이었고, 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환), 재고 불일치 건수 월 200건 → 3건", "expected_signal": "구체적인 동시성 문제(예: 캐시 스파이크, 락 경쟁)와 분산 락을 적용한 구현 방식, 결과 개선을 포함한 기술적 사고 과정을 설명"}, {"category": "CS_FUNDAMENTAL", "question": "Outbox 패턴에서 트랜잭션의 동기화를 위해 사용하는 데이터베이스 테이블과 메시지 큐 간의 상태 일관성을 유지하는 방식은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "Outbox 내부의 트랜잭션 커밋 순서와 DB 테이블 상태를 동기화하는 메커니즘(예: 두 개의 트랜잭션의 동기화, 실패 시 롤백)을 명확히 설명"}, {"category": "TECH_CHOICE", "question": "Spring Boot 3에서 JPA와 QueryDSL을 사용해 정산 배치 성능을 개선했을 때, 인덱스 재설계와 청크 단위 처리가 각각 어떤 성능 문제를 해결했나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "인덱스 재설계와 청크 처리가 해결한 구체적인 성능 문제(예: I/O 지연, 메모리 부족)와 그로 인한 성능 개선을 정량화"}], "latency_sec": 34.546, "in_tokens": 3227, "out_tokens": 988} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "일정 타임라인에서 항목 2천 개 이상일 때 스크롤 끊김 문제를 react-window 가상화로 해결했을 때, 가상화 전후의 INP 지표 변화와 그에 따른 사용자 경험 개선을 구체적으로 설명해 주세요.", "job_category": "FRONTEND", "target_evidence": "react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "가상화 전후 INP 지표 변화와 사용자 경험 개선에 대한 정량적 데이터 및 구현 방식의 구체적 설명을 포함"}, {"category": "TECH_CHOICE", "question": "Kakao Map SDK에서 마커 500개를 클러스터링한 이유와 useMemo를 통해 좌표 변환을 캐싱한 구현 방식의 효율성은 어떻게 평가되나요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "클러스터링의 필요성과 useMemo를 통한 캐싱이 성능 향상에 기여한 방식과 그 효과를 구체적으로 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "오프라인 편집 기능에서 IndexedDB에 낙관적 업데이트를 저장하고, 온라인 복귀 시 last-write-wins 방식으로 동기화를 수행했을 때, 이 방식이 충돌을 어떻게 해결했는지 구체적으로 설명해 주세요.", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "last-write-wins 방식이 충돌을 어떻게 처리했는지, 그리고 이 방식의 한계나 개선 방향을 언급"}, {"category": "TECH_CHOICE", "question": "이미지 업로드 시 클라이언트에서 WebP 변환을 수행한 이유와 presigned URL을 이용해 S3에 직접 업로드하는 구현에서 보안 및 성능 측면에서 어떤 고려사항이 있었나요?", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "WebP 변환의 이유와 presigned URL을 통해 보안 및 성능 측면에서 고려한 구체적 사례 설명"}, {"category": "CS_FUNDAMENTAL", "question": "TanStack Query v5를 사용하여 서버 상태를 관리할 때, 쿼리의 캐싱 전략과 데이터 불일치 문제를 예방하기 위한 구체적인 방식은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "서버 상태는 TanStack Query v5", "expected_signal": "TanStack Query v5의 캐싱 전략과 데이터 불일치 예방 방식에 대한 구체적 기술적 설명"}], "latency_sec": 25.621, "in_tokens": 2982, "out_tokens": 868} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 14에서 슬로우 쿼리 p95를 2.3초에서 180ms로 개선한 과정에서, 복합 인덱스 설계와 파티셔닝 전략을 선택한 배경은 무엇인가요?", "job_category": "DBA", "target_evidence": "복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할", "expected_signal": "구체적인 성능 문제 분석 과정과, 파티셔닝이 월 단위 데이터에 적합한 이유를 설명하며, 쿼리 패턴과 데이터 접근 빈도를 기반으로 한 설계 결정을 제시"}, {"category": "TECH_CHOICE", "question": "Terraform을 사용해 VPC·RDS·EKS를 모듈화한 이유는 무엇이며, 각 모듈의 구조적 독립성은 어떻게 보장했나요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "모듈화가 환경 간 일관성과 배포 효율성에 기여했음을 설명하고, 각 모듈의 입력/출력 정의와 의존성 관리 방식을 구체적으로 제시"}, {"category": "PROJECT_DEEP_DIVE", "question": "RDS 스토리지 풀로 쓰기 중단 사고에서 CloudWatch 알람과 오토스케일링을 도입한 구체적인 절차와 실패 원인 분석은 어떻게 했나요?", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "사고 발생 시점의 모니터링 지표와, 오토스케일링 트리거 조건 설정 과정을 설명하며, 사전 예방 조치와 사후 대응 체계를 제시"}, {"category": "TECH_CHOICE", "question": "HPA를 CPU 70% 기준으로 설정하고, 월급날 트래픽 피크에 대비한 사전 스케일아웃 CronJob을 운영한 이유는 무엇인가요?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "70% 기준이 트래픽 피크 전에 리소스 부족을 예측하고, CronJob이 사전에 클러스터를 확장하는 메커니즘을 설명하며, 실패 사례 없이 성공한 사례를 제시"}, {"category": "BEHAVIORAL", "question": "ArgoCD 도입으로 배포 리드타임이 1일에서 30분으로 개선된 과정에서, 팀원들과의 협업 방식과 의사결정 과정은 어떻게 했나요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "GitOps 도입 전의 팀 내 배포 프로세스 문제를 설명하고, 팀원들과의 공감과 피드백을 기반으로 한 결정 과정을 구체적으로 제시"}, {"category": "CS_FUNDAMENTAL", "question": "PostgreSQL의 autovacuum 튜닝이 슬로우 쿼리 개선에 기여한 메커니즘은 무엇이며, 어떤 상황에서 튜닝이 필요했나요?", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "autovacuum이 블록 레코드 삭제와 인덱스 유지에 기여했음을 설명하고, 튜닝이 필요했던 데이터 활동 패턴(예: 높은 INSERT/DELETE)을 구체적으로 제시"}], "latency_sec": 31.548, "in_tokens": 2960, "out_tokens": 1155} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "알림 봇 프로젝트에서 SQLite를 사용한 실패 경험에서 배운 트랜잭션 격리 수준의 핵심 차이를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "공간적 격리 수준(READ COMMITTED, REPEATABLE READ 등)의 차이와 실제 중복 발송 문제와의 연결을 명확히 설명하며, 실제 문제 해결 과정에서의 학습 과정을 제시합니다."}, {"category": "BEHAVIORAL", "question": "팀원과 감정이 상한 경험에서, 이후에 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꾸는 과정에서 본인의 구체적 행동과 그 결과는 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "STAR 구조를 따르며, 상황, 과제, 행동, 결과를 구체적으로 제시하고, 그 과정에서의 감정적 반응과 협업 개선 효과를 명확히 드러냅니다."}, {"category": "TECH_CHOICE", "question": "OpenAPI 명세를 기반으로 Mock 서버를 띄워 프론트엔드 팀과 협업한 경험에서, API 스펙의 불일치를 어떻게 예방했나요?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이 후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "Mock 서버 도입과 명세 문서화를 통해 프론트와의 스펙 불일치를 사전에 예방했으며, 이로 인한 개발 지연 감소를 정량적으로 제시합니다."}, {"category": "BEHAVIORAL", "question": "사용자 800명이 매일 쓰는 서비스에서 알림이 누락된 사건에서, 신뢰를 만드는 서비스의 본질은 무엇이라고 느꼈나요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "서비스의 지속성과 신뢰성 사이의 관계를 본인의 경험을 기반으로 설명하며, '멈추지 않는 서비스'라는 개념이 기술적 구현과 사용자 신뢰에 어떤 영향을 미쳤는지 구체적으로 제시합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "알림 봇의 크롤러가 멈춰 공지가 누락된 사건에서, 그 상황을 해결하기 위해 어떤 구조적 개선을 했고, 그 결과는 무엇이었나요?", "job_category": "BACKEND", "target_evidence": "학부 동아리에서 학사 공지 알림 봇을 만들며 사용자 800명이 매일 쓰는 서비스를 운영해 본 경험이 있습니다. 새벽에 크롤러가 멈춰 공지가 누락됐을 때 동아리원들의 항의를 직접 받으며, 기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "크롤러의 장애 대응 메커니즘(예: 재시작, 로그 모니터링, 알림 히스토리 저장 등)을 구체적으로 제시하고, 그로 인한 서비스 신뢰도 향상과 사용자 반응을 설명합니다."}], "latency_sec": 31.43, "in_tokens": 2956, "out_tokens": 1147} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 낙관적 락을 분산 락으로 전환한 이유와 그 과정에서 발생한 문제는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "재고 불일치 건수 월 200건 → 3건. 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "구체적인 동시성 문제 발생 상황과 분산 락 도입 전후 성능/안정성 변화를 설명하며, 전환 결정 기준을 명확히 제시"}, {"category": "TECH_CHOICE", "question": "Kafka를 주문 서비스 이벤트 파이프라인에 도입한 이유와, 결제 콜백 지연 시 중복 주문을 방지하기 위해 멱등 키 테이블을 어떻게 설계했나요?", "job_category": "BACKEND", "target_evidence": "MSA 전환: 주문 서비스를 별도 서비스로 분리, Kafka 기반 이벤트 발행/구독 구조 도입. 결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결", "expected_signal": "Kafka의 장점과 멱등 키 테이블 설계에서 사용한 키 구조, 트랜잭션 격리 수준, 데이터 일관성 보장 방식을 구체적으로 설명"}, {"category": "CS_FUNDAMENTAL", "question": "PostgreSQL에서 트랜잭션 격리 수준을 어떻게 설정했고, 이 설정이 결제 중복 주문 문제 해결에 어떤 영향을 미쳤나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성. 실패 경험: SQLite로 시작한 후 동시 쓰기 락 문제로 중복 발송됨", "expected_signal": "트랜잭션 격리 수준의 선택 기준과 그 설정이 중복 주문 방지에 미친 영향을 명확히 설명하며, SQLite에서 PostgreSQL로의 전환 배경을 포함"}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 Redis 캐시와 DB write-behind를 결합한 구조에서, 캐시 불일치를 방지하기 위한 구체적인 로직은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "캐시와 DB 간 동기화 로직, 불일치 발생 시 처리 방식, 그리고 이로 인한 재고 불일치 건수 감소를 구체적으로 설명"}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 프론트엔드 팀과 API 스펙 해석이 달라 통합이 지연된 상황에서, 어떻게 협업을 개선했고 그 결과는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "상황 설명 후, 구체적인 행동(OpenAPI 작성, Mock 서버 도입), 그리고 그 결과(통합 이슈 0건)를 명확히 제시하며, 팀원 감정 문제를 어떻게 해소했는지 언급"}], "latency_sec": 39.3, "in_tokens": 4573, "out_tokens": 1017} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연 시 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결했으나, 이 과정에서 멱등 키 테이블의 데이터 일관성 유지 방식은 어떻게 설계했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "데이터 일관성 유지 방식(예: 트랜잭션 범위, 키 생성 로직, 상태 관리)과 이를 통해 중복 주문이 0건으로 유지된 구체적 메커니즘을 설명"}, {"category": "TECH_CHOICE", "question": "MSA 전환 시 Kafka를 이벤트 파이프라인으로 선택한 이유는 무엇이며, 주문 서비스 분리 후 Kafka 메시지의 순서 보장 방식은 어떻게 구현했나요?", "job_category": "BACKEND", "target_evidence": "모놀리식 → MSA 전환: 주문 서비스를 별도 서비스로 분리, Kafka 기반 이벤트 발행/구독 구조 도입", "expected_signal": "Kafka를 선택한 기술적 이유(예: 확장성, 비동기 처리)와 주문 이벤트의 순서 보장을 위한 구현 방식(예: 순서 키, 컨슈머 그룹 설정)을 명확히 제시"}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 Redis 캐시와 DB write-behind를 사용했을 때, 동시성 문제를 해결하기 위해 분산 락을 도입한 구체적인 로직은 무엇인가요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "분산 락을 사용한 구체적인 코드 구조나 락 키 설계, 그리고 이를 통해 월 200건 → 3건의 불일치 감소를 달성한 과정을 설명"}, {"category": "CS_FUNDAMENTAL", "question": "Outbox 패턴에서 트랜잭션 범위를 어떻게 관리했는지, 그리고 이로 인해 결제 서비스와 주문 서비스 간의 데이터 일관성 문제를 어떻게 예방했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "Outbox 내 트랜잭션 범위와 서비스 간 데이터 일관성 보장 방식(예: DB 트랜잭션, 커밋 순서)을 기술하고, 이로 인한 실질적 성과를 연결"}, {"category": "TECH_CHOICE", "question": "Spring Boot 3과 Kotlin을 사용하면서 JPA와 QueryDSL을 통합한 쿼리 성능 최적화 방식은 무엇이며, 정산 배치 성능 개선에서 5시간 → 40분으로의 개선은 어떤 구체적 조치에서 비롯되었나요?", "job_category": "BACKEND", "target_evidence": "정산 배치 성능 개선: 5시간 → 40분 (QueryDSL 튜닝, 청크 단위 처리, 인덱스 재설계)", "expected_signal": "QueryDSL 튜닝 및 청크 처리, 인덱스 재설계 등 구체적인 최적화 기법과 그 결과를 정량적으로 연결"}], "latency_sec": 25.82, "in_tokens": 3227, "out_tokens": 965} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "일정 타임라인에서 항목 2천 개 이상일 때 스크롤 끊김 문제를 react-window 가상화로 해결했으나, 이 과정에서 가상화의 최적화 전략은 무엇이었나요?", "job_category": "FRONTEND", "target_evidence": "항목 2천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "가상화를 통해 렌더링 범위를 제어하고, item height 계산 및 메모리 사용량 최적화를 구체적으로 설명한 내용을 포함"}, {"category": "TECH_CHOICE", "question": "Kakao Map SDK 마커 500개를 클러스터링했을 때 useMemo로 좌표 변환 캐싱을 선택한 이유는 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "클러스터링과 캐싱이 성능 향상에 기여했고, React의 상태 관리 및 렌더링 최적화 원리에 기반한 선택지를 명확히 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "오프라인 편집 기능에서 IndexedDB에 낙관적 업데이트를 저장한 후 온라인 복귀 시 동기화를 어떻게 구현했나요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "Dexie의 데이터 구조와 동기화 로직을 구체적으로 설명하고, last-write-wins 방식의 한계와 CRDT의 필요성을 인지한 내용을 포함"}, {"category": "CS_FUNDAMENTAL", "question": "Vite와 React 18의 동시 사용에서, 빌드 시간과 렌더링 성능 사이의 균형을 어떻게 관리했나요?", "job_category": "FRONTEND", "target_evidence": "Vite + React 18 + TypeScript, 상태 관리는 Zustand, 서버 상태는 TanStack Query v5", "expected_signal": "Vite의 HMR과 React 18의 Concurrent Mode가 성능에 기여했고, 빌드 시간과 렌더링 지연 간의 조화를 구체적으로 설명"}, {"category": "TECH_CHOICE", "question": "이미지 업로드에서 클라이언트에서 WebP 변환을 선택한 이유는 무엇인가요? S3에 presigned URL을 사용하는 방식의 장단점을 설명해 주세요.", "job_category": "FRONTEND", "target_evidence": "이미지 업로드: presigned URL 로 S3 직접 업로드, 클라이언트에서 WebP 변환", "expected_signal": "WebP의 파일 크기 효율성과 브라우저 지원, presigned URL의 보안 및 접근 제어 기능을 기반으로 한 선택 이유를 구체적으로 제시"}], "latency_sec": 26.048, "in_tokens": 2982, "out_tokens": 888} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "PostgreSQL 14에서 슬로우 쿼리 p95를 2.3초에서 180ms로 개선한 과정에서, 복합 인덱스 설계와 파티셔닝 전략을 구체적으로 어떻게 적용했나요?", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "복합 인덱스의 컬럼 선택 기준과 파티셔닝 전략(예: 월 단위, 테이블 분할 기준)에 대한 구체적 설계 사례와 성과 기반 평가를 설명"}, {"category": "TECH_CHOICE", "question": "Terraform을 사용해 VPC·RDS·EKS를 모듈화했을 때, 각 서비스별 모듈 구조와 환경별 workspace 분리 방식은 어떻게 설계했나요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별(dev/stg/prod) workspace 분리", "expected_signal": "모듈 구조의 계층적 설계와 각 환경별 workspace 설정 방식에 대한 구체적 사례와 재사용성 기반 설명"}, {"category": "PROJECT_DEEP_DIVE", "question": "RDS 스토리지 풀로 쓰기 중단 사고에서 CloudWatch 알람과 오토스케일링을 적용한 구체적인 절차와 설정 파라미터는 무엇인가요?", "job_category": "INFRA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "CloudWatch 알람 조건과 오토스케일링 트리거 설정의 구체적 파라미터와 사고 대응 흐름을 설명"}, {"category": "TECH_CHOICE", "question": "ArgoCD 도입으로 배포 리드타임을 1일에서 30분으로 개선한 과정에서, GitOps 흐름과 배포 파이프라인의 핵심 구성 요소는 무엇인가요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1일 → 30분", "expected_signal": "GitOps 흐름에서의 커밋 → 리소스 상태 확인 → 배포 트리거 구조와 ArgoCD의 상태 관리 기능 활용 사례를 명확히 설명"}, {"category": "CS_FUNDAMENTAL", "question": "HPA 기준을 CPU 70%로 설정하고, 월급날 10시 트래픽 피크에 대비해 사전 스케일아웃 CronJob을 운영했을 때, 이 설정이 트래픽 변동성에 어떻게 반응하는지 구체적으로 설명해 주세요.", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "CPU 70% 기준이 트래픽 피크에 대한 예측 정확도와 사전 스케일아웃의 실행 주기, 실패 사례 없이 성공한 사례를 설명"}, {"category": "BEHAVIORAL", "question": "RDS 스토리지 풀로 쓰기 중단 사고 발생 시, 팀원들과의 협업 방식과 의사결정 과정에서 본인의 구체적 역할과 결과는 무엇이었나요?", "job_category": "DBA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "사고 발생 시 팀 내 역할 분담, 의사결정 흐름, 그리고 문제 해결 후 팀의 개선 방향에 대한 구체적 기여를 설명"}], "latency_sec": 31.395, "in_tokens": 2960, "out_tokens": 1145} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion {\"questions\": [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"알림 봇 프로젝트에서 SQLite를 사용한 실패 경험에서 배운 트랜잭션 격리 수준의 핵심 차이를 설명해 주세요.\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"알림 봇 DB를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.\", \"expectedSignal\": \"공간적 격리 수준(READ COMMITTED, REPEATABLE READ 등)의 차이를 명확히 설명하고, 중복 발송 문제와 그 해결 과정에서의 실제 적용 사례를 제시합니다.\"}, {\"category\": \"BEHAVIORAL\", \"question\": \"캡스톤 프로젝트에서 프론트와 API 스펙 해석이 달라 팀이 지연된 상황에서, 당신이 제안한 Mock 서버 도입 방식의 구체적 행동과 그 결과는 무엇이었나요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.\", \"expectedSignal\": \"STAR 구조를 따르며, 상황, 과제, 행동, 결과를 구체적으로 제시하고, 그 과정에서의 협업 역", "latency_sec": 28.943, "in_tokens": 2956, "out_tokens": 1025} +{"label": "local-qwen3-4b-instruct", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 분산 락을 도입한 이유와, Redis 캐시와 DB write-behind 간의 동시성 문제를 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환), 재고 불일치 건수 월 200건 → 3건", "expected_signal": "분산 락 도입 배경과 캐시-DB 간 동기화 시점의 정확한 설계를 설명하며, 실제 문제 발생 시나리오와 해결 방식을 구체적으로 제시"}, {"category": "TECH_CHOICE", "question": "Kafka를 이벤트 파이프라인으로 도입하면서, 주문 서비스와 결제 서비스 간의 메시지 전달 지연 문제를 어떻게 예방했나요?", "job_category": "BACKEND", "target_evidence": "MSA 전환: 주문 서비스를 별도 서비스로 분리, Kafka 기반 이벤트 발행/구독 구조 도입. 배포 단위 축소로 배포 주기 2주 → 2일", "expected_signal": "Kafka의 블로킹, 컨슈머 레이턴시, 토픽 디자인 등에 대한 구체적 고려 사항을 제시하고, 지연 문제를 예방하기 위한 설계 결정 과정을 설명"}, {"category": "CS_FUNDAMENTAL", "question": "멱등 키 테이블을 사용해 중복 주문을 방지했을 때, 멱등 키의 값이 중복될 수 있는 상황은 어떤 경우가 되나요? 그 상황에서 어떻게 처리했나요?", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "멱등 키의 동작 원리와 중복 가능성의 실제 사례를 제시하고, 키 생성 로직과 트랜잭션 격리 수준에서의 처리 방식을 구체적으로 설명"}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 팀원과의 협업을 개선한 경험에서, 어떤 구체적인 행동이 결과에 가장 기여했나요?", "job_category": "BACKEND", "target_evidence": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2주가 지연된 적이 있습니다. 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3건에서 0건으로 줄었습니다.", "expected_signal": "STAR 구조를 따르며, 구체적인 행동(예: 명세 작성, Mock 서버 도입), 그 행동이 초래한 결과(통합 이슈 0건), 그리고 그 과정에서의 의사결정 과정을 명확히 제시"}, {"category": "PROJECT_DEEP_DIVE", "question": "GitHub 레포에서 오프라인 편집 기능을 IndexedDB에 낙관적 업데이트를 저장한 후, last-write-wins 방식을 사용했을 때, 이 방식이 발생할 수 있는 데이터 불일치 문제는 무엇인가요? 어떻게 해결했나요?", "job_category": "BACKEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "낙관적 업데이트와 last-write-wins의 한계를 정량적으로 설명하고, 실제 데이터 불일치 사례와 CRDT 등 대안 방식의 고려 사항을 제시"}], "latency_sec": 40.384, "in_tokens": 4573, "out_tokens": 1065} +{"label": "local-qwen3-4b-instruct", "suite": "followup:cold", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "결제 키에 유니크 제약을 걸어 두 번째 요청을 기존 주문을 돌려주는 부분인데, 그 유니크 키의 구체적인 값(예: 결제 ID, 주문 ID 등)과 어떻게 결제 승인 콜백에서 추출되는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 10.665, "ttft_sec": 8.709, "in_tokens": 1708, "out_tokens": 119} +{"label": "local-qwen3-4b-instruct", "suite": "followup:after-cold", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "멱등 키와 Outbox 패턴을 함께 쓴 이유 중, 예를 들어 중복 주문이 발생할 수 있는 특정 실패 케이스를 막는 데 어떤 역할을 했나요? (예: 콜백이 지연되고, 메시지가 처리되지 않아서 주문이 중복되는 상황)", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 2.651, "ttft_sec": 0.569, "in_tokens": 1535, "out_tokens": 127} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제는 두 가지 핵심 실패 케이스를 동시에 고려해야 합니다. 먼저, 멱등 키는 동일한 주문 요청이 여러 번 처리되지 않도록 보장합니다. 결제 승인 콜백이 지연되더라도, 주문 서비스가 이미 처리한 주문인지 확인하기 위해 주문 ID와 결제 ID를 기반으로 멱등 키를 생성하여 중복 요청을 차단합니다. 이는 주문 서비스가 결제 승인을 기다리고 있을 때, 동일한 주문이 여러 번 재전송되는 것을 막습니다. 반면, Outbox 패턴은 트랜잭션 경계를 명확히 하며, 주문 생성과 결제 승인 사이의 상태 변화를 DB에 저장해 트랜잭션 실패 시도를 복구할 수 있도록 합니다. 예를 들어, 결제 승인 콜백이 실패했을 경우, 주문이 완료되지 않았음을 인지하고, 이전 상태를 복구하여 중복 주문이 발생하지 않도록 합니다. 따라서 멱등 키는 중복 주문 요청을 막고, Outbox 패턴은 트랜잭션의 일관성을 보장하여, 결제 지연 상황에서의 데이터 일관성 문제를 동시에 해결합니다.", "answer_rewrite": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제는 두 가지 핵심 실패 케이스를 겪을 수 있습니다. 먼저, 멱등 키는 주문 요청이 중복으로 전송되지 않도록 합니다. 결제 승인 콜백이 지연되더라도, 주문 서비스가 이미 처리한 주문인지 확인하기 위해 주문 ID와 결제 ID를 기반으로 멱등 키 테이블을 활용하여 동일한 주문 요청이 두 번 이상 처리되지 않도록 합니다. 이는 결제 승인 지연 시에도 주문 서비스가 중복 주문을 생성하지 않도록 보장합니다. 반면, Outbox 패턴은 주문 생성과 결제 승인 사이의 트랜잭션 경계를 명확히 하며, 주문 생성 후 결제 승인 콜백이 실패했을 경우, DB에 저장된 트랜잭션 상태를 기반으로 복구할 수 있도록 합니다. 예를 들어, 결제 콜백이 실패했을 경우, 주문이 완료되지 않았음을 인지하고, 이전 상태를 복구하여 중복 주문이 발생하지 않도록 합니다. 이처럼 멱등 키는 중복 요청을 막고, Outbox 패턴은 트랜잭션 실패 시의 데이터 일관성을 보장하여, 결제 지연 상황에서의 안정성을 확보했습니다.", "coaching_comment": "무엇이 실패했는지 구체적으로 구분하는 것이 핵심입니다. 멱등성은 중복 요청을 막고, 트랜잭션 경계는 상태 복구를 가능하게 하며, 이 두 가지의 역할을 명확히 설명해야 합니다."}, "latency_sec": 61.447, "in_tokens": 1561, "out_tokens": 750} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 영향을 주는 주요 점은 xmin horizon이 늘어나기 때문입니다. MVCC는 트랜잭션의 상태를 시간에 따라 관리하며, 각 트랜잭션은 시작 시 xmin 값을 가지며, 이 값이 끝날 때까지 해당 트랜잭션의 데이터를 '살아있는' 것으로 간주합니다. 오래된 트랜잭션은 vacuum이 이 값을 확인할 때까지 'dead tuple'을 제거하지 못하게 됩니다. 이로 인해 vacuum은 그 트랜잭션의 데이터를 '사라진' 것으로 간주하지 못하고, 결과적으로 dead tuple이 쌓이게 되며, 이는 테이블의 bloat를 유발합니다. 예를 들어, 특정 커넥션에서 오래된 트랜잭션이 끝나지 않으면, 그 트랜잭션의 xmin 값이 계속 유지되어 vacuum이 그 이후에 생성된 dead tuple을 제거하지 못하게 됩니다. 이는 특히 장기 실행 중인 트랜잭션(예: 대규모 업데이트)이 있을 때 특히 문제를 일으킬 수 있습니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum의 작동을 지연시킬 수 있습니다. MVCC는 각 트랜잭션에 대해 xmin 값을 가지며, 이 값이 끝날 때까지 해당 트랜잭션의 데이터는 '살아있는' 것으로 간주됩니다. 만약 트랜잭션이 오래 지속되면, vacuum이 그 트랜잭션의 xmin 값을 확인할 때까지 데이터를 '사라진' 것으로 간주하지 못합니다. 이로 인해 dead tuple이 누적되고, 테이블 내부에 bloat가 발생합니다. 예를 들어, 대규모 업데이트 작업 중에 트랜잭션이 오래 지속되는 경우, vacuum이 그 트랜잭션의 데이터를 제거하지 못해 테이블 크기가 계속 커지게 됩니다. 이는 성능 저하와 공간 낭비로 이어질 수 있으므로, 적절한 트랜잭션 종료 및 vacuum 실행을 관리하는 것이 중요합니다.", "coaching_comment": "오래된 트랜잭션의 xmin 값이 vacuum의 horizon을 뒤쫓는다는 점을 명확히 설명해야 합니다."}, "latency_sec": 73.135, "in_tokens": 997, "out_tokens": 570} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 통해 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 이 과정에서 팀원들이 제 방식을 옳다고 보는 것에 대해 반발하며 감정적으로 불만을 표시했고, 이후에는 단순히 '내가 맞다'는 고집을 벗어나, 결정 전에 대안 두 가지를 함께 비교하는 방식으로 협업을 조정했습니다. 이 변화 이후, 스프린트 단위 통합 이슈가 3건에서 0건으로 줄어들었고, 팀원 간의 갈등이 명확히 감소했습니다. 이 경험을 통해 저는 단순한 기술적 해결보다는, 의견 충돌 시 소통의 구조를 설계하는 것이 협업 효율을 높이는 데 더 중요하다는 것을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 그러나 이 방식을 옳다고 고집하면서 팀원들이 감정적으로 반발했고, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 협업을 재구성했습니다. 이 변화 이후, 스프린트 단위 통합 이슈가 3건에서 0건으로 줄었고, 팀원 간의 갈등이 명확히 감소했습니다. 이 경험을 통해 저는 기술적 제안보다는, 의견 충돌 시 소통의 구조를 설계하는 것이 협업의 질을 결정짓는다는 점을 깨달았습니다.", "coaching_comment": "감정적 반발을 경고하는 구체적인 행동과 그 후의 구조적 변화를 명확히 보여야 합니다."}, "latency_sec": 32.046, "in_tokens": 1392, "out_tokens": 527} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 3, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제는 두 가지 핵심 실패 케이스를 동시에 막기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다. 먼저, 멱등 키는 동일한 주문 요청이 중복으로 처리되지 않도록 보장합니다. 예를 들어, 결제 승인 콜백이 지연되더라도, DB에 이미 처리된 주문이 있는지 확인하는 키를 사용해 동일한 주문이 두 번 처리되지 않도록 합니다. 이는 결제 성공 후 주문 상태를 업데이트하는 과정에서, 이미 처리된 주문이 다시 들어오지 않도록 보호합니다. 반면, Outbox 패턴은 결제 승인 이벤트가 성공적으로 처리되었는지, 그리고 주문이 실제로 생성되었는지를 트랜잭션 경계 내에서 관리합니다. 결제 승인 이벤트가 DB에 저장되기 전에 결제 성공 여부를 확인하고, 실패 시 이벤트를 버리거나 재전송을 방지함으로써, 주문이 결제 승인 없이 중복 생성되지 않도록 합니다. 이 두 패턴은 각각 '주문 중복'과 '트랜잭션 무결성'을 해결하며, 결제 콜백 지연 상황에서 결제 후 주문이 중복으로 생성되지 않도록 구체적인 경계를 설정합니다.", "answer_rewrite": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제를 해결하기 위해, 멱등 키와 Outbox 패턴을 함께 적용했습니다. 먼저, 멱등 키를 사용해 동일한 주문 요청이 중복으로 처리되지 않도록 했습니다. 결제 승인 콜백이 지연되더라도, DB에 이미 처리된 주문의 고유 키(예: order_id + payment_id)를 기반으로 중복 체크를 수행하여 주문이 두 번 생성되지 않도록 했습니다. 이는 결제 성공 후 주문 상태 업데이트 시, 이미 처리된 주문이 다시 들어오지 않도록 보장했습니다. 또한, Outbox 패턴을 통해 결제 승인 이벤트가 DB에 저장되기 전에 결제 성공 여부를 트랜잭션 경계 내에서 검증했습니다. 결제 실패 시 이벤트는 Outbox에 저장되지 않거나, 재전송되지 않도록 하여 주문이 결제 없이 생성되지 않도록 했습니다. 이처럼 두 패턴은 각각 '주문 중복'과 '결제 트랜잭션 무결성'을 구체적으로 막았고, 결제 지연 상황에서도 주문의 일관성을 유지했습니다.", "coaching_comment": "무엇이 실패하는지 구체적으로 구분하고, 각 패턴이 어떤 실패 케이스를 막는지 명확히 설명하는 것이 핵심입니다."}, "latency_sec": 19.376, "in_tokens": 1561, "out_tokens": 708} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 4, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 xmin horizon과 관련이 있습니다. MVCC는 트랜잭션의 독립성을 보장하기 위해 각 트랜잭션이 시작될 때 하나의 xmin 값을 부여합니다. 이 xmin 값은 트랜잭션이 종료될 때까지 유지되며, vacuum은 이 값보다 작은 xmin을 가진 'dead tuple'만 제거합니다. 만약 오래된 트랜잭션이 계속 열려 있다면, 그 트랜잭션의 xmin 값이 vacuum의 xmin horizon을 초과하게 되고, 그 이하의 dead tuple은 제거되지 못합니다. 이로 인해 dead tuple이 쌓이게 되고, 테이블의 bloat가 발생합니다. 예를 들어, 특정 테이블에 오래된 트랜잭션이 존재하면, vacuum이 그 트랜잭션의 xmin을 기준으로 제거를 지연하게 되고, 이로 인해 데이터 파일이 점차 커지게 됩니다. 이는 성능 저하와 저장 공간 낭비를 초래할 수 있습니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 xmin horizon과 dead tuple 회수 지연에 있습니다. MVCC는 각 트랜잭션에 대해 시작 시 xmin 값을 부여하고, 그 값이 트랜잭션 종료 전까지 유지됩니다. vacuum은 현재 xmin horizon보다 작은 트랜잭션의 dead tuple만 제거합니다. 만약 오래된 트랜잭션이 계속 열려 있다면, 그 xmin 값이 vacuum의 horizon을 초과하게 되고, 그 이하의 dead tuple은 제거되지 않아 테이블 내에 누적됩니다. 이로 인해 dead tuple이 쌓이게 되고, 테이블의 bloat가 발생합니다. 예를 들어, 특정 테이블에 오래된 트랜잭션이 존재하면, vacuum이 그 트랜잭션의 xmin을 기준으로 제거를 지연하게 되고, 이로 인해 테이블 크기가 지속적으로 커지게 됩니다.", "coaching_comment": "오래된 트랜잭션의 xmin이 vacuum의 horizon을 초과하게 되는 점을 명확히 설명해야 합니다. 이는 dead tuple 제거 지연과 bloat 발생의 핵심 원인입니다."}, "latency_sec": 43.729, "in_tokens": 997, "out_tokens": 566} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 5, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 이 과정에서 팀원들이 제 방식을 '옳다고' 고집해 반발했고, 감정적 갈등이 생겼습니다. 그 이후 저는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 협업을 재구성했고, 스프린트 단위로 통합 이슈가 3건에서 0건으로 줄어들었습니다. 이 경험을 통해 저는 단순한 기술적 제안을 넘어서, 팀원의 입장도 고려한 소통 방식이 결과에 더 큰 영향을 미친다는 것을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 하지만 팀원들이 제 방식을 '옳다고' 고집해 반발했고, 감정적 갈등이 생겼습니다. 그 이후 저는 결정 전에 대안 두 가지를 함께 비교하고, 팀원의 의견을 수렴하는 방식으로 협업을 재구성했습니다. 결과적으로 스프린트 단위로 통합 이슈가 3건에서 0건으로 줄어들었고, 팀 내 의사소통의 품질이 개선되었습니다.", "coaching_comment": "감정적 갈등이 발생했음을 인정하고, 그 이후에 구체적으로 어떤 방식으로 개선했는지를 설명해야 합니다."}, "latency_sec": 76.202, "in_tokens": 1392, "out_tokens": 465} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 6, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제는 두 가지 핵심 실패 케이스를 동시에 막기 위해 멱등 키와 Outbox 패턴을 함께 사용했습니다. 먼저, 멱등 키는 동일한 주문 요청이 여러 번 처리되지 않도록 하며, 결제 승인 후 주문 상태를 DB에 저장할 때 이미 처리된 주문인지 확인하는 데 사용됩니다. 이는 결제 콜백이 지연되더라도, 동일한 주문 요청이 두 번 이상 처리되지 않도록 보장합니다. 반면, Outbox 패턴은 주문 생성과 결제 승인 사이의 트랜잭션 경계를 명확히 하여, 결제 승인 콜백이 실패했을 때도 주문 상태를 일관되게 유지할 수 있도록 합니다. 예를 들어, 결제 승인 콜백이 실패하면 Outbox에서 주문 상태를 '결제 완료'로 업데이트하지 않고, '결제 대기' 상태로 유지함으로써, 중복 주문이 발생하지 않도록 하고, 결제가 실패했을 때도 정산 서비스가 중복 주문을 처리하지 않게 합니다. 이 두 패턴은 각각 '주문 요청의 중복'과 '트랜잭션의 일관성'을 해결하며, 결제 지연 상황에서 지속적인 안정성을 보장합니다.", "answer_rewrite": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제를 해결하기 위해, 저는 멱등 키와 Outbox 패턴을 함께 도입했습니다. 먼저, 멱등 키는 주문 생성 시 결제 승인을 기다리는 동안, 이미 처리된 주문인지 확인하는 데 사용되었습니다. 주문 테이블에 '결제 승인 완료' 상태가 없으면, 주문을 생성하고 멱등 키를 기반으로 중복 요청을 차단했습니다. 이는 결제 콜백이 지연되더라도, 동일한 주문이 두 번 이상 처리되지 않도록 했습니다. 그리고 Outbox 패턴은 주문 생성과 결제 승인 사이의 트랜잭션 경계를 명확히 하여, 결제 콜백이 실패했을 때도 주문 상태를 일관되게 유지할 수 있도록 했습니다. 예를 들어, 결제 승인 콜백이 실패하면 Outbox에서 주문 상태를 '결제 완료'로 업데이트하지 않고, '결제 대기' 상태로 유지해, 중복 주문이 발생하지 않도록 했습니다. 이로 인해 결제 지연 상황에서도 중복 주문이 0건 발생했고, 주문 서비스의 안정성이 크게 향상되었습니다.", "coaching_comment": "곱셈적 효과를 보이기 위해 각 패턴이 막는 실패 케이스를 구체적으로 구분하고, 그에 따른 시스템 행동을 설명해야 합니다."}, "latency_sec": 81.051, "in_tokens": 1561, "out_tokens": 728} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 7, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 영향을 주는 주요 점은 xmin horizon의 확장입니다. MVCC는 트랜잭션을 통해 데이터의 일관성을 유지하면서, 각 트랜잭션의 시작점을 xmin으로 기록합니다. 오래된 트랜잭션이 계속 열려 있으면, 그 xmin 값이 vacuum이 제거할 수 있는 dead tuple의 최소값(즉, xmin horizon)을 높이게 됩니다. 이로 인해, vacuum이 그 이전 트랜잭션 이후에 생성된 dead tuple만 제거할 수 있게 되고, 그 사이에 생성된 dead tuple은 제거되지 않아 테이블에 bloat가 쌓입니다. 예를 들어, 특정 트랜잭션이 1시간 이상 실행되고 있다면, 그 xmin이 vacuum의 horizon을 초과하게 되고, 이후에 생성된 dead tuple도 그 xmin보다 작아야 제거 가능하므로, 실제로는 제거되지 않게 됩니다. 이는 데이터베이스의 성능 저하와 저장 공간 고갈을 유도할 수 있습니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 영향을 주는 핵심은 xmin horizon의 확장입니다. MVCC는 각 트랜잭션의 시작점을 xmin으로 기록하며, vacuum은 그 xmin보다 작은 값의 dead tuple만 제거할 수 있습니다. 만약 오래된 트랜잭션이 계속 열려 있다면, 그 xmin 값이 계속 유지되어 vacuum의 xmin horizon이 높아지게 됩니다. 이로 인해, 이후 생성된 dead tuple이 그 xmin보다 크거나 같아도 제거되지 않아, dead tuple이 쌓이게 되고 테이블에 bloat가 발생합니다. 예를 들어, 특정 테이블에서 오래된 트랜잭션이 계속 실행되고 있다면, vacuum이 그 트랜잭션 이후에 생성된 데이터를 제거하지 못해 데이터베이스의 공간 사용률이 점점 증가하게 됩니다. 이는 성능 저하와 저장 공간 고갈의 원인이 됩니다.", "coaching_comment": "오래 열린 트랜잭션의 xmin이 vacuum의 horizon을 초과시켜 dead tuple 제거를 지연시키는 점을 구체적으로 설명해야 합니다."}, "latency_sec": 80.694, "in_tokens": 997, "out_tokens": 549} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 8, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했고, 이로 인해 스프린트 단계에서 통합 이슈가 3건에서 0건으로 줄어들었습니다. 그러나 초기에는 제 방식이 옳다고 고집해 팀원들과 감정적 갈등이 생겼습니다. 이후 저는 결정 전에 대안 두 가지를 함께 비교하고, 팀원들과 함께 논의하는 방식으로 전환했고, 이로 인해 팀 내 의사소통이 개선되었고, 이후 프로젝트 전체의 협업 효율이 향상되었습니다. 이 경험을 통해 저는 단순히 '내 방식이 맞다'고 주장하는 것이 아니라, 팀원과의 공감과 협업을 기반으로 문제를 해결해야 한다는 점을 깨달았습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 이 방식으로 인해 스프린트 단계에서 통합 이슈가 3건에서 0건으로 줄어들었습니다. 그러나 초기에는 제 방식이 옳다고 고집해 팀원들과 감정적 갈등이 생겼습니다. 이후 저는 결정 전에 대안 두 가지를 함께 비교하고, 팀원들과 함께 논의하는 방식으로 전환했고, 이로 인해 팀 내 협업이 원활해졌고, 이후 프로젝트의 전체 개발 속도가 향상되었습니다.", "coaching_comment": "감정적 갈등이 있었음을 인정하고, 그 후에 구체적으로 어떤 방식으로 개선했는지 설명하는 것이 신뢰를 줍니다."}, "latency_sec": 75.747, "in_tokens": 1392, "out_tokens": 529} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 9, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제는 두 가지 핵심 실패 케이스를 동시에 해결해야 합니다. 먼저, 멱등 키는 동일한 주문 요청이 여러 번 처리되지 않도록 보장합니다. 결제 승인 콜백이 지연되더라도, 이미 처리된 주문에 대해 동일한 주문 ID로 중복 요청이 올 수 있는 상황을 막기 위해 주문 테이블에 멱등 키를 저장하고, 이후 요청이 동일한 키를 가진 경우 중복 처리를 방지합니다. 이는 결제 승인 후 주문이 완료된 상태인지 확인하지 않은 경우의 중복 주문을 막습니다. 반면, Outbox 패턴은 트랜잭션 경계를 명확히 하여, 결제 승인 요청이 실패하거나 콜백이 오지 않아도 주문 상태가 일관되게 유지되도록 합니다. 결제 서비스에서 주문 생성 트랜잭션을 완료하고, 결제 승인 결과를 Outbox에 저장한 후, 콜백이 오지 않아도 주문 상태는 '결제 대기' 상태로 유지되며, 이후 콜백이 오면 해당 상태를 반영합니다. 이처럼 멱등 키는 중복 요청을 막고, Outbox 패턴은 트랜잭션 외부의 실패 상황에서 데이터 일관성을 보장합니다. 두 패턴을 함께 사용함으로써, 요청의 중복과 트랜잭션의 완전성 실패를 동시에 예방할 수 있습니다.", "answer_rewrite": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제는 두 가지 실패 케이스를 구분해서 해결했습니다. 먼저, 멱등 키는 동일한 주문 ID를 가진 요청이 여러 번 도달할 경우 중복 주문을 막습니다. 주문 생성 시 주문 ID를 멱등 키 테이블에 저장하고, 이후 요청이 동일한 ID를 가진 경우 처리를 거부하여 중복 주문을 방지합니다. 이는 결제 승인 콜백이 지연되더라도, 이미 처리된 주문에 대한 요청이 다시 들어올 수 있는 상황을 막습니다. 반면, Outbox 패턴은 트랜잭션 경계를 확보하여, 결제 승인 요청이 실패하거나 콜백이 오지 않아도 주문 상태가 일관되게 유지됩니다. 주문 생성 트랜잭션을 완료하고, 결제 승인 결과를 Outbox에 저장한 후, 콜백이 오지 않아도 주문 상태는 '결제 대기'로 유지되며, 이후 콜백이 오면 해당 상태를 반영합니다. 이처럼 멱등 키는 요청 수준의 중복을 방지하고, Outbox 패턴은 트랜잭션 외부의 실패 상황에서 데이터 일관성을 보장합니다. 두 패턴을 함께 적용함으로써, 중복 주문과 트랜잭션 실패의 두 가지 핵심 실패 케이스를 동시에 막을 수 있었습니다.", "coaching_comment": "중복 주문과 트랜잭션 실패를 구체적인 실패 케이스로 구분하고, 각 패턴이 어떻게 그 케이스를 막는지 명확히 설명해야 합니다."}, "latency_sec": 83.411, "in_tokens": 1561, "out_tokens": 825} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 10, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 xmin horizon과 관련이 있습니다. MVCC는 트랜잭션의 독립성을 보장하기 위해 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리합니다. 오래 열린 트랜잭션은 그 xmin을 기준으로 데이터를 '사용 중'으로 표시하고, 이로 인해 vacuum이 그 트랜잭션의 끝을 기다려야 합니다. 이는 dead tuple(사라져야 할 트랜잭션의 데이터)을 제거하는 데 지연을 초래합니다. 특히, 이 지연이 지속되면 테이블에 bloat가 생기며, 성능 저하와 함께 디스크 사용량 증가로 이어질 수 있습니다. 예를 들어, long-running transaction이 계속 중인 경우 vacuum이 그 트랜잭션의 xmin을 넘지 못해, 그 이후에 생성된 dead tuple이 제거되지 않아 테이블이 점차 커지게 됩니다. 이는 특히 대규모 테이블이나 고주파 트랜잭션 환경에서 문제로 작용합니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션은 vacuum이 dead tuple을 제거할 때 xmin horizon을 차단합니다. MVCC는 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리하므로, 오래 열린 트랜잭션은 그 xmin을 기준으로 데이터를 '사용 중'으로 표시하고, vacuum은 그 트랜잭션이 끝날 때까지 이 기준을 넘을 수 없습니다. 이로 인해 dead tuple이 제거되지 않아 테이블 내부에 bloat가 쌓이게 되고, 이는 성능 저하와 디스크 사용량 증가를 초래할 수 있습니다. 예를 들어, 특정 테이블에 오래된 트랜잭션이 존재할 경우, vacuum이 그 트랜잭션의 xmin을 넘지 못해, 그 이후에 생성된 데이터가 사라지지 않게 되며, 이는 테이블의 크기를 지속적으로 늘리는 결과를 낳습니다.", "coaching_comment": "오래 열린 트랜잭션의 xmin horizon이 vacuum의 작동을 차단한다는 점을 명확히 설명해야 합니다."}, "latency_sec": 72.746, "in_tokens": 997, "out_tokens": 572} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 11, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 그때 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 이 과정에서 팀원들이 제 방식을 옳다고 생각하는 데 반발하며 감정적으로 반발했고, 이후에는 결정 전에 반드시 두 가지 대안을 함께 비교하는 방식으로 접근을 바꿨습니다. 이 변화 이후, 스프린트 단위 통합 이슈가 3건에서 0건으로 줄어들었고, 팀 내 의사소통의 질이 향상되었습니다. 이 경험을 통해 저는 단순한 정답을 내리기보다, 다수의 관점과 대안을 고려하는 것이 협업의 핵심이라는 것을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연되는 상황이 있었습니다. 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 그러나 팀원들이 제 방식을 옳다고 생각하는 데 반발하며 감정적으로 반발했고, 그 후 저는 결정 전에 반드시 두 가지 대안을 함께 논의하는 방식으로 접근을 수정했습니다. 이 변화 이후, 스프린트 단위 통합 이슈가 3건에서 0건으로 줄어들었고, 팀 내 갈등이 줄어들고 소통이 더 효율적으로 이루어졌습니다. 이 경험을 통해 저는 단순한 정답보다는 다수의 관점과 대안을 고려하는 것이 협업에서 더 큰 신뢰를 만든다는 점을 깨달았습니다.", "coaching_comment": "감정적 반발이 있었음을 인정하고, 그 후에 구체적으로 어떤 방식으로 변화를 도입했는지 보여줘야 합니다."}, "latency_sec": 67.671, "in_tokens": 1392, "out_tokens": 512} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 12, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제는 두 가지 핵심 실패 케이스를 동시에 막기 위해 멱등 키와 Outbox 패턴을 조합했습니다. 먼저, 멱등 키는 동일한 주문 요청이 두 번 이상 처리되지 않도록 보장합니다. 예를 들어, 결제 승인 콜백이 지연되더라도, 주문 서비스 내에서 이미 처리된 주문을 다시 생성하지 않도록 주문 ID와 결제 요청 ID를 기반으로 멱등 키 테이블에 기록하여 중복을 차단합니다. 이는 주문 서비스의 내부 트랜잭션 경계에서 중복 주문을 방지합니다. 반면, Outbox 패턴은 결제 승인 상태가 DB에 반영되기 전에 결제 결과가 실패하거나 지연될 경우, 주문이 완전히 취소되거나 재처리되지 않도록 보장합니다. 즉, 결제 승인 콜백이 오지 않았을 때도, 주문이 완전히 완료되지 않도록 하여, 결제 상태와 주문 상태 간의 불일치를 막습니다. 이 두 패턴은 각각 '중복 생성'과 '트랜잭션 완전성'이라는 실패 케이스를 구체적으로 차단하며, 결제 지연 상황에서 주문의 일관성을 유지하는 데 필수적입니다.", "answer_rewrite": "결제 승인 콜백 지연 시 중복 주문이 발생할 수 있는 문제를 해결하기 위해, 저는 멱등 키와 Outbox 패턴을 함께 적용했습니다. 먼저, 멱등 키를 사용해 주문 요청이 이미 처리되었는지 확인했습니다. 결제 승인 콜백이 지연되더라도, 주문 서비스 내에서 동일한 주문 요청이 두 번 이상 처리되지 않도록 주문 ID와 결제 요청 ID를 기반으로 멱등 키 테이블에 기록했습니다. 이는 주문 서비스 내부에서 중복 주문을 방지합니다. 그 외, Outbox 패턴을 통해 결제 승인 콜백이 오지 않았을 경우에도, 주문 상태가 완전히 완료되지 않도록 하였습니다. 결제 결과가 DB에 반영되기 전에 결제 상태가 '승인'이 되지 않았을 경우, 주문 상태를 '취소'로 전환하고, 결제 결과가 오지 않았음을 기록하는 방식으로 트랜잭션 경계를 확보했습니다. 이로 인해, 결제 지연 시에도 주문 상태와 결제 상태 간의 불일치를 막고, 중복 주문 0건을 달성할 수 있었습니다.", "coaching_comment": "명확히 구분된 실패 케이스를 각 패턴이 막는 방식을 설명해야 합니다. 멱등성은 중복 생성, 트랜잭션 경계는 상태 불일치를 막는다는 구조를 강조해야 합니다."}, "latency_sec": 73.978, "in_tokens": 1561, "out_tokens": 733} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 13, "ok": true, "coaching": {"model_answer": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 주로 xmin horizon과 관련이 있습니다. MVCC는 트랜잭션의 독립성을 위해 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리합니다. 오래된 트랜잭션이 아직 종료되지 않았다면, 그 트랜잭션의 xmin 값이 'xmin horizon'으로 설정되며, 이후에 생성된 dead tuple은 그 xmin보다 작거나 같은 값을 가진 트랜잭션에 의해 생성된 것이므로, vacuum이 그 dead tuple을 제거하지 못합니다. 이로 인해 dead tuple이 쌓이게 되고, 테이블의 bloat가 발생할 수 있습니다. 예를 들어, 장기적으로 실행되는 트랜잭션(예: 대용량 업데이트)이 종료되지 않으면, 그 트랜잭션의 xmin이 계속 유지되며, 이후에 생성된 테이블 데이터는 그 xmin보다 높은 값을 가질 수 없기 때문에 vacuum이 제거할 수 없는 dead tuple이 남게 됩니다. 이는 테이블의 크기가 점차 커지고, 성능 저하를 유발할 수 있습니다.", "answer_rewrite": "PostgreSQL의 MVCC에서 오래 열린 트랜잭션이 vacuum에 미치는 영향은 xmin horizon과 dead tuple 회수 지연에 있습니다. MVCC는 각 트랜잭션의 시작 시점(xmin)을 기준으로 데이터를 관리하며, 트랜잭션이 종료되지 않으면 그 xmin이 xmin horizon에 유지됩니다. vacuum은 xmin horizon보다 작은 값을 가진 dead tuple만 제거할 수 있기 때문에, 오래된 트랜잭션이 종료되지 않으면 그 이후에 생성된 dead tuple은 vacuum이 제거하지 못합니다. 이로 인해 dead tuple이 쌓이게 되고, 테이블의 bloat가 발생합니다. 예를 들어, 대용량 업데이트 작업이 오래 진행되거나, 롤백되지 않은 트랜잭션이 남아 있다면, 그 트랜잭션의 xmin이 계속 유지되어 vacuum이 효과적으로 작동하지 못하게 됩니다. 이는 테이블의 크기와 I/O 부하를 증가시켜 성능 저하를 유발할 수 있습니다.", "coaching_comment": "오래된 트랜잭션의 xmin이 xmin horizon을 유지하는 점을 명확히 설명하고, 그로 인한 dead tuple 제거 지연과 bloat 연결을 구체적으로 제시해야 합니다."}, "latency_sec": 73.555, "in_tokens": 997, "out_tokens": 602} +{"label": "local-qwen3-4b-instruct", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 14, "ok": true, "coaching": {"model_answer": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연된 경험을 가졌습니다. 당시 저는 OpenAPI 명세를 먼저 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 이 과정에서 팀원은 제가 스펙을 '정답'으로 삼는 태도를 보여서 감정이 상했고, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 접근을 바꾸었습니다. 예를 들어, 스펙 수정 시에는 '직접 명세를 수정'과 '추가 문서로 설명'을 함께 제안해 팀원들의 의견을 반영했고, 이로 인해 이후 스프린트에서 통합 이슈가 3건에서 0건으로 줄어들었습니다. 이 경험을 통해 저는 단순한 의견 수렴을 넘어, 팀원의 입장과 기술적 현실을 동시에 고려하는 협업 방식이 필요하다는 점을 배웠습니다.", "answer_rewrite": "캡스톤 프로젝트에서 프론트엔드 팀원과 API 스펙 해석이 달라 통합이 2주 지연된 상황이 있었습니다. 저는 먼저 OpenAPI 명세를 작성하고, Mock 서버를 띄워 프론트 팀이 병렬로 개발할 수 있도록 제안했습니다. 그러나 이 과정에서 제가 스펙을 '정답'으로 고집한 태도가 팀원에게 부정적인 반응을 유발했고, 그 후로 저는 결정 전에 대안 두 가지를 함께 제안하는 방식으로 접근을 수정했습니다. 예를 들어, 스펙 수정 시에는 '명세 변경'과 '추가 설명 문서'를 함께 제안해 팀원들의 의견을 반영했습니다. 이로 인해 이후 스프린트에서 통합 이슈가 3건에서 0건으로 줄어들었고, 팀 내의 갈등이 사라지며 협업의 투명성이 향상되었습니다.", "coaching_comment": "의견 충돌 시 감정적 반응을 피하고, 대안 제시를 통해 팀원의 입장도 반영하는 것이 핵심입니다."}, "latency_sec": 67.51, "in_tokens": 1392, "out_tokens": 555} +{"label": "local-qwen3-4b-instruct", "suite": "followup:during-fanout", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "결제 키에 유니크 제약을 걸어 두 번째 요청을 돌려주는 부분인데, 그 유니크 제약이 어떤 컬럼에 적용되었고, 그 값이 어떻게 생성되는지 구체적으로 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 5.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 78.779, "ttft_sec": 77.151, "in_tokens": 1708, "out_tokens": 101} +{"label": "local-qwen3-4b-instruct", "suite": "fanout_wall", "wall_sec": 224.064, "ok": true} diff --git a/docs/research/llm-eval-2026-09/raw/local-qwen3.5-4b.jsonl b/docs/research/llm-eval-2026-09/raw/local-qwen3.5-4b.jsonl new file mode 100644 index 0000000..d63109f --- /dev/null +++ b/docs/research/llm-eval-2026-09/raw/local-qwen3.5-4b.jsonl @@ -0,0 +1,80 @@ +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "동일한 트랜잭션 내에서 outbox 테이블에 주문 정보를 기록하신 구체적 SQL 또는 애플리케이션 로직은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "PARTIAL_STAR", "correctness": 5.0}, "latency_sec": 7.079, "ttft_sec": 4.308, "in_tokens": 1411, "out_tokens": 76} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-weak-vague", "rep": 0, "ok": true, "followup_question": "중복 주문을 막는 멱등 키와 트랜잭션 관리가 각각 구체적으로 어떤 실패 시나리오를 방지하는지 말씀해 주세요.", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.464, "ttft_sec": 3.771, "in_tokens": 1292, "out_tokens": 76} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 0, "ok": true, "followup_question": "그렇다면 xmin horizon 이 vacuum 회수 작업에 미치는 구체적인 영향은 무엇이라고 생각하시나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 5.775, "ttft_sec": null, "in_tokens": 1252, "out_tokens": 64} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 0, "ok": true, "followup_question": "React 18 의 자동 배칭이 setTimeout 내부에도 적용되는 이유는 무엇인가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 5.69, "ttft_sec": null, "in_tokens": 1254, "out_tokens": 61} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-clarification", "rep": 0, "ok": true, "followup_question": "HPA 가 트래픽 피크를 감지하고 자동으로 스케일아웃하는 데 걸리는 지연 시간과, 이를 예측 가능한 피크를 미리 대응하는 두 가지 전략의 차이점을 다시 설명해 주실 수 있을까요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 7.006, "ttft_sec": 3.788, "in_tokens": 1284, "out_tokens": 91} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-confirm-short", "rep": 0, "ok": true, "followup_question": "그럼 outbox 릴레이의 폴링 주기는 몇 초인가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 3.0, "logic": 3.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.579, "ttft_sec": 3.571, "in_tokens": 1266, "out_tokens": 58} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 0, "ok": true, "followup_question": "이력서에는 CPU 70% 기준과 트래픽 피크 대비 사전 스케일아웃을 운영하셨는데, 실제 설계는 어땠나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.492, "ttft_sec": 4.778, "in_tokens": 1566, "out_tokens": 77} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 0, "ok": true, "followup_question": "특히 seq scan 을 해결한 복합 인덱스 (user_id, created_at) 가 p95 를 900ms 까지 낮춘 데에 기여한 비중은 어느 정도인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 8.091, "ttft_sec": 5.131, "in_tokens": 1678, "out_tokens": 84} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 0, "ok": true, "followup_question": "변경된 INP 120ms 는 Profiler 가 측정했거나 실제 Lighthouse 점수 개선으로 확인되었나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.574, "ttft_sec": 4.955, "in_tokens": 1638, "out_tokens": 70} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-personality-star", "rep": 0, "ok": true, "followup_question": "OpenAPI 명세와 Mock 서버를 도입하신 결정의 핵심 근거와 예상되는 기술적 트레이드오프는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.392, "ttft_sec": 3.9, "in_tokens": 1351, "out_tokens": 71} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 0, "ok": true, "followup_question": "\"의견이 다를 때 대화를 많이 한다\"는 구체적 대화 방식과, 그 결과로 팀 성과가 어떻게 달라졌는지 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 3.0, "structure": "PARTIAL_STAR", "correctness": null}, "latency_sec": 6.539, "ttft_sec": 3.73, "in_tokens": 1287, "out_tokens": 79} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 0, "ok": true, "followup_question": "충돌 빈도를 구체적으로 수치로 말씀하신다면, 변경 전과 변경 후의 비율은 어떻게 되셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.219, "ttft_sec": 3.907, "in_tokens": 1330, "out_tokens": 68} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 0, "ok": true, "followup_question": "주문 서비스에서 CANCELLED 로 변경되는 보상 흐름이 실제로 실행되는 시점은 언제인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.043, "ttft_sec": 4.863, "in_tokens": 1603, "out_tokens": 65} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-english-mixed", "rep": 0, "ok": true, "followup_question": "네트워크 요청 40% 감소는 화면별 staleTime 세분화 때문인가요, 아니면 TanStack Query 의 기본 중복 방지 기능 때문인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.316, "ttft_sec": 3.719, "in_tokens": 1310, "out_tokens": 73} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-strong-backend", "rep": 1, "ok": true, "followup_question": "동일한 트랜잭션 내 이벤트 발행을 보장하기 위해 Outbox 패턴을 선택하신 구체적인 기술적 이유는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.707, "ttft_sec": 4.282, "in_tokens": 1411, "out_tokens": 71} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "중복 주문을 막기 위해 멱등 키를 사용하셨는데, 트랜잭션 경계와 어떻게 조화를 이루셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.252, "ttft_sec": 3.762, "in_tokens": 1292, "out_tokens": 71} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 1, "ok": true, "followup_question": "xmin horizon 설정이 어떻게 vacuum 지연으로 이어지는지 구체적으로 알고 계셨나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 0.0, "logic": 0.0, "structure": "NONE", "correctness": null}, "latency_sec": 5.711, "ttft_sec": null, "in_tokens": 1252, "out_tokens": 63} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 1, "ok": true, "followup_question": "React 18 의 자동 배칭이 비동기 콜백 내부에도 적용되는 이유는 무엇인가요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 5.872, "ttft_sec": null, "in_tokens": 1254, "out_tokens": 65} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-clarification", "rep": 1, "ok": true, "followup_question": "CLARIFICATION\nHPA 의 반응 지연 시간과 트래픽 피크를 사전에 감지하여 스케일아웃하는 시점의 차이를 다시 쉽게 설명해 주실 수 있을까요?\n{\"specificity\": null, \"logic\": null, \"structure\": \"NONE\", \"correctness\": null}", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 6.464, "ttft_sec": null, "in_tokens": 1284, "out_tokens": 75} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-confirm-short", "rep": 1, "ok": true, "followup_question": "DONT_KNOW\n\n{\"specificity\": null, \"logic\": null, \"structure\": \"NONE\", \"correctness\": null}", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 4.941, "ttft_sec": null, "in_tokens": 1266, "out_tokens": 43} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 1, "ok": true, "followup_question": "이력서에 CPU 70% 기준과 월급날 사전 스케일아웃을 언급하셨는데, 실제 메모리 기준은 왜 설정하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.562, "ttft_sec": 4.711, "in_tokens": 1566, "out_tokens": 74} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 1, "ok": true, "followup_question": "파티셔닝 전 p95 가 900ms 로 내려간 인덱스 변경의 구체적인 성능 지표는 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.674, "ttft_sec": 5.216, "in_tokens": 1678, "out_tokens": 72} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 1, "ok": true, "followup_question": "변경된 높이 캐시 전략이 동적 레이아웃에서 실제 성능 향상에 기여한 구체적인 수치나 사례가 있나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.334, "ttft_sec": 4.958, "in_tokens": 1638, "out_tokens": 70} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-personality-star", "rep": 1, "ok": true, "followup_question": "OpenAPI 명세와 Mock 서버를 제안하신 결정에 앞서, 당시 팀원들이 왜 그 방식을 거부했나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.268, "ttft_sec": 3.885, "in_tokens": 1351, "out_tokens": 68} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 1, "ok": true, "followup_question": "\"대화를 많이 한다\"는 구체적인 행동이나, 그 결과로 팀 성과가 어떻게 개선되었는지 숫자나 사례로 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.356, "ttft_sec": 3.7, "in_tokens": 1287, "out_tokens": 76} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 1, "ok": true, "followup_question": "충돌 빈도를 줄이려다 오히려 DB 부하가 커진 건가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.25, "ttft_sec": 4.005, "in_tokens": 1330, "out_tokens": 65} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 1, "ok": true, "followup_question": "주문 서비스의 주문 상태를 CANCELLED 로 바꾸는 보상 흐름에서, 결제 서비스의 취소 요청이 실제로 전달되었는지 어떻게 검증하시나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.509, "ttft_sec": 4.858, "in_tokens": 1603, "out_tokens": 74} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-english-mixed", "rep": 1, "ok": true, "followup_question": "네트워크 요청 40% 감소는 화면별 staleTime 설정과 invalidateQueries 사용에 기인한 건가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.122, "ttft_sec": 3.725, "in_tokens": 1310, "out_tokens": 69} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-strong-backend", "rep": 2, "ok": true, "followup_question": "동일한 트랜잭션 내 주문 저장과 Outbox 이벤트 발행 시, 트랜잭션 롤백 시 어떤 데이터 상태가 남게 되나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.026, "ttft_sec": 4.282, "in_tokens": 1411, "out_tokens": 77} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-weak-vague", "rep": 2, "ok": true, "followup_question": "중복 주문을 막기 위해 멱등 키를 사용하셨는데, 트랜잭션 경계와 어떻게 연계하셨나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "NONE", "correctness": null}, "latency_sec": 6.218, "ttft_sec": null, "in_tokens": 1292, "out_tokens": 73} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dont-know-explicit", "rep": 2, "ok": true, "followup_question": "xmin horizon 이 트랜잭션 종료 시점까지 지연되면 vacuum 이 어떻게 작동하는지 구체적으로 설명해 주실 수 있나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 6.004, "ttft_sec": null, "in_tokens": 1252, "out_tokens": 71} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dont-know-stt", "rep": 2, "ok": true, "followup_question": "React 18 의 자동 배칭이 비동기 콜백 내부에서도 업데이트를 배칭한다는 점을 알고 계셨나요?", "answer_intent": "DONT_KNOW", "answer_evaluation": null, "latency_sec": 5.949, "ttft_sec": null, "in_tokens": 1254, "out_tokens": 70} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-clarification", "rep": 2, "ok": true, "followup_question": "HPA 가 트래픽 피크를 감지하고 파드를 추가하는 데 걸리는 시간과, 이를 미리 예측해 스케일아웃을 동시에 수행했을 때의 이점을 다시 설명해 주실 수 있을까요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 6.843, "ttft_sec": 3.786, "in_tokens": 1284, "out_tokens": 87} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-confirm-short", "rep": 2, "ok": true, "followup_question": "outbox 릴레이를 별도 프로세스로 폴링하는 대신, Redis Pub/Sub 같은 실시간 메커니즘을 사용하신 건가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.18, "ttft_sec": 3.635, "in_tokens": 1266, "out_tokens": 70} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-infra-fact-error", "rep": 2, "ok": true, "followup_question": "이력서에 CPU 70% 기준과 월급날 피크 대비 사전 스케일아웃을 운영하셨던 건가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 2.0, "logic": 2.0, "structure": "NONE", "correctness": 3.0}, "latency_sec": 7.242, "ttft_sec": 4.763, "in_tokens": 1566, "out_tokens": 71} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-dba-correct-with-context", "rep": 2, "ok": true, "followup_question": "autovacuum 의 scale_factor 를 0.2 에서 0.05 로 낮춘 이유는 Dead tuple 축적 방지 외에 다른 고려사항이 있으신가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.832, "ttft_sec": 5.136, "in_tokens": 1678, "out_tokens": 77} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-frontend-strong", "rep": 2, "ok": true, "followup_question": "변경된 항목 높이를 캐싱하기 위해 구체적으로 어떤 키나 구조를 사용하셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.256, "ttft_sec": 4.97, "in_tokens": 1638, "out_tokens": 65} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-personality-star", "rep": 2, "ok": true, "followup_question": "OpenAPI 명세와 Mock 서버를 제안하신 결정에 대한 구체적인 근거를 더 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.235, "ttft_sec": 3.928, "in_tokens": 1351, "out_tokens": 67} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-personality-rambling", "rep": 2, "ok": true, "followup_question": "CLARIFICATION\n질문하신 '의견 충돌'과 '해결 과정'을 구체적 사례나 행동으로 설명해 주시겠습니까?\n{\"specificity\": 1, \"logic\": 1, \"structure\": \"NONE\", \"correctness\": null}", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 6.071, "ttft_sec": null, "in_tokens": 1287, "out_tokens": 65} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-stt-messy-normal", "rep": 2, "ok": true, "followup_question": "충돌 빈도를 월 200 건에서 3 건으로 줄이신 구체적 기준은 무엇인가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.175, "ttft_sec": 3.889, "in_tokens": 1330, "out_tokens": 66} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-long-answer-history", "rep": 2, "ok": true, "followup_question": "주문 서비스의 주문 상태가 CANCELLED 로 변경되는 보상 흐름의 구체적인 실행 시점과 조건을 말씀해 주실 수 있나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 7.525, "ttft_sec": 4.869, "in_tokens": 1603, "out_tokens": 75} +{"label": "local-qwen3.5-4b", "suite": "followup", "case_id": "f-english-mixed", "rep": 2, "ok": true, "followup_question": "mutation 후 invalidateQueries 로 목록만 갱신하는 건가요? 전체 캐시를 지우셨나요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 6.099, "ttft_sec": 3.756, "in_tokens": 1310, "out_tokens": 66} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생하는 문제의 핵심은 '외부 이벤트의 재발생'과 '트랜잭션 경계의 불확실성'입니다. 멱등 키는 Kafka 메시지의 재전송 (재발생) 을 방지하여 같은 주문이 두 번 처리되는 것을 막고, 트랜잭션 (Outbox 패턴) 은 DB 변경이 완료되기 전까지 메시지를 발행하지 않음으로써, DB 롤백 후에도 중복 발행을 방지합니다. 두 방식을 함께 쓴 이유는 멱등 키만으로는 트랜잭션 내의 오류 (롤백) 를 막을 수 없으므로, 트랜잭션이 성공적으로 완료된 상태임을 보장해야 하기 때문입니다.", "answer_rewrite": "중복 주문을 방지하기 위해 멱등 키와 트랜잭션 (Outbox 패턴) 을 함께 적용했습니다. 먼저 멱등 키는 Kafka 메시지가 재전송될 경우에도 같은 주문을 두 번 처리하지 않도록 ID 기반 중복을 막습니다. 또한 트랜잭션 (Outbox 패턴) 은 DB 변경이 완료되지 않은 상태에서는 메시지를 발행하지 않아, DB 롤백 시에도 중복 발행을 방지했습니다. 두 방식을 병행함으로써 외부 이벤트 재발생과 내부 트랜잭션 오류를 모두 차단하여 중복 주문 0 건을 달성했습니다.", "coaching_comment": "두 패턴이 각각 어떤 실패 케이스 (재발생 vs 트랜잭션 롤백) 를 막는지 구체적으로 구분하여 설명해야 합니다."}, "latency_sec": 18.753, "in_tokens": 1310, "out_tokens": 327} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 0, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은 xmin horizon 을 낮게 유지하여, 해당 트랜잭션이 종료될 때까지 해당 데이터의 tuple 을 'dead tuple'로 인식하지 못하게 만듭니다. 이는 트랜잭션이 종료될 때까지 해당 데이터가 reclaim list 에 추가되지 못하게 하여, vacuum 과정이 해당 데이터를 즉시 회수하지 못하게 합니다. 결과적으로 테이블의 실제 데이터 크기보다 더 많은 공간이 할당되어 테이블 bloat 가 발생하고, 전체적인 vacuum 지연 시간이 길어집니다. 만약 과거에 PostgreSQL 의 트랜잭션 관리나 MVCC 메커니즘에 대한 학습 경험을 가지고 있다면, 이러한 개념을 설명할 때 구체적인 예시를 들어 설명하는 것이 좋습니다.", "answer_rewrite": "MVCC 에서 오래 열린 트랜잭션은 xmin horizon 을 낮게 유지하여, 해당 트랜잭션이 종료될 때까지 해당 데이터가 reclaim list 에 추가되지 못하게 합니다. 이로 인해 vacuum 이 해당 데이터를 즉시 회수하지 못하게 되어 테이블 bloat 가 발생하고, 전체적인 vacuum 지연 시간이 길어집니다.", "coaching_comment": "지원자 답변이 '모르겠다'로 끝났으므로, 지원자의 실제 학습 경험이나 기술적 이해도를 바탕으로 구체적인 설명 구조를 제안해야 합니다."}, "latency_sec": 14.991, "in_tokens": 871, "out_tokens": 273} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 0, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2 주 지연된 경험이었습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축해 프론트엔드 팀과 병렬 개발을 가능하게 했으며, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 다만 초기에는 제 방식이 옳다고 고집하며 팀원 간 감정 상을 초래한 점이 있었습니다. 이후에는 결정 전 대안 두 가지를 비교하는 방식을 도입하여 신뢰를 회복했습니다. 이 경험은 기술적 해결책보다 '투명한 의사결정 과정'이 팀워크와 결과에 더 중요한 것을 가르쳐 주었습니다.", "answer_rewrite": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2 주 지연된 경험이었습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축해 프론트엔드 팀과 병렬 개발을 가능하게 했으며, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 다만 초기에는 제 방식이 옳다고 고집하며 팀원 간 감정 상을 초래한 점이 있었습니다. 이후에는 결정 전 대안 두 가지를 비교하는 방식을 도입하여 신뢰를 회복했습니다. 이 경험은 기술적 해결책보다 '투명한 의사결정 과정'이 팀워크와 결과에 더 중요한 것을 가르쳐 주었습니다.", "coaching_comment": "단순히 '소통이 중요하다'고 말하는 대신, 구체적인 갈등 상황, 본인이 취한 행동, 정량적 결과, 그리고 그 후의 변화까지 STAR 구조로 서술해야 합니다."}, "latency_sec": 19.72, "in_tokens": 1183, "out_tokens": 362} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 1, "ok": true, "coaching": {"model_answer": "결제 승인 콜백 지연 시 중복 주문이 발생했을 때 멱등 키와 Outbox 패턴을 병용한 이유는 두 패턴이 서로 다른 실패 영역을 보완하기 때문입니다. 멱등 키는 DB 트랜잭션 내의 **중복 처리 실패**를 방지하며, Outbox 패턴은 **DB 가락 (Deadlock) 또는 서비스 다운으로 인한 이벤트 발행 실패**를 막습니다. 예를 들어, 멱등 키만 사용하면 트랜잭션이 락으로 인해 완료되지 않아 이벤트가 발행되지 않으면서도 DB 가 막혀버릴 수 있습니다. 반면 Outbox 만 사용하면 트랜잭션이 성공적으로 완료되었으나 외부 시스템 (카프카) 에 연결 실패로 인해 이벤트가 전달되지 않는 경우를 처리하지 못합니다. 저는 MSA 전환 과정에서 주문 서비스 분리를 통해 트랜잭션 경계를 명확히 하고, 멱등 키로 DB 내 중복을 차단하며, Outbox 를 통해 트랜잭션 성공 시 반드시 이벤트 발행을 보장하는 구조를 설계했습니다. 이를 통해 결제 승인 지연 시에도 중복 주문 0 건을 유지했습니다.", "answer_rewrite": "결제 승인 콜백 지연으로 인한 중복 주문 문제를 멱등 키와 Outbox 패턴을 함께 사용하여 해결했습니다. 멱등 키는 DB 트랜잭션 내에서 같은 주문이 두 번 처리되는 것을 막고, Outbox 패턴은 트랜잭션이 성공적으로 완료되었으나 외부 시스템 (카프카) 에 이벤트가 전달되지 않는 실패 케이스를 방지하기 위해 사용했습니다. MSA 전환 과정에서 주문 서비스를 분리하고 Kafka 기반 이벤트 파이프라인을 도입한 결과, 결제 승인 지연 상황에서도 중복 주문 0 건을 달성했습니다.", "coaching_comment": "두 패턴이 각각 해결하려는 구체적인 실패 케이스(트랜잭션 내 중복 vs 트랜잭션 외 이벤트 전달 실패) 를 명확히 구분하여 설명해야 합니다."}, "latency_sec": 22.687, "in_tokens": 1310, "out_tokens": 421} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은 xmin horizon 을 낮게 유지하여, 해당 트랜잭션이 종료될 때까지 해당 튜플이 'dead tuple'로 인식되지 못하게 막습니다. 이는 트랜잭션 종료 시점까지 해당 데이터가 reclaim 할 수 없게 되어 테이블 bloat 를 유발하고, vacuum 작업이 이를 제거하기까지 지연되게 만듭니다. 만약 지원자가 실제 PostgreSQL 운영 경험이 있다면, '오래된 트랜잭션이 쌓이면 vacuum 가 비효율적으로 작동하여 테이블 부피가 실제 데이터 양보다 크게 늘어나는(bloat) 문제를 경험했다'는 구체적인 사례를 들어 설명하는 것이 좋습니다.", "answer_rewrite": null, "coaching_comment": "모르는 내용을 인정하는 대신, 기본 개념은 설명하고 지원자 경험과 연결해 답변을 완성해야 합니다."}, "latency_sec": 11.363, "in_tokens": 871, "out_tokens": 187} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 1, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 인해 통합 직전 2 주가 지연된 경험이었습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 제안했고, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 하지만 초기에는 제 방식이 옳다고 주장하며 감정이 상한 점을 인정하고, 이후에는 결정 전에 대안 두 가지를 비교하는 방식을 도입하여 팀원들의 참여를 높였습니다. 이는 기술적 정확성보다 팀원들의 신뢰와 협력을 우선시하는 태도 변화가 결과적으로 더 빠른 통합 속도를 가져왔음을 보여줍니다.", "answer_rewrite": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 인해 통합 직전 2 주가 지연된 경험이었습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 제안했고, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 다만 초기에는 제 방식이 옳다고 주장하며 감정이 상한 점을 인정하고, 이후에는 결정 전에 대안 두 가지를 비교하는 방식을 도입하여 팀원들의 참여를 높였습니다. 기술적 정확성보다 팀원들의 신뢰와 협력을 우선시하는 태도 변화가 결과적으로 더 빠른 통합 속도를 가져왔음을 보여줍니다.", "coaching_comment": "단순히 '소통이 중요함'이라고만 말하기보다, 구체적인 갈등 상황과 행동, 그리고 그 결과로 얻은 정량적 데이터를 제시해야 합니다."}, "latency_sec": 19.476, "in_tokens": 1183, "out_tokens": 357} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-weak-backend", "rep": 2, "ok": true, "coaching": {"model_answer": "결정적 트랜잭션 (Outbox 패턴) 과 멱등성 (Idempotency) 은 서로 다른 실패 모드를 막기 위해 함께 사용했습니다. 트랜잭션 경계를 명확히 하여 DB 내의 '주문 생성'과 '결제 처리'를 하나의 단위로 묶어, 결제 API 가 지연되어 재콜백이 오더라도 동일한 트랜잭션 내에서 이미 처리된 상태를 방지합니다. 반면 멱등 키는 외부에서 발생한 콜백 (예: 결제 게이트웨이 재전송) 을 처리할 때, 동일한 요청 ID 를 가진 데이터가 들어오더라도 중복 실행을 막아줍니다. 즉, 트랜잭션은 내부적 일관성을, 멱등 키는 외부적 재시도 공격을 막는다는 차이입니다.", "answer_rewrite": "결정적 트랜잭션 (Outbox 패턴) 과 멱등성 (Idempotency) 을 함께 적용했습니다. Outbox 패턴은 결제 승인 콜백이 지연되어 재전송될 경우, 트랜잭션 경계가 명확히 되어 이미 처리된 상태를 DB 가 인지하도록 보장합니다. 또한 멱등 키는 외부에서 동일한 요청 ID 가 여러 번 들어오더라도 중복 실행을 방지하여, 결제 지연으로 인한 중복 주문 0 건을 달성했습니다.", "coaching_comment": "두 패턴이 해결하는 실패 케이스의 근본적 차이 (내부적 일관성 vs 외부적 재시도) 를 명확히 구분하여 설명해야 합니다."}, "latency_sec": 19.009, "in_tokens": 1310, "out_tokens": 333} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-dont-know-cs", "rep": 2, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은 xmin horizon 을 낮추어 해당 트랜잭션이 종료될 때까지 Dead Tuple 를 회수하지 못하게 만듭니다. 즉, 트랜잭션이 끝날 때까지 해당 데이터는 Heap Header 에 남아 테이블 Bloat 를 유발하며, 이 상태가 지속될수록 Vacuum 수행 시 Dead Tuple 를 처리하는 데 추가적인 CPU 와 I/O 가 소요되어 성능 저하를 초래합니다. 예를 들어, 오래된 트랜잭션이 끝날 때까지 기다려야 할 경우, Vacuum 는 해당 데이터 블록을 스캔하고 Heap Header 를 업데이트하는 작업을 더 많이 수행해야 하므로, 전체적인 Vacuum 수행 시간이 지연되고 테이블의 물리적 크기가 불필요하게 커지는 Bloat 문제를 심화시킵니다.", "answer_rewrite": "이 질문은 지원자의 실제 답변이 빈 답변으로, 지원자의 답변을 출발점으로 더 좋게 고쳐 쓸 수 없습니다. 지원자가 '잘 모르겠습니다'라고 답변한 점을 고려할 때, 지원자는 이 개념에 대한 기초 지식이 부족하거나 학습이 필요함을 시사합니다. 따라서 답변을 보강하기 위해 필요한 구체적인 경험이나 기술적 근거가 없으므로, 지원자가 이 주제를 공부하고 이해하는 것이 가장 현실적인 접근입니다.", "coaching_comment": "PostgreSQL MVCC의 동작 원리, 특히 xmin horizon 과 Dead Tuple 회수 메커니즘에 대한 기초 지식을 먼저 습득해야 합니다."}, "latency_sec": 16.748, "in_tokens": 871, "out_tokens": 312} +{"label": "local-qwen3.5-4b", "suite": "coaching", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌 경험으로, 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 지연 2 주가 발생한 사례를 들 수 있습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 준비하여 프론트엔드 팀과 병렬 개발을 제안했고, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 다만 초기에는 제 방식이 옳다고 고집하여 팀원과의 감정적 마찰이 발생했고, 이를 교훈으로 얻어 이후에는 결정 전 대안 두 가지를 비교하는 방식으로 접근하는 습관을 들였습니다. 이는 기술적 정확성과 팀워크를 균형 있게 고려하는 태도를 보여줍니다.", "answer_rewrite": "팀원과의 의견 충돌 경험으로, 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 지연 2 주가 발생한 사례를 들 수 있습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 준비하여 프론트엔드 팀과 병렬 개발을 제안했고, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 다만 초기에는 제 방식이 옳다고 고집하여 팀원과의 감정적 마찰이 발생했고, 이를 교훈으로 얻어 이후에는 결정 전 대안 두 가지를 비교하는 방식으로 접근하는 습관을 들였습니다. 이는 기술적 정확성과 팀워크를 균형 있게 고려하는 태도를 보여줍니다.", "coaching_comment": "고집으로 인한 감정적 마찰을 솔직하게 인정하고 구체적인 개선 행동 (대안 비교 방식) 을 언급해야 신뢰감을 높일 수 있습니다."}, "latency_sec": 18.866, "in_tokens": 1183, "out_tokens": 341} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-backend-tech", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"결제 콜백 지연 시 중복 주문을 멱등 키와 Outbox 패턴으로 해결했을 때, Outbox 패턴이 어떻게 지연된 콜백을 감지하고 재처리 흐름을 보장했는지 구체적으로 설명해 주시겠어요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성\", \"expectedSignal\": \"Outbox 패턴의 동작 원리, 재처리 로직, 데이터 정합성 보장 방식을 명확히 설명할 수 있는지 확인.\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"모놀리식 아키텍처에서 주문 서비스를 분리하고 Kafka 이벤트 파이프라인을 도입한 결정에 대한 근거와, 이 전환이 시스템의 확장성이나 유지보수에 어떤 실질적 영향을 미쳤는지 설명해 주시겠어요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"MSA 전환 프로젝트에서 주문 서비스 분리 및 Kafka 이벤트 파이프라인 설계, 배포 단위 축소로 배포 주기 2주 → 2일\", \"expectedSignal\": \"MSA 전환의 기술적/운영적 근거, 배포 주기 단축 등 구체적인 성과 지표에 대한 이해를 평가.\"}, {\"category\": \"CS_FUNDAMENTAL\", \"question\": \"", "latency_sec": 43.527, "in_tokens": 2691, "out_tokens": 777} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-frontend-repo", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "2000 개 이상의 타임라인 항목에서 가상화를 도입해 성능을 4 배 개선했을 때, 실제 구현 과정에서 가장 큰 기술적 난관이 무엇이었나요?", "job_category": "FRONTEND", "target_evidence": "일정 타임라인: 항목 2 천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \"virtualize timeline, INP 480ms -> 120ms\")", "expected_signal": "가상화 라이브러리 선택 시 고려한 핵심 요소와 구체적인 최적화 전략을 명확히 설명할 수 있는지 확인"}, {"category": "TECH_CHOICE", "question": "오프라인 편집을 위해 IndexedDB 와 낙관적 업데이트를 선택한 배경은 무엇이며, 충돌 해결 방식의 한계점을 어떻게 인지하고 있나요?", "job_category": "FRONTEND", "target_evidence": "오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \"CRDT 검토 필요\")", "expected_signal": "데이터 동기화 전략의 트레이드오프를 이해하고, CRDT 등 대안 기술에 대한 인식을 가지고 있는지 평가"}, {"category": "CS_FUNDAMENTAL", "question": "500 개 이상의 지도 마커를 클러스터링하고 좌표를 useMemo 로 캐싱했을 때, 메모리 누수나 캐시 갱신 시점의 핵심 고려사항은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "지도 마커 렌더링: Kakao Map SDK 마커 500 개를 클러스터링, useMemo 로 좌표 변환 캐싱", "expected_signal": "React 의 렌더링 사이클과 메모리 관리 원리를 실제 프로젝트 맥락에 적용해 설명할 수 있는지 확인"}, {"category": "BEHAVIORAL", "question": "Lighthouse 점수를 68 에서 91 로 끌어올린 구체적인 조치와 그 과정에서 본인의 주도적 역할은 무엇이었나요?", "job_category": "FRONTEND", "target_evidence": "Lighthouse 성능 점수 68 → 91 (PR #57 설명)", "expected_signal": "성능 최적화 프로젝트에서 본인의 구체적인 행동과 정량적 결과를 STAR 방식으로 명확히 서술할 수 있는지 확인"}, {"category": "PROJECT_DEEP_DIVE", "question": "Vitest 단위 테스트 42 개와 Playwright E2E 6 개를 작성하며, 실제 개발 워크플로우에 통합하기 위해 고려한 테스트 전략은 무엇인가요?", "job_category": "FRONTEND", "target_evidence": "테스트/품질: Vitest 단위 테스트 42 개, Playwright E2E 6 개", "expected_signal": "단위 테스트와 E2E 테스트의 적절한 조합과 CI/CD 파이프라인에의 통합 방식을 이해하고 있는지 평가"}], "latency_sec": 39.679, "in_tokens": 2517, "out_tokens": 746} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "거래내역 테이블 파티셔닝으로 p95 쿼리 시간이 180ms 로 개선되었는데, 월 단위 분할 전략을 선택한 결정적 요인은 무엇인가?", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3 초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "데이터 분할의 성능 개선 효과와 유지보수 비용 간의 트레이드오프를 고려한 구체적인 설계 근거를 제시하는지 확인."}, {"category": "TECH_CHOICE", "question": "CronJob 을 통해 트래픽 피크 시 사전 스케일아웃을 운영하시는데, CPU 70% 기준이 실제 트래픽 패턴에 최적화되었는지 검증 방법은?", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10 시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "정적 스케줄링의 한계를 인지하고 동적 조정이나 히스토리 분석을 통해 최적화 기준을 설정하는지 평가."}, {"category": "CS_FUNDAMENTAL", "question": "스토리지 풀 사용 중단 사고를 CloudWatch 알람과 오토스케일링으로 해결하셨는데, RDS 스토리지 풀의 자동 확장 메커니즘과 알람의 지연 발생 원인은?", "job_category": "INFRA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40 분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "클라우드 스토리지 아키텍처의 작동 원리와 모니터링 시스템의 시간적 지연 특성을 이해하는지 확인."}, {"category": "BEHAVIORAL", "question": "복잡한 인프라 변경이나 DB 튜닝 작업에서 팀원이나 상사와 의견 충돌이 있었을 때, 어떻게 해결했는지 구체적인 사례를 들어 설명해 보세요.", "job_category": "INFRA", "target_evidence": "", "expected_signal": "갈등 상황에서 자신의 역할을 명확히 하고, 데이터와 논리로 설득하며 팀을 이끄는 리더십 역량을 보여줄 수 있는지 확인."}, {"category": "PROJECT_DEEP_DIVE", "question": "ArgoCD 를 도입하여 배포 리드타임을 단축하셨는데, 기존 CI/CD 파이프라인의 병목 현상이 무엇이었으며 GitOps 전환 시 가장 큰 기술적 도전 과제는?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1 일 → 30 분", "expected_signal": "프로젝트 개선 과정에서 겪은 구체적인 기술적 난제와 이를 해결하기 위해 수행한 분석 및 실험 과정을 상세히 설명하는지 평가."}, {"category": "BEHAVIORAL", "question": "4 년차 인프라 엔지니어로서 가장 큰 성취가 무엇인지, 그리고 그 과정에서 배운 가장 중요한 교훈은?", "job_category": "INFRA", "target_evidence": "", "expected_signal": "성공적인 프로젝트 경험을 바탕으로 자신의 성장 과정과 미래의 기술적 비전을 명확히 제시하는지 확인."}], "latency_sec": 44.868, "in_tokens": 2511, "out_tokens": 869} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 0, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "알림 봇 프로젝트에서 SQLite 의 동시 쓰기 락 문제를 해결하기 위해 PostgreSQL 로 마이그레이션할 때, 트랜잭션 격리 수준 설정에서 겪은 구체적인 기술적 난관은?", "job_category": "BACKEND", "target_evidence": "알림 봇 DB 를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3 일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "트랜잭션 격리 수준 (Read Committed 등) 이 데이터 무결성에 미친 영향과 문제 해결 과정의 구체적 기술적 통찰."}, {"category": "BEHAVIORAL", "question": "프론트엔드 팀과 API 스펙 해석 차이로 인한 갈등 상황에서, 감정을 식혀 팀워크를 회복하기 위해 본인이 구체적으로 어떤 행동과 태도를 취했는지?", "job_category": "BACKEND", "target_evidence": "초반에 제 방식이 옳다고 고집해 팀원과 감정이 상한 적도 있어, 이후에는 결정 전에 대안 두 가지를 함께 비교하는 방식으로 바꿨습니다.", "expected_signal": "갈등 상황에서 감정을 조절하고 대안 제시를 통한 협상 및 팀워크 회복에 대한 구체적인 행동과 태도."}, {"category": "TECH_CHOICE", "question": "학부 동아리에서 알림 봇을 개발할 때, 서비스의 신뢰성을 확보하기 위해 '멈추지 않는 서비스'를 구현하는 과정에서 가장 중요하게 생각했던 기술적 결정은?", "job_category": "BACKEND", "target_evidence": "기능보다 '멈추지 않는 서비스'가 신뢰를 만든다는 것을 배웠습니다.", "expected_signal": "서비스 가용성과 신뢰성 확보를 위해 선택한 기술적 접근 방식과 그 배경에 대한 이해."}, {"category": "BEHAVIORAL", "question": "캡스톤 프로젝트에서 통합 이슈를 3 건에서 0 건으로 줄이는 데 기여한 OpenAPI 명세와 Mock 서버 도입 경험에서, 본인이 주도한 구체적인 역할과 그로 인한 정량적 결과는?", "job_category": "BACKEND", "target_evidence": "저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3 건에서 0 건으로 줄었습니다.", "expected_signal": "프로젝트 성공에 기여한 구체적인 역할과 정량적 결과 (3 건에서 0 건 감소) 에 대한 명확한 설명."}, {"category": "BEHAVIORAL", "question": "알림 봇 프로젝트에서 DB 변경으로 인해 3 일간 문제를 해결하는 과정에서, 본인이 겪은 실패와 이를 극복하며 얻은 가장 큰 교훈은?", "job_category": "BACKEND", "target_evidence": "원인을 찾는 데 3 일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.", "expected_signal": "기술적 실패를 겪은 후 얻은 구체적인 교훈과 이를 바탕으로 한 성장에 대한 성찰."}], "latency_sec": 41.016, "in_tokens": 2488, "out_tokens": 783} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 0, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"Outbox 패턴을 도입할 때, Kafka 메시지 발행과 DB 트랜잭션 간의 정합성을 어떻게 보장했는지 구체적으로 설명해 주세요.\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성\", \"expectedSignal\": \"트랜잭션 격리 수준과 이벤트 소싱의 결합 방식을 이해하고, 장애 시 데이터 무결성을 유지하는 구체적인 설계 논리를 제시할 수 있는지 확인.\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"낙관적 락에서 분산 락으로 전환한 결정 배경은 무엇이며, 이 변경이 재고 불일치 문제를 해결하는 데 어떤 물리적 영향을 미쳤나요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"실시간 재고 동기화: Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환), 재고 불일치 건수 월 200건 → 3건\", \"expectedSignal\": \"락 컨텍스트의 한계를 인지하고, 고해용량 환경에서 데이터 정합성을 확보하기 위해 분산 락을 선택한 기술적 근거와 그 효과를 명확히 설명할 수 있는지 평가.\"}, {\"category\": \"BEHAVIORAL\", \"questi", "latency_sec": 51.936, "in_tokens": 3768, "out_tokens": 911} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-backend-tech", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "결제 콜백 지연으로 인한 중복 주문 문제를 멱등 키와 Outbox 패턴으로 해결했을 때, Outbox 패턴이 어떻게 지연된 콜백을 처리하는지 구체적으로 설명해 보세요.", "job_category": "BACKEND", "target_evidence": "결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성", "expected_signal": "Outbox 패턴의 동작 원리와 데이터 흐름을 명확히 설명하고, 멱등 키가 어떻게 중복 발생을 방지하는지 이해하고 있는지 확인합니다."}, {"category": "TECH_CHOICE", "question": "모놀리식 아키텍처에서 주문 서비스를 분리하고 Kafka 기반 이벤트 파이프라인을 도입한 결정에 대한 근거와 기대 효과를 구체적으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "MSA 전환 프로젝트에서 주문 서비스 분리 및 Kafka 이벤트 파이프라인 설계", "expected_signal": "MSA 전환의 기술적 필요성 (확장성, 유지보수성 등) 과 Kafka 도입의 구체적인 효과를 논리적으로 연결할 수 있는지 확인합니다."}, {"category": "PROJECT_DEEP_DIVE", "question": "실시간 재고 동기화 프로젝트에서 낙관적 락을 분산 락으로 전환한 결정에 대한 이유와 그로 인한 재고 불일치 건수 감소 효과를 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)", "expected_signal": "락 전략 변경이 왜 필요한지 (락 충돌, 성능 저하 등) 와 그로 인한 정량적 결과 (불일치 건수 감소) 를 연결하여 설명할 수 있는지 확인합니다."}, {"category": "CS_FUNDAMENTAL", "question": "대용량 트래픽 환경에서 데이터 정합성을 지키는 서버를 만들 때, 분산 데이터베이스 환경에서 트랜잭션의 정합성을 보장하기 위한 핵심 원리는 무엇인가요?", "job_category": "BACKEND", "target_evidence": "대용량 트래픽에서도 데이터 정합성을 지키는 서버를 만드는 데 관심이 많습니다.", "expected_signal": "분산 환경에서의 트랜잭션 정합성 (ACID, 2PC 등) 에 대한 기본 개념과 이를 구현하기 위한 기술적 접근을 이해하고 있는지 확인합니다."}, {"category": "BEHAVIORAL", "question": "주문/결제 도메인에서 일 평균 12만 건의 트래픽을 처리하며 장애 대응 과정에서 가장 큰 어려움은 무엇이었는지, 그리고 그것을 극복하기 위해 본인이 어떤 행동을 취했는지 구체적으로 설명해 주세요.", "job_category": "BACKEND", "target_evidence": "장애 대응: 결제 승인 지연으로 인한 중복 주문 이슈를 멱등 키 + Outbox 패턴으로 해결", "expected_signal": "고난도 문제 해결 과정에서 본인의 구체적인 행동과 그로 인한 결과를 STAR 방식으로 명확히 서술할 수 있는지 확인합니다."}], "latency_sec": 41.012, "in_tokens": 2691, "out_tokens": 764} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-frontend-repo", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"2000 개 이상의 타임라인 항목에서 가상화를 도입해 성능을 4 배 개선했을 때, 실제 구현 과정에서 가장 큰 기술적 난관과 해결 전략은?\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"일정 타임라인: 항목 2 천 개 이상일 때 스크롤 끊김 → react-window 가상화 도입 (커밋 메시지: \\\"virtualize timeline, INP 480ms -> 120ms\\\")\", \"expectedSignal\": \"가상화 라이브러리 선택 기준, 캐싱 전략, 실제 성능 측정 데이터 해석 능력\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"오프라인 편집을 위해 IndexedDB 와 낙관적 업데이트를 선택한 배경은 무엇이며, 충돌 해결 전략의 한계점은?\", \"jobCategory\": \"FRONTEND\", \"targetEvidence\": \"오프라인 편집: IndexedDB(Dexie) 에 낙관적 업데이트를 저장 후 온라인 복귀 시 동기화. 충돌은 last-write-wins (TODO 주석: \\\"CRDT 검토 필요\\\")\", \"expectedSignal\": \"데이터 동기화 문제 인식, CRDT 등 최신 패턴에 대한 이해도, 기술적 타당성 판단 능력\"}, {\"category\": \"CS_FUNDAMENTAL\", \"question\": \"TanStack Query 를 서버 상태 ", "latency_sec": 35.015, "in_tokens": 2517, "out_tokens": 638} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-infra-dba-multi", "rep": 1, "ok": true, "questions": [{"category": "PROJECT_DEEP_DIVE", "question": "거래내역 테이블의 월 단위 파티셔닝을 도입했을 때, 데이터 분할 기준과 쿼리 조건에 따른 파티션 스캔 최적화 과정에서 가장 큰 기술적 난관은 무엇이었나요?", "job_category": "DBA", "target_evidence": "PostgreSQL 14 (RDS) 운영: 슬로우 쿼리 p95 2.3 초 → 180ms (복합 인덱스 재설계, autovacuum 튜닝, 파티셔닝으로 거래내역 테이블 월 단위 분할)", "expected_signal": "파티셔닝 전략 수립 시 고려한 데이터 분할 기준과 실제 성능 개선 수치에 대한 구체적인 기술적 통찰."}, {"category": "TECH_CHOICE", "question": "배포 리드타임을 1 일에서 30 분으로 단축하기 위해 ArgoCD 를 도입했을 때, 기존 CI/CD 파이프라인과 GitOps 워크플로우를 통합하는 과정에서 겪은 주요 리스크와 해결 방안은 무엇인가요?", "job_category": "INFRA", "target_evidence": "ArgoCD GitOps 도입으로 배포 리드타임 1 일 → 30 분", "expected_signal": "GitOps 도입 시 발생할 수 있는 배포 실패 시나리오를 예측하고, 이를 완화하기 위해 취한 구체적인 조치에 대한 이해."}, {"category": "BEHAVIORAL", "question": "2024 년 3 월 RDS 스토리지 풀 사용 중단 사고를 겪었을 때, CloudWatch 알람과 오토스케일링 기능을 적용하기까지의 대응 과정과 그 결과로 얻은 교훈은 무엇인가요?", "job_category": "INFRA", "target_evidence": "장애: 2024.03 RDS 스토리지 풀로 쓰기 중단 40 분 → CloudWatch 알람 + 스토리지 오토스케일링 적용", "expected_signal": "장애 발생 시 초기 대응 행동과, 이를 통해 시스템의 자동 복구 능력을 강화한 구체적인 개선 조치."}, {"category": "CS_FUNDAMENTAL", "question": "HPA 기준을 CPU 70% 로 설정하여 트래픽 피크 대비 사전 스케일아웃을 운영 중인데, CPU 사용률과 실제 메모리/네트워크 부하 간의 상관관계를 고려할 때, 현재 설정이 병목 현상을 유발할 수 있는 위험은 무엇인지 설명해 보세요.", "job_category": "INFRA", "target_evidence": "HPA 기준을 CPU 70% 로 설정, 트래픽 피크(월급날 10 시) 대비 사전 스케일아웃 CronJob 운영", "expected_signal": "CPU 중심의 자동 스케일링이 메모리 부족이나 네트워크 대역폭 제한과 같은 다른 리소스 부족을 놓칠 수 있음을 인지하고, 이를 보완하기 위한 고려 사항."}, {"category": "PROJECT_DEEP_DIVE", "question": "EKS 기반 쿠버네티스 클러스터 3 개를 운영하며 파드 약 400 개를 관리하고 있는데, 환경별 (dev/stg/prod) 워크스페이스를 Terraform 으로 분리했을 때, 환경 간 리소스 충돌을 방지하기 위한 구체적인 전략은 무엇이었나요?", "job_category": "INFRA", "target_evidence": "Terraform 으로 VPC·RDS·EKS 모듈화, 환경별 (dev/stg/prod) workspace 분리", "expected_signal": "Terraform 모듈화 과정에서 환경 식별자 관리, 네임스페이스 분리, 또는 네트워크 정책 적용 등 충돌 방지를 위한 구체적인 기술적 접근법."}, {"category": "BEHAVIORAL", "question": "4 년차 인프라 엔지니어로서 현재까지 가장 큰 성취감을 느낀 프로젝트나 경험은 무엇이며, 그 과정에서 본인의 역할과 기여도는 어떻게 했나요?", "job_category": "INFRA", "target_evidence": "CKA, AWS SAA / Kubernetes, EKS, Terraform, ArgoCD, Prometheus, Grafana, PostgreSQL, Redis", "expected_signal": "성취감의 원천이 되는 구체적인 프로젝트 사례와, 그 과정에서 지원자가 주도적으로 수행한 행동과 기여도."}], "latency_sec": 51.082, "in_tokens": 2511, "out_tokens": 1013} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-personality-coverletter", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"알림 봇 프로젝트에서 SQLite 에서 PostgreSQL 로 DB 를 변경하며 트랜잭션 격리 수준을 공부한 과정은 구체적으로 어떤 점이였나요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"알림 봇 DB 를 SQLite 로 시작했다가 동시 쓰기 락 문제로 알림이 중복 발송되었습니다. 원인을 찾는 데 3 일이 걸렸고, PostgreSQL 로 이전하며 트랜잭션 격리 수준을 공부하게 됐습니다.\", \"expectedSignal\": \"트랜잭션 격리 수준 (Isolation Level) 의 차이와 동시성 문제 해결에 대한 구체적인 기술적 이해를 보여야 함.\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"프론트엔드 팀과 API 스펙 해석이 달라 지연이 발생했을 때, OpenAPI 명세와 Mock 서버를 제안한 결정의 근거와 예상 효과는 무엇이었나요?\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"저는 OpenAPI 명세를 먼저 작성하고 Mock 서버를 띄워 프론트가 병렬로 개발하도록 제안했고, 이후 스프린트에서는 통합 이슈가 3 건에서 0 건으로 줄었습니다.\", \"expectedSignal\": \"API 설계의 중요성과 Mock 서버를 통한 병렬 개발의 효율성에 대한 명확한 기술적 근거와 결과 지표를 제시해야 함.\"}, {\"categor", "latency_sec": 41.807, "in_tokens": 2488, "out_tokens": 805} +{"label": "local-qwen3.5-4b", "suite": "questions", "case_id": "q-long-context-p90", "rep": 1, "ok": false, "error": "OutputParserException: Failed to parse GeneratedQuestionPool from completion [{\"category\": \"PROJECT_DEEP_DIVE\", \"question\": \"Outbox 패턴을 도입했을 때, Kafka 메시지 재전송 시 트랜잭션 무결성을 어떻게 보장했는지 구체적으로 설명해 주세요.\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"결제 승인 콜백 지연 시 중복 주문 발생 문제: 멱등 키 테이블 + Transactional Outbox 로 해결, 중복 주문 0건 달성\", \"expectedSignal\": \"Outbox 패턴의 구현 세부사항과 재전송 시 트랜잭션 격리 수준에 대한 명확한 이해를 보여줌.\"}, {\"category\": \"TECH_CHOICE\", \"question\": \"낙관적 락에서 분산 락으로 제어 방식을 변경한 결정 배경과, 이 전환이 재고 불일치 문제를 어떻게 해결했는지 설명해 주세요.\", \"jobCategory\": \"BACKEND\", \"targetEvidence\": \"실시간 재고 동기화 프로젝트: Redis 기반 재고 캐시 + DB write-behind, 동시성 제어(낙관적 락 → 분산 락 전환)\", \"expectedSignal\": \"락 메커니즘의 한계 인식과 분산 락 도입의 기술적 타당성에 대한 논리적 추론 능력을 보여줌.\"}, {\"category\": \"BEHAVIORAL\", \"question\": \"DB 선택 과정에서 SQLite 에서 PostgreSQL 로 변경하며 트랜잭션 격리 수준을 공부하게 된 구체적인 상황과 그 과정에서 얻은 ", "latency_sec": 287.183, "in_tokens": 3768, "out_tokens": 746} +{"label": "local-qwen3.5-4b", "suite": "followup:cold", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "멱등 키가 중복 주문을 막는 데 기여한 구체적인 실패 케이스 (예: PG 재전송 시) 와 Outbox 가 막는 실패 케이스 (예: DB 트랜잭션 중단 시 이벤트 누락) 는 어떻게 다른가요?", "answer_intent": "NORMAL", "answer_evaluation": null, "latency_sec": 15.47, "ttft_sec": 11.815, "in_tokens": 1411, "out_tokens": 99} +{"label": "local-qwen3.5-4b", "suite": "followup:after-cold", "case_id": "f-weak-vague", "rep": 1, "ok": true, "followup_question": "중복 주문을 막기 위해 멱등 키를, 지연 처리를 위해 Outbox 패턴을 각각 어떤 상황에서 선택하셨는지 구체적으로 말씀해 주실 수 있나요?", "answer_intent": "CLARIFICATION", "answer_evaluation": null, "latency_sec": 6.643, "ttft_sec": 3.823, "in_tokens": 1292, "out_tokens": 81} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 0, "ok": true, "coaching": {"model_answer": "중복 주문을 막기 위해 멱등 키와 Outbox 패턴을 **상호 보완적**으로 사용했습니다. 멱등 키는 '동일한 메시지 반복'을 방지하는 **입력 측의 안전장치**로, Kafka 재시도 시에도 중복 처리가 안 되도록 DB 레벨에서 필터링합니다. 반면 Outbox 패턴은 '트랜잭션 내 메시지 발행 실패'나 'DB 커밋 전 취소'와 같은 **트랜잭션 경계 실패**를 방지합니다. 예를 들어, 결제 승인 지연으로 인해 주문이 취소된 후 재발생 시 멱등 키로 중복을 막고, 초기 결제 트랜잭션이 커밋되지 않은 상태에서 Kafka 메시지를 발행하지 못했을 때 Outbox 패턴이 이를 해결합니다.", "answer_rewrite": "중복 주문을 방지하기 위해 멱등 키와 Outbox 패턴을 함께 적용했습니다. 멱등 키는 Kafka 재시도 시에도 동일한 주문이 반복되지 않도록 DB 레벨에서 필터링하는 **입력 측 안전장치**로, Outbox 패턴은 트랜잭션 커밋 전 메시지 발행 실패를 방지하는 **트랜잭션 경계 보호**로 각각 역할을 담당했습니다. 결제 승인 지연으로 인한 주문 취소 후 재발생 시 멱등 키가 중복을 막고, 초기 트랜잭션이 정상적으로 커밋되지 않은 상태에서 메시지 발행이 실패했을 때 Outbox 패턴이 이를 해결하여 중복 주문 0 건을 달성했습니다.", "coaching_comment": "두 패턴이 해결하려는 구체적인 실패 시나리오(입력 측 반복 vs 트랜잭션 경계 실패)를 명확히 구분하여 설명해야 합니다."}, "latency_sec": 20.906, "in_tokens": 1310, "out_tokens": 377} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 1, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은xmin horizon 을 낮게 유지하여 dead tuple 회수를 지연시키고, 테이블 bloat 를 유발합니다. 트랜잭션이 종료되지 않으면xmin 값이 계속 갱신되지 않아, 이 트랜잭션이 생성한 tuple 들이 'dead tuple' 로 인식되지 못합니다. 이는 VACUUM FULL 이 수행될 때까지 유효하지 않은 데이터가 테이블에 남아 공간을 비효율적으로 차지하게 만듭니다. 따라서 트랜잭션은 곧 종료되거나, VACUUM FULL 을 통해 명시적으로 회수되어야 합니다.", "answer_rewrite": "이 질문은 지원자의 실제 답변이 비어있었기 때문에, 지원자가 이 내용을 알고 있었다면 어떻게 답했는지 구조화된 예시를 제시합니다. '오래 열린 트랜잭션은 xmin horizon 을 낮게 유지하여 dead tuple 회수를 지연시키고 테이블 bloat 를 유발합니다. 트랜잭션이 종료되지 않으면 xmin 값이 갱신되지 않아, 해당 tuple 들이 dead tuple 로 인식되지 못합니다. 이는 VACUUM FULL 이 수행될 때까지 유효하지 않은 데이터가 테이블에 남아 공간을 비효율적으로 차지하게 만듭니다. 따라서 트랜잭션은 곧 종료되거나, VACUUM FULL 을 통해 명시적으로 회수되어야 합니다.'", "coaching_comment": "모르겠다라고 답하기보다, MVCC 와 xmin horizon 의 관계에 대해 기본 개념을 먼저 설명하고 불확실성을 인정해야 합니다."}, "latency_sec": 86.789, "in_tokens": 871, "out_tokens": 325} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 2, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 발생했습니다. 통합 직전 2 주가 지연되는 위기 상황에서, 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 제안했습니다. 이는 통합 이슈를 3 건에서 0 건으로 줄이고 전체 개발 기간을 단축시켰습니다. 다만, 초기에는 제 방식을 고집하며 팀원과의 감정적 마찰을 빚었습니다. 이후에는 기술적 결정 전에 대안 두 가지를 비교하고 합의점을 찾는 방식으로 접근하여 신뢰를 회복했습니다. 이는 '기술적 우위'보다 '공통된 목표'를 먼저 설정하는 것이 협업의 핵심임을 깨닫게 했습니다.", "answer_rewrite": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 발생했습니다. 통합 직전 2 주가 지연되는 위기 상황에서, 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 제안했습니다. 이는 통합 이슈를 3 건에서 0 건으로 줄이고 전체 개발 기간을 단축시켰습니다. 다만, 초기에는 제 방식을 고집하며 팀원과의 감정적 마찰을 빚었습니다. 이후에는 기술적 결정 전에 대안 두 가지를 비교하고 합의점을 찾는 방식으로 접근하여 신뢰를 회복했습니다. 이는 '기술적 우위'보다 '공통된 목표'를 먼저 설정하는 것이 협업의 핵심임을 깨닫게 했습니다.", "coaching_comment": "충돌의 구체적 상황과 해결 과정의 정량적 결과 (2 주 지연, 3 건→0 건) 를 명확히 제시해야 합니다."}, "latency_sec": 106.696, "in_tokens": 1183, "out_tokens": 371} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 3, "ok": true, "coaching": {"model_answer": "중복 주문을 막기 위해 멱등 키와 Outbox 패턴을 **복합적으로** 적용했습니다. 멱등 키는 DB 트랜잭션 내의 **동기적 중복 방지**에 필수적이었으며, Outbox 패턴은 **트랜잭션이 커진 후에도 발생할 수 있는 비동기적 실패**를 막기 위해 필요합니다.\n\n구체적으로, 멱등 키는 결제 승인 콜백이 지연되어 2 회 주문이 생성되더라도, 2 번째 주문 시 멱등 키 테이블에 이미 존재하는지 확인하여 **동기적으로** 중복을 차단했습니다. 이는 트랜잭션이 성공/실패를 확정하는 순간이므로 즉각적인 안전성을 보장합니다.\n\n반면, Outbox 패턴은 트랜잭션이 커져서 (예: 재고 감소 + 주문 생성) 결제 서비스의 트랜잭션이 **중단**되었을 때, 멱등 키만으로는 **비동기적으로** 재시도 로직을 처리하지 못해 **재주문**이 발생할 위험이 있었습니다. Outbox 패턴은 트랜잭션이 종료되더라도 메시지를 Kafka에 안전하게 기록하고, 결제 서비스 재시도 로직에서 멱등 키를 다시 검증하도록 하여, **트랜잭션 경계를 넘어선 상황**까지 중복을 방지했습니다.\n\n결론적으로, 멱등 키는 **트랜잭션 내의 즉시 중복 방지**에, Outbox 패턴은 **트랜잭션 종료 후의 재시도 중복 방지**에 각각 역할을 하여 중복 주문 0 건을 달성했습니다.", "answer_rewrite": "중복 주문을 막기 위해 멱등 키와 Outbox 패턴을 **복합적으로** 적용했습니다. 멱등 키는 DB 트랜잭션 내의 **동기적 중복 방지**에 필수적이었으며, Outbox 패턴은 **트랜잭션이 커진 후에도 발생할 수 있는 비동기적 실패**를 막기 위해 필요합니다.\n\n구체적으로, 멱등 키는 결제 승인 콜백이 지연되어 2 회 주문이 생성되더라도, 2 번째 주문 시 멱등 키 테이블에 이미 존재하는지 확인하여 **동기적으로** 중복을 차단했습니다. 이는 트랜잭션이 성공/실패를 확정하는 순간이므로 즉각적인 안전성을 보장합니다.\n\n반면, Outbox 패턴은 트랜잭션이 커져서 (예: 재고 감소 + 주문 생성) 결제 서비스의 트랜잭션이 **중단**되었을 때, 멱등 키만으로는 **비동기적으로** 재시도 로직을 처리하지 못해 **재주문**이 발생할 위험이 있었습니다. Outbox 패턴은 트랜잭션이 종료되더라도 메시지를 Kafka에 안전하게 기록하고, 결제 서비스 재시도 로직에서 멱등 키를 다시 검증하도록 하여, **트랜잭션 경계를 넘어선 상황**까지 중복을 방지했습니다.\n\n결론적으로, 멱등 키는 **트랜잭션 내의 즉시 중복 방지**에, Outbox 패턴은 **트랜잭션 종료 후의 재시도 중복 방지**에 각각 역할을 하여 중복 주문 0 건을 달성했습니다.", "coaching_comment": "지원자 답변은 '잘 처리했다'는 표현만 반복하여 구체적인 실패 시나리오와 각 패턴의 고유한 역할을 명확히 구분하지 못했습니다."}, "latency_sec": 69.944, "in_tokens": 1310, "out_tokens": 747} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 4, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은 xmin horizon 을 낮춰서 해당 트랜잭션보다 작은 xmin 을 가진 tuple 을 'dead tuple'로 인식하게 하지만, 해당 트랜잭션이 끝날 때까지는 즉시 회수되지 않고 vacuum 가 기다려야 합니다. 이는 테이블에 불필요한 공간이 남는 'bloat'를 유발하고, vacuum 작업이 지연되거나 성능 저하를 초래할 수 있습니다. 만약 지원자가 실제로 트랜잭션 관리나 vacuum 관련 경험을 가지고 있다면, '오래된 트랜잭션이 xmin 을 낮추어 dead tuple 회수 시점을 늦춘 결과, 테이블 bloat 가 발생하고 vacuum 작업이 지연되는 현상을 경험했다'는 식으로 구체적인 상황을 언급하면 더 설득력 있는 답변이 됩니다.", "answer_rewrite": null, "coaching_comment": "지원자 답변은 모범 답안처럼 핵심 개념을 설명하지 못했으므로, 이 질문은 기술적 이해도를 묻는 것이므로 구체적인 개념 설명이 필요합니다."}, "latency_sec": 33.598, "in_tokens": 871, "out_tokens": 225} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 5, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2 주 지연된 경험이었습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 가능하게 했으며, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 하지만 초기에는 제 방식을 고집하며 팀원과의 감정적 갈등이 발생했고, 이를 교훈으로 '결정 전 대안 두 가지 비교' 방식으로 접근하여 이후에는 갈등을 최소화했습니다. 이는 기술적 효율성과 팀워크를 동시에 고려하는 유연한 의사결정 능력이 필요함을 보여줍니다.", "answer_rewrite": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2 주 지연된 경험이었습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 가능하게 했으며, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 하지만 초기에는 제 방식을 고집하며 팀원과의 감정적 갈등이 발생했고, 이를 교훈으로 '결정 전 대안 두 가지 비교' 방식으로 접근하여 이후에는 갈등을 최소화했습니다.", "coaching_comment": "고집으로 인한 감정적 갈등을 인정하고 구체적인 개선 조치 (대안 비교) 를 명시해야 신뢰감을 줄 수 있습니다."}, "latency_sec": 110.822, "in_tokens": 1183, "out_tokens": 308} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 6, "ok": true, "coaching": {"model_answer": "중복 주문은 '결제 승인 지연'이라는 **비동기적 실패 시나리오**에서 발생하므로, 멱등성과 트랜잭션 경계 관리가 필수입니다. 먼저 **Outbox 패턴**은 DB 트랜잭션 내로 결제 승인 콜백 이벤트 기록을 보장하여, DB 가 롤백되더라도 이벤트가 누락되지 않도록 합니다. 이는 'DB 롤백 후 이벤트 누락'이라는 실패 케이스를 막습니다. 하지만 Outbox 만으로는 재시도 로직이 없으므로, **멱등 키**를 추가하여 동일한 주문에 대한 중복 처리를 방지합니다. 이는 '네트워크 지연으로 인한 재전송 시 중복 처리'라는 실패 케이스를 막습니다. 결국 두 패턴을 함께 쓰는 것은 '트랜잭션 내 기록 보장'과 '비동기 재시도 시 중복 방지'를 동시에 해결하기 위함입니다.", "answer_rewrite": "중복 주문은 결제 승인 지연이라는 비동기 실패 시나리오에서 발생했기 때문에, 멱등성과 트랜잭션 경계 관리를 함께 적용했습니다. **Outbox 패턴**을 통해 DB 트랜잭션 내에서 결제 승인 콜백 이벤트를 기록함으로써, DB 가 롤백되더라도 이벤트가 누락되지 않도록 '트랜잭션 내 기록 보장'을 구현했습니다. 이를 바탕으로 **멱등 키**를 추가하여, 네트워크 지연 등으로 인한 재전송 시 동일한 주문에 대한 중복 처리를 방지하는 '비동기 재시도 시 중복 방지'를 구현했습니다. 두 패턴을 함께 적용함으로써 중복 주문 0 건을 달성했습니다.", "coaching_comment": "Outbox 패턴이 트랜잭션 내 기록 보장을, 멱등 키가 재시도 시 중복 방지를 담당한다는 역할을 명확히 구분하여 설명하세요."}, "latency_sec": 119.524, "in_tokens": 1310, "out_tokens": 396} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 7, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은 xmin horizon 이 해당 트랜잭션 ID 보다 낮아져서 해당 트랜잭션이 생성한 tuple 들을 'dead tuple' 로 인식하지 못하게 막습니다. 이는 트랜잭션이 끝날 때까지 해당 tuple 가 reclaim list 에 추가되지 않아 vacuum 이 이를 즉시 회수하지 못하게 하고, 결과적으로 테이블에 비활성화된 데이터가 쌓이는 bloat 를 유발합니다. 이런 경우 테이블의 실제 사용 가능 공간보다 더 많은 공간이 할당되어 저장 공간 효율이 떨어지고, bloat 가 심해지면 index 유지 비용 증가나 join 성능 저하 등 전체적인 DB 성능에 악영향을 미칩니다.", "answer_rewrite": "오래 열린 트랜잭션은 xmin horizon 이 해당 트랜잭션 ID 보다 낮아져서 해당 트랜잭션이 생성한 tuple 들을 'dead tuple' 로 인식하지 못하게 막습니다. 이는 트랜잭션이 끝날 때까지 해당 tuple 가 reclaim list 에 추가되지 않아 vacuum 이 이를 즉시 회수하지 못하게 하고, 결과적으로 테이블에 비활성화된 데이터가 쌓이는 bloat 를 유발합니다. 이런 경우 테이블의 실제 사용 가능 공간보다 더 많은 공간이 할당되어 저장 공간 효율이 떨어지고, bloat 가 심해지면 index 유지 비용 증가나 join 성능 저하 등 전체적인 DB 성능에 악영향을 미칩니다.", "coaching_comment": "지원자 답변이 비어있으므로, 이 질문은 기술적 개념을 정확히 정의하고 그 원인과 결과를 연결하는 것이 핵심입니다."}, "latency_sec": 100.844, "in_tokens": 871, "out_tokens": 342} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 8, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌 경험은 캡스톤 프로젝트에서 API 스펙 해석 차이로 인한 통합 지연 문제였습니다. 저는 오픈 API 명세와 모의 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 제안했고, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄이는 성과를 냈습니다. 다만 초기에는 자신의 방식을 고집하며 감정적 대립을 유발했고, 이를 교훈으로 대안 2 가지를 비교 검토하는 의사결정 프로세스를 도입했습니다. 이는 기술적 정확성과 팀 내 신뢰를 동시에 확보하는 데 기여했습니다.", "answer_rewrite": "팀원과의 의견 충돌 경험은 캡스톤 프로젝트에서 API 스펙 해석 차이로 인한 통합 지연 문제였습니다. 저는 오픈 API 명세와 모의 서버를 먼저 구축하여 프론트엔드 팀과 병렬 개발을 제안했고, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄이는 성과를 냈습니다. 다만 초기에는 자신의 방식을 고집하며 감정적 대립을 유발했고, 이를 교훈으로 대안 2 가지를 비교 검토하는 의사결정 프로세스를 도입했습니다. 이는 기술적 정확성과 팀 내 신뢰를 동시에 확보하는 데 기여했습니다.", "coaching_comment": "단순히 '소통이 중요하다'고 말하기보다, 구체적인 행동과 정량적 결과를 통해 어떻게 갈등을 해결했는지 STAR 구조로 명확히 서술해야 합니다."}, "latency_sec": 101.99, "in_tokens": 1183, "out_tokens": 322} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 9, "ok": true, "coaching": {"model_answer": "결정적 트랜잭션의 경계(Outbox)와 멱등성(Idempotency)은 서로 다른 실패 모드를 막기 위해 함께 사용했습니다. Outbox 패턴은 DB 트랜잭션 내의 비즈니스 로직이 완료되었더라도, 외부 시스템(결제 서비스) 응답이 지연되거나 네트워크 오류로 인해 이벤트가 발송되지 않는 경우를 방지합니다. 반면 멱등 키는 이미 발송된 이벤트가 재처리될 경우에도 동일한 작업을 수행하지 않도록 보장합니다. 이 두 가지를 병용하지 않으면, Outbox만 있으면 재발송 시 트랜잭션이 다시 실행되어 중복 주문이 발생할 수 있고, 멱등성만 있으면 이벤트가 발송되지 않은 경우를 처리할 수 없습니다. 저는 이 문제를 해결하기 위해 주문 완료 시 Outbox에 이벤트 저장 후 트랜잭션 커밋, 그리고 결제 콜백 처리 시 멱등 키를 체크하여 재발송 방지하는 아키텍처를 설계했습니다.", "answer_rewrite": "중복 주문을 방지하기 위해 멱등 키와 Outbox 패턴을 함께 적용했습니다. Outbox 패턴은 DB 트랜잭션 내부에서 주문이 완료되었더라도 외부 시스템(결제 서비스) 응답 지연으로 인해 이벤트가 발송되지 않는 경우를 막기 위해 사용됩니다. 반면 멱등 키는 이미 발송된 이벤트가 재처리될 경우에도 동일한 작업을 수행하지 않도록 보장합니다. 이 두 패턴을 함께 사용하면, Outbox만으로는 재발송 시 트랜잭션이 다시 실행되어 중복 주문이 발생할 수 있고, 멱등성만으로는 이벤트가 발송되지 않은 경우를 처리할 수 없기 때문입니다. 저는 주문 완료 시 Outbox에 이벤트 저장 후 트랜잭션 커밋, 그리고 결제 콜백 처리 시 멱등 키를 체크하여 재발송 방지하는 아키텍처를 설계했습니다.", "coaching_comment": "Outbox 패턴이 해결하는 '이벤트 발송 실패'와 멱등성이 해결하는 '재발송 처리'라는 두 가지 실패 케이스의 차이를 명확히 구분하여 설명하세요."}, "latency_sec": 106.277, "in_tokens": 1310, "out_tokens": 461} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 10, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은 xmin horizon(최소 트랜잭션 ID) 값을 낮게 유지하여, 해당 트랜잭션이 종료하기 전까지 생성된 tuple이 dead tuple로 인식되지 못하게 합니다. 이는 Vacuum 작업이 해당 트랜잭션 종료 시점 이전의 데이터만 삭제할 수 있음을 의미하며, 트랜잭션이 영구적으로 끝나지 않으면 Dead Tuple가 테이블에 남아 테이블 Bloat를 유발합니다. 따라서 트랜잭션이 오래 지속되면 Vacuum 효율이 떨어지고, 테이블 용량이 실제 사용량보다 커지는 문제가 발생합니다.", "answer_rewrite": "MVCC 에서 오래 열린 트랜잭션은 xmin horizon 값을 낮게 유지하기 때문에, 해당 트랜잭션이 종료되기 전까지 생성된 tuple이 Dead Tuple로 인식되지 못합니다. 이는 Vacuum 작업이 해당 트랜잭션 종료 시점 이전의 데이터만 삭제할 수 있음을 의미하며, 트랜잭션이 오래 지속되면 Dead Tuple가 테이블에 남아 테이블 Bloat를 유발할 수 있습니다.", "coaching_comment": "모르는 내용을 인정하되, 핵심 개념 (xmin horizon, Dead Tuple, Bloat) 을 정의하고 그 간의 인과관계를 논리적으로 연결해 주세요."}, "latency_sec": 95.801, "in_tokens": 871, "out_tokens": 270} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 11, "ok": true, "coaching": {"model_answer": "팀원과 의견 충돌이 발생한 캡스톤 프로젝트 경험에서, 프론트엔드 팀원과 API 스펙 해석이 달라 통합 직전 2 주가 지연된 상황입니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드를 병렬 개발하도록 제안했고, 이를 통해 스프린트 내 통합 이슈를 3 건에서 0 건으로 줄이는 성과를 냈습니다. 다만 초반에 제 방식이 옳다고 고집하여 팀원 간 감정적 마찰이 발생했고, 이를 교훈으로 삼아 이후에는 결정 전 대안 두 가지를 비교하는 방식과 팀원들의 우려를 경청하는 태도를 유지하며 협업 효율을 높였습니다.", "answer_rewrite": "팀원과 의견이 충돌했던 캡스톤 프로젝트 경험에서, API 스펙 해석이 달라 통합 직전 2 주가 지연된 적이 있습니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축하여 프론트엔드를 병렬 개발하도록 제안했고, 이를 통해 스프린트 내 통합 이슈를 3 건에서 0 건으로 줄이는 성과를 냈습니다. 다만 초반에 제 방식이 옳다고 고집하여 팀원 간 감정적 마찰이 발생했고, 이를 교훈으로 삼아 이후에는 결정 전 대안 두 가지를 비교하는 방식과 팀원들의 우려를 경청하는 태도를 유지하며 협업 효율을 높였습니다.", "coaching_comment": "충돌 발생 시 자신의 의견을 단정 짓지 않고 대안을 제시하며 팀원들의 우려를 경청하는 구체적인 행동과 그로 인한 정량적 개선 효과를 강조해야 합니다."}, "latency_sec": 93.869, "in_tokens": 1183, "out_tokens": 357} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-weak-backend", "rep": 12, "ok": true, "coaching": {"model_answer": "중복 주문 문제는 '결제 승인 지연'이라는 **시간적 불일치**와 'DB 트랜잭션 완료 후 외부 호출 실패'라는 **트랜잭션 경계** 문제의 결합이므로, 두 패턴을 보완적으로 적용했습니다. 멱등 키는 **동일한 이벤트가 2 회 이상 처리될 경우**를 막는 최종 안전장치로, Kafka에서 2 회 이상 동일한 주문 ID 를 받은 경우에만 처리를 수행하도록 구현했습니다. 반면 트랜잭션 경계 (Outbox) 는 **DB 트랜잭션이 완료된 후에도 외부 시스템 (결제 게이트웨이) 에 연결 실패**할 때, 이벤트가 큐에 쌓이지 않고 바로 사라지는 문제를 방지했습니다. 만약 Outbox 만 사용했다면 DB 트랜잭션이 성공해도 외부 호출 실패 시 이벤트가 누락되어 멱등 키가 생성되지 않아 재발생할 수 있었으며, 멱등 키 만 사용했다면 외부 호출 실패 시 이벤트가 재발생 없이 사라져 트랜잭션의 일관성이 깨질 수 있었습니다.", "answer_rewrite": "중복 주문 문제는 '결제 승인 지연'이라는 시간적 불일치와 'DB 트랜잭션 완료 후 외부 호출 실패'라는 트랜잭션 경계 문제의 결합이므로, 두 패턴을 보완적으로 적용했습니다. 멱등 키는 **동일한 이벤트가 2 회 이상 처리될 경우**를 막는 최종 안전장치로, Kafka에서 2 회 이상 동일한 주문 ID 를 받은 경우에만 처리를 수행하도록 구현했습니다. 반면 트랜잭션 경계 (Outbox) 는 **DB 트랜잭션이 완료된 후에도 외부 시스템 (결제 게이트웨이) 에 연결 실패**할 때, 이벤트가 큐에 쌓이지 않고 바로 사라지는 문제를 방지했습니다. 만약 Outbox 만 사용했다면 DB 트랜잭션이 성공해도 외부 호출 실패 시 이벤트가 누락되어 멱등 키가 생성되지 않아 재발생할 수 있었으며, 멱등 키 만 사용했다면 외부 호출 실패 시 이벤트가 재발생 없이 사라져 트랜잭션의 일관성이 깨질 수 있었습니다.", "coaching_comment": "두 패턴이 각각 막는 구체적인 실패 케이스 (외부 호출 실패 vs 이벤트 재처리) 를 명확히 구분하여 설명하세요."}, "latency_sec": 103.301, "in_tokens": 1310, "out_tokens": 519} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-dont-know-cs", "rep": 13, "ok": true, "coaching": {"model_answer": "오래 열린 트랜잭션은 xmin 값이 오래 전으로 내려가 있어, 해당 트랜잭션이 삭제한 tuple 을 회수할 수 없는 'xmin horizon' 을 형성합니다. 이로 인해 해당 트랜잭션이 종료될 때까지 해당 tuple 은 dead tuple 로 간주되지 못해 vacuum 에서 즉시 회수되지 않습니다. 이 과정에서 테이블에 회수되지 않은 빈 공간이 축적되어 'table bloat'가 발생하며, 이는 쿼리 성능 저하와 저장소 낭비를 초래합니다.", "answer_rewrite": "오래 열린 트랜잭션은 xmin horizon 을 형성하여 해당 트랜잭션 종료 전까지 tuple 을 즉시 회수하지 못하게 합니다. 이로 인해 테이블에 빈 공간이 축적되어 bloat 가 발생하고 쿼리 성능이 저하될 수 있습니다.", "coaching_comment": "기대된 핵심인 xmin horizon 과 bloat 발생 원인을 명확히 연결하여 설명해야 합니다."}, "latency_sec": 98.489, "in_tokens": 871, "out_tokens": 214} +{"label": "local-qwen3.5-4b", "suite": "coaching:fanout15x5", "case_id": "c-personality-rambling", "rep": 14, "ok": true, "coaching": {"model_answer": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2 주 지연된 경험입니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축해 프론트엔드 팀과 병렬 개발을 가능하게 했으며, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 하지만 초기에 제 방식이 옳다고 고집하여 감정적 대립이 발생했습니다. 이후에는 결정 전 대안 두 가지를 비교해 보는 방식으로 접근하여 팀워크를 개선했습니다. 이는 기술적 해결책보다 소통 프로세스의 개선이 장기적인 팀 효율성을 높인다는 것을 증명했습니다.", "answer_rewrite": "팀원과의 의견 충돌은 캡스톤 프로젝트에서 API 스펙 해석 차이로 통합 직전 2 주 지연된 경험입니다. 저는 OpenAPI 명세와 Mock 서버를 먼저 구축해 프론트엔드 팀과 병렬 개발을 가능하게 했으며, 이를 통해 통합 이슈를 3 건에서 0 건으로 줄였습니다. 하지만 초기에 제 방식이 옳다고 고집하여 감정적 대립이 발생했습니다. 이후에는 결정 전 대안 두 가지를 비교해 보는 방식으로 접근하여 팀워크를 개선했습니다.", "coaching_comment": "감정적 대립이 발생했던 구체적인 상황을 인정하고, 그로 인한 팀워크 개선의 구체적인 행동과 결과를 더 명확하게 서술해야 합니다."}, "latency_sec": 91.758, "in_tokens": 1183, "out_tokens": 312} +{"label": "local-qwen3.5-4b", "suite": "followup:during-fanout", "case_id": "f-strong-backend", "rep": 0, "ok": true, "followup_question": "멱등 키를 유니크 제약으로 구현하신 건가요?", "answer_intent": "NORMAL", "answer_evaluation": {"specificity": 4.0, "logic": 4.0, "structure": "NONE", "correctness": 4.0}, "latency_sec": 111.486, "ttft_sec": 109.622, "in_tokens": 1411, "out_tokens": 58} +{"label": "local-qwen3.5-4b", "suite": "fanout_wall", "wall_sec": 304.74, "ok": true} diff --git a/docs/research/llm-provider-evaluation-2026-09.md b/docs/research/llm-provider-evaluation-2026-09.md new file mode 100644 index 0000000..3ead119 --- /dev/null +++ b/docs/research/llm-provider-evaluation-2026-09.md @@ -0,0 +1,125 @@ +# LLM 제공자 검토 — 로컬 LLM · 오픈 모델 대안 (2026-09-17) + +> 회의(2026-09-21) 안건용. 실험 하네스: [`ai/scripts/llm_eval/`](../../ai/scripts/llm_eval/README.md) + +## 1. 결론 + +1. **운영은 현재 구성(학교 게이트웨이 Gemini 3.5 Flash-Lite + 3.1 Pro)을 유지한다.** 품질·지연·안정성 모두 비교 대상 중 최상위권이다. +2. **이 서버(GTX 1660 Ti 6GB)에서의 로컬 LLM 전환은 권장하지 않는다.** 블라인드 품질 점수가 절반 수준이고, GPU 1장이 요청을 직렬 처리해 동시 사용 시 꼬리질문이 33~111초로 무너진다. +3. **게이트웨이 의존 리스크 대비책(Plan B)은 오픈 가중치 모델로 준비한다.** 1순위 Gemma 4 31B(품질 Gemini 동급, 단 꼬리질문 9초), Flash 대안은 Solar Pro 4 또는 gpt-oss-120b. PR #234 로 티어별 엔드포인트를 환경변수만으로 바꿀 수 있다. +4. **Kimi 는 로컬 불가(최소 16GB+), API 로는 Gemini 보다 비싸거나 비슷하다(K2.6 1천 세션당 $82, K3 $279).** Qwen·Kimi API 는 외부 키가 없어 실측하지 못했다 — 키가 생기면 같은 하네스로 한 명령에 측정 가능. + +## 2. 무엇을 어떻게 측정했나 + +- **운영 체인 그대로**: 질문 풀 생성(JSON 파서), 스트리밍 꼬리질문(`//` 태그), 답변 코칭. 프롬프트·파서 수정 없음. +- **케이스(합성)**: 질문 풀 5(백엔드·프론트·인프라+DBA 복수 직군·자소서 인성·긴 문맥 p90), 꼬리질문 14(강한/약한 답, 명시적·STT형 "모름", 재설명 요청, 확인형 단답, 이력서와 사실 불일치, 긴 답변+대화이력, 영문 혼용 등 정답 라벨 포함), 코칭 3. 입력 크기는 운영 `ai_request_logs` 분포(질문 풀 입력 p50 3.1k / p90 4.7k 토큰, 답변 p50 162자·max 2,583자)에 맞춤. +- **반복**: 꼬리질문·코칭 3회, 질문 풀 2회. +- **자동 지표**: 태그/JSON 준수, 의도 분류 정확도, 점수 라벨 정확도(강한 답 ≥3, 약한 답 ≤2, 확인형 단답 null), 사실대조 규칙(컨텍스트 없으면 correctness=null), 근거 인용이 자료에 실재하는지, 질문 중복, 외국 문자 혼입, 지연(TTFT·p90), 콜드스타트, 코칭 15건×동시 5 fan-out, fan-out 중 다른 사용자 꼬리질문 지연. +- **블라인드 품질 채점**: 같은 케이스의 후보 출력을 익명(A,B,C…)·무작위 순서로 섞어 **Gemini 3.1 Pro 와 Claude Opus 5** 가 1~5점 채점. 판정자 간 ±1점 이내 일치 90%. + - Gemini 판정자는 Google 계열(Gemini·Gemma)에 0.4~0.9점 후하게 줬다 → **아래 순위 판단은 Claude 판정 점수를 우선 참고**. +- **환경**: 로컬은 ana-server Ollama 0.20.7, 전 모델 `num_ctx 8192` 파생 모델, 워밍업 후 측정. 게이트웨이 모델은 운영 AI 컨테이너에서 호출(게이트웨이 오버헤드 포함). + +## 3. 결과 + +### 3.1 품질 (블라인드 채점 overall, 5점 만점) + +| 모델 | 경로 | 꼬리질문 (Claude / 평균) | 질문 풀 (Claude / 평균) | 코칭 (Claude / 평균) | +|---|---|---|---|---| +| Gemini 3.1 Pro (현 Pro) | 게이트웨이 | — | 4.4 / 4.5 | — | +| **Gemini 3.5 Flash-Lite (현 Flash)** | 게이트웨이 | **4.0 / 4.2** | 4.2 / 4.2 | 4.3 / 4.2 | +| **Gemma 4 31B** (오픈 가중치) | 게이트웨이 | 3.9 / 4.4 | 4.0 / 4.3 | 4.0 / 4.3 | +| Solar Pro 4 (Upstage, 비공개 가중치) | 게이트웨이 | 3.8 / 3.6 | 3.8 / 3.4 | 4.7 / 4.3 | +| gpt-oss-120b (max_tokens 2048) | 게이트웨이 | 3.3 / 3.1 | 2.4 / 2.7 | 2.7 / 2.3 | +| Llama 4 Maverick | 게이트웨이 | 3.3 / 3.0 | 2.8 / 2.3 | 3.0 / 2.7 | +| Qwen3 4B Instruct | 로컬 | 2.6 / 2.5 | 3.0 / 3.1 | 2.3 / 2.2 | +| Qwen3.5 4B (thinking off) | 로컬 | 2.7 / 2.5 | 2.7 / 2.5 | 2.0 / 1.8 | +| A.X 4.0 Light 7B (SKT) | 로컬 | 2.1 / 1.9 | 2.7 / 2.5 | 2.3 / 2.2 | +| Mi:dm 2.0 Mini (KT) | 로컬 | 1.6 / 1.5 | 2.0 / 2.0 | 전부 실패 | + +판정자가 지적한 대표 문제: +- 로컬 소형: 재설명 요청에 원 질문을 그대로 반복, 사소한 질문(키 형식·길이), 코칭 리라이트가 지원자 답변을 무시하고 모범답안을 복사. +- Solar Pro 4: 깊이는 최상급이나 질문이 장황(질문 풀 80자 이내 0%)하고 **기대 신호(정답)를 질문에서 누설**. +- gpt-oss / Llama 4: 질문 풀 깊이 부족, 코칭 리라이트가 원 답변과 무관. + +### 3.2 형식 준수·채점 신뢰도 (자동 지표) + +| 모델 | 태그 준수 | 의도 분류 | 점수 라벨 | 사실대조 규칙 | 질문 풀 성공 | 긴 문맥 질문 풀 | +|---|---|---|---|---|---|---| +| Gemini 3.5 Flash-Lite | 100% | 100% | 100% | 100% | 90% | 1/2 | +| Gemini 3.1 Pro | — | — | — | — | 100% | 2/2 | +| Gemma 4 31B | 100% | 100% | 100% | 100% | 100% | 2/2 | +| Solar Pro 4 | 100% | 95% | 88% | 100% | 100% | 2/2 | +| gpt-oss-120b (512 토큰) | 55% | 100% | 42% | 73% | 100% | 2/2 | +| gpt-oss-120b (2048 토큰) | 100% | 100% | 100% | 100% | — | — | +| Llama 4 Maverick | 100% | 93% | 91% | 82% | 100% | 2/2 | +| Qwen3 4B Instruct | 100% | 100% | 82% | 58% | 90% | 2/2 | +| Qwen3.5 4B | 33% | 93% | 18% | 70% | 50% | 0/2 | +| A.X 4.0 Light | 100% | 91% | 76% | 55% | 70% | 1/2 | +| Mi:dm 2.0 Mini | 29% | 14% | 9% | 73% | 30% | 1/2 | +| Kanana-2-3B | 출력이 깨진 문자열("관 관 관…") — Ollama 0.20.7 의 아키텍처 지원 문제로 추정, 평가 제외 | + +- **Mi:dm 2.0 Mini 는 모든 답변을 DONT_KNOW 로 분류**했다. 운영에서는 DONT_KNOW 꼬리질문을 Core 가 폐기하므로 면접이 진행되지 않는다. +- **gpt-oss-120b 는 추론을 끌 수 없어** 운영값 `LLM_FLASH_MAX_TOKENS=512` 에서 추론이 토큰을 다 써 질문이 비었다. 2048 로 올리면 규칙은 모두 지키나 지연이 늘어난다. +- 외국 문자 혼입(중국어 등)은 모든 모델 0%. + +### 3.3 지연 + +| 모델 | 꼬리질문 중간값 / p90 | 첫 질문 토큰 | 질문 풀 중간값 | 코칭 15건×동시5 총시간 | fan-out 중 타 사용자 꼬리질문 | 모델 언로드 후 첫 호출 | +|---|---|---|---|---|---|---| +| Gemini 3.5 Flash-Lite | **2.0s / 5.8s** | 1.5s | 4.2s | **11s** | **2.1s** | — | +| Gemini 3.1 Pro | — | — | 24.7s | — | — | — | +| Gemma 4 31B | 9.2s / 54s | 3.2s | 43.7s | — | — | — | +| Solar Pro 4 | 2.3s / 4.4s | 1.3s | 16.2s | — | — | — | +| gpt-oss-120b (2048) | 4.3s / 5.5s | 3.9s | 15.4s | — | — | — | +| Llama 4 Maverick | 1.9s / 2.8s | 1.3s | 7.3s | — | — | — | +| Qwen3 4B Instruct | 3.3s / 5.5s | 1.7s | 31.4s | 224s | **79s** | 10.7s | +| Qwen3.5 4B | 6.4s / 7.6s | 4.0s | 41.0s | 305s | 111s | 15.5s | +| A.X 4.0 Light | 4.3s / 6.4s | 2.1s | 35.1s | 231s | 81s | 12.2s | +| Mi:dm 2.0 Mini | 1.9s* | — | 17.2s | 99s (전부 실패) | 33s | 7.7s | + +\* DONT_KNOW 로만 분류해 질문 스트리밍이 생략된 값. + +운영 실측(참고): Gemini 꼬리질문 스트림 p50 1.6s, 질문 풀(Pro) p50 14.4s. + +## 4. 로컬 LLM 이 이 서버에서 안 되는 이유 (정량) + +1. **직렬 처리**: Ollama 는 GPU 1장에서 요청을 순서대로 처리한다. 피드백 코칭(세션당 ~15건, 동시 5)이 도는 동안 다른 사용자의 꼬리질문이 33~111초 대기 → 실시간 면접 불가. +2. **VRAM 6GB 한계**: 7B급·비전 포함 모델(Qwen3.5 4B 6.4GB)은 CPU 로 넘쳐 느려진다. 4B급만 온전히 올라가는데 품질이 부족하다. +3. **문맥 절단**: Ollama 기본 `num_ctx` 4096. 운영 질문 풀 입력 p90 4.7k 토큰 — 실제로 긴 문맥 케이스가 정확히 4,096 토큰에서 잘렸다. 파생 모델(`PARAMETER num_ctx 8192`) 필수. +4. **GPU 간헐 인식 실패**: 오늘 `ggml_cuda_init: failed to initialize CUDA` 가 여러 차례 발생해 **오류 없이 CPU 로 폴백**(지연 10배). 두 번 모두 배포(`docker compose up --build`) 후 4~10분 안이었다 — 인과는 미확정. 같은 Ollama 를 쓰는 devlog/devtalk/mcp 에도 영향. +5. **서빙 호환성**: Kanana-2 는 깨진 출력, Gemma 4 E2B 는 Ollama 업그레이드 필요(공유 컨테이너라 미실시). +6. **모델 언로드**: 기본 keep_alive 5분 후 내려가면 첫 호출 +8~15초 (`LLM_FLASH_TIMEOUT_SEC=10` 초과). + +## 5. 비용 (게이트웨이가 사라져 유료 API 로 갈 경우) + +세션 1회 = 질문 풀 1 + 답변 10(꼬리질문 10) + 피드백(패널 3·종합 1·자기소개 1·코칭 10). 토큰은 운영 로그 평균. 정가 기준, Pro thinking 토큰 미포함(과소추정). + +| 옵션 | 세션당 | 1천 세션 | +|---|---|---| +| 현재 구성 Gemini Flash-Lite + 3.1 Pro | $0.069 | $69 | +| Gemini 3.5 Flash-Lite 단독 | $0.037 | $37 | +| Solar Pro 4 | $0.025 | $25 | +| DeepSeek V4.1 Flash (OpenRouter) | $0.025 | $25 | +| Qwen3.8-Flash (Alibaba) | $0.011 | $11 | +| gpt-oss-120b (DeepInfra) | $0.003 | $3 | +| Kimi K2.6 (Moonshot) | $0.082 | $82 | +| Kimi K3 (Moonshot) | $0.279 | $279 | + +현재 누적 사용량은 세션 95건·사용자 4명 수준이라 어느 옵션이든 월 수 달러 이하다. 비용보다 **품질과 게이트웨이 지속성**이 결정 요인. + +## 6. 회의에서 결정할 것 + +1. **로컬 LLM 운영 전환 보류**에 동의하는가. +2. **학교 게이트웨이 키의 유효 기간·사용 정책** 확인 담당자 (Plan B 의 시급성을 결정). +3. **Plan B 지정**: Pro 티어 → Gemma 4 31B(또는 유료 Gemini), Flash 티어 → Solar Pro 4(질문 길이·정답 누설 프롬프트 보정 필요) 또는 gpt-oss-120b(`LLM_FLASH_MAX_TOKENS` 상향). +4. **외부 API 키(OpenRouter 등) 확보 여부** — 확보 시 Qwen3.8-Flash·DeepSeek·Kimi 를 같은 하네스로 실측. +5. **공유 Ollama GPU 끊김** 조치 여부 (다른 프로젝트 영향). +6. 로컬을 계속 검토한다면 필요한 하드웨어: 31B급(Gemma 4 31B 등)을 올릴 수 있는 VRAM 24GB 이상 GPU. 동시성은 vLLM 등 배치 서빙 필요. + +## 7. 한계 + +- 케이스는 합성 22개(꼬리질문 14·질문 풀 5·코칭 3)로, 통계적 유의성보다 **명확한 격차 확인**용이다. 상위권(Gemini·Gemma·Solar) 간 0.1~0.3점 차는 오차 범위로 본다. +- LLM 판정은 사람 평가를 대체하지 않는다. 판정자 계열 편향이 관찰됐다(§2). +- 게이트웨이 모델 지연에는 게이트웨이 오버헤드가 포함된다. Gemma 4 31B 의 9초는 게이트웨이 경유 값이며 다른 제공자에서는 다를 수 있다. +- Qwen API(3.8-Flash 등)·Kimi·DeepSeek 는 키가 없어 가격·공개 벤치만 조사했다(미실측). +- 로컬 결과는 GTX 1660 Ti · Ollama 0.20.7 기준. llama.cpp 직접 서빙은 3~10% 빠르다는 보고가 있으나 직렬 처리 문제는 동일하다.