Skip to main content

DVRP 배차 최적화 엔진의 기술 구조 , 제약 기반 경로 계산과 AI 보정

배차 최적화는 말로 하면 단순하다. "트럭에 화물을 싣고 가장 효율적인 경로로 배송한다." 하지만 실제로 구현하면 조합 폭발이 일어나는 NP-hard 문제다. 50건의 배송을 8대의 트럭에 배정하는 경우의 수는 8의 50승에 가깝다. 모든 경우를 탐색해서 최적해를 찾는 건 현재의 컴퓨팅 파워로도 불가능하다. DVRP(Dynamic Vehicle Routing Problem)는 이 문제를 실시간으로, 현실의 제약 조건 하에서 풀어야 한다.

이 글은 REINDEERS DVRP의 경로 최적화 엔진이 어떤 구조로 설계되었는지, 어떤 제약 조건을 어떻게 처리하는지, 그리고 AI가 이 과정에서 어떤 역할을 하는지에 대한 기술적인 이야기다. 동시에, DVRP가 왜 단순한 최적화 엔진이 아니라 조직도에 등록될 "물류 Agent"의 심장이 되는지에 대한 이야기이기도 하다.

조금 더 정확히 말하면 이렇다. REINDEERS와 POP, DVRP는 지금 AI로 전환되는 구조 위에 올라서 있다. 사람은 "오늘 배송 방침"을 결정한다 , 비용 우선인지, 정시 배송 우선인지, 특정 고객 우선인지. 실제 배차와 재배차, 지연 대응, 운전자 지시는 조직도 안에 등록된 물류 Agent가 수행한다. DVRP 엔진은 이 물류 Agent의 "손과 발"에 해당한다. 제약 기반 계산이 Agent의 실행 엔진이고, 그 위에 AI 레이어가 "왜 이 결정인가"를 언어로 설명하는 층이다.

VRP: 문제 정의

Vehicle Routing Problem(VRP)은 운영 연구(Operations Research)의 고전적인 문제다. 1959년 Dantzig와 Ramser가 처음 공식화한 이후로 60년 넘게 연구되었고, 아직도 완벽한 해법은 없다. NP-hard 문제이기 때문에 최적해를 보장하는 다항 시간 알고리즘이 존재하지 않는다.

기본 VRP는 이렇게 정의된다. 하나의 창고(depot)에서 출발하는 차량들이 주어진 고객들을 방문하고 창고로 돌아온다. 목표는 총 이동 거리(또는 시간, 비용)를 최소화하되, 차량의 적재 용량을 초과하지 않는 것이다.

이 기본 정의에 현실의 제약 조건을 추가하면 문제가 기하급수적으로 복잡해진다. REINDEERS DVRP는 현실의 여러 제약 조건을 동시에 처리해야 한다.

현실의 제약 조건

학술 VRP와 실제 배차의 가장 큰 차이는 제약 조건의 수와 복잡도다. 논문에서는 보통 1~3개의 제약을 다루지만, 현실에서는 동시에 10개 이상의 제약이 걸린다. DVRP 엔진이 처리하는 제약 조건을 하나씩 보자.

적재 제약: CBM과 중량의 이중 한계

트럭에는 두 가지 용량 한계가 있다. 부피(CBM, Cubic Meter)와 중량(kg). 10톤 트럭이라도 가벼운 화물이 부피를 다 채우면 중량 여유가 남아도 더 실을 수 없다. 반대로 무거운 화물은 중량 한도에 먼저 도달한다. 두 제약을 동시에 만족해야 한다.

# 적재 가능 여부 판정

def can_load(truck, delivery):
    remaining_cbm = truck.max_cbm - truck.current_cbm
    remaining_weight = truck.max_weight - truck.current_weight
    return (delivery.cbm <= remaining_cbm) and (delivery.weight <= remaining_weight)

# 예시: 6톤 트럭, 최대 20 CBM
# 현재 적재: 12 CBM, 3,500 kg
# 신규 화물: 6 CBM, 1,800 kg
# → CBM: 12+6=18 <= 20 (OK), 중량: 3500+1800=5300 <= 6000 (OK) → 적재 가능

# 신규 화물: 9 CBM, 1,200 kg
# → CBM: 12+9=21 > 20 (초과) → 적재 불가 (중량은 여유 있지만 부피 초과)

시간 창(Time Window)

고객마다 화물을 받을 수 있는 시간대가 있다. 공장은 보통 08:00~17:00, 물류 센터는 06:00~22:00, 건설 현장은 07:00~15:00처럼 다르다. 배송이 이 시간 창 밖에 도착하면 수령 거부되거나 재방문해야 한다.

시간 창 제약은 경로 순서에 직접적인 영향을 준다. A 고객이 08:00~10:00, B 고객이 14:00~16:00이라면, 같은 경로에 있어도 A를 오전에, B를 오후에 방문하도록 순서를 잡아야 한다. 시간 창이 겹치는 고객들은 유연하게 순서를 바꿀 수 있지만, 엄격한 시간 창을 가진 고객은 경로 설계의 고정점이 된다.

운전자 근무 시간

관련 법규에 따른 운전 시간 제한과 의무 휴식 규정이 있다. 이 규정을 무시하면 사고 위험과 법적 리스크가 동시에 발생한다. 경로 계획에 운전자의 누적 운전 시간과 휴식 시간이 반드시 포함되어야 한다.

차량 유형

냉동 차량, 위험물 차량, 일반 화물차는 서로 대체할 수 없다. 냉동 식품은 냉동 차량에만 실을 수 있고, 화학 물질은 위험물 차량에만 실을 수 있다. 차량 유형별 가용 대수가 제한되어 있으므로, 화물의 특성과 차량의 특성을 매칭하는 것도 최적화의 일부다.

적재 순서 (LIFO)

트럭에 화물을 적재할 때 순서가 중요하다. 마지막에 배송할 화물을 먼저 싣고, 처음 배송할 화물을 마지막에 싣는다(Last In, First Out). 이 제약이 없으면 배송 현장에서 화물을 찾기 위해 다른 화물을 전부 내려야 하는 상황이 생긴다. 경로 순서와 적재 순서가 역순으로 일치해야 한다.

다중 창고 (Multi-Depot)

REINDEERS 파트너들은 하나의 창고에서만 출발하지 않는다. 방콕에 2개, 이스턴 시보드에 1개, 치앙마이에 1개처럼 여러 창고가 있을 수 있다. 각 트럭은 자신이 속한 창고에서 출발하고, 업무 종료 후 해당 창고(또는 지정된 다른 위치)로 돌아간다. 배송을 어떤 창고의 어떤 트럭에 배정하느냐에 따라 전체 경로가 달라진다.

알고리즘 접근: 초기해 생성과 개선

이 모든 제약을 만족하면서 최적에 가까운 해를 찾는 것이 DVRP 엔진의 핵심이다. 접근 방식은 두 단계로 나뉜다. 먼저 "괜찮은 해"를 빠르게 만들고(초기해 생성), 그 해를 반복적으로 개선한다(로컬 서치).

초기해: Nearest Neighbor Heuristic

가장 직관적인 방법이다. 창고에서 출발해서 가장 가까운 미방문 배송지를 순서대로 방문한다. 탐욕적(greedy) 접근이라 최적은 아니지만, 빠르게 "그런대로 괜찮은" 해를 만들어낸다. 의사코드로 표현하면 이렇다.

def nearest_neighbor(depot, deliveries, trucks):
    """Nearest Neighbor 기반 초기해 생성"""
    unassigned = list(deliveries)
    routes = {truck.id: Route(depot=depot) for truck in trucks}

    while unassigned:
        for truck in trucks:
            if not unassigned:
                break

            current_location = routes[truck.id].last_stop or depot
            # 제약 조건을 만족하면서 가장 가까운 배송지 탐색
            candidates = [
                d for d in unassigned
                if can_load(truck, d)
                and within_time_window(routes[truck.id], d)
                and within_driver_hours(routes[truck.id], d)
                and compatible_vehicle_type(truck, d)
            ]

            if not candidates:
                continue

            nearest = min(candidates, key=lambda d: distance(current_location, d.location))
            routes[truck.id].add_stop(nearest)
            unassigned.remove(nearest)

    return routes

이 알고리즘의 시간 복잡도는 O(n^2 * m)이다. n은 배송 건수, m은 트럭 수. 50건 8대 기준으로 수 밀리초 안에 결과가 나온다. 품질은 최적 대비 10~25% 정도 나쁘지만, 이 단계의 목적은 "개선 가능한 출발점"을 만드는 것이므로 충분하다.

개선: Local Search Operators

초기해를 반복적으로 개선하는 단계다. 세 가지 연산자(operator)를 사용한다.

2-opt: 하나의 경로 내에서 두 구간을 선택하고 순서를 뒤집는다. 경로가 교차하는 비효율을 제거하는 데 효과적이다. A→B→C→D→E 경로에서 B→C→D 구간을 뒤집으면 A→D→C→B→E가 된다. 뒤집은 결과가 더 짧으면 채택한다.

Or-opt: 하나의 경로에서 연속된 1~3개의 배송지를 다른 위치로 옮긴다. 예를 들어 A→B→C→D→E에서 B-C를 빼내 D 뒤에 넣으면 A→D→B→C→E가 된다. 2-opt보다 공격적인 변경으로 더 큰 개선을 찾을 수 있다.

Relocate: 경로 간 이동이다. 한 트럭의 배송지를 다른 트럭의 경로로 옮긴다. 트럭 간 부하 균형을 맞추고, 전체 이동 거리를 줄이는 데 사용한다.

def local_search(routes, max_iterations=1000):
    """Local Search로 초기해 개선"""
    best_score = calculate_score(routes)
    improved = True
    iteration = 0

    while improved and iteration < max_iterations:
        improved = False
        iteration += 1

        # 1. 경로 내 2-opt
        for route in routes.values():
            for i in range(len(route.stops) - 1):
                for j in range(i + 2, len(route.stops)):
                    new_route = two_opt_swap(route, i, j)
                    if is_feasible(new_route) and calculate_score(new_route) < best_score:
                        route.stops = new_route.stops
                        best_score = calculate_score(routes)
                        improved = True

        # 2. 경로 내 Or-opt (1~3개 연속 이동)
        for route in routes.values():
            for segment_size in [1, 2, 3]:
                for i in range(len(route.stops) - segment_size):
                    segment = route.stops[i:i+segment_size]
                    for j in range(len(route.stops)):
                        if j == i:
                            continue
                        new_route = or_opt_move(route, segment, i, j)
                        if is_feasible(new_route) and calculate_score(new_route) < best_score:
                            route.stops = new_route.stops
                            best_score = calculate_score(routes)
                            improved = True

        # 3. 경로 간 Relocate
        for route_a in routes.values():
            for route_b in routes.values():
                if route_a.id == route_b.id:
                    continue
                for stop in route_a.stops:
                    for pos in range(len(route_b.stops) + 1):
                        new_a, new_b = relocate(route_a, route_b, stop, pos)
                        new_total = calculate_score(new_a) + calculate_score(new_b)
                        old_total = calculate_score(route_a) + calculate_score(route_b)
                        if is_feasible(new_a) and is_feasible(new_b) and new_total < old_total:
                            route_a.stops = new_a.stops
                            route_b.stops = new_b.stops
                            best_score = calculate_score(routes)
                            improved = True

    return routes

Local Search의 핵심은 "개선이 없을 때까지 반복"이다. 매 iteration마다 모든 가능한 변경을 시도하고, 개선이 발견되면 적용한 뒤 다시 처음부터 탐색한다. 개선이 하나도 발견되지 않으면 종료한다(local optimum 도달). 50건 8대 규모에서 보통 100~300 iteration 내에 수렴하며, 수행 시간은 1~3초 수준이다.

스코어링 함수: 무엇이 "좋은 경로"인가

Local Search가 "개선되었다"를 판단하려면, 경로의 품질을 숫자로 평가하는 함수가 필요하다. DVRP의 스코어링 함수는 네 가지 요소의 가중합이다.

Score = w1 * Distance + w2 * TimeViolation + w3 * (1 - Utilization) + w4 * Cost

# Distance:       총 이동 거리 (km). 작을수록 좋다.
# TimeViolation:   시간 창 위반 합계 (분). 0이 이상적.
#                  도착 시간이 time window를 벗어난 분의 합산.
# Utilization:     적재율 (0~1). 1에 가까울수록 좋다.
#                  CBM 기준 적재율과 중량 기준 적재율 중 높은 값 사용.
# Cost:           총 비용 (유류비 + 통행료 + 인건비). 작을수록 좋다.

# 가중치 예시 (비용 우선 테넌트)
w1 = 0.3   # 거리
w2 = 5.0   # 시간 위반 (페널티 높음)
w3 = 0.2   # 적재율
w4 = 0.5   # 비용

# 가중치 예시 (정시 배송 우선 테넌트)
w1 = 0.2   # 거리
w2 = 10.0  # 시간 위반 (페널티 매우 높음)
w3 = 0.1   # 적재율
w4 = 0.3   # 비용

여기서 중요한 설계 결정이 있다. 가중치가 테넌트별로 설정 가능하다. 어떤 파트너는 물류비 절감이 최우선이고, 어떤 파트너는 정시 배송이 생명이다. 정시 배송을 우선하는 테넌트는 TimeViolation의 가중치를 높게 설정하면, 다소 먼 거리를 돌더라도 시간 창을 엄격히 준수하는 경로가 선택된다.

TimeViolation에 높은 가중치를 주는 이유는 "위반을 0으로 만들기" 위해서다. 시간 창 위반이 1분이라도 있으면 스코어가 크게 나빠지므로, Local Search가 시간 창 위반을 없애는 방향으로 강하게 수렴한다.

AI 보정 레이어

여기까지가 전통적인 OR(Operations Research) 접근이다. 잘 작동하지만 한계가 있다. 가장 큰 한계는 이동 시간 추정이다. 아래에서 설명하는 AI 보정 레이어는 현재 데이터를 축적 중이며, 충분한 데이터가 쌓이면 적용할 예정이다.

ETA 예측: 구글 맵으로는 부족하다

지도 API(Google Maps, HERE)가 제공하는 이동 시간은 도로 거리와 일반적인 교통 상황 기반이다. 하지만 실제 배송에서는 추가적인 시간이 소모된다. 화물 하차 시간(화물 크기와 층수에 따라 10분~1시간), 서류 확인 시간(통관 화물은 더 길다), 대기 시간(공장이나 물류센터의 게이트 앞 대기), 주차 및 이동 시간(도심 배송은 주차만 15분 걸리기도 한다).

이런 "비이동 시간"은 지도 API로는 알 수 없다. DVRP 엔진은 과거 배송 이력 데이터를 학습하여 실제적인 ETA를 예측한다.

# ETA 예측 모델의 입력 피처

features = {
    # 이동 관련
    "map_estimated_minutes": 45,       # 지도 API 기본 추정
    "distance_km": 32.5,               # 이동 거리

    # 시간 패턴
    "departure_hour": 9,               # 출발 시각
    "day_of_week": 2,                  # 화요일
    "is_holiday": False,               # 공휴일 여부

    # 목적지 특성
    "dest_type": "factory",            # 공장 / 물류센터 / 건설현장 / 기타
    "dest_zone": "eastern_seaboard",   # 지역 구분
    "has_loading_dock": True,          # 하역장 유무

    # 화물 특성
    "total_cbm": 8.5,                  # 화물 부피
    "num_items": 12,                   # 화물 개수
    "requires_signature": True,        # 서명 필요 여부

    # 과거 실적
    "dest_avg_service_time": 35,       # 이 목적지의 평균 서비스 시간
    "dest_avg_wait_time": 12,          # 이 목적지의 평균 대기 시간
}

# 출력: 예상 총 소요 시간 (이동 + 서비스 + 대기)
predicted_total_minutes = model.predict(features)
# → 97분 (지도 API 45분 + 서비스 35분 + 대기 12분 + 보정 5분)

이 모델은 과거 배송 완료 데이터를 학습한다. 실제 출발 시각, 실제 도착 시각, 실제 하역 완료 시각이 기록되어 있으므로, "이 조건에서 실제로 얼마나 걸렸는가"를 학습할 수 있다. 데이터가 충분히 쌓인 경로에서는 지도 API보다 더 정확한 ETA를 제공할 수 있을 것으로 기대한다. 현재 DVRP 베타 운영을 통해 데이터를 축적하는 단계다.

교통 패턴 학습

방콕의 교통은 악명 높다. 같은 경로라도 오전 7시와 오전 10시의 이동 시간이 2~3배 차이 난다. 이 시간대별 교통 패턴을 과거 데이터에서 학습한다.

특히 산업 단지 주변의 교통 패턴은 일반 도로와 다르다. 이스턴 시보드(Eastern Seaboard) 산업 지대는 공장 출퇴근 시간인 07:00~08:00과 17:00~18:00에 극심한 정체가 발생하지만, 그 외 시간에는 비교적 원활하다. 이런 지역 특화 패턴을 학습하면 배차 시점에 더 정확한 이동 시간을 반영할 수 있다.

시간대 방콕 도심 이스턴 시보드 치앙마이
06:00~08:00 1.8x 2.2x 1.3x
08:00~10:00 2.5x 1.4x 1.5x
10:00~15:00 1.3x 1.0x 1.0x
15:00~18:00 2.8x 1.9x 1.4x
18:00~22:00 1.5x 1.1x 1.0x

* 배수는 기본 이동 시간 대비 실제 소요 시간의 비율. 1.0x = 정체 없음. 일반적으로 알려진 교통 패턴 기반 참고치.

동적 재배차: 실시간 변화에 대응

DVRP의 "D"는 Dynamic이다. 아침에 최적화한 경로가 오후까지 최적이리라는 보장은 없다. 새로운 배송이 추가되거나, 트럭이 고장 나거나, 특정 배송이 취소되거나, 도로가 막힐 수 있다. 이런 변화에 실시간으로 대응하는 것이 동적 재배차다.

신규 배송 삽입 알고리즘

가장 빈번한 동적 이벤트는 "새로운 배송 추가"다. 급한 발주가 들어오거나, 이전에 보류된 배송이 확정되는 경우다.

신규 배송을 처리하는 방법은 두 가지가 있다. 전체를 처음부터 다시 최적화하는 것(re-optimization)과, 기존 경로에 신규 배송만 삽입하는 것(insertion). 전자가 품질이 더 좋지만, 이미 출발한 트럭의 경로를 변경하면 혼란이 생긴다. DVRP 엔진은 후자를 기본으로 사용하되, 미출발 경로에 대해서는 re-optimization을 적용한다.

def insert_new_delivery(delivery, active_routes):
    """신규 배송을 기존 경로에 최적 삽입"""
    best_insertion = None
    best_score_delta = float('inf')

    for route in active_routes:
        # 이미 완료된 구간은 건드리지 않음
        insertable_positions = get_future_positions(route)

        for pos in insertable_positions:
            # 제약 조건 확인
            if not can_insert(route, delivery, pos):
                continue

            # 삽입 시 스코어 변화량 계산
            new_route = insert_at(route, delivery, pos)
            score_delta = calculate_score(new_route) - calculate_score(route)

            if score_delta < best_score_delta:
                best_score_delta = score_delta
                best_insertion = (route.id, pos)

    if best_insertion:
        apply_insertion(best_insertion, delivery)
        return {"status": "inserted", "route": best_insertion[0], "position": best_insertion[1]}
    else:
        # 어떤 경로에도 삽입 불가 → 새 경로 생성 또는 디스패처에게 알림
        return {"status": "no_feasible_insertion", "alert": "dispatcher"}

모든 활성 경로의 모든 삽입 가능 위치를 시도해서, 스코어 증가가 가장 적은 위치에 삽입한다. 어떤 위치에도 제약을 만족하면서 삽입할 수 없으면, 새 경로를 생성하거나 디스패처에게 판단을 요청한다.

트럭 지연 시 재배차

트럭이 예상보다 늦어지고 있다면, 남은 경로의 시간 창 위반 가능성을 실시간으로 계산한다. 위반이 예상되면 해당 배송을 다른 트럭으로 재배정하거나, 고객에게 지연 알림을 보낸다.

def handle_delay(truck_id, current_delay_minutes):
    """트럭 지연 시 남은 경로 재평가"""
    route = get_active_route(truck_id)
    remaining_stops = get_remaining_stops(route)

    violations = []
    accumulated_delay = current_delay_minutes

    for stop in remaining_stops:
        predicted_arrival = stop.original_eta + timedelta(minutes=accumulated_delay)
        if predicted_arrival > stop.time_window_end:
            violations.append({
                "stop": stop,
                "violation_minutes": (predicted_arrival - stop.time_window_end).minutes
            })

    if violations:
        # 위반이 경미하면 고객 알림만, 심각하면 재배정 시도
        for v in violations:
            if v["violation_minutes"] <= 30:
                notify_customer(v["stop"], delay=v["violation_minutes"])
            else:
                attempt_reassignment(v["stop"], active_routes)

실제 시나리오: 방콕 50건 배송

가상 시나리오로 엔진의 동작을 보자. 방콕과 이스턴 시보드에 걸쳐 50건의 배송을 8대의 트럭으로 처리하는 상황을 가정한다.

입력 조건

창고 2곳: 방콕 방나(Bangna), 이스턴 시보드 라용(Rayong)
트럭 8대: 6톤 일반 4대, 10톤 일반 2대, 냉동 1대, 위험물 1대
배송 50건: 방콕 도심 15건, 방콕 외곽 12건, 이스턴 시보드 18건, 치앙마이 5건
시간 창: 08:00~12:00 (20건), 09:00~17:00 (22건), 14:00~18:00 (8건)
냉동 화물 3건, 위험물 1건

엔진이 처리하는 과정은 이렇다.

먼저 차량 유형 매칭이 수행된다. 냉동 화물 3건은 냉동 트럭에 우선 배정된다. 위험물 1건은 위험물 트럭에 배정된다. 나머지 46건이 일반 트럭 6대에 배분된다.

다음으로 창고 배정이다. 방콕 배송 27건은 방나 창고에서, 이스턴 시보드 18건은 라용 창고에서 출발한다. 치앙마이 5건은 거리가 멀어 별도 경로로 처리된다(방나 출발, 1대 전담).

Nearest Neighbor로 초기해를 생성하면, 총 이동 거리 약 850km, 시간 창 위반 6건(합계 95분)이 나온다. 여기에 Local Search를 적용하면 200 iteration 후 이동 거리 720km, 시간 창 위반 0건으로 개선된다. 총 처리 시간은 약 2초.

배차 결과는 디스패처에게 시각적으로 제공된다. 각 트럭의 경로, 예상 시간, 적재율이 표시되고, 디스패처는 결과를 검토한 후 확정하거나 수동으로 조정할 수 있다.

스코어링 가중치 튜닝

스코어링 함수의 가중치는 DVRP 엔진의 성격을 결정한다. 이 가중치를 테넌트별로 설정할 수 있게 한 이유는, "좋은 배차"의 정의가 파트너마다 다르기 때문이다.

식품 유통업체는 정시 배송이 절대적이다. 신선 식품의 시간 창 위반은 곧 폐기를 의미한다. 이런 테넌트는 TimeViolation 가중치를 극단적으로 높게 설정한다. 거리가 좀 늘어나더라도 모든 배송이 시간 창 안에 도착하는 게 우선이다.

건설 자재 업체는 비용이 더 중요할 수 있다. 자재가 30분 늦어도 큰 문제가 없지만, 물류비는 직접적으로 마진에 영향을 준다. 이런 테넌트는 Cost 가중치를 높이고 TimeViolation 가중치를 낮춘다.

이 가중치는 초기에 파트너와의 미팅에서 결정하고, 실제 운영 데이터를 보면서 점진적으로 조정한다. 장기적으로는 AI가 운영 결과를 분석해서 가중치 조정을 제안하는 구조로 발전시킬 계획이다.

REINDEERS 생태계와의 연결

DVRP는 독립된 배차 시스템이 아니다. REINDEERS 생태계의 일부로서, 다른 서비스들과 이벤트 기반으로 연결된다.

POP에서 출고 확정 이벤트가 발생하면 DVRP에 배차 가능한 화물이 추가된다. REINDEERS에서 DO(Delivery Order)가 생성되면 DVRP에 배송 요청이 들어온다. 배송이 완료되면 REINDEERS의 거래 상태가 업데이트되고, 구축 중인 Document AI가 배송 완료 확인서를 생성할 수 있게 된다.

포워딩 비딩 시스템과도 연결된다. 자체 배송이 아닌 포워더 위탁 배송의 경우, 비딩 시스템에서 선정된 포워더의 예상 배송 일정이 DVRP에 반영되어 전체 물류 스케줄을 통합 관리할 수 있다.

그리고 이 모든 데이터가 AI Agent(AX)의 knowledge base에 축적된다. "이 경로는 평균적으로 얼마나 걸리는가", "이 포워더는 정시 배송률이 어느 정도인가", "이 화물 유형의 최적 배차 패턴은 무엇인가" , 이런 인사이트가 거래 전체에 걸쳐 활용될 수 있다.

사람 디스패처와 물류 Agent의 역할 분담

DVRP가 조직도의 '물류 Agent'로 통합될 때 가장 많이 받는 질문은 "그럼 디스패처는 사라지는가"이다. 우리가 설계한 답은 명확하다. 디스패처는 사라지지 않는다. 역할이 바뀐다.

작업 이전 (사람) 이후 (사람 + 물류 Agent)
당일 배송 50건 배차 사람이 엑셀·지도를 보며 수동 배정 Agent가 제안, 디스패처는 방침·예외만 확인
긴급 배송 삽입 전화로 기사에게 직접 지시 Agent가 최적 삽입 계산, 디스패처는 승인
트럭 고장 대응 남은 배송 재분배 수동 계산 Agent가 재배차안 제시, 디스패처는 고객 통보 승인
파트너별 방침 설정 사람이 암묵적 경험으로 판단 사람이 "정시 우선/비용 우선" 방침 명시, Agent가 적용
이상 징후 탐지 기사 보고를 기다림 Agent가 이벤트 로그에서 이상 패턴 감지 후 보고

AI Agent 진화 4단계(Tool → Assistant → Agent Team → Autonomous Operator) 관점으로 보면, DVRP의 현재 위치는 Tool 단계에서 Assistant 단계로 넘어가는 지점이다. 엔진은 이미 제약 기반 계산과 Local Search로 "괜찮은 배차안"을 수 초 안에 만들어낸다. 다음 단계는 그 배차안을 물류 Agent가 자연어로 설명하고, 디스패처는 예외만 승인하는 구조다. Agent Team 단계로 가면 여러 창고·여러 파트너의 물류 Agent들이 서로 조율하게 된다. Autonomous Operator 단계에서는 사람의 관여가 "오늘은 고객 A의 긴급 납기에 집중하자" 수준의 방향 제시로 축소된다. 이 로드맵에서 사람은 사라지는 대신 시간이 풀린다. 디스패처 한 명이 지금 관리하는 양의 몇 배를 볼 수 있게 된다.

DVRP 엔진은 계속 진화 중이다. 메타휴리스틱(Simulated Annealing, Genetic Algorithm) 도입, 강화학습 기반 동적 재배차, 다목적 최적화(Pareto optimal)가 다음 단계 연구 주제다. 이런 기술적 발전을 현실의 제약 조건 속에서 실용적으로 적용하는 게 우리의 과제다. 그리고 그 모든 발전은 결국 "DVRP 엔진의 결정을 물류 Agent가 조직도 안에서 사람 대신 집행하는" 방향으로 수렴한다.

관련 글

Popular posts from this blog

Reindeers Workflow: B2B 파트너 업무 효율과 자동화를 위한 워크플로우 플랫폼

B2B 국제 무역에서 하나의 거래가 완료되기까지 관여하는 시스템과 사람의 수는 예상보다 훨씬 많다. 견적 요청에서 시작해 공급사 선정, 발주, 포워딩 비딩, 통관 서류 준비, 출하, 배송, 정산까지 — 각 단계마다 서로 다른 담당자가 서로 다른 도구에서 수작업을 반복한다. 이 현장에서 반복적으로 발생하는 비효율은 분명하다. 바이어가 견적을 확정하면 공급사에게 이메일이나 메신저로 직접 통보해야 하고, 결제가 완료되면 수동으로 정산 시트에 옮기면서 1~3일이 소요된다. 출하 후에는 선적 정보를 기반으로 CI, PL, CO를 수동 생성하며 누락이 발생하고, 배송 완료 후 공급사/포워더 정산을 수작업으로 대조하면서 오차가 누적된다. ERP, 이메일, 스프레드시트, CRM에 같은 데이터를 반복 입력하는 것도 일상이다. 이 문제들의 공통점은 명확하다. "이벤트가 발생했을 때 후속 작업이 자동으로 실행되지 않는다" 는 것이다. 견적이 확정되었다는 '사실'은 시스템에 기록되지만, 그 사실이 다음 단계의 업무를 자동으로 트리거하지는 않는다. Reindeers Workflow는 이 문제를 해결하기 위해 만들어졌다. 단순히 "자동화 도구를 제공한다"가 아니라, REINDEERS 플랫폼에서 발생하는 실제 거래 이벤트를 기반으로 후속 업무가 자동 실행되는 구조를 만드는 것이다. REINDEERS 플랫폼과의 연결: 거래 이벤트가 워크플로우를 트리거한다 Reindeers Workflow의 가장 중요한 차별점은 범용 자동화 도구가 아니라 REINDEERS 본 플랫폼의 거래 이벤트에 직접 연결 된다는 것이다. REINDEERS에서 발생하는 핵심 거래 이벤트가 MQ(Message Queue)를 통해 워크플로우의 트리거가 된다. 거래 이벤트 트리거되는 워크플로우 실행 내용 quote.confirmed 공...

레인디어스, Buybly로 동남아시아 산업자재 시장 혁신

B2B 오픈마켓 REINDEERS, 한국 기업의 글로벌 진출을 돕다 레인디어스, 머신러닝 기반의 산업자재 매칭 솔루션으로 경쟁력 강화 김명훈 레인디어스 대표 산업자재 시장의 복잡성과 유통장벽은 많은 기업들에게 큰 도전 과제가 되어왔다. 특히 동남아시아 시장 진출을 원하는 한국의 산업자재 제조사들은 현지의 불투명한 거래 환경과 물류 문제로 어려움을 겪어왔다. 이러한 상황에서 레인디어스의 REINDEERS 플랫폼은 새로운 기회를 제시하고 있다. REINDEERS는 B2B 오픈마켓으로, 한국 기업들이 손쉽게 동남아시아 시장에 진출할 수 있도록 지원하며, 유통의 복잡성을 해결하는 혁신적인 솔루션으로 주목받고 있다. 이러한 변화의 중심에는 레인디어스 대표가 있다. 그는 지난 9년간 태국에서의 경험을 바탕으로 고객의 pain point를 해결하기 위해 REINDEERS를 개발했다. 이번 인터뷰를 통해 그의 비전과 경영 철학, 그리고 REINDEERS가 어떻게 산업자재 시장을 변화시키고 있는지에 대해 깊이 있는 이야기를 나누게 되었다. 김명훈 레인디어스 대표 -.소개 레인디어스는 국내 산업자재 제조사들이 동남아시아 시장에 쉽게 진출할 수 있도록 돕는 B2B 오픈마켓인 REINDEERS를 운영하고 있다. 해외 시장 진출에서 가장 큰 장애물인 유통, 물류, 무역의 장벽을 해결해주는 것이 이 플랫폼의 핵심이다. REINDEERS는 단순한 거래 플랫폼이 아니라, 산업자재 구매와 공급 과정을 간소화하고 최적화하는 One-Stop 솔루션으로 자리 잡았다. 레인디어스의 서비스는 REINDEERS와 Enterprise Solution(ERP, POP, WMS)으로 구성되어 있다. 이 솔루션은 동남아시아 현지의 고객사와 공급사에 맞춤형으로 제공되며, 산업현장의 선진화를 이끌어낸다. 기업 운영과 생산 관리, 재고 관리를 전산화해 이익을 극대화하는 데 기여하고 있다. REINDEERS는 산업현장에서 획득한 Raw data를 활용해 인공지능 분석을 통해 발주 ...

JD 플랫폼 매니저 (Platform Manager )

🇰🇷 플랫폼 매니저 (운영 / 글로벌 B2B & AI Agent 기반 자동화 플랫폼) 회사명: (주)레인디어스 | REINDEERS Co., Ltd. 근무지: 서울 / 방콕 (Hybrid 가능) 고용형태: 정규직 (계약-전환형 가능) 회사 소개 REINDEERS는 산업자재 및 무역 중심의 글로벌 B2B 플랫폼을 운영하는 기술 기반 기업입니다. 한국, 태국, 말레이시아, 중국 4개 주요 아시아 시장에서 견적–발주–물류(3PL)–통관–정산–재고관리(WMS)를 통합 관리하는 시스템을 제공합니다. REINDEERS는 POP과 DVRP를 AI로 전환되는 구조로 설계하고 있습니다. 사람은 전략과 방향을 결정하고, 실제 업무는 AI Agent가 실행하는 구조입니다. 조직도에 직원을 등록할 때 사람, AI Agent, 로봇 중에서 선택할 수 있으며, 같은 워크플로우와 같은 권한 체계로 협업합니다. CEO Agent가 전사 전략과 자원 배분을 총괄하고, 구매·생산·영업·물류·재무·통관 Agent가 각 부서 업무를 자율적으로 실행합니다. REINDEERS는 운영 중심의 플랫폼 관리 전문가를 찾습니다. 본 포지션은 플랫폼의 운영·유지·관리·발전·확장을 담당하며, 사람 담당자와 AI Agent, 그리고 향후 합류할 로봇 작업자가 같은 조직도 안에서 협업하는 환경을 관리하는 역할을 맡습니다. (※ 개발 업무를 직접 수행하지 않으며, 개발팀 및 AI Agent 팀과 협업해 개선을 주도합니다.) 이 포지션이 일하는 환경 REINDEERS는 POP과 DVRP를 "조직도 기반 AI 법인" 구조로 설계하고 있습니다. 외부 AI 도구를 연결하는 방식이 아니라, AI Agent가 회사 조직 구조에 직접 통합되어 있습니다. 플랫폼 매니저는 이 Agent들이 정상적으로 작동하는지 모니터링하고, 예외 상황에 대한 승인과 에스컬레이션을 처리하며, 사람 운영자와 AI Agent 간의 협업 경계를 정의하는 역할을 합니다. 현재는 Tool 단계(사...