
웹 엔지니어였던 내가 AI 엔지니어가 되기 위해 했던 일
요약
백엔드 엔지니어가 LLM 기반 프로덕트를 만드는 AI 엔지니어로 전환하며 겪은 실무 경험을 공유합니다. 수학적 이론보다는 시스템 설계, 토큰 이해, 모델 비교 검증 등 실무적인 역량의 중요성을 강조합니다.
핵심 포인트
- AI 엔지니어는 모델 제작자보다 LLM을 활용한 제품 설계자가 주류임
- 토큰, 컨텍스트 윈도우, 비용 및 레이턴시의 특성 이해가 필수적임
- 정밀도, 레이턴시, 비용의 3개 축을 기준으로 모델을 비교 검증해야 함
- 무조건 똑똑한 모델보다 태스크에 적합한 모델을 선택하는 것이 중요함
안녕하세요, 株式会社estra에서 엔지니어를 하고 있는 후쿠치입니다.
"AI 엔지니어"라는 말, 굉장히 핫해서 최근 자주 들리지만, 범위가 너무 넓어서 어디서부터 손을 대야 할지 모르지 않나요?
저는 평범한 백엔드 엔지니어였지만, LLM을 이용하게 되고 평가나 가드레일(Guardrail) 설계까지 수행해 오면서 알게 된 것들이 있습니다.
이 기사에서는 그 과정에서 실제로 했던 일들을 공유합니다. 배우는 순서와 실무에서 처음 맞닥뜨리는 논점이 무엇인지 알 수 있을 것입니다.
원래는 백엔드를 담당했습니다. API를 작성하고, DB를 설계하고, 가끔 인프라를 만지는 일 말이죠. 머신러닝 (Machine Learning) 경험은 제로였고, 행렬 곱셈도 가물가물한 수준이었습니다.
그럼에도 어떻게든 해낼 수 있었던 이유는, 지금 요구되는 "AI 엔지니어"의 상당수가 모델을 만드는 사람이 아니라 "LLM을 사용하여 프로덕트(Product)를 만드는 사람"이기 때문입니다.
Chip Huyen의 저서 「AI Engineering」에서는 이 직종을 명확히 구분하고 있으며, 필요한 것은 학습 이론보다 시스템 설계와 평가 능력이라고 서술하고 있습니다. 백엔드 경험은 오히려 그대로 활용됩니다.
따라서 수학부터 다시 공부할 필요는 없습니다. 저도 하지 않았습니다 (물론 지식이 있는 것이 좋겠지만, 필요할 때 찾아보는 방식으로도 충분했습니다). 이 기사에서도 머신러닝의 수학이나 모델 자체 제작은 다루지 않습니다.
가장 먼저 한 일은 LLM의 구조를 대략적으로 이해하는 것이었습니다. 실무에서 파악해야 할 것은 딱 3가지뿐이었습니다.
토큰 (Token)
LLM은 문장을 토큰이라는 단위로 처리하며, 과금도 레이트 리밋 (Rate Limit)도 토큰 단위입니다.
컨텍스트 윈도우 (Context Window)
한 번에 전달할 수 있는 토큰 수의 상한선으로, 시스템 프롬프트(System Prompt)도 대화 이력도 입력 문서도 모두 이 범위 안에 담아야 합니다.
비용과 레이턴시 (Latency)의 특성
요금은 입출력 토큰 수에 비례하여 증가합니다. 또한 처리 시간 측면에서는 Attention의 계산량이 입력 길이에 대해 제곱으로 증가하는 성질이 있기 때문에, 입력이 길수록 응답도 느려지기 쉽습니다. 긴 문장을 무심코 던지면 비싸고 느리다, 라고 기억해 두는 것만으로 실무에서는 충분합니다.
컨텍스트 윈도우는 "책상의 넓이" 이미지입니다. 책상에 올라가는 자료만 참조할 수 있고, 큰 책상에서 작업할수록 시간과 비용이 많이 듭니다. 이 감각이 있으면 나중에 설명할 RAG나 프롬프트 설계 이야기가 모두 연결됩니다.
반대로, Transformer의 내부 구조나 학습 메커니즘에는 처음에는 깊이 파고들지 않았습니다. 논문을 읽는 것보다 API를 호출하는 것이 압도적으로 빠릅니다.
OpenAI와 Vertex AI (Gemini)를 모두 사용했습니다. 의도적으로 그렇게 했다기보다 요구사항 속에서 자연스럽게 그렇게 되었는데, 결과적으로 가장 배움이 컸던 부분이었습니다.
빠른 단계에서 했던 것이 모델 비교 검증입니다.
동일한 태스크에 대해 여러 모델을 실행하여 정밀도(Accuracy)・레이턴시(Latency)・비용의 3개 축으로 비교합니다. 정밀도는 정답 데이터 (Ground Truth)를 준비하여 대조합니다. 이 정답 데이터는 현장에서 골드 앤서 (Gold Answer, GA)라고 불리기도 합니다. 명칭만 다를 뿐 가리키는 것은 같습니다.
| 축 | 측정 방법 | 주의할 점 |
|---|---|---|
| 정밀도 | Ground Truth와 대조하여 정답률을 산출 | 정답 데이터 제작이 가장 힘듭니다. 이 부분을 소홀히 하면 모든 것이 어긋납니다. |
| ... |
직접 해보며 알게 된 것은 "가장 똑똑한 모델이 정답"은 아니라는 점입니다. 플래그십 모델은 확실히 정밀도가 높지만, 레이턴시는 2배이고 비용은 5배인 경우가 있습니다.
태스크에 따라서는 작은 모델로도 정밀도가 거의 변하지 않는 경우가 있는데, 그럴 때는 답이 명백히 작은 모델 쪽입니다.
이 검증 패턴 (평가 데이터셋을 만든다 → 여러 모델로 돌린다 → 3개 축으로 비교한다)은 어떤 상황에서도 재사용할 수 있는 자산이 되었습니다.
요금은 빈번하게 개정되므로, 이 기사에는 일부러 구체적인 금액을 적지 않겠습니다. 공식 요금 페이지를 확인하는 습관을 들이는 것이 가장 빠른 길입니다.
제가 한 일은 크게 두 가지입니다.
첫 번째는 어노테이션 (Annotation)입니다. 모델이 수행하게 하고 싶은 태스크의 정답 데이터를 수작업으로 만드는 작업입니다. 지루하지만, 이 작업을 한 덕분에 "이 태스크의 어려움은 어디에 있는가", "모델이 어디서 틀릴 것인가"를 체감할 수 있게 되었습니다. 이후의 평가 설계와도 직결됩니다.
두 번째는 분류한 뒤에 프롬프트를 나누어 출력하는 설계입니다. 입력 이미지를 처음에 가벼운 모델로 카테고리 분류하고, 카테고리별로 전용 프롬프트를 가진 후속 처리로 라우팅(Routing)합니다.
구조만 의사 코드 (Pseudo code)로 나타내면 다음과 같습니다.
category = classify_image(image) # 가벼운 모델로 분류
prompt = PROMPTS[category] # 카테고리 전용 프롬프트 선택
result = generate(prompt, image) # 본 처리는 고정밀 모델로 실행
하나의 거대한 프롬프트로 모든 케이스에 대응하려고 하면, 특정 케이스를 수정했을 때 다른 케이스가 망가지는 '두더지 잡기' 게임이 됩니다. 분류를 통해 분기시키면 프롬프트를 작게 유지할 수 있고, 카테고리 단위로 정밀도를 측정하고 수정할 수 있습니다. 이는 Anthropic이 「Building Effective Agents」에서 말하는 워크플로(Workflow)형 설계 그 자체이며, 실무에서는 에이전트에게 자유롭게 맡기는 것보다 이 형태에 정착되는 경우가 많습니다.
음성 받아쓰기(Transcription) 태스크도 수행했습니다. Whisper 계열의 API를 사용하는 것 자체는 간단하지만, 실무에서 효과를 본 것은 전후 처리였습니다.
구조를 조금 보충하자면, Whisper는 음성 파형을 그대로 읽는 것이 아닙니다. 고속 푸리에 변환 (FFT)을 통해 짧은 시간 창(Time window)마다 주파수 성분으로 분해하고, 스펙트로그램 (정확히는 log-Mel 스펙로그램. 시간 × 주파수의 강도 맵)으로 변환한 뒤 모델에 입력합니다.
즉 내부적으로는 음성을 '이미지와 같은 데이터'로 취급하는 것입니다. 또한 모델의 입력 사이즈가 고정되어 있기 때문에, Whisper는 음성을 30초 단위로 끊어서 처리합니다. 이 두 가지를 알고 있으면, 후술할 분할 처리 이야기나 무음 구간에서 이상한 출력(Hallucination, 환각)이 나오기 쉬운 이유를 납득할 수 있습니다.
API에는 파일 크기 상한이 있으므로, 긴 음성은 시간 기준으로 분할하여 병렬로 던지고 결과를 결합합니다. 그리고 받아쓰기 결과를 그대로 신뢰하지 마세요.
Whisper는 무음 구간에서 정형적인 환각(존재하지 않는 관용구)을 내뱉을 때가 있습니다. 받아쓰기 결과를 후속 처리에 넘기기 전에, 기지의 패턴을 차단 목록(Blocklist)으로 제거하는 후처리를 끼워 넣는 것을 추천합니다.
"API를 호출하기만 하면 되는 거 아냐"라고 생각했던 태스크일수록, 이런 투박한 처리가 본체인 경우가 많습니다. LLM을 호출하기 전의 전처리와 후처리는 매우 중요합니다.
프롬프트는 형식을 익히고 나니 안정되었습니다. 제가 사용하는 형식은 이것뿐입니다.
- 역할과 완료 조건을 처음에 작성한다
- 참조 자료나 입력은 XML 태그나 구분자로 명시적으로 감싼다
- 예시 (Few-shot)를 1~3개 넣는다. 많다고 좋은 것이 아니다
- 출력은 JSON 스키마로 강제한다
- "판단할 수 없는 경우에는 추측하지 말고
unknown을 반환한다"라고 도망갈 길을 마련해둔다
특히 효과적이었던 것은 4번과 5번입니다. 출력 형식을 프롬프트로 "부탁"하던 시절에는 파싱 에러(Parsing error)와의 싸움이었지만, 구조화된 출력(Structured Output, 스키마 강제)으로 전환한 이후로는 재시도 처리가 거의 사라졌습니다. 5번을 넣으면 모델이 억지로 답을 지어내는 케이스가 눈에 띄게 줄어듭니다.
또 하나, 은근히 효과적인 것이 출력의 "쓰는 순서"입니다. JSON 스키마를 설계할 때, 저는 reason (판단 이유)을 먼저, answer (결론)를 나중에 배치합니다.
{
"reason": "이미지 왼쪽 상단에 수기 서명이 있으며, 판정 기준 A에 해당하기 때문",
"answer": "category_a"
...
LLM은 문장을 앞에서부터 순차적으로 생성하기 때문에, answer를 먼저 배치하면 결론을 먼저 내놓은 뒤 이유를 나중에 덧붙이는 형태가 됩니다. 반대로 reason을 먼저 배치하면, 이유를 써 내려가는 과정이 그대로 사고의 초안이 되어 결론의 정밀도가 올라갑니다. Chain-of-Thought (사고의 연쇄)라고 불리는 테크닉을 스키마의 항목 순서로 구현하는 이미지입니다. 필드 배열 하나로 정답률이 바뀐다는 사실은 처음에는 꽤 놀라웠습니다.
솔직히 LLM을 사용한 프로덕트를 만드는 데 있어 가장 중요한 것은 이 부분이라고 생각합니다.
LLM의 출력은 매번 바뀌기 때문에, "좋아진 것 같다"라는 느낌만으로는 프롬프트를 변경할 수 없습니다. 그래서 평가 프롬프트를 사용한 오프라인 평가 시스템을 만들었습니다. 구조는 단순합니다. 평가용 데이터셋에 대해 본 프로ンプト를 일괄 실행하고, 그 출력을 다른 LLM이 관점별로 채점하게 합니다. 이른바 LLM-as-a-Judge (LLM을 이용한 자동 평가)입니다.
운영하며 배운 점이 3가지 있습니다.
- 측정하는 쪽과 측정되는 쪽을 분리한다
평가 프롬프트와 본 프로ンプト를 섞으면 어느 쪽을 수정했는지 알 수 없게 됩니다. - 기계로 판정할 수 있는 관점을 LLM에게 묻지 않는다
글자 수나 포맷처럼 규칙으로 판정할 수 있는 항목은 코드로 체크하여, LLM 판단 (LLM Judge) 결과를 덮어씁니다. 이것이 더 저렴하고 확실합니다. -
판단 자체를 의심하라
LLM 판단 (LLM Judge)에는 위치 편향 (Position Bias)이나, 답변이 장황할수록 높게 평가하는 경향이 있습니다. 사람의 채점 결과와 대조하며 판단 프롬프트를 조정하는 캘리브레이션 (Calibration) 과정이 필요했습니다.
사실의 정확성에 대해서는, Ground Truth와 대조하여 정밀도 (Precision) / 재현율 (Recall)을 산출하는 평가도 별도로 만들었습니다. 어노테이션 (Annotation) 경험이 여기서 빛을 발했습니다.
또 하나, 시작하기 전에는 상상하지 못했던 것이 도메인 지식 (Domain Knowledge)의 중요성입니다. 평가 관점을 결정할 때나, "이 출력이 업무적으로 정답인가"를 판정할 때나 해당 영역의 지식이 필요합니다. 프롬프트 (Prompt)를 작성할 때도 마찬가지로, 업무 규칙이나 예외 사항을 언어화하여 모델에 전달하는 것은 엔지니어의 몫입니다. 저는 어노테이션을 직접 수행했던 경험과, 업무에 정통한 사람들에게 끊임없이 질문했던 덕분에 어떻게든 해낼 수 있었습니다. 기술만 공부해서는 평가 체계를 만들 수 없다는 점을 강조하고 싶습니다.
「AI Engineering」에서도 평가는 반복해서 강조되며, 저자는 평가를 AI 도입의 최대 병목 현상 (Bottleneck)이라고 부릅니다. 실감하는 바와 마찬가지로, 프롬프트를 쓸 줄 아는 사람보다 평가를 설계할 수 있는 사람이 압도적으로 희귀합니다.
LLM의 출력을 그대로 사용자에게 내보내는 것은 위험합니다. 그래서 가드레일 (Guardrail)을 설계했습니다. 크게 두 가지 방식을 사용했습니다.
하나는 규칙 기반 (Rule-based) 체크입니다. NG 워드 설정 등 결정적으로 판정할 수 있는 것은 코드로 걸러냅니다. LLM에게 판단하게 하는 것보다 빠르고 저렴하며 확실합니다. 다른 하나는 분류 기반 (Classification-based) 체크로, 입력을 분류기 (Classifier)에 통과시켜 주의가 필요한 카테고리에 해당하면 일반 플로우에서 제외하고, 정형 응답이나 사람에게 전달하는 에스컬레이션 (Escalation) 같은 별도의 경로로 보냅니다.
설계 시 고민되는 지점은 트레이드오프 (Trade-off)입니다. 가드레일을 엄격하게 설정하면 위험한 출력은 줄어들지만, 문제가 없는 입력까지 잘못 걸러내는 비율 (오거부율, False Rejection Rate)이 높아집니다. 전부 거부하면 공격 성공률은 0이 되겠지만, 그것은 더 이상 프로덕트라고 할 수 없겠지요. 어디에 선을 그을지는 비즈니스 판단의 영역이며, 엔지니어는 그 판단의 근거가 될 수 있는 수치를 제시할 수 있어야 한다는 것이 저의 결론이었습니다.
웹 엔지니어의 감각으로는 API 호출이 수십 밀리초 (ms) 단위이지만, LLM은 아무렇지 않게 수 초가 걸립니다. 게다가 종량제 과금 방식입니다. 이 부분을 설계에 녹여낼 수 있느냐가, 돌아가는 데모와 운영 가능한 프로덕트를 가르는 차이였습니다.
레이턴시 (Latency)는 p50이 아니라 p90 / p99로 확인해야 합니다. LLM의 레이턴시는 꼬리가 긴 (Long-tailed) 분포를 가지므로 평균값은 신뢰하기 어렵습니다. 응답이 늦어질 경우를 대비해 다른 프로바이더 (Provider)나 재시도 (Retry)를 병행하여 실행하고, 더 빨리 돌아온 쪽을 채택하는 헤징 (Hedging) 실행 설계도 사용했습니다.
비용은 태스크 (Task)마다 모델 크기를 구분해서 사용하는 것만으로도 자릿수가 달라집니다. 분류는 가벼운 모델, 생성은 고정밀 모델을 사용하는 적재적소의 원칙입니다. 시스템 프롬프트 (System Prompt)처럼 매번 동일한 내용을 보내는 부분은 프롬프트 캐시 (Prompt Cache)를 사용하면 입력 비용을 크게 절감할 수 있습니다. 견적 단계에서는 "1 요청당 입력 토큰 수 × 월간 요청 수"를 토큰 단가로부터 역산합니다. 이렇게 하면 해당 기능이 사업으로서 성립할 수 있는지를 초기에 파악할 수 있습니다.
「AI Engineering」에는 프롬프팅 (Prompting) → RAG → 파인튜닝 (Fine-tuning) 순으로 시도한다는 원칙이 있습니다. 비용과 복잡성이 낮은 순서입니다. 해당 도서에는 "파인튜닝은 형식을 위한 것이고, RAG는 사실을 위한 것이다"라는 정리도 있는데, 문제 상황에서 역으로 찾아보면 다음과 같습니다.
| 문제 상황 | 해결책 |
|---|---|
| 지시문 작성법으로 개선될 것 같다 | 우선 프롬프팅 |
| ... | |
| 실제로 분류와 프롬프트의 분기, 즉 프롬프팅의 고도화만으로 요건을 충족할 수 있었습니다. 최신 모델일수록 지시 이행 능력 (Instruction Following)이 향상되어, 프롬프트만으로 해결 가능한 케이스가 늘어나고 있습니다. RAG가 필요한 규모의 지식 베이스 (Knowledge Base)를 다루게 된다면, 그때 배워도 늦지 않다고 생각합니다. |
링크 모음은 하지 않겠습니다. 제가 실제로 읽은 순서대로 두 가지만 꼽겠습니다.
첫 번째는 도서 「AI Engineering」 (Chip Huyen 저, O'Reilly). 이 글에 등장한 평가 주도 (Evaluation-driven), 가드레일, 추론 최적화, 프롬프트 → RAG → FT의 순서가 모두 이 책에 체계적으로 실려 있습니다. 실무에 들어가기 전이나 후나 모두 유용합니다.
두 번째는 Anthropic의 엔지니어링 블로그, 특히 「Building Effective Agents」입니다. 워크플로우 (Workflow)와 에이전트 (Agent)의 구분은 이 글의 분류 → 분기 설계 아이디어의 모태가 되었습니다.
그 외에는 각 프로바이더 (Provider)의 공식 문서입니다. 요금, 모델, 제한 값 (Limit)은 반드시 1차 정보로 확인하는 습관을 들이세요. 2차 정보는 금방 낡아버립니다 (이 기사를 포함해서 말이죠).
돌이켜보며 가장 전하고 싶은 것은, 차이를 만드는 것은 프롬프트 (Prompt)의 숙련도가 아니라, 평가 (Evaluation) · 가드레일 (Guardrail) · 비용 (Cost)이라는 「운용의 논점」을 설계할 수 있는가 하는 점입니다. 그리고 이 부분은 백엔드 엔지니어 (Backend Engineer)의 경험이 그대로 무기가 되는 영역입니다.
웹 엔지니어 (Web Engineer)로부터의 전향은 생각보다 훨씬 현실적입니다. 우선은 작은 태스크 (Task)라도 좋으니, 평가 데이터셋 (Evaluation Dataset)을 하나 만드는 것부터 시작해 보세요. 프롬프트를 수정하기 전에 「어떻게 되어야 좋아졌다고 말할 수 있는가」를 결정하는 것. 이 순서를 몸으로 익히는 것이 제가 했던 일 중에서 가장 효과적이었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기