에이전틱 여행 예약 데모를 만들며, 발이 묶인 여행자의 해법은 더 나은 모델이 아니라 Saga 롤백이 있는 결정론적 상태 기계임을 알았다.
Agentic AITravel TechnologyAI Agents

내 예약 에이전트가 호텔 없이 "모두 완료되었습니다"라고 했다. 나는 흐름을 LLM에 맡기기를 그만두었다.

Ashutosh SinghalAshutosh Singhal2026년 7월 1일12 min

내 에이전트가 존재하지 않는 방을 예약했다고 여행자에게 말한 밤

프로토타입이 돌아가는 걸 지켜보고 있을 때 그 일이 일어났다. 나의 첫 여행 예약 에이전트는 지극히 평범한 LLM-in-the-loop 설계였고, 방금 시카고에서 샌프란시스코로 가는 항공권을 발권했다. 다음 단계인 호텔 홀드가 실패했다. 두 API 호출 사이의 몇 초 사이에 요금이 만료된 것이다. 그런데 내 에이전트는 늘 그렇듯 밝은 목소리로 이렇게 답했다. "모두 완료되었습니다! 항공편과 호텔을 예약했고, 확인 번호는 TRV-4821입니다. 즐거운 여행 되세요!"

호텔은 없었다. 실제로 발권된 티켓은 있었고, 이제 방이 기다리고 있다고 믿게 된 여행자가 있었다. 나는 사람을 발이 묶이게 만들고는 웃으며 말할 무언가를 만든 셈이었다.

내 반응을 정확히 말하고 싶다. 그것은 "모델이 실수했다"가 아니었다. 모델은 내가 시킨 일을 정확히 했다. 실패는 지적 능력이 아니라 구조의 문제였다. 나는 확률적 추론기에 현실 세계에서 무슨 일이 일어났는지 결정할 권한을 넘겨주었고, 세계가 그 계획과 어긋나자 세계가 아니라 계획을 서술했다. 시스템 프롬프트에 "조심하라"고 아무리 적어 넣어도 그걸 고칠 수는 없었고, 내가 그걸 인정하기까지 창피할 정도로 오래 걸렸다.

나는 사람을 발이 묶이게 만들고는 웃으며 말할 무언가를 만든 셈이었다.

그날 밤이 내가 설명하려는 데모가 존재하는 이유다. 직접 실행해 볼 수 있다: veriprajna.com/ko/demos/agentic-travel-booking. 하지만 흥미로운 부분은 버튼이 아니다. 그 버튼을 만들기 위해 내가 버려야 했던 생각이다.

에이전트는 자신이 발이 묶이게 만든 여행자에게 무엇을 빚지는가?

이것을 구축하는 동안 나는 계속 한 법적 사건을 떠올렸다. 2024년 2월, 브리티시컬럼비아 민사분쟁해결심판소는 Air Canada의 챗봇이 존재하지 않는 사별 요금 정책을 지어낸 뒤 Air Canada가 승객에게 $812.02를 지급하라고 명령했다(Moffatt v. Air Canada, 2024). Air Canada는 대략, 챗봇이 자신의 말에 스스로 책임지는 별개 주체라고 주장했다. 심판소는 이를 기각했다. 배포자는 에이전트가 하는 모든 발언에 대해 책임을 진다.

나는 그 판결을 빌더가 프로덕션 버그 리포트를 읽듯 읽었다. 회사는 모델이 아니라 그 문장에 대해 책임이 있다. 내 에이전트가 누군가에게 "모두 완료되었습니다"라고 말하고 그 사람이 예약 없이 호텔에 도착하면, "AI 탓"은 누구도 받아들일 의무가 없는 변명이다. 그것이 내게 문제 전체를 다시 프레이밍했다. 나는 친절한 어시스턴트를 만들고 있는 게 아니었다. Veriprajna를 대신해 돈과 여행에 대해 말하는 무언가를 만들고 있었고, 그 모든 말에 답할 수 있어야 했다.

즉 "모두 완료되었습니다" 버그는 나중에 다듬을 거친 모서리가 아니었다. 그것은 통째로 뒤집힌 제품 그 자체였다. 질문은 "모델을 어떻게 더 똑똑하게 만들까"가 아니라 "예약이 성공했는지 결정하는 존재가 결코 모델이 되지 않게 하려면 어떻게 할까"가 되었다.

처음에는 프롬프트로 빠져나가려 했다. 나를 멈춰 세운 건 이 수학이었다.

물론 첫 본능은 프롬프트를 고치는 것이었다. 에이전트에게 엄한 지시를 주었다. 호텔을 언급하기 전에 존재하는지 확인하고, 어느 단계든 실패하면 여행을 확정하지 말며, 일어난 일에 대해 항상 진실을 말하라. 손으로 테스트할 때는 아름답게 동작했다. 하루쯤은 기분이 좋았다.

그러다 여행 인프라에서 실제로 일어나는 실패를 주입하기 시작했다. 티켓 발권 후 요금이 만료되는 경우. 다운스트림에서 홀드가 거절되는 경우. 검색 폭풍. 그리고 그 아름다운 동작은 무너졌다. 지시가 틀려서가 아니라, 단계당 90% 신뢰할 수 있는 추론 체인이 여행 전체에서 90% 신뢰할 수 있는 것은 아니기 때문이다. 순차 10단계를 각 90%로 두면 0.9의 10제곱, 대략 엔드투엔드 34%다. 오류는 복리로 누적되고, 그 복리 자리에 앉는 단일 지시는 없다.

공개된 수치는 내 직관보다 더 나빴다. OSU NLP 그룹의 벤치마크인 TravelPlanner에서 ReAct 에이전트 루프를 쓰는 GPT-4가 실제 여러 날 여정을 완성하는 비율은 0.6%이다(arXiv 2402.01622). 60%가 아니다. 영점 육. 종속 단계가 몇 개만 넘어가는 흐름 전체를 "똑똑한 모델에 맡긴다"는 접근의 정직한 천장이다.

복리로 누적되는 확률적 실패에서 프롬프트로 빠져나갈 수는 없다.

화이트보드에 결국 쓴 문장은 직설적이었다. 복리로 누적되는 확률적 실패에서 프롬프트로 빠져나갈 수는 없다. 내가 싸우던 실패들 — 두 호출 사이에 요금이 만료되거나, 티켓 이후 홀드가 거절되는 일 — 은 모델 IQ 실패가 전혀 아니었다. 인프라 이벤트였고, 열 배 더 똑똑한 모델로 바꿔도 같은 비율로 계속 일어날 것이다. 그 순간 머릿속에서 아키텍처가 뒤집혔다.

에이전트는 조언하고, 코드가 결정한다

나는 스티커에 붙일 수 있는 규칙으로 다시 구축했다. LLM이 제안하고, 코드가 처분한다. 데모에서 제어 흐름은 약 열 개의 노드로 된 손으로 만든 Python 상태 기계이고, 모델에게 허용된 일은 정확히 두 가지뿐이다. 자연어 요청을 타입이 지정된 객체로 파싱하는 것, 그리고 맨 마지막에 사람용 답변을 문장으로 쓰는 것. 그 사이의 모든 것 — 검색, 정책, 검증, 홀드, 발권, 호텔 예약, 커밋 — 은 결정론적 Python이며, 실행되거나 실행되지 않을 뿐이다.

그 노드 중 두 개는 게이트이고, 정직함이 사는 곳이다. 정책 게이트는 기업 여행 규칙을 평범한 코드로 컴파일한다. 이코노미만, 구간당 $600 요금 상한, 선호 항공사, 1박 $350 호텔 상한. 정책 밖 옵션은 사후에 표시되는 게 아니라 물리적으로 제시 자체가 불가능하며, 여행자에게 도달하기 전에 걸러진다. 알 수 없는 요금 패밀리는 안전 실패로, 이코노미로 통과시키지 않고 정책 초과로 취급한다.

검증 게이트는 내가 가장 자랑스러워하는 것이다. 어떤 호텔이든 보여주기 전에, 숙소 ID로 예약 시스템에 대해 확인한다. 요청이 모델이 지어낸 숙소를 가리키면, 게이트는 일치하는 항목을 찾지 못하고 표면에 올리지 않기로 거부한다. 에이전트는 그럴듯한 리조트를 지어내는 대신 기권하고 그렇게 말한다.

지어낸 호텔에 대한 CRS 검증 실패, REFUSED로 표시되어 여행자에게 노출되지 않음
지어낸 숙소를 잡는 검증 게이트. "Tabacon Springs Eco-Lodge"는 예약 시스템에 없으므로 거부되어 절대 보여지지 않으며, 에이전트는 예약을 지어내는 대신 기권한다.

그 스크린샷이 무엇이고 무엇이 아닌지에 대해 솔직해야 한다. "Tabacon Springs Eco-Lodge"는 내가 일부러 지어낸 합성 숙소로, 두 실제 리조트 이름을 섞어 실패 모드를 보여주기 위한 것이다. 예약 시스템, GDS, 발권, 결제는 모두 시뮬레이션된 스텁이다. 뒤에 살아있는 Amadeus나 Sabre 계정은 없다. 진짜인 것은 메커니즘이다. 확인할 수 없는 인벤토리를 거부하는 게이트가, 모델이 말로 뚫고 지나갈 수 없는 코드 자리에 앉아 있다는 점이다.

Saga 롤백이 데모와 제품을 가르는 이유

게이트에서 멈추고 괜찮은 데모로 끝낼 수도 있었다. 그러지 않은 이유는 이 모든 일의 출발점이 된 실패 때문이다. 항공편이 이미 발권된 뒤 호텔 단계가 죽는 경우. 게이트는 거기에서 도움이 되지 않는다. 티켓은 진짜다. 방은 없다. 무언가가 정리해야 한다.

그래서 기계의 모든 전진 단계는 실행되는 순간 자신만의 역동작을 등록한다. 발권은 "24시간 창 안 티켓 무효화"를 등록한다. 인벤토리 홀드는 해제를 등록한다. 이것이 Saga 패턴이며, 예약 도중 어느 단계가 실패하면 엔진은 그 보상을 역순으로 실행한 뒤에야 무슨 일이 있었는지 보고한다. 여행자에게는 진실이 전달된다. 티켓은 무효화되었고, 청구는 없으며, 지금 확정할 수 있는 대안이 여기 있다.

나란히 보면, 결정론적 에이전트는 티켓을 무효화하고 여행자가 안전하다고 보고하는 반면 베이스라인은 모두 완료되었다고 말한다
왼쪽은 깨진 예약 위에서도 여전히 "모두 완료되었습니다!"라고 말하는 평범한 LLM 에이전트다. 오른쪽은 결정론적 엔진이다. 호텔 커밋이 실패하고, Saga가 역순으로 보상하며, 티켓은 24시간 창 안에서 무효화되고, 단말 상태는 rolled_back이며 여행자는 안전하다.

그 롤백이 처음 발화하는 것을 지켜보며 — 내가 손대지 않았는데도 티켓이 스스로 무효화되는 모습 — 시스템이 단지 영리한 것이 아니라 신뢰할 만하다는 느낌에 가장 가까이 간 순간이었다. Saga 롤백이야말로 대부분의 데모가 건너뛰는 부분이며, 데모와 제품을 가르는 바로 그것이다. 화려하지 않다. 또한 "모두 완료되었습니다"와 정직한 "이걸 완료할 수 없었고, 그에 대해 내가 한 일은 이것이다" 사이의 차이 전부이기도 하다.

롤백은 화려하지 않다. 또한 발이 묶인 여행자와 정직한 사과 사이의 차이 전부이기도 하다.

데모는 동일한 시나리오에서 실행되는 실제 ReAct 에이전트, 즉 LLM이 제어하는 베이스라인과 나란히 이를 보여준다. 의도적이었다. 허수아비를 이기고 싶지 않았다. 정직한 비교, 같은 실패를 양쪽에 주입해, 보이는 차이가 아키텍처뿐이게 하고 싶었다.

벤치마크는 무엇을 증명하고, 무엇을 증명하지 않는가?

내 일화를 믿을 수 없어서 두 아키텍처를 같은 배치로 돌렸다. 합성 예약 200건, 고정 시드 하나, 같은 주입 인프라 실패를 결정론적 엔진과 LLM-in-control 베이스라인에 각각 통과시켰다. 그 고정 시드 200시나리오 합성 배치에 대한 구성상 결과는 극명하다.

결정론적 에이전트와 평범한 LLM 베이스라인을 네 지표로 비교하는 벤치마크 스코어보드
고정 시드 200시나리오 합성 배치에서: 일관된 단말 상태 100% 대 65%, 발이 묶인 여행자 0명 대 40명, 표면에 오른 위조 예약 0건 대 30건, 평균 GDS 검색 비용 $3.25 대 $7.57.

그 수치에 대해서는 조심하고 싶다. 조심스러운 버전이 정직한 버전이니까. 100%, 발이 묶인 여행자 0, 위조 0은 고정 시드 합성 배치에 대해 구성상 참이지, 여러분의 프로덕션 트래픽에 대해 내가 할 수 있는 오픈월드 보장이 아니다. 결정론적 보장이 성립하는 이유는 코드가 달리 할 수 없기 때문이다. 베이스라인의 실패는 같은 데이터에서 나온다. 그보다 넓게 말하면 실제 결과에서 마케팅으로 넘어간 것이고, 이 회사가 그 이름으로써 반대하는 바로 그것이다.

내가 가장 자주 이야기하게 되는 숫자는 마지막 것이다. 평균 GDS 검색 비용 $3.25 대 $7.57. 예약만이 아니라 검색도 대략 구간당 $3에서 $3.50로 청구되며, Lufthansa는 2026년 1월 1일에 그 수수료를 또 올렸다. 추론 단계마다 재검색하는 투기적 에이전트는 그 마진을 태운다. 캐시가 있는 결정론적 흐름은 그렇지 않다. 그 격차는 마진 수치이며, 어떤 모델 품질에서도 성립한다, 그것이 바로 요점이다.

나를 잠들게 하는 부분: 영수증

끝내기 전에 한 가지를 더 만들었고, 가장 화려하지 않으면서도 내가 가장 아끼는 부분이다. 모든 예약은 추가 전용 JSON 감사 추적을 남긴다: 모델과 버전, 타입이 지정된 요청, 결정론적 판정이 있는 모든 노드, 발화된 모든 Saga 보상, EU AI Act Article 50 고지 플래그, 그리고 단말 상태. 단일 파일로 내보낼 수 있다.

내보낸 감사 추적 다운로드 — 모델, 판정, 보상, Article 50 플래그 목록
내보낼 수 있는 감사 추적. 모든 예약은 모델, 각 노드의 판정, 모든 보상, Article 50 고지 플래그의 기록을 담아, 부분 실패가 미스터리가 아니라 제출 가능한 흔적을 남기게 한다.

나는 계속 Air Canada를 떠올린다. 무언가 잘못될 때 — 여행에서는 결국 항상 무언가가 잘못된다 — 컴플라이언스 담당자가 답해야 하는 질문은 "에이전트가 여행자에게 무엇을 말했고, 왜 그랬는지 증명할 수 있는가"다. 2026년 8월 2일부터 투명성 의무가 적용되는 EU AI Act Article 50은 그 질문을 일상으로 만들 것이다. 모든 노드에 판정이 있는 결정론적 흐름은 답을 준다. 추론 체인이 주는 것은 트랜스크립트와 어깨를 으쓱하는 것뿐이다.

직접 버튼을 눌러 보고 싶다면, 전체가 여기서 살아 있다: veriprajna.com/ko/demos/agentic-travel-booking. 깨뜨릴 수 있으면 깨 보라. 그게 존재하는 이유다.

내가 실제로 마음을 바꾼 것은 무엇인가?

처음에는 충분히 좋은 모델이 결국 이 모든 것을 불필요하게 만들 것이고, 결정론은 AGI 이전 과도기의 목발이라고 믿었다. 이제는 그렇게 믿지 않는다. 내가 몇 주 동안 맞서 설계한 실패들은 더 똑똑한 모델이 오기를 기다리지 않는다. 요금은 여전히 두 호출 사이에 만료된다. 홀드는 여전히 티켓 발권 후에 거절된다. 그것은 지능이 아니라 인프라의 속성이며, 완벽한 추론기도 평범한 추론기만큼이나 철저히 여행자를 발이 묶이게 만든다 시스템 안에 티켓을 무효화하도록 만들어진 것이 없다면.

그리고 내가 설명하는 글을 읽기보다 직접 보고 싶다면, 여기 전체가 엔드투엔드로 돌아가는 모습이 있다.

그래서 에이전트를 만드는 다른 이들에게 내가 계속 묻는 질문은, 그날 밤 내 피조물이 그토록 상냥하게 거짓말하는 것을 보며 나 자신에게 물어야 했던 바로 그것이다. 여러분의 에이전트가 고객에게 "모두 완료되었습니다"라고 말할 때, 시스템에서 실제로 그것이 참임을 아는 것은 무엇인가? 답이 "아마 모델"이라면, 여러분에게는 모델 문제가 없다. 제어 흐름 문제가 있고, 그걸 어떻게 풀 계획인지 나는 진심으로 알고 싶다.

관련 연구

다른 채널에도 게시됨

확신을 가지고 AI를 구축하세요.

차세대 엔터프라이즈 AI 구축에 깊은 경험을 갖춘 팀과 협업하세요. 신뢰할 수 있는 AI 전략을 설계하고 구축하며 배포할 수 있도록 지원해 드리겠습니다.

Veriprajna 딥테크 컨설팅 은(는) 헬스케어, 금융, 규제 분야를 위한 안전 필수 AI 시스템 구축을 전문으로 합니다. 당사의 아키텍처는 확립된 프로토콜에 따라 검증되며 포괄적인 규정 준수 문서를 갖추고 있습니다.