타히니는 참깨입니다: 작은 오픈 모델에게 숨겨진 알레르겐을 찾아내도록 가르치기
요약
BoldPrint는 레시피를 입력하면 EU/UK 및 미국 규정에 맞는 알레르겐 라벨을 자동으로 생성하는 도구입니다. 이 도구는 단순한 재료 목록 강조를 넘어, 영양 정보표와 Nutri-Score까지 계산하여 제공합니다. 특히 타히니처럼 이름만으로는 숨겨진 알레르겐(참깨)을 찾아내어 사용자에게 정확하게 경고하는 기능이 핵심입니다.
핵심 포인트
- 레시피 기반의 자동 알레르겐 라벨링 솔루션 제시
- 영양 정보표, Nutri-Score 등 규제 준수 요소 통합 제공
- 숨겨진 성분(예: 타히니=참깨)을 식별하는 고도화된 기능 구현
- 소규모 식품 판매자 및 시장 노점상에게 실질적 가치 제공
이것은 Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle에 제출하는 내용입니다.
내가 만든 것 (What I Built)
만약 당신이 파머스 마켓에서 바나나 브레드를 판매한다면, 법은 이미 당신의 스티커에 대한 의견을 가지고 있습니다.
EU와 영국에서는 14가지 주요 알레르겐(major allergens)을 재료 목록에 강조해야 하며, 보통 볼드체로 처리합니다. 미국에서는 9가지 주요 알레르겐에 대해 "Contains:" 라인이 필요합니다. 대형 브랜드들은 이를 위해 식품 기술자(food technologists)를 고용합니다. 토요일 아침에 베이킹하는 사람은 레시피 카드와 라벨 프린터, 그리고 페스토에 견과류가 들어있을지도 모른다는 신경질적인 느낌을 가지고 있습니다. (실제로 들어있습니다. 잣과 치즈도요.)
BoldPrint는 붙여넣은 레시피를 인쇄 가능한 알레르겐 라벨로 변환합니다. 이 도구는 어떤 언어로 된 레시피든 읽고, 각 재료가 무엇으로 만들어졌는지 계산하여 다음을 인쇄합니다:
재료: 강력분(gluten 함유), 따뜻한 물, 이스트, 올리브 오일, 타히니(sesame 함유), 바질 페스토(milk 및 nuts 함유), 바닷소금.
그리고 시장 베이커들이 손으로 하기 싫어하는 부분을 처리합니다: 레시피의 양을 기반으로 계산된 영양 정보표 (nutrition table) (EU/UK "Nutrition declaration", 미국 "Nutrition Facts" 또는 인도네시아 "Informasi Nilai Gizi"), EU 판매자를 위한 계산된 Nutri-Score, 그리고 규정에서 요구하는 대로 무게가 무거운 순서로 정렬된 재료 목록입니다. 하나의 라벨, 세 가지 토글 스위치로, PNG 또는 스티커 용지용 90mm PDF 파일로 저장할 수 있습니다.
가장 어려운 부분은 숨겨진 알레르겐입니다: 이름만으로는 무엇이 들어있는지 알 수 없는 재료들입니다. 타히니는 참깨(sesame)입니다. 기(Ghee)는 우유(milk)입니다. 우스터 소스에는 멸치(anchovies)가 들어있습니다. Pinoli는 이탈리아어로 잣(pine nuts)을 의미합니다. 비스코프(Biscoff)에는 밀과 콩이 포함되어 있습니다. 스니커즈 바는 땅콩, 우유, 콩, 달걀로 이루어져 있습니다.
누가 돈을 지불할까요: 가정 및 소규모 베이킹 업체, 시장 노점상 요리사, 그리고 작은 Etsy 식품 판매자들입니다. 라벨에 오류가 생기는 것은 리콜(recall), 벌금 또는 더 나쁜 경우 병원에 입원한 고객을 의미할 수 있습니다. "레시피를 붙여넣고, 스티커를 인쇄하면 타히니까지 잡아준다"는 기능은 현재 이 작업을 수동으로 하는 사람들에게 매우 매력적인 판매 포인트입니다.
데모
코드
GitHub logo derbyps / boldprint
BoldPrint
레시피를 붙여넣으면 식품 라벨을 얻습니다: 알레르겐은 굵게 표시되며, 영양 성분표와 Nutri-Score가 제공됩니다. PNG 또는 PDF로 저장할 수 있습니다.
DEV × Hacktoberfest 2026 오픈 소스 AI 챌린지, 2주차: _사이드 허슬(Side Hustle)_을 위해 제작되었습니다.
실시간 데모: boldprint.onrender.com (무료 서버는 유휴 상태일 때 잠들기 때문에 첫 번째 라벨은 최대 1분까지 걸릴 수 있습니다)

누가 사용하나요
홈 베이커, 시장 노점상 및 소규모 온라인 식품 판매자입니다. EU/UK 규정은 재료 목록에서 14가지 알레르겐을 강조하도록 요구하며, 미국은
단순히 사전만으로는 안 될까? 저 역시 처음에는 그런 생각을 했습니다. 그래서 직접 하나를 만들고 측정해 보았습니다. Open Food Facts의 성분 분류 체계는 환상적인 공개 데이터셋입니다. 수십 개의 언어로 된 수천 가지의 성분이 포함되어 있으며, 각 성분에 함유된 알레르겐과 연결되어 있습니다. 저는 이를 32,000개 항목으로 이루어진 어휘집(lexicon)으로 만들었습니다. 제가 직접 작성하고 라벨링한 32개의 실제 레시피에 대해, 이 어휘집만으로는 알레르겐의 11%를 놓쳤고, 32개 라벨 중 최소 하나라도 오류가 있는 것이 9개였습니다. 이 시스템은 "디종(Dijon)"이 머스터드라는 것을 모르고, 스니커즈 바에 땅콩과 계란이 있다는 것도 몰랐으며, 그린 커리 페이스트 속에 숨겨진 새우 페이스트를 놓쳤습니다. 또한 "tahinni"나 "worchestershire" 같은 오타도 시스템을 무너뜨렸습니다. 이 모든 누락 사례들은 위험한 종류의 오류입니다. 라벨은 완벽해 보였을 것입니다.
그 어휘집은 여전히 프로젝트에서 가장 가치 있는 부분입니다. 다만 이제는 제품 그 자체가 아니라, _교사(teacher)이자 안전망(safety net)_이 되었습니다.
1. 추론할 필요가 없는 신뢰할 수 있는 학습 데이터. 저는 10개 언어로 3,000개의 합성 레시피를 생성했습니다. 이 레시피들에는 지저분한 양의 표현, 글머리 기호, 오타, 제목, 조리 단계 등이 포함되어 있습니다. 모든 알레르겐 라벨은 다른 모델의 의견이 아니라, 어휘집과 수작업으로 선별된 재정의 목록(miso: [soy], worcestershire sauce: [fish], EU 규정에 따라 귀리가 글루텐으로 간주됨...`)을 통해 나옵니다. 전체 성분 중 20%는 학습에서 완전히 제외되어, 테스트 세트가 기억력보다는 일반화 능력을 측정하도록 했습니다.
2. Tinker를 사용한 지도 미세 조정(SFT). 저는 LoRA 어댑터를 사용하여 Qwen3-8B (Apache-2.0) 모델을 Tinker로 파인튜닝했습니다. 그 결과, 이 모델은 레시피당 각 성분과 해당 알레르겐이 포함된 하나의 엄격한 JSON 객체를 반환합니다.
3. 중요성을 아는 보상 기반의 강화학습(RL). 제가 가장 자랑스러워하는 부분이자 Tinker를 사용한 이유입니다. 알레르겐 라벨링에서 오류는 대칭적이지 않습니다. "견과류가 포함될 수 있음"이라는 추가 경고 문구 하나는 스티커에 단어 하나를 낭비하게 만들지만, 하나의 누락은 누군가에게 에피펜(EpiPen)을 필요로 할 수도 있는 상황이 될 수 있습니다. 따라서 보상 구조는 다음과 같습니다:
-10 (모델이 놓친 알레르겐당)
-1 (추가로 표시한 알레르겐당)
-10 (실제 알레르겐, 그리고 출력이 유효한 JSON이 아닐 경우 추가 -5점)
...
Tinker는 트레이닝 루프 자체(샘플링, 자체 Python으로 점수 계산, forward_backward, optim_step)를 제공하므로, 도메인 특화 보상 설계가 연구 프로젝트 전체가 아닌 약 40줄로 줄어듭니다. 20회 이상의 RL 단계를 거치면서, 트레이닝 배치당 라벨에서 놓치는 알레르겐은 약 0.05에서 0.02 미만으로 떨어졌고, 평균 보상은 대략 세 배(0.22 → 0.66) 증가했습니다.
4. 결과.
제가 직접 작성하고 라벨링한 32개의 실제 레시피(브랜드명, 오타, 여러 언어 포함)에 대해:
| 놓치는 알레르겐 ↓ | 누락된 라벨 수 ↓ | |
|---|---|---|
| Qwen3-8B (미훈련) | 74.0% | 25 / 32 |
| ... |
보유(held-out) 합성 레시피 300개에 대해 미세 조정된 모델은 알레르겐의 1.6%를 놓치는 반면, 미훈련 모델은 29.8%를 놓칩니다. 전체 표는 eval/out/table.md에 있으며, python eval/benchmark.py를 실행하면 저장된 출력에서
실험실 없이 영양 정보 분석 및 라벨링 시스템 구현
6. 실험실 없는 영양 분석. 모델의 재료 목록은 영양 성분표의 근간이 됩니다. 각 레시피 줄은 그램(컵, "2 EL", "1 c. à soupe", "레몬 즙 1개 분량", "캔 1개")으로 변환되며, 프랑스 식품 기관인 CALNUT의 공개 영양 성분표와 약 130개의 수작업 매핑된 주요 식재료 및 Open Food Facts 분류 체계(taxonomy) 링크를 통해 연결됩니다. 이후 합산되어 최종 무게로 나뉩니다. 이 규칙들은 의도적으로 지루합니다: EU 및 미국 반올림표, 2023년 Nutri-Score 알고리즘, 그리고 "성분 데이터를 기반으로 계산되었으며, 실험실 분석 결과가 아님"이라고 명시하는 라벨 문구입니다. 앱이 추측해야 하는 모든 것(페스토 한 컵, "병아리콩 캔", 매칭할 수 없는 성분)은 영양 확인 패널에 표시되며, 사용자는 그램을 직접 입력하거나 다른 식품을 선택하여 모델 호출 없이 라벨을 다시 그릴 수 있습니다.
7. 라벨은 웹 페이지가 아닌 이미지입니다. 미리보기(preview), PNG 및 PDF는 동일한 작은 캔버스 렌더러로 그려지기 때문에 보이는 것이 곧 인쇄되는 것입니다. HTML 스크린샷이나 로드할 PDF 라이브러리가 필요하지 않습니다: 이 PDF는 하나의 JPEG를 감싸고 있는 약 40줄의 JavaScript로 구성되어 있습니다.
스택: Qwen3-8B · Tinker (LoRA SFT + RL, OpenAI 호환 추론) · Open Food Facts 분류 체계 · CALNUT (ANSES) · FastAPI · canvas · Render (무료 웹 서비스) · 250개 이상의 pytest 테스트 및 Playwright 검사.
총 학습 비용: 평가 실행을 포함하여 Tinker 크레딧 약 $2.30
오픈 혁신이 중요한 이유
이 프로젝트에만 국한된 세 가지 이유가 있습니다:
- 신뢰할 수 있는 라벨링을 가능하게 한 오픈 데이터. 훈련 라벨은 자원봉사자들이 관리하는 Open Food Facts에서 가져왔으며, 다국어 지원이 되고 라이선스가 부여되어 제가 이를 기반으로 구축할 수 있었습니다. 폐쇄형 모델(closed model)만 사용했다면 저는 또 다른 AI의 추측을 다른 AI의 추측으로 평가했을 것입니다.
- 오픈 가중치(open weights)는 모델이 무엇에 집중해야 하는지 바꿀 수 있게 해줍니다. 폐쇄형 API를 사용하면 "주의하라"고 프롬프트할 수는 있지만, 놓친 알레르겐에 -10점을 부여하고 이를 기준으로 훈련시키는 것은 불가능합니다. Qwen3-8B와 Tinker를 사용하여 저는 어댑터(adapter)를 소유했고, 보상(reward)을 선택했으며, 필요하다면 가중치를 다운로드하여 다른 곳에서 실행할 수 있습니다.
- 비즈니스 모델은 작고 저렴해야 합니다. 부업(side hustle)이 높은 라벨당 API 비용을 감당하기는 어렵습니다. 특정 작업에 특화된 8B 모델은 1,000개 라벨당 약 $0.12의 비용이 들기 때문에, 제빵사에게 한 달에 몇 달러를 청구하고도 여전히 수익을 낼 여지가 생깁니다.
수상 부문 (Prize Categories)
- Tinker 활용 최우수: 사용자 정의 비대칭 안전 보상(custom asymmetric safety reward)을 사용한 SFT 후 RL; 상기 기준선 비교 참고.
- Render 활용 최우수: 라이브 데모는 Render 무료 웹 서비스에서 실행됩니다 (FastAPI,
main으로부터 자동 배포,/healthz상태 확인, 환경 변수를 통한 지출 한도 설정).
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기