Claude 활용 AI 멀티에이전트로 축산물 배차 TMS 만들기 — 100대 차량·200건 오더가 카카오 지도 위 실제 도로를 달린다

소개

저는 축산물 운송 플랫폼 구축중입니다.

배차 프로그램은 시장에 많지만, 일반 화물용 TMS는 우리 도메인에 잘 안 맞아요. 축산물 운송은 다음과 같은 법적·생물학적 제약을 동시에 만족해야 합니다.

  • 축산법 제17조의3 — 가축운반차량 GPS 의무장착 (미장착 과태료 300만원)

  • 가축전염병 예방법 제19조 — ASF/구제역/AI 발생지 반경 10km 이동 제한

  • 축산물 위생관리법 — 냉장 0~4℃, 냉동 -18℃ 이하 유지

  • 동물보호법 제11조 — 생체 운송 시 연속 운행 시간 제한

  • 화물자동차 운수사업법 표준운임 — 표준운임 + 부가세 전자발행

기존 TMS는 위 제약 중 어느 것도 자동 반영을 못 하니, "오더 검증 → 차량 매칭 → 라우팅 → 운임 산출 → 모니터링"을 각각 도메인 지식을 가진 멀티에이전트로 분리해서 만들어보자는 게 출발점이었습니다.

목표는 거창했지만 저는 코딩이 능숙하지 않습니다. 그래서 Claude Code에 자연어로 요청하면서 처음부터 끝까지 만들어 봤고, 그 과정을 공유합니다.


진행 방법

사용한 도구

도구

용도

Claude Code (Opus 4.7)

메인 — 자연어로 코드·디버깅·문서화

카카오 디벨로퍼스

지도 SDK + 모빌리티 길찾기 API (실거리·도로 vertex)

Streamlit

운영 대시보드 UI

Google OR-Tools

멀티디포 CVRP 라우팅 솔버

Python 3.12 (python-embed)

런타임

핵심 프롬프트와 진행 흐름

1) 시작 — "배차 프로그램 가동할수 있어?"

세션을 이 한 줄로 시작했습니다. Claude가 프로젝트 구조를 읽고 시드 데이터로 한 번 돌려본 다음, 가장 먼저 만난 문제가 시드 차량 12대의 소독필증이 모두 만료돼서 "차량 0대"로 OR-Tools가 죽는 상황이었어요. 코드가 아니라 데이터 문제를 짚어주는 게 인상적이었습니다.

2) 스케일 업 — "100대 가상데이터 가동하여 설계 해줘. 그리고 대시보드로 실제로 카카오 모빌리티에서 구현하도록 해줘"

이 한 줄에 Claude가 작업을 분해했습니다.

  • 결정적 난수 기반 시드 생성기 (data/generate_seed.py) — 차량 100대 + 오더 200건, 한국 축산 거점(농장/LPC/공판장/마트) 좌표 hotspot으로 분포 생성

  • 카카오 지도 SDK + 폴리라인 + 범례 + 마커 + InfoWindow

  • 키 없을 때 자동 폴백(Folium/OSM)

# 차량 시드 생성 — 5% 의도적 자격미달(필터 검증용)
is_noncompliant = rng.random() < 0.05
if is_noncompliant:
    disinfect_until = future_date(rng, today, -180, -30)  # 만료
    gps = False
else:
    disinfect_until = future_date(rng, today, 30, 540)
    gps = True

3) "실제로 차량경로는 직선이 아니고 실제도로 주행하는 것인데 지도상에 나타난 것은 그렇지 않아"

가장 중요한 한마디였습니다. 처음에는 단순히 두 좌표를 직선으로 잇고 있었는데, 이걸 보고 카카오 모빌리티 길찾기 API를 통합했어요. 그리고 Claude가 한발 더 나갔습니다 — "시각화만의 문제가 아니라 거리·시간·운임 계산 전부 직선 기준이라 잘못 나와있다"고 짚어주면서 2-pass 구조로 재설계.

# 좌표 4자리 반올림(±11m)으로 캐시 키 → 같은 OD는 1회만 호출
def _cache_key(o_lat, o_lng, d_lat, d_lng):
    return f"{_round(o_lat)},{_round(o_lng)}->{_round(d_lat)},{_round(d_lng)}"

# ThreadPoolExecutor로 8 워커 병렬 + 진행률 콜백
def build_matrix(pairs, max_workers=8, progress_cb=None):
    ...

결과: 실제 도로 거리가 직선 거리의 1.16~1.32배. 운임이 그만큼 저평가되고 있었던 거예요.

4) "순차적으로 만들어 줘"

남은 작업을 한 번에 처리. 도중에 "미배차는 용차 차량을 더 투입해서 처리하면 시나리오 추가"라는 도메인 요구사항을 던졌고, Claude가 SPOT-001~108 가상 용차를 자동 투입하는 시나리오를 즉시 구현했습니다.

# 미배차 오더에 가상 용차(SPOT) 일대일 배정 — 단가 +20% 할증
spot_vehicle = {
    "vehicle_id": f"SPOT-{i:03d}",
    "carrier_name": "외주 (용차)",
    "current_lat": order["shipper_lat"],  # 픽업 지점 현장 배차 가정
    "is_spot": True,
}
subtotal = int(cost["subtotal"] * (1 + surcharge))  # +20%

OR-Tools도 멀티디포 CVRP + 픽업-배송 페어 + 8시간 운행 제약 + 미배차 페널티로 정상화했고, 차량당 8시간 초과 0건으로 들어왔습니다.

캡처

[직접 첨부 — 다음 캡처를 추천]

  • 한반도 지도에 차량별 컬러 폴리라인이 도로를 따라가는 모습

  • 운임 분석 차트 (자가 vs 용차)

  • 카카오 모빌리티 적용 전/후 비교 (직선 → 도로 형태)


결과와 배운 점

최종 결과

지표

차량 시드

100대 (92대 적격 + 8대 의도적 자격미달)

오더 시드

200건 (돼지 118 / 한우 46 / 육계 36)

OR-Tools 라우팅

자가 52대 배정 / 8시간 초과 0건

용차 자동 투입

SPOT-001~107로 미배차 잔여 처리

미배차

0건 (목표 달성)

운임 (자가 + 용차 +20%)

약 2.46억원

카카오 모빌리티 API 호출

OD 약 350쌍 (캐시 적중 시 0건)

시행착오 (이게 가장 도움될 부분)

  1. Python 환경 segfault.venv가 손상된 시스템 Python을 가리켜 모든 명령이 죽었어요. Claude가 다른 정상 Python(python-embed)을 찾아 우회. 코드가 아닌 환경 문제를 의심하는 습관이 중요.

  2. Streamlit이 카카오 SDK를 차단st.components.v1.html이 만드는 srcdoc iframe은 외부 스크립트를 못 받아옵니다. 새 탭에서 SDK URL을 열면 정상 JS가 오는데 iframe 안에서만 안 됐어요. 해결: enableStaticServing=true + ui/static/ 폴더에 HTML 파일로 떨어뜨려 /app/static/ 경로로 일반 iframe.

  3. 카카오 도메인 등록 누락domain mismatched! caller=http://localhost:8501. 콘솔에서 앱 설정 → 플랫폼 키 → JavaScript SDK 도메인http://localhost:8501 정확히 등록(슬래시 끝 X, https 아님)하고 저장 버튼까지 눌러야 적용. 입력만 하고 저장 안 한 게 문제였어요.

  4. 직선 거리로 운임 계산 — 화면에 직선이 보여서 그제야 "이거 운임도 잘못 계산되는 거 아닌가?" 깨달았습니다. 실거리는 1.21.3배라서 운임이 2030% 저평가됨. AI에게 결과를 의심하는 질문을 던지는 게 큰 개선으로 이어졌습니다.

꿀팁 5가지

  1. 에러 메시지에서 멈추지 말고 서버 응답을 직접 확인하세요. curl로 카카오 SDK에 Referer: http://localhost:8501 헤더 붙여 보내면 401과 domain mismatched 메시지가 바로 나옵니다. Claude가 이렇게 디버깅하는 걸 보고 배웠어요.

  2. "이거 잘못된 거 아닌가요?" 같은 질문이 가장 큰 개선을 만듭니다. AI가 만든 결과를 의심하는 한마디가 코드 한 줄 짜는 것보다 임팩트 큽니다.

  3. 시드 데이터를 결정적 난수로 만드세요. random.seed(20260524) 한 줄 추가하면 매번 똑같은 데이터가 나와 검증·재현·시연이 쉬워집니다.

  4. API 캐싱은 좌표 반올림 + 영구 캐시로. 좌표 소수 4자리(±11m)면 같은 곳으로 취급, JSON 파일에 누적 저장하면 두 번째 실행부터 0 API 호출.

  5. 도메인 전문가의 한마디가 코드 100줄보다 가치 있습니다. "용차 시나리오 추가"라는 한 줄 요구사항이 미배차 113건을 0건으로 바꿨어요. AI에게 도메인 지식을 자연어로 던지는 게 최고의 프롬프트입니다.

도움이 필요한 부분

  • OR-Tools 튜닝: 자가 차량 92대 중 52대만 사용되고 40대가 유휴 상태입니다. 시드의 지리적 편향(충남·전남 집중) 때문인데, 더 효율적인 분배 알고리즘을 아시는 분 조언 환영합니다.

  • 실시간 GPS 연동: 지금은 시뮬레이션 슬라이더로 추적합니다. 실제 GPS 디바이스 → MQTT/WebSocket 스트림을 어떻게 가장 가볍게 받을지 고민 중입니다.

  • 카카오 모빌리티 무료 한도(일 50K) 이후 비용 구조 — 실제 운영 단계에서는 OD 매트릭스를 자체 PostGIS + OSRM으로 가져가야 할지 검토 중입니다.

앞으로의 계획

  1. KAHIS Open API 연동 — 지금은 수동 입력인 방역대를 실시간으로 가져오기

  2. mtrace.go.kr 축산물이력제 API — 오더 입력 시 이력번호 자동 검증

  3. 국세청 e세로 — 운임 확정 후 전자세금계산서 자동 발행

  4. MCP 서버화 — 각 외부 API를 MCP로 래핑해서 Claude Agent SDK로 본격 전환


도움 받은 글

한국사이트 스크린샷

숫자 목록이 포함된 한국어 앱 스크린샷

한국음악의 인기를 보여주는 그래프

한국 증권 거래소의 스크린샷
검은 화면에 표시된 한국어 앱 스크린샷

다양한 위치가 있는 한국 지도

1
밀어주고 끌어주는

온·오프라인 AI 스터디

AI로 어디까지 할 수 있는지
직접 확인하실 분만 신청하세요.