LLM을 프로덕션에 붙이는 순간, 가장 먼저 맞닥뜨리는 현실이 있다. 모델은 생각보다 지시를 잘 따르지 않는다. 그리고 프로바이더마다 '구조화 출력'의 의미가 제각각이다. 이론상 JSON을 돌려주겠다고 약속한 API가 실제로는 네 가지 다른 방언을 쓰고, 세 곳은 아예 약속 자체를 지킬 보장이 없다. 여기서 파이프라인 신뢰성 문제가 시작된다.
원칙 1: 구조화 출력은 스펙트럼이다, 보장이 아니다
CommitBrief 코드 리뷰 도구의 사례는 이 문제를 정면으로 드러낸다. 동일한 Finding 스키마를 7개 프로바이더에서 받아내야 하는데, 각자의 구현 방식이 완전히 다르다. Anthropic은 tool_use로 스키마를 강제하고, OpenAI는 strict json_schema로 서버 사이드에서 검증한다. Gemini는 MIME 타입과 응답 스키마를 조합하고, Ollama는 format: "json" 플래그 하나로 '어떤 JSON이든 내보낸다'고 약속할 뿐이다. DeepSeek, Mistral, Cohere는 프롬프트 지시에만 의존한다.
이걸 한 줄로 정리하면: API 레벨에서 스키마 형태까지 강제하는 프로바이더는 셋뿐이고, 나머지 넷은 당신의 파서가 책임진다. 이 차이를 인지하지 못하고 파이프라인을 설계하면, 특정 프로바이더로 교체하는 순간 조용히 깨진다. 팀이 멀티 프로바이더 전략을 쓰고 있다면, 지금 당장 각 API의 구조화 출력 보장 수준을 표로 정리해두길 권한다.
원칙 2: 진짜 계약은 모델이 아니라 파서가 맺는다
CommitBrief가 이 문제를 푼 방식이 흥미롭다. 프로바이더별 강제 수준이 다르더라도, 모든 응답을 동일한 ParseFindings 함수 하나로 통과시킨다. 단순히 JSON 파싱 여부를 체크하는 게 아니라, severity 값이 닫힌 어휘 안에 있는지, file과 title과 description이 비어 있지 않은지까지 필드 단위로 검증한다. 엄격한 스키마 프로바이더든 프롬프트만 믿는 프로바이더든, 검증 로직은 동일하다.
실패 시 전략도 명확하다. 파싱 실패 시 한 번 재시도하고, 두 번 모두 실패하면 raw 텍스트를 마크다운으로 렌더링하고 경고를 출력한다. 파이프라인은 절대 크래시하지 않는다. 토큰 비용은 두 번의 시도 합산으로 정확하게 기록되고, 저하(degrade) 응답은 캐시에 기록되어 재실행 시 재경고하지 않는다. 이 설계가 시사하는 바는 간단하다. LLM 출력에 대한 계약의 주체는 모델이 아니라 파서여야 한다.
이 원칙은 경량 에이전트 설계에도 그대로 적용된다. dev.to의 한 글은 LangChain, AutoGen, CrewAI 없이 60줄 Python으로 에이전트를 구현하는 과정을 보여준다. 핵심 구조는 세 가지—메시지 딕셔너리 리스트로 구현되는 상태(State), 함수 매핑 테이블인 도구(Tools), 그리고 LLM 호출과 도구 실행을 반복하는 while 루프다. 100MB 프레임워크가 추상화해주는 것들이 결국 이 세 가지인데, 추상화 레이어가 두꺼워질수록 50줄짜리 스택 트레이스의 어디서 무엇이 실패했는지 알 수 없게 된다. 디버깅 가시성이 신뢰성의 전제조건이라면, 추상화 비용을 먼저 따져야 한다.
원칙 3: 재시도 루프는 신뢰성이 아니라 복잡성을 증폭시킨다
세 번째 원칙은 실패 사례에서 가장 선명하게 드러난다. Azure DevOps 티켓 자동 수정 파이프라인을 세 번 반복 구현한 경험담은 AI-First 팀이 빠지기 쉬운 함정을 정확히 짚는다. 1차 루프에서 40% 성공률, 2차에서 55%까지 올렸지만, 기능을 추가할수록 새로운 엣지 케이스가 기하급수적으로 늘었다. 3차에서 임베딩 기반 중복 제거, 멀티 레포 라우팅, 자동 롤백을 모두 붙였더니 로컬 모델 서버가 하루에 890번 메모리 오류를 냈다.
원인은 단순했다. 독립적인 재시도 루프를 가진 두 컨슈머가 동일한 로컬 모델 서버를 공유하고 있었다. 메모리가 부족해지면 재시도가 오히려 상황을 악화시키는 구조였다. OOM 상태에서 재시도하지 말 것, 컨슈머를 직렬화할 것, 로컬 바이너리를 npx 대신 직접 사용할 것—수정 자체는 간단했지만, 이 패턴을 발견하기까지 세 번의 루프가 필요했다.
이 실패가 던지는 교훈은 재시도 정책이 아니라 동시성 제어 설계다. LLM을 포함한 파이프라인에서 재시도는 흔히 '신뢰성을 높이는 방법'으로 여겨지지만, 리소스 경쟁이 있는 환경에서 독립적인 재시도 루프는 장애를 증폭시킨다. CommitBrief가 재시도를 딱 한 번으로 제한하고 그 이상은 저하 모드로 빠지도록 설계한 이유가 여기 있다.
팀에 적용할 때 먼저 확인할 것들
세 사례를 종합하면 LLM 통합 파이프라인의 신뢰성 설계는 세 층위에서 동시에 이뤄져야 한다. 프로바이더 레이어—각 API의 구조화 출력 보장 수준을 명시적으로 문서화하고, 프롬프트만 믿는 프로바이더에는 반드시 별도 파서 검증을 붙인다. 파서 레이어—모든 LLM 응답은 단일 검증 함수를 통과하게 설계하고, 실패 시 저하 경로를 미리 정의해둔다. 실행 레이어—재시도 루프를 설계할 때 컨슈머 간 리소스 경쟁 시나리오를 반드시 테스트한다.
모델의 품질이 개선될수록 '구조화 출력이 왜 안 되지?'라는 질문은 점점 줄어들 것이다. 하지만 프로바이더가 다양해지고 파이프라인이 복잡해질수록, 신뢰성의 책임은 모델에서 파이프라인 설계자에게로 더 명확하게 넘어온다. 내일 당장 팀의 LLM 통합 코드에서 재시도 로직과 파서 검증 코드를 찾아보라. 그게 없거나 프로바이더마다 다르다면, 그 파이프라인은 지금 운이 좋은 것이다.