Qwen에게 Qwen 기반 앱을 만들게 하고, 나는 리뷰어의 자리에 앉았다
요약
Qwen 모델을 활용하여 B2B 견적서 작성을 자동화하는 에이전트 'QuotePilot' 개발 사례를 소개합니다. 모델이 직접 계산이나 법률 작성을 하지 않도록 설계하여 정확성을 높이고, 인간의 검토 단계를 포함한 워크플로우를 구축했습니다.
핵심 포인트
- Qwen 모델을 활용한 6단계 자동화 파이프라인 구축
- LLM의 산술 연산 및 법률 작성 오류를 방지하기 위한 코드 기반 계산 방식 채택
- 인간의 최종 승인 단계를 포함한 Human-in-the-loop 에이전트 설계
- 매우 낮은 비용으로 고효율의 비즈니스 자동화 구현
대부분의 해커톤 게시물은 AI가 무엇을 _하는지(does)_에 대해 다룹니다. 이 글은 또한 누가 그것을 _썼는지(wrote)_에 대한 것이기도 합니다. QuotePilot — 국경 간 B2B 문의 이메일을 승인된 이중 언어(EN/中文) 견적서로 변환하는 오토파일럿(autopilot) — 은 런타임(runtime) 시 Qwen에 의해 구동됩니다. 하지만 앱 자체도 상당 부분 Qwen 모델들에 의해 작성되었으며, 저는 리뷰어의 자리에 앉아 각 조각을 수락하거나 거절하는 동안 작은 하네스(harness)를 통해 전달된 모델들을 지시했습니다. 전체 빌드에 소요된 총 모델 비용은 해커톤 크레딧 40달러 중 1달러 미만이었습니다.
그것이 실제로 어떤 느낌이었는지, 어디에서 마법 같았는지, 그리고 어디에서 양손으로 운전대를 꽉 잡고 있어야 했는지에 대해 말씀드리겠습니다.
- 라이브 데모: https://mark24680617.github.io/quotepilot/ (데모 로그인:
judge/ `qwen2026") - 리포지토리 (Repo): https://github.com/mark24680617/quotepilot
- 2분 데모 영상:
문제는 지루하고, 비용이 많이 들며, 에이전트(agent)에게 완벽하다
중국에 판매하는 미국의 한 소프트웨어 회사는 모든 문의 이메일에 수동으로 답변합니다. 요청 사항을 읽고(종종 중국어로 되어 있음), 가격을 조회하고, 대량 구매 할인을 적용하고, 오늘 환율로 USD⇄CNY를 변환하며, 올바른 국경 간 법률 및 세무 조항(HKIAC 중재, 중국어 텍스트 우선 원칙, "fapiao(발표) 발행 불가" 메모 등)이 포함된 이중 언어 견적서를 초안합니다. 문의 하나당 1~2시간이 소요되며, 잘못된 환율이나 누락된 세금 조항과 같은 실수는 매우 비용이 많이 드는 종류의 실수입니다.
이것은 실제 워크플로우(workflow)이며, 실제 브레이크 페달이 내장되어 있습니다. 즉, 견적서가 발송되기 전에 누군가가 항상 검토한다는 것입니다. 따라서 설계는 스스로 이루어졌습니다. 전체 과정을 1분 이내에 수행하고 정확히 한 번의 인간의 결정 단계에서 멈추는 에이전트(agent) 말입니다.
라우팅(Routing): 모델에는 언어를, 코드에는 장부를
QuotePilot은 접수(intake) → 실시간 외환(live FX) → 가격 책정(pricing) → 규칙 리스크(rule risk) → AI 리스크 스캔(AI risk sweep) → 이중 언어 초안 작성(bilingual drafting)의 6단계 파이프라인(pipeline)을 실행한 후, 인간의 게이트(gate)에서 멈춥니다. 세 개의 Qwen 모델이 작업을 분담합니다:
| 역할 | 모델 |
|---|---|
| Planner / 이중 언어 초안 작성 (bilingual drafting) | qwen-max |
| ... |
내가 그은 단 하나의 가장 중요한 선: LLM은 절대 산술 연산을 하지 않으며, 법률 용어를 직접 작성하지 않는다. 모든 가격은 Python의 Decimal을 사용하여 코드로 계산됩니다. 모든 법률 조항은 변호사가 작성한 듯한 고정된 이중 언어 텍스트입니다. 모델은 고객이 어떤 카탈로그 항목을 의도했는지 선택하고 따뜻한 커버 레터를 작성할 뿐입니다. 모델이 $150 imes $290 imes 0.92 = $40,020라고 결정하게 두지는 않습니다. 이것은 단순한 스타일의 선호 문제가 아닙니다. 데모(demo)와 실제로 계약에 사용할 수 있는 결과물 사이의 차이입니다.
# 모델은 "150석에 대한 CitizenReady를 원합니다" → SKU CR-ENT로 매핑합니다.
# 돈 계산은 항상 코드가 수행합니다.
net = (unit_price * qty * (100 - discount_pct) / 100).quantize(CENT, ROUND_HALF_UP)
Qwen이 코드를 작성하게 하기
나는 약 150줄 규모의 디스패처(dispatcher, scripts/qwen_dev.py)를 구축했습니다. 작업 사양(task spec)을 전달하면, 선택된 Qwen 모델로 사양을 보내고, 반환된 파일들을 스테이징 영역(staging area)으로 파싱하며, 토큰 사용량을 장부에 추가합니다. 내가 검토하기 전까지는 아무것도 리포지토리(repo)에 반영되지 않습니다. 빌드 과정 동안 Qwen은 FastAPI 백엔드, 승인 대시보드, 설정 UI, 실행 인덱스 등을 작성했습니다. 총 14번의 디스패치(dispatch)를 수행했으며, 총 비용은 0.81달러로 건당 몇 센트 수준이었습니다. 데모 영상의 나레이션조차 Qwen(qwen3-tts-flash)이 담당했습니다.
여기서 나타난 패턴은 다음과 같습니다: 인터페이스(interface)를 정확하게 기술하면, 코드 모델은 이를 매우 인상적으로 채워 넣습니다. 나의 작업 사양이 정확한 함수 시그니처(function signature), 엔드포인트 형태(endpoint shape), 데이터 모델(data model)을 고정했을 때, qwen3-coder-plus는 약간의 수정만 거치면 바로 사용할 수 있는 코드를 생성했습니다. 반면 내가 모호하게 지시했을 때는 그럴듯해 보이지만 계약 조건(contract)을 놓친 코드가 나왔습니다.
전쟁 이야기 (누구의 빌드도 깨끗하지 않다)
Alibaba Cloud의 fcapp.run 도메인은 HTML을 강제로 다운로드합니다. 저의 첫 배포는 curl로는 작동했지만, 브라우저에서는 페이지를 렌더링하는 대신 다운로드해 버렸습니다. 시스템 도메인이 Content-Disposition: attachment를 설정하고 3xx 리다이렉트(anti-phishing, 피싱 방지)를 금지하기 때문입니다. 이 문제를 해결하면서 아키텍처를 더 나은 방향으로 재설계했습니다. GitHub Pages에 정적 싱글 페이지 앱(SPA)을 올리고, Function Compute의 CORS가 활성화된 JSON API와 통신하도록 만들었습니다. fetch()는 다운로드 헤더를 신경 쓰지 않으며, 이제 심사위원들은 모든 요청이 Alibaba Cloud 백엔드로 명확하게 전달되는 깔끔한 HTTPS 페이지를 볼 수 있습니다.
custom.debian10은 Python 3.10이 아닌 Python 3.7을 제공합니다. 문서는 3.10을 약속했지만, 인스턴스 내부 조사 결과는 달랐습니다. 런타임을 custom.debian12(Python 3.11)로 전환하고, cp311 manylinux용 휠(wheels)을 다시 벤더링(re-vendoring)하여 콜드 스타트(cold starts) 문제를 해결했습니다.
코드 모델에게 70KB 크기의 파일을 다시 출력하라고 요구하지 마세요. 하나의 큰 프론트엔드 변경 사항을 위해 Qwen에게 업데이트된 index.html 전체를 반환하라고 요청했습니다. 하지만 결과물은 원래보다 23KB나 더 작았습니다. 모델이 설정 모듈 전체를 조용히 삭제해 버렸고, 제가 요청한 기능은 구현조차 하지 않았기 때문입니다. 교훈을 얻었습니다: 코드 모델에게는 파일 전체가 아니라 변경될 함수만 주고, 결과물을 디프(diff)로 비교해야 합니다. 결국 저는 그 기능을 직접 손으로 작성했습니다.
적대적 리뷰(adversarial review) 단계를 통해 11개의 실제 버그를 잡아냈습니다. 다중 기업 리팩토링(multi-company refactor)을 배포하기 전에, 작은 멀티 에이전트(multi-agent) 리뷰를 실행했습니다. 버그를 찾아내는 에이전트와 각 버그를 *반박(refute)*하려는 독립적인 검증 에이전트를 배치했습니다. 이를 통해 설정 저장 시마다 422 에러를 발생시켰을 할인 필드(discount-field) 이름 불일치 문제와, 자유 형식의 설정 필드에 존재하는 저장형 XSS(stored-XSS) 문제를 발견했습니다. 두 문제 모두 그대로 배포되었을 것입니다. 검증된 결과만 남겼고, 회의론자들이 노이즈를 제거했습니다.
데모를 촬영하다가 가장 결정적인 버그를 발견했습니다. 데모 영상은 프로그래밍 방식으로 녹화됩니다 (Playwright가 실제 앱을 구동하고, ffmpeg가 각 장면을 음성 해설에 맞춰 자릅니다). 편집 후 승인(edit-then-approve) 장면을 프레임 단위로 검토하던 중, 발행된 견적서 문서가 여전히 편집 전(pre-edit) 숫자를 보여주고 있다는 사실을 알아차렸습니다. 오케스트레이터(orchestrator)가 인간의 검토 단계(human gate) 이전에 보유하고 있던 견적 객체(quote object)를 렌더링하고 있었고, 그 사이 편집 엔드포인트(edit endpoint)는 검토 단계의 복사본을 교체해 버린 것입니다. 화면상에는 총액이 $32,550로 표시되었지만, 생성된 결과물(artifact)에는 $21,930로 적혀 있었습니다. 한 줄의 수정, 회귀 테스트(regression test), 재배포 — 그리고 새로운 규칙을 세웠습니다: 판사가 보는 것처럼 자신의 데모를 직접 감시하라.
인간의 검토 단계(human gate)가 곧 제품이다
QuotePilot을 완전히 자율적으로 만들고 일을 끝내버리는 것은 쉬운 일이었을 것입니다. 흥미로운 제품 결정은 그 반대였습니다. 바로 '일시 정지(pause)'를 훌륭하게 만드는 것이었습니다. 운영자는 초안이 작성된 견적서, 리스크 플래그(risk flags), 그리고 자연어 요약(plain-language summary)을 확인하고, 승인, 거절 또는 편집(approve, reject, or edit) — 수량, 가격, 할인 조정, 품목 추가 또는 삭제 — 을 할 수 있습니다. 운영자가 편집하면 서버는 Decimal 타입으로 가격을 재계산하고 문서를 다시 렌더링하며, 승인 시에는 운영자가 본 것과 정확히 일치하는 내용을 발행합니다. block 수준의 심각도를 가진 리스크 플래그가 있으면 승인 자체가 즉시 차단됩니다.
제동 장치가 있는 자율성. 계약서가 되는 문서에 있어서 이것이 승부처이며, 판사가 기억해주길 바라는 핵심 요소입니다.
"AI가 작성하고 인간이 검토한다"는 것이 실제로 느껴지는 방식
이 방식은 기계적인 폭넓은 작업(mechanical breadth) — CRUD 엔드포인트, 폼 UI, 배선(wiring), 명세에 따른 테스트(tests-to-spec) — 에 있어 진정으로 탁월하며, 빠르고 저렴합니다. 하지만 **금전적 계산(money math), 보안에 민감한 파싱(security-sensitive parsing), 또는 대용량 파일 수술(large-file surgery)**을 맡길 곳은 아닙니다. 바로 그런 지점이 자신감 있지만 틀린 출력값이 비용을 발생시키는 지점이기 때문입니다. 검토자의 역할은 형식적인 절차가 아닙니다. 어떤 출력을 즉시 신뢰할 수 있는지, 어떤 것을 한 줄씩 읽어야 하는지를 파악하는 것이며, 모델이 원장(ledger) 근처에 절대 접근하지 못하게 하는 것입니다.
Qwen이 QuotePilot의 대부분을 구축했습니다. 저는 Qwen이 절대 계산을 하지 못하도록 확실히 조치했습니다.
직접 사용해 보기: https://mark24680617.github.io/quotepilot/ (데모 로그인: judge / qwen2026) · 코드: https://github.com/mark24680617/quotepilot
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기