
AI 에이전트의 환각(Hallucination) 방지: 에이전트가 메모리에 기록하기 전에 검증하기
요약
AI 에이전트가 환각을 일으켜 잘못된 데이터를 메모리에 기록하는 문제를 방지하기 위한 'Memory Guardrails' 기법을 소개합니다. 데이터가 스토어에 저장되기 전 스키마 검증을 통해 오류가 영구화되는 것을 막는 방법을 다룹니다.
핵심 포인트
- 에이전트의 메모리 환각은 잘못된 컨텍스트를 영구화하여 이후 세션에 악영향을 미침
- 잘못된 데이터 저장 시 지속적인 토큰 비용 낭비와 신뢰도 저하 발생
- BeforeToolCallEvent와 같은 결정론적 훅을 사용하여 쓰기 작업 전 검증 필요
- 스키마 기반 검증을 통해 유효한 데이터만 에이전트 상태에 기록 가능
💻 이 시리즈의 모든 코드는 단일 리포지토리에 있습니다: resilient-agent-harness-sample-for-aws. 이 포스트는 Memory Guardrails (
01-memory-guardrails)의 데모입니다. 리포지토리를 클론하고 단계별 안내를 따르세요.
언어 모델(Language Model)이 환각(Hallucination)을 일으키면 한 번 수정하면 됩니다. 하지만 _에이전트(Agent)_가 환각을 일으키면, 잘못된 데이터를 자신의 메모리에 기록하고, 이후 이어지는 모든 세션에서 그 데이터를 신뢰할 수 있는 컨텍스트(Context)로 다시 읽어들입니다. 오류가 영구적이 되어버리는 것입니다.
이것이 바로 아무도 경고해주지 않는 함정입니다. 에이전트의 메모리는 곧 컨텍스트입니다. 스토어(Store)에 도달하는 무엇이든 다음번에 프롬프트(Prompt)로 다시 로드됩니다. 따라서 모델이 아무도 정의하지 않은 값을 지어내어 저장하는 날에는, 에이전트가 단순히 답변을 틀리는 것에 그치지 않고, 그 쓰레기 데이터를 향후 모든 대화에서 진실로 다시 로드하며, 매번 이를 다시 읽기 위해 토큰(Token) 비용을 지불하게 됩니다. 더 나은 프롬프트도 여기서는 당신을 구원할 수 없습니다. 잘못된 데이터가 이미 에이전트가 신뢰하는 스토어 안에 들어있기 때문입니다. 기록하는 순간에 이를 막아야 합니다.
구체적인 실행을 위해, 저는 작은 여행 에이전트를 구축하고 의도적으로 그 메모리를 망가뜨리려 시도했습니다. 처음부터 끝까지 실행 가능한 전체 데모는 resilient-agent-harness 리포지토리에 있습니다.
아래 다이어그램이 전체적인 개념을 보여줍니다: 모델이 추출 과정에서 데이터를 환각(Hallucination)할 수 있지만, 결정론적 훅(deterministic hook)인 BeforeToolCallEvent가 해당 쓰기 작업을 스키마(schema)에 따라 검증하며, 유효하지 않은 쓰기 작업은 agent.state에 도달하기 전에 취소됩니다. 따라서 검증된 데이터만이 다음 세션에 지속(persist)됩니다.
데모는 무엇인가요?
이 에이전트는 Strands Agents로 구축되었으며 두 가지 도구(tool)를 가지고 있습니다:
book_flight: Duffel 샌드박스에서 실제 요금을 검색하고 예약 정보를 에이전트의 메모리에 저장합니다.recall_bookings: 에이전트가 저장한 내용을 읽어옵니다.
메모리는 에이전트의 네이티브 agent.state이며, FileSessionManager를 통해 디스크에 영구 저장됩니다. 여기서 Strands의 진가가 처음으로 드러납니다. 저는 스토리지 계층(storage layer)을 직접 작성한 적이 없습니다. 동일한 session_id를 사용하여 새로운 Agent를 구축하면, 디스크로부터 이전 상태와 메시지 히스토리를 자동으로 복구합니다. 이는 이 데모에서
메모리 가드레일 (Memory guardrail)은 AI 에이전트가 행동하고 메모리에 기록하기 전에 실행되는 결정론적 (deterministic) 체크입니다. 이는 데이터를 스키마 (schema)에 따라 검증하고, 일치하지 않을 경우 호출을 취소하여 도구가 잘못된 입력값으로 실행되지 않도록 하고 깨끗한 데이터만 저장되도록 합니다. 환각된 데이터는 애초에 기록되지 않기 때문에 영구적인 메모리로 전환되지 않습니다.
핵심 키워드는 _결정론적 (deterministic)_입니다. 우리는 두 번째 모델에게 "이것이 괜찮아 보이나요?"라고 묻는 것이 아닙니다. 그렇게 하면 환각을 일으킬 수 있는 요소를 하나 더 추가하는 꼴이 됩니다. 대신 우리는 동일한 입력에 대해 항상 동일한 판결을 내리는 순수 Python 기반의 검증을 실행합니다.
가드레일은 어떻게 작동하나요?
Strands에서 이를 위한 네이티브한 위치는 BeforeToolCallEvent 훅 (hook)입니다. 이는 메모리 쓰기 도구가 실행되기 전에 실행되며, 호출을 취소할 수 있습니다:
# guardrail.py — 훅이 예약(booking) 도구 실행 '전'에 실행되어 유효하지 않은 쓰기를 취소합니다.
from strands.hooks import BeforeToolCallEvent, HookProvider, HookRegistry
...
validate_entry는 순수 Python으로 작성되었습니다. 훅은 이를 위한 얇은 어댑터 역할을 합니다. 스키마 (FLIGHT_SCHEMA, 데모 기준)는 에이전트의 현실 정의입니다. 필수 필드가 존재해야 하고, 숫자는 숫자여야 하며, 날짜는 YYYY-MM-DD 형식을 갖춰야 하고, 객실 등급은 허용된 집합 내에 있어야 하며, 알 수 없는 필드는 거부됩니다. 여기서 Strands의 강점이 두 번째로 드러납니다. 훅을 한 번만 등록하면 도구의 코드를 수정하지 않고도 사용자가 직접 작성하지 않은 도구를 포함하여 모든 메모리 쓰기 도구를 제어할 수 있습니다. 모델이 추출 과정에서 얼마든지 환각을 일으키더라도, 게이트 (gate)가 무엇을 메모리로 전환할지 결정합니다.
왜 더 나은 프롬프트 대신 훅을 사용하나요?
시스템 프롬프트 (system prompt)에 포함된 지침은 모델이 무시할 수 있는 요청이며, 압박을 받는 상황에서는 실제로 무시될 수 있습니다. 반면 훅 (hook)은 강제적인 적용입니다. 만약 훅이 쓰기 작업을 취소하면, 모델이 무엇을 결정했는지와 상관없이 도구 (tool)는 실행되지 않습니다. 가드레일 (guardrail)의 '결정'은 결정론적 (deterministic)이지만, 모델이 특정 실행에서 잘못된 데이터를 생성하는 것은 결정론적이지 않습니다. 이것이 바로 프롬프트가 아닌 훅이 프로덕션 (production) 환경에 적용되는 정확한 이유입니다.
전과 후: 두 에이전트, 한 줄의 차이
저는 동일한 시나리오를 두 가지 방식으로, 즉 두 개의 분리된 에이전트로 실행합니다. 독자가 볼 수 있는 유일한 차이점은 hooks=[guardrail]입니다. 동일한 모델, 동일한 두 개의 도구, 동일한 프롬프트, 동일한 세션입니다.
여행자가 존재하지 않는 "ultra" 캐빈 클래스 (cabin class)를 예약해 달라고 요청합니다 (허용된 집합은 economy, premium_economy, business, first입니다).
가드레일이 없는 에이전트 #1은 단순히 book_flight를 호출합니다. 결코 유효할 수 없는 요청에 Duffel API의 실제 호출을 소모하고, 잘못된 "ultra" 예약을 agent.state에 저장합니다. 그리고 이 데이터는 재시작 후에도 살아남습니다. 동일한 session_id를 가진 완전히 새로운 에이전트가 디스크에서 이를 직접 다시 불러옵니다. 회상 (recall)을 수행할 때, 에이전트는 이 잘못된 예약을 진실로 읽고 사용자에게 비용을 청구합니다.
가드레일이 있는 에이전트 #2 (hooks=[guardrail])는 유효하지 않은 book_flight가 실행되기 전에 이를 취소합니다. API 호출이 소모되지 않으며, 아무런 잘못된 데이터도 저장되지 않습니다. 에이전트는 여행자에게 캐빈 클래스가 유효하지 않다고 알리고 실제 클래스를 요청합니다. 여행자가 이를 economy로 수정하면, 오직 그 유효한 예약만이 저장됩니다. 동일한 재시작 이후에도 메모리에는 단 하나의 깨끗한 예약만 남게 됩니다.
노트북은 각 실행 시 Strands 메트릭 API의 실제 토큰을 측정합니다. 다음은 제 실행 결과입니다 (사용자의 수치는 실행 및 모델에 따라 달라질 수 있으며, 이것이 직접 실행해 보아야 하는 이유입니다):
| SIN hook | CON hook | |
|---|---|---|
| 재시작 후 예약 (reservas después del reinicio) | 2 (하나는 "극도로" 나쁨) | 1 (유효한 것만) |
| 회상 토큰 (recall tokens) | 1,871 | 1,213 |
가드레일 (guardrail)을 적용한 에이전트는 토큰을 약 35% 적게 사용하면서도 올바른 예약을 반환합니다. 잘못된 데이터가 다시 읽히도록 메모리에 입력되지 않았기 때문입니다. 가드레일이 없는 에이전트는 존재해서는 안 될 예약을 다시 불러오기 위해 더 많은 비용을 지불합니다. 여러분의 모델과 여행자 입력값으로 직접 실행해 보며 동일한 양상이 나타나는지 확인해 보세요.
스키마 가드레일 (schema guardrail)이 잡아낼 수 없는 것
스키마는 구조 (structure) 오류를 차단합니다: 잘못된 타입, 존재하지 않는 옵션, 합리적인 범위를 벗어난 가격, 정의되지 않은 필드 등이 이에 해당합니다. 하지만 스키마는 그럴듯하지만 틀린 값 (plausible-but-incorrect value), 예를 들어 형식은 완벽하게 유효한 숫자이지만 해당 경로에는 맞지 않는 요금과 같은 오류는 잡아낼 수 없습니다. 이것은 실제적인 한계이며, 데모는 과장하는 대신 이 점을 명시하고 있습니다. 이러한 경우를 위해 샘플에서는 실제 캡처된 요금과 실제 정답 (ground truth)을 대조하는 두 번째 선택적 계층인 교차 검증 (cross-check)을 추가했지만, 스키마만으로는 잘못된 의미론 (semantics)을 잡아낼 수 없습니다.
자주 묻는 질문 (FAQ)
이것이 모든 환각 (hallucination)을 막아주나요?
아니요. 이것은 환각된 데이터가 신뢰할 수 있는 컨텍스트로서 저장되고 다시 읽히는 것을 막아줍니다. 이것이 바로 오류를 증폭시키는 근본적인 결함입니다. 모델은 여전히 개별 응답에서 환각을 일으킬 수 있지만, 가드레일은 그 오류가 영구적인 메모리가 되는 것을 방지합니다.
왜 두 번째 모델로 검증하지 않나요?
두 번째 모델을 추가하는 것은 똑같이 실수할 수 있는 또 다른 비결정론적 (non-deterministic) 구성 요소를 추가하는 것이기 때문입니다. 스키마 체크는 결정론적 (deterministic)이며, 동일한 입력에 대해 항상 동일한 판결을 내리고, 순수 파이썬 (Python)만으로 구현 가능하여 비용이 저렴합니다.
이것은 OpenAI에서만 작동하나요, 아니면 AWS에서만 작동하나요?
둘 다 아닙니다. Strands는 모델에 구애받지 않습니다 (agnostic): 통합 모델 인터페이스 (unified model interface)를 통해 제공자를 교체할 수 있으므로, 동일한 코드가 Amazon Bedrock (SDK 기본값), Anthropic, OpenAI 또는 Ollama를 통한 로컬 모델에서 실행됩니다. 이 데모는 테스트를 위해 API 키만 있으면 되기 때문에 기본적으로 OpenAI gpt-4o-mini를 사용하지만, 이는 여전히 클라우드 호출이며 사용자의 로컬 머신에 있는 모델은 아닙니다. 프로덕션 환경에서는 동일한 훅 (hook)을 Amazon Bedrock AgentCore Memory와 같은 내구성이 있는 저장소 (durable store) 앞에 변경 없이 배치할 수 있습니다.
직접 실행해 보세요
가드레일 (guardrail)이 있는 에이전트와 없는 에이전트 두 가지를 포함한 전체 데모, 실제 세션 재시작, 그리고 토큰 (token) 비교는 하나의 실행 가능한 노트북 (notebook)으로 구성되어 있습니다. 리포지토리 (repo)를 클론 (clone)하고 실행하세요:
git clone https://github.com/elizabethfuentes12/resilient-agent-harness-sample-for-aws.git
cd resilient-agent-harness-sample-for-aws/01-memory-guardrails
...
노트북을 선호하시나요? test_memory_guardrails.ipynb를 열고 위에서 아래로 실행하세요.
이 패턴은 Governed Memory (Taheri, 2026년 3월)를 따릅니다. 벤치마크 (benchmark) 수치와 전체 내용은 리포지토리의 README에 있습니다. 이 데모가 재현하는 것은 메커니즘입니다: 쓰기 전에 도구의 경계 (frontier of tools)에서 검증하는 것입니다.
프로덕션 환경에서 당신을 괴롭혔던 환각 (hallucination)은 무엇이었나요: 지어낸 필드, 잘못된 열거형 (enum), 혹은 보기에는 괜찮았지만 실제로는 아니었던 값이었나요? 댓글로 알려주세요.
감사합니다!
🇻🇪 Dev.to Linkedin GitHub Twitter Instagram Youtube
[

](/elizabethfuentes12)
Elizabeth Fuentes L팔로우
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기