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

무색

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

연락처

contact@museck.com

사업자 정보

상호: 무색

대표: 배성재

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

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

© 2026 무색. All rights reserved.
개인정보처리방침·이용약관·연락처
INCHEON, KR
BabelDOC 커스텀 번역 모델 — 모듈 파이프라인
논문 번역기
2026. 1. 9.

BabelDOC에 내 번역 모델 끼워넣기 (fork 없이)

BabelDOCvLLMeditable-installStrategy-patternPDF-translation

영어 논문을 읽는 건 꽤 고된 일이다. 특히 30페이지짜리 논문을 한 편 읽고 나면 머리가 지끈거린다. 그래서 "PDF 번역기를 직접 만들자"는 생각에 이르렀고, BabelDOC이라는 오픈소스 도구를 발견했다. 문제는 BabelDOC이 기본으로 지원하는 번역 모델이 OpenAI API뿐이라는 점. 로컬 GPU에 올려둔 내 모델을 쓰고 싶었다.

BabelDOC을 fork해서 수정할까 잠깐 고민했지만, 업스트림 업데이트를 따라가기가 번거로울 게 뻔했다. 대신 editable install이라는 방법을 택했다. 그리고 BabelDOC 내부의 Strategy 패턴 덕분에 생각보다 깔끔하게 커스텀 모델을 붙일 수 있었다.

Editable Install로 오픈소스 끼워넣기

오픈소스 라이브러리를 수정해야 할 때 보통 세 가지 선택지가 있다.

  1. Fork: 내 저장소로 복사해서 수정. 업스트림 따라가기가 고통.
  2. Wrapper: 라이브러리 위에 래퍼를 씌움. 내부 구조에 접근이 안 될 수 있음.
  3. Editable Install: 소스를 클론한 뒤 pip install -e .로 설치. 소스를 직접 고치면 바로 반영된다.

BabelDOC은 내부에 babeldoc/translator/ 디렉토리가 있고, 여기에 Translator 클래스 파일을 추가하면 된다. editable install 상태에서 이 디렉토리에 파일을 넣으면 BabelDOC이 바로 인식한다. fork처럼 전체 코드를 관리할 필요가 없다는 게 큰 장점이다.

BaseTranslator 상속으로 커스텀 모델 구현

BabelDOC은 BaseTranslator라는 추상 클래스를 제공한다. 이걸 상속받아 do_translate와 do_llm_translate 두 메서드를 구현하면 끝. 전형적인 Strategy 패턴이다.

나는 두 가지 Translator를 만들었다.

  • RosettaTranslator (야놀자 Rosetta 4B): 번역만 하는 전용 모델. 용어 추출 같은 LLM 기능이 없다.
  • GLMTranslator (GLM 범용 LLM): 번역도 하고 용어 자동 추출도 가능한 범용 모델.

Rosetta는 번역 전용이라 do_llm_translate를 NotImplementedError로 막아뒀다. 구현 자체는 단순하다.

# rosetta.py - 번역 전용 모델
class RosettaTranslator(BaseTranslator):
    name = "Rosetta"
    def do_translate(self, text, ...):
        # Rosetta 전용 입출력 형식 처리
        ...
    def do_llm_translate(self, ...):
        raise NotImplementedError  # 번역 전용이므로 LLM 기능 없음

각 모델에는 별도의 CLI 스크립트를 만들었다. 모델마다 기본 설정이 다르기 때문이다. 예를 들어 Rosetta는 용어 자동 추출을 꺼야 하고, GLM은 켜둬야 한다.

# yanolja_translate_pdf.py - Rosetta용 CLI
config = TranslationConfig(
    translator=translator,
    auto_extract_glossary=False,   # 번역 전용 모델
    watermark_output_mode=WatermarkOutputMode.NoWatermark,
)

모델 비교를 위한 파일명 태깅

번역 모델이 두 개가 되니 출력 파일을 구분할 방법이 필요해졌다. BabelDOC의 기본 출력 파일명은 paper.ko.mono.pdf 형식인데, 여기에 모델 이름을 끼워넣어 paper.Rosetta-4B.ko.mono.pdf처럼 만들었다.

def rename_with_model(pdf_path):
    parts = p.name.split(".")
    if len(parts) >= 4:
        parts.insert(-3, model_tag)
    new_path = p.parent / ".".join(parts)
    p.rename(new_path)

단순해 보이지만 파일명에 점이 여러 개인 경우(예: attention.is.all.you.need.ko.mono.pdf) 삽입 위치를 잘못 잡아서 한참 헤맸다. 뒤에서 세 번째 점 앞에 넣어야 하는데, split 결과의 인덱스를 잘 계산해야 한다.

삽질 기록: 번역 전용 모델의 함정

가장 큰 삽질은 번역 전용 모델과 범용 LLM의 차이를 간과한 것이었다. BabelDOC에는 auto_extract_glossary라는 옵션이 있는데, 이걸 켜면 번역 전에 용어를 자동 추출한다. 당연히 LLM 기능이 필요한 작업이다.

Rosetta에 이 옵션을 True로 설정했더니 용어 추출 단계에서 NotImplementedError가 터졌다. 번역 전용 모델이니까 do_llm_translate를 구현하지 않았는데, 용어 추출이 바로 그 메서드를 호출한 것이다. 교훈은 간단하다. 모델의 능력 범위에 맞춰 설정을 분리해야 한다는 것.

또 하나 주의할 점. editable install로 BabelDOC 내부에 파일을 추가하면 git pull로 업데이트할 때 충돌이 생길 수 있다. 나는 커스텀 파일을 별도 git 리포로 관리하고 심볼릭 링크를 거는 방식으로 해결했다. 업스트림 코드와 내 코드가 섞이지 않게 분리하는 게 핵심이다.

정리: fork 대신 editable install을 선택한 이유

오픈소스에 기능을 추가할 때 fork는 가장 자유도가 높지만 유지보수 비용도 크다. editable install은 제약이 있지만 (내부 확장 포인트가 있어야 함) 업스트림과의 동기화가 훨씬 쉽다. BabelDOC의 경우 BaseTranslator라는 명확한 확장 포인트가 있어서 editable install이 맞는 선택이었다.

지금은 Rosetta와 GLM 두 모델로 같은 논문을 번역해서 결과를 비교하고 있다. 다음 글에서는 이 번역 품질을 더 끌어올리기 위해 동시성 튜닝과 재시도 전략을 만든 이야기를 쓸 예정이다.

자주 묻는 질문

BabelDOC에 커스텀 번역 모델을 추가하는 방법은?
BaseTranslator를 상속받아 do_translate와 do_llm_translate 메서드를 구현하면 된다. editable install 상태에서 translator 디렉토리에 파일을 추가하면 fork 없이 커스텀 모델을 붙일 수 있다.
editable install이 fork보다 나은 점은?
업스트림 업데이트를 git pull로 바로 반영할 수 있다. fork는 전체 코드를 관리해야 하지만 editable install은 확장 포인트에 파일만 추가하면 되므로 유지보수 비용이 낮다.
번역 전용 모델과 범용 LLM의 차이는?
번역 전용 모델(Rosetta)은 번역만 하고 용어 자동 추출 같은 LLM 기능은 없다. 범용 LLM(GLM)은 번역과 용어 추출을 모두 처리할 수 있다. 모델 능력 범위에 맞춰 auto_extract_glossary 설정을 분리해야 한다.
논문 번역기(1/8)
Next

100페이지 논문 번역이 40분 걸릴 때: LLM 동시성과 재시도 전략