기술

청크 5,446개가 2분 만에 완주했는데, LLM 을 한 번도 부른 적이 없었습니다

2026.09.2210분 읽기

재개 트리거를 건 지 2분 만에 완료 배너가 떴습니다. 사내 제안서 지식검색 도구의 문서 파이프라인으로, 청크를 LLM 에 넣어 엔티티와 관계를 뽑아 그래프에 적재하는 단계였습니다. 전체 12만 6천 청크 중 미추출분 5,446개가 남아 있어 다시 돌린 참이었습니다.

화면의 숫자는 「엔티티 0 · 관계 0 · 실패 0」이었습니다. 실패가 0이니 화면만 보면 성공입니다. 그런데 이 2분 동안 LLM 은 한 번도 호출된 적이 없었습니다.


의심은 배너가 아니라 산출물에서 시작됐습니다

처음 걸린 것은 엔티티 총량이었습니다. 청크 5,446개를 처리했으면 그래프의 엔티티 수가 늘어야 하는데 그대로였습니다. 대시보드가 아니라 산출물을 봤기 때문에 잡힌 것입니다.

두 번째 신호는 속도였습니다. 5,446개를 2분에 끝냈으니 청크당 7ms 입니다. LLM 호출은 네트워크 왕복 한 번에도 그보다 오래 걸립니다. 7ms 는 「빨랐다」가 아니라 「네트워크를 안 탔다」는 뜻이었습니다.

원인은 LLM 게이트웨이 컨테이너의 구독 인증 만료였습니다. 구독 하나를 에이전트 프로세스 하나, 로컬 CLI 하나, 컨테이너 속 게이트웨이 하나가 나눠 물고 있었습니다.

셋이 번갈아 토큰을 갱신하면서 리프레시 토큰이 서로를 무효화했습니다. 컨테이너 쪽은 「이미 다른 클라이언트가 소비한 토큰」 상태로 멈춰 있었습니다.


방어선 네 겹이 전부 통과됐습니다

인증 만료 자체는 흔한 일입니다. 문제는 그 오류가 완료 배너까지 오는 동안 어디에서도 멈추지 않았다는 점입니다. 방어선이 네 겹 있었고, 네 겹이 다 열려 있었습니다.

인증 — 만료됐습니다. 세 클라이언트가 공유하는 구조라 언제든 다시 만료될 수 있었습니다.

게이트웨이 — 상류의 인증 오류를 HTTP 200 과 사람이 읽는 경고 문자열로 바꿔 내려보냈습니다. 이 한 번의 번역이 아래 방어를 전부 무력화했습니다.

파서 — 그 문자열을 JSON 으로 못 읽자 빈 결과 객체로 삼켰습니다. 관대하게 만든 처리가 여기서는 사실 왜곡이 됐습니다.

호출부 — 예외가 없으니 성공으로 보고 추출 완료 표시를 찍었습니다.

넷 중 가장 비싼 것은 네 번째입니다. 앞의 셋은 그 시점의 작업을 날렸지만, 네 번째는 재시도 자격을 날렸습니다. 빈 결과를 「완료」로 저장하면 원인을 고친 뒤에도 그 청크는 미추출 목록에 다시 올라오지 않습니다.

작업을 한 번 잃고, 다시 할 기회를 한 번 더 잃는 셈입니다. 조용히 묻혀서 아무도 찾지 못합니다.

실패가 위로 올라가지 않는 구조는 처음 본 것이 아니었습니다. 에이전트가 없는 도구를 부르고도 그 실패를 모델에게 알려주지 않아 「등록 완료」가 보고된 일이 있었습니다.

청크 5,446개가 2분 만에 완주했는데, LLM 을 한 번도 부른 적이 없었습니다 그림 1


진단이 어려웠던 세 지점

호스트에서 인증 상태를 조회하면 「로그인됨 · 토큰 정상」이었습니다. 멈춰 있던 것은 컨테이너뿐이었습니다. 호스트가 로그인돼 있다는 사실은 컨테이너에 대해 아무것도 말해주지 않았습니다.

에러 메시지가 안내한 복구 경로도 이 구조에서는 성립하지 않았습니다. 컨테이너에는 데이터 볼륨만 마운트돼 있어 호스트의 인증 파일을 볼 수 없었습니다. 결국 컨테이너에 독립 device-code 로그인을 줘서 자기 토큰을 갖게 했습니다.

로그도 믿을 수 없었습니다. 하루 종일 한 모델명을 찍고 있었지만, 실제로 호출된 모델은 설정에 적힌 다른 값이었습니다. 클라이언트 기본값이 하드코딩돼 있어서였습니다.


코드에서 고친 것 — 비었다와 해석 불가는 다릅니다

첫 번째는 「비었다」와 「해석 불가」를 가르는 것이었습니다. 파싱 실패는 전용 예외로 올립니다. 반면 빈 JSON 객체는 종전대로 정상 처리합니다.

표나 목차처럼 엔티티가 안 나오는 청크가 실제로 있습니다. 빈 결과까지 예외로 올리면 정상 문서를 끝없이 재시도하게 됩니다. 구분선은 「파싱 불가」 하나뿐입니다.

두 번째는 중단 조건입니다. 연속 20건이 실패하면 라운드를 중단하고 중단됨 상태를 돌려줍니다. 중단됐으면 후속 정제와 요약도 건너뜁니다. 같은 LLM 을 쓰는 단계라 돌려봐야 또 빈 결과입니다.

세 번째는 제출 방식입니다. 이전에는 전량을 먼저 제출하고 실패하면 취소하는 구조였습니다. 그런데 프로바이더가 즉시 실패를 뱉을 때 소요가 0.03초였습니다. 제출해 둔 작업이 취소되기 전에 전부 실패로 소진됐습니다.

그래서 동시성의 8배 크기 배치 단위로 나눠 제출하게 바꿨습니다. 처리량은 조금 깎이는 대신 중단이 실제로 듣습니다. 마지막으로 빈 요약은 저장하지 않습니다. 미작성 대상을 조회하는 쿼리도 빈 문자열을 대상으로 잡게 고쳤습니다.

청크 5,446개가 2분 만에 완주했는데, LLM 을 한 번도 부른 적이 없었습니다 그림 2


되돌리기의 대가 — 정상분 694개

잘못 찍힌 완료 표시를 되돌려야 했습니다. 당일 것만 골라내면 되는 일인데, 완료 표시에 시각이 없었습니다. `done = true` 하나뿐인 필드는 「어디까지가 오염인가」에 답하지 못했습니다.

차선책으로 해당 17개 사업에서 「완료인데 언급 관계가 0」인 노드 6,140개를 통째로 되돌렸습니다. 그중 694개는 원래부터 비어 있던 정상 청크였고, 다시 추출하는 데 약 50분이 들었습니다. 표시에 시각 하나만 있었으면 이 50분은 없었을 겁니다.

그래서 같은 날 완료 표시에 타임스탬프를 같이 남기게 바꿨습니다. 옛 노드는 값이 비어 있으면 이전 것으로 보면 되니 마이그레이션은 필요 없었습니다. 수습과 재발 방지를 같은 날 붙인 것이 이 사건에서 제일 잘한 일입니다.

청크 5,446개가 2분 만에 완주했는데, LLM 을 한 번도 부른 적이 없었습니다 그림 3


같은 모양이 한 번 더 — 재료가 0인 프롬프트

사건을 정리하는 사이에 같은 형태를 하나 더 찾았습니다. 상위 커뮤니티 요약은 하위 군집들의 요약을 재료로 만드는데, 하위 군집이 하나도 없는 상위 커뮤니티가 79개 중 37개였습니다. 재료가 빈 프롬프트가 그대로 LLM 에 갔습니다.

모델은 성실하게 답했습니다. 「정보 부족」, 「입력 항목 누락」 같은 문장이 돌아왔고, 그 문장이 그대로 요약 제목으로 저장됐습니다. 에러는 없었습니다. LLM 호출 37회가 낭비됐고, 그래프에는 의미 없는 노드 37개가 남았습니다.

고침은 프롬프트 앞에 게이트를 두는 것이었습니다. 요약 대상을 「살아남은 하위 군집의 부모」 집합으로 제한하면 재료가 없는 커뮤니티는 애초에 대상이 아닙니다.

기존 37개는 담고 있는 엔티티가 0인지 먼저 세고 지웠습니다. 엔티티 소속 관계 45,281건이 삭제 전후 동일했습니다.


점검 목록

성공 카운터가 아니라 산출물이 실제로 늘었는지, 그리고 정상 소요의 하한선보다 빠르지 않았는지 봅니다. 「실패 0」과 「너무 빠름」은 아무것도 안 했다는 신호일 수 있습니다.

게이트웨이·어댑터·프록시가 상류 오류를 200 으로 번역하지 않는지 확인합니다. 자기 소유라면 오류는 오류 형태로 내보냅니다.

파서는 「빈 값」과 「해석 불가」를 다른 경로로 보냅니다.

상태 플래그에는 시각을 같이 남깁니다. 사고가 났을 때 복구 범위를 자르는 재료가 됩니다.

빈 입력이 프롬프트에 닿기 전에 막습니다. 모델은 빈 입력에도 답하고, 그 답은 데이터로 저장됩니다.


7ms 짜리 완주와 10시간짜리 완주

파이프라인은 결국 완주했습니다. 청크 126,050개 중 미추출 0, 엔티티 122,210개, 관계 238,844개입니다. 추출 호출 6,001회에 총 10시간, 약 5,170만 토큰이 들었습니다. 7ms 짜리 완주와 10시간짜리 완주 사이에 이 글의 내용이 전부 있습니다.

돌아보면 이 작업은 「멈춘 것을 다시 돌린 일」보다 「조용히 실패하던 것을 찾아 고친 일」에 가깝습니다. 그리고 이 종류의 고장은 한 번으로 끝나지 않았습니다.

에러가 한 번도 안 났는데 실제로는 일이 안 되고 있던 사건이 뒤이어 더 있었습니다. 이 글은 그중 가장 그럴듯한 성공의 모습을 한 첫 번째입니다. 같은 모양의 사건 하나를 먼저 적어 둔 글이 있습니다.


연작 「에러 없이 조용히 틀린다」

이 글은 다섯 편 중 1편입니다. 에러가 한 번도 안 났는데 실제로는 일이 안 되고 있던 사례를 이어서 다룹니다.

#LLM파이프라인#조용한실패#게이트웨이#예외설계#타임스탬프#지식그래프#배치처리#구독인증