← 기술 블로그

3,800종 첨가물 번역: 수작업 100개에서 LLM 421개까지

Phase: 4 — 보강 시리즈: AI 협업 개발기 대응 스토리: 운영 블로그 15화

이 글의 배경이 되는 이야기는 15화: 감칠맛 조미료의 정체에서 읽을 수 있습니다.

이 글을 읽으면 알 수 있는 것


문제: “L-글루탐산나트륨”을 이해하는 사람

식약처 원재료 사전에는 약 3,800종의 첨가물이 등록되어 있습니다. 이 이름들은 대부분 화학 명칭입니다.

이 이름을 성분표에서 보고 “아, 이건 MSG구나”라고 바로 알 수 있는 사람은 많지 않습니다.

서비스의 목표는 “이 첨가물이 뭔지, 왜 들어가 있는지” 알려주는 것이었습니다. 두 가지 정보가 필요했습니다.

  1. 용도 분류: 감미료, 보존료, 유화제 등 (왜 들어가 있는지)
  2. 일상어 번역: “MSG (감칠맛 조미료)” 같은 쉬운 이름 (뭔지)

1단계: 수작업 번역 100건

3,800종 전부를 사람이 번역하는 것은 비현실적이었습니다. 하지만 전부 할 필요가 없었습니다.

첨가물의 출현 빈도는 극단적으로 편중되어 있습니다. 상위 100개 첨가물이 실제 제품 데이터의 약 85%를 커버합니다.

그래서 가장 많이 등장하는 첨가물부터 우선순위를 두었습니다.

수작업 번역에서 가장 신경 쓴 원칙이 있었습니다.

“공포가 아니라 이해.”

# 이렇게 쓰지 않습니다
"유해한 보존료"
"위험한 착색료"

# 이렇게 씁니다
"미생물 번식을 억제하여 보존 기간을 늘리는 보존료"
"식품에 색을 입히는 착색료"

첨가물이 좋은지 나쁜지는 이 서비스가 판단할 문제가 아닙니다. 식약처가 안전성을 평가해서 허가한 것이고, 서비스는 “이게 뭔지, 왜 들어가 있는지”만 알려줍니다.


2단계: LLM으로 나머지 확장

수작업 100건으로 85.3%를 커버했지만, 나머지 14.7%도 채워야 했습니다. 여기서 LLM(Gemini)을 도입했습니다.

입력 설계

LLM에게 제공하는 정보:

- 표준명: 폴리소르베이트80
  영문명: Polysorbate 80
  대분류: 식품첨가물(B)
  출현 빈도: 2,847회

표준명만 주면 LLM이 추측해야 할 부분이 많습니다. 영문명, 대분류, 출현 빈도까지 함께 제공하여 맥락을 풍부하게 했습니다.

출력 강제

LLM의 응답에 세 가지 강제 조건을 두었습니다.

  1. 용도 분류 Enum 강제: 식약처 공식 31개 분류 + 가공보조제, 이 목록에 없는 분류를 쓰면 거부
  2. 금지 표현 목록: “유해”, “위험”, “독성”, “암 유발”, “과다 섭취 시…” 등을 시스템 프롬프트에서 명시적으로 금지
  3. JSON 스키마 강제: 자유 텍스트가 아닌 구조화된 JSON으로 응답
[절대 금지]
- "유해", "위험", "독성", "암 유발" 등 공포 조장 표현
- "과다 섭취 시..." 등 부작용/경고성 멘트
- "화학적", "인위적인" 등 비하 표현

이 규칙이 없으면, LLM은 인터넷에서 학습한 “첨가물 = 나쁜 것” 편향을 반영할 가능성이 있습니다.

검증 파이프라인

LLM이 반환한 결과는 자동 검증을 거칩니다.

  1. 필수 필드 누락 확인 (plain_name, purpose_category, one_line_desc)
  2. purpose_category가 허용된 Enum 목록에 있는지 확인
  3. one_line_desc 길이 체크 (50자 초과 시 경고)
  4. 검증 통과한 건만 DB에 적재, is_verified=False로 표시

is_verified=False가 핵심입니다. LLM이 생성한 번역은 “초안”이며, 사람이 검수하기 전까지 사용자에게 노출되지 않습니다.


갈림길: 왜 전부 LLM으로 하지 않았는가

방법장점단점
전체 LLM 생성빠름검수 부담 큼, 톤 일관성 보장 어려움
전체 수작업품질 확실3,800종은 비현실적
수작업 기반 + LLM 확장핵심은 사람이, 롱테일은 AI가두 단계 관리 필요

수작업 100건은 단순히 번역 결과만이 아니라, LLM에게 “이런 톤과 수준으로 작성하라”는 참고 기준이기도 했습니다.


운영 구조

실제 적재는 두 단계로 나뉘어 있습니다.

  1. 시드 데이터 적재: 수작업 번역 + 가공보조제 94종 포함, source='manual', is_verified=True
  2. LLM 생성 적재: 미번역 B코드 첨가물 대상, source='llm', is_verified=False

LLM 호출에는 Rate Limit 대응(지수 백오프 재시도)과 API 키 없이도 JSON 파일에서 로드할 수 있는 우회 경로가 포함되어 있습니다.


결과

항목수치
전체 첨가물~3,800종
수작업 번역 (시드)~200건 (일반 + 가공보조제)
LLM 생성 번역~421건
합계~621건
실제 제품 커버리지~96.0%

3,800종 중 621건만 번역했는데 96%를 커버하는 이유는, 나머지 3,200종 대부분이 실제 제품에 거의 등장하지 않기 때문입니다.

한계

LLM 번역의 검수가 아직 완료되지 않았습니다. is_verified=False 상태의 번역이 남아 있습니다. 검수 완료 전까지는 사용자에게 노출되지 않습니다.

가공보조제의 번역은 사실상 불필요할 수 있습니다. 가공보조제는 최종 제품에 잔류하지 않는 성분입니다. 성분표에 거의 등장하지 않으므로 번역 우선순위가 낮지만, 완전성을 위해 포함했습니다.

한 줄 교훈

AI 번역의 핵심은 “빠르게 초안을 만드는 것”이 아니라 “틀린 것이 사용자에게 도달하지 않게 하는 것”입니다. is_verified=False라는 한 줄이 서비스 품질을 지킵니다.


다음 글: 식약처 고시가 바뀌면 코드도 바뀌어야 한다 — RSS 모니터링