무색
기술블로그
에세이
연구
소개

무색

소프트웨어로 비즈니스의 가능성을 만듭니다. 웹·앱 개발, 음성 AI, 자동화 콘텐츠 제작까지 — 기술이 필요한 곳에 무색이 있습니다.

연락처

contact@museck.com

사업자 정보

상호: 무색

대표: 배성재

사업자등록번호: 577-58-00836

인천광역시 연수구 인천타워대로 323, 에이동 8층 801-802호 AB-132 (송도동, 송도 센트로드)

© 2026 무색. All rights reserved.
개인정보처리방침·이용약관·연락처
INCHEON, KR
병렬 용어 추출과 stream-json 파싱 — stipple 키 비주얼
논문 번역기
2026. 2. 13.

번역 파이프라인 병렬화: asyncio.gather()와 Claude Code stream-json 파싱 수정

asyncioclaude-codepythonperformance

논문 번역 파이프라인이 잘 돌아가고 있었다. 용어 추출하고, 레이아웃 분석하고, 번역하고. 그런데 '잘 돌아간다'와 '빠르게 돌아간다'는 다른 문제다. 순차적으로 실행되던 두 단계를 병렬로 바꾸고, Claude Code headless 모드의 stream-json 파싱이 깨지는 문제를 수정한 이야기다.

문제: 순차 실행이라는 보이지 않는 병목

번역 파이프라인에서 용어(glossary) 추출과 BabelDOC 레이아웃 분석은 완전히 독립적인 작업이다. 용어 추출은 Claude Code headless로 PDF에서 전문 용어를 뽑아내고, 레이아웃 분석은 BabelDOC이 PDF의 구조를 파악한다. 서로의 결과를 참조하지 않는다.

그런데 이 두 작업이 순차 실행되고 있었다. 용어 추출이 끝나야 레이아웃 분석이 시작됐다. PDF 하나에 용어 추출 30초, 레이아웃 분석 20초라면 총 50초. 병렬로 돌리면 30초면 끝나는 일이다.

해결: asyncio.gather()로 병렬화

Python의 asyncio.gather()를 쓰면 독립적인 비동기 작업을 간단하게 병렬로 실행할 수 있다.

코드 변경은 3줄이다. 하지만 체감 속도 차이는 크다. 두 작업 중 더 오래 걸리는 쪽의 시간만 기다리면 되니까, 실질적으로 한 단계가 공짜가 된 셈이다.

두 번째 문제: Claude Code stream-json 파싱 실패

용어 추출은 Claude Code를 headless 모드로 돌려서 처리한다. 이때 --output-format stream-json 옵션으로 진행률을 실시간 추적하는데, 어느 날부터 파싱이 깨지기 시작했다.

원인은 Claude Code의 stream-json 출력 형식 변경이었다. 기존에는 stream_event 키로 이벤트를 구분했는데, 업데이트 이후 type 필드에 assistant와 result로 구분하는 방식으로 바뀌었다.

작업 로그 추적 기능 추가

stream-json 파싱을 고치면서 작업 로그(task logs) 추적 기능도 함께 넣었다. headless 실행 중 stdout에서 단계별 진행 기록을 남기도록 했다. 이전에는 Claude Code가 뭘 하고 있는지 끝날 때까지 알 수 없었는데, 이제는 '용어 추출 중... 15/30 용어 발견' 같은 로그가 실시간으로 찍힌다.

소소한 삽질들

vLLM의 --no-sync 함정

vLLM을 uv run --no-sync vllm serve로 시작하고 있었다. --no-sync는 실행 전에 패키지를 동기화하지 않는 옵션인데, vLLM 패키지가 업데이트되면 wheel 파일이 404로 날아간다. 결국 --no-sync를 제거하고 매번 동기화하도록 바꿨다. 실행 속도보다 안정성이 중요한 경우다.

용어 추출 전용 모드

번역 없이 용어만 뽑고 싶을 때가 있다. 새 논문의 전문 용어를 미리 확인하거나, 용어 사전을 관리할 때 쓴다. translate-paper 에이전트에 '용어 추출 전용 모드'를 추가해서 번역 단계를 건너뛸 수 있게 했다.

교훈

  • 독립적인 작업은 병렬화 가능성을 항상 의심하자. 순차 실행이 디폴트인 코드에서 병렬화 포인트를 찾는 건 성능 개선의 가장 쉬운 방법이다.
  • 외부 프로세스의 출력 형식은 변한다. Claude Code 같은 CLI 도구의 출력 포맷은 버전마다 바뀔 수 있다. 방어적 파싱과 에러 핸들링이 필수다.
  • 진행률 로그는 디버깅의 생명선이다. 장시간 실행되는 작업에서 중간 상태를 모르면 디버깅이 불가능하다. 투자 대비 효과가 가장 좋은 기능이다.

마무리

'작동하는 것'에서 '빠르게 작동하는 것'으로 넘어가는 과정은 대부분 이런 식이다. 거창한 아키텍처 변경이 아니라, 순차 실행을 병렬로 바꾸고, 깨진 파싱을 고치고, 로그를 추가하는 작은 변경의 누적이다. 3줄 바꿔서 20초를 아꼈다. 논문 100편 번역하면 33분이다.

자주 묻는 질문

asyncio.gather()로 병렬화하면 얼마나 빨라지나요?
독립적인 두 작업(용어 추출 30초, 레이아웃 분석 20초)을 병렬 실행하면 총 30초만 걸립니다. 더 오래 걸리는 작업의 시간만 기다리면 되기 때문입니다.
Claude Code headless 모드의 stream-json 출력이 바뀌면 어떻게 대응하나요?
이벤트 타입 필드를 방어적으로 파싱하고, 알 수 없는 타입은 무시하는 방식으로 처리합니다. 버전 업데이트에 따른 출력 형식 변경에 대비해야 합니다.
용어 추출 전용 모드는 언제 사용하나요?
번역 없이 새 논문의 전문 용어만 미리 확인하거나 용어 사전을 관리할 때 사용합니다. 번역 단계를 건너뛰어 시간을 절약할 수 있습니다.
논문 번역기(8/8)
Prev

vLLM이 두 번 뜨는 날: nvidia-smi에서 GPU API로