
AI에게 3개월 동안 레스토랑 운영을 맡겨보았습니다. 이를 안전하게 유지해 준 아키텍처를 소개합니다.
요약
AI 에이전트가 레스토랑 주문 시스템을 운영하며 겪은 환각 및 오류 사례를 분석합니다. AI가 상태(state)를 직접 제어하게 두지 않고, 별도의 검증 레이어를 통해 실행을 통제하는 아키텍처의 중요성을 강조합니다.
핵심 포인트
- AI는 의도를 이해하지만, 실행 결과는 코드로 검증해야 함
- LLM의 환각 현상으로 인한 잘못된 도구 호출 방지 필요
- 검증 레이어를 통해 시스템 상태(state) 오염 차단
- 검증 오류를 AI에게 피드백하여 자가 복구 유도
AI에게 3개월 동안 레스토랑 운영을 맡겨보았습니다. 이를 안전하게 유지해 준 아키텍처를 소개합니다.
3개월 전, 저는 AI 레스토랑 주문 시스템을 구축하기 시작했습니다. 고객들은 영어, 프랑스어, 또는 중국어로 시스템과 대화합니다. AI는 실제 웨이터처럼 자연스러운 대화를 통해 주문을 받습니다.
저는 AI가 고객이 원하는 것을 이해하게 만드는 것이 가장 어려운 부분일 것이라고 생각했습니다.
제 생각이 틀렸습니다. 진짜 어려운 부분은 AI가 하지 말아야 할 행동을 하지 못하도록 막는 것이었습니다.
문제가 발생했음을 깨달은 순간
첫 번째 주. 한 고객이 다음과 같이 입력합니다: "랍스터 롤(lobster roll)을 원해요."
AI는 메뉴를 검색합니다. 랍스터 롤은 품절 상태입니다. 하지만 AI는 어쨌든 add_to_cart("lobster-roll")를 호출합니다.
왜일까요? LLM(대규모 언어 모델)은 무언가를 "아는" 것이 아니기 때문입니다. 그들은 다음 토큰(token)을 예측합니다. 그리고 검색 결과 이후에 가장 가능성 높은 다음 토큰은... 그 결과에 따라 행동하는 것입니다.
저는 프롬프트(prompt)를 수정했습니다. "품절된 아이템은 절대 추가하지 마세요." 효과가 있었습니다. 하루 동안은 말이죠.
그 후 AI가 아이템 ID를 환각(hallucinating)하기 시작했습니다. "smash-burger"가 "smash-burger-with-extra-pickles"가 되었습니다. 도구 호출(tool call)은 실패했고, AI는 혼란에 빠졌으며, 고객은 아무것도 받지 못했습니다.
그다음에는 AI가 음수 수량을 추가했습니다. 버거 -1개. 고객이 "버거는 원하지 않아요"라고 말하자, AI가 '제거 = 음수 수량으로 추가'라고 추론했기 때문입니다.
세 번의 실패. 세 가지의 서로 다른 근본 원인. 이 모든 것은 AI를 너무 많이 신뢰한 데서 비롯되었습니다.
모든 것을 바꾼 규칙
저는 포스트잇에 문장 하나를 적어 화면에 붙였습니다:
AI는 의도(intent)를 이해합니다. 코드는 실행(execute)합니다. AI가 상태(state)를 직접 제어하게 두지 마세요.
이제 AI가 호출할 수 있는 모든 도구는 두 개의 레이어(layer)를 가집니다:
{
name: "add_to_cart",
description: "고객의 주문에 아이템을 추가합니다",
...
AI는 어떤 도구를 어떤 파라미터(parameter)와 함께 호출할지 결정합니다. 하지만 설계상 AI는 절대로 validate()를 우회할 수 없습니다. 결코 말이죠.
운영 환경에서 이를 통해 잡아낸 것들
3개월 후, 검증 레이어(validation layer)가 차단한 내역은 다음과 같습니다:
| AI가 시도한 것 | 발생 원인 | 차단 주체 |
|---|---|---|
| 랍스터 롤 추가 (품절) | 검색 결과의 [SOLD OUT] 태그를 무시함 | validate: !item.available |
| ... |
잘못된 데이터가 장바구니에 도달한 적은 단 한 번도 없었습니다. AI는 실수를 했습니다 — 모든 LLM(Large Language Model)이 그렇듯 말이죠. 하지만 상태(state)를 오염시키지는 않았습니다.
아키텍처 (The architecture)
🧑 고객 메시지: "랍스터 롤이랑 샐러드 주세요"
↓
🤖 AI: [메뉴 검색, 결정: add_to_cart("lobster-roll"), add_to_cart("quinoa-salad")]
...
핵심 통찰은 이것입니다: 검증 오류(validation error)가 AI에게 다시 전달된다는 점입니다. AI는 오류를 읽고 복구합니다. 사과를 하고, 대안을 제안합니다. 마치 주방에 확인한 뒤 나쁜 소식을 들고 돌아온 실제 웨이터처럼 행동합니다.
이는 오류를 조용히 삼켜버리는 것보다 훨씬 낫습니다. AI는 피드백으로부터 실시간으로 학습합니다.
미들웨어(middleware)가 잘못된 접근 방식인 이유
대부분의 AI 에이전트 프레임워크는 미들웨어(middleware)를 사용합니다. 즉, 모든 도구 호출(tool call) 전에 실행되는 함수를 사용하는 방식입니다.
// 미들웨어 패턴 — 다른 모든 이들이 사용하는 방식
function middleware(toolName, args) {
if (toolName === "add_to_cart") {
...
이 방식은 확장성(scale)이 없습니다. 미들웨어는 '어떤' 도구가 호출되었는지는 알지만, '왜' 호출되었는지 — 즉, 이 특정 도구가 어떤 비즈니스 조건(business condition)을 필요로 하는지는 알지 못합니다. 도구가 5개만 되어도 여러분의 미들웨어는 200줄짜리 switch 문이 되어버릴 것입니다.
도구별 validate() 방식은 무한히 확장 가능합니다. 모든 도구는 각자의 안전 규칙을 지니고 있습니다. 새 도구를 추가하면 검증 로직도 추가됩니다. 도구를 삭제하면 검증 로직도 함께 사라집니다. 유지 관리해야 할 중앙 파일이 필요 없습니다.
내가 만든 것: Agent Kit
나는 이 패턴을 추출하여 작고 오픈 소스인 TypeScript 프레임워크로 만들었습니다:
github.com/ChoukeLee/agent-kit
단 4개의 파일로 구성되어 있습니다. 선택한 AI 제공자(AI provider) 외에는 의존성(dependencies)이 없습니다. Claude, OpenAI, DeepSeek 등 도구 호출(tool calling)을 지원하는 것이라면 무엇이든 작동합니다.
데모는 레스토랑 주문 봇입니다. 5분 안에 실행해 볼 수 있습니다:
npm install
export ANTHROPIC_API_KEY="your-key"
npx tsx smoke-test.ts
내가 배운 것
AI 제품을 만드는 것은 AI를 더 똑똑하게 만드는 것이 아닙니다. AI가 실수를 할 것이라는 점을 인정하고, 그 실수가 아무것도 해치지 못하도록 시스템을 설계하는 것입니다.
검증 벽 (Validation wall)은 단순한 안전망이 아닙니다. 그것은 하나의 설계 철학입니다:
- AI는 자신이 잘하는 일을 합니다: 모호한 인간의 언어를 이해하는 것
- 코드는 자신이 잘하는 일을 합니다: 100%의 신뢰성으로 규칙을 강제하는 것
- 그들은 정의된 인터페이스를 통해 통신합니다: 도구 호출 (Tool calls)은 결과를 반환하고, 검증 오류 (Validation errors)는 수정 사항을 반환합니다.
그 포스트잇은 여전히 제 화면에 붙어 있습니다. 만약 여러분이 AI 도구 호출 (Tool calling)을 사용하여 무언가를 만들고 있다면, 여러분의 화면에도 그것을 적어두세요.
저는 안전한 AI 도구 호출 (Tool-calling)을 위한 경량 프레임워크인 Agent Kit을 만들고 있습니다. 또한 AI 레스토랑 컨시어지인 Maison Gourmande도 개발 중입니다. 아비장에 거주하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기