본문 바로가기

클로드는 정말 당신의 이름을 기억하고 있을까? - LLM과 컨텍스트

2026.10.1614분 읽기
클로드는 정말 당신의 이름을 기억하고 있을까? - LLM과 컨텍스트

에이전트를 만든다고 가정하고 정중하게 자기소개를 해보자.

import anthropic

client = anthropic.Anthropic()

client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "내 이름은 영수야."},
    ],
)

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "내 이름이 뭐라고 했지?"},
    ],
)

print(response.content[0].text)
# 이전에 이름을 알려주신 적이 없어요.

세 줄 전에 알려준 이름을 모른다.

두 번째 호출을 받은 모델에게 첫 번째 호출은 존재한 적이 없다. 호출과 호출 사이에 모델이 들고 있는 건 아무것도 없다.

그런데 이상하다. 내가 쓰는 클로드와 코덱스는 내 직업이 뭐고 나이도 뭔지 다 알고 있던데, 어떻게 기억하는거지?

이름 하나 못 외우는 이 모델로 상담 챗봇을 만든다고 치고, 챗봇이 커 갈 때마다 어디서 사고가 나는지 보자.

매번 처음부터 다시 읽어 준다

영화 「메멘토」의 주인공은 새로운 기억을 몇 분 이상 붙잡지 못한다. 그래서 폴라로이드 사진에 메모를 적고, 중요한 건 몸에 타투로 새긴다. 눈을 뜰 때마다 그걸 보고 지금 상황을 다시 파악한다.

LLM 앱이 기억하는 방법도 크게 다르지 않다. 매번 지난 대화를 전부 다시 보낸다.

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "내 이름은 영수야."},
        {"role": "assistant", "content": "반가워요, 영수 님!"},
        {"role": "user", "content": "내 이름이 뭐라고 했지?"},
    ],
)

print(response.content[0].text)
# 영수라고 하셨어요.

이제야 이름을 부른다.

채팅 앱은 사용자가 메시지를 하나 보낼 때마다 그때까지 오간 대화 전체를 다시 묶어서 넘긴다. 모델은 매번 처음 보는 대화록 한 장을 받아 읽고, 그다음 말을 이어 쓴다. 서른 번째 메시지를 보낼 때도 첫 번째 인사부터 다시 읽는다.

이 대화록 한 장, 모델이 답을 만들 때 볼 수 있는 입력 전체를 컨텍스트(Context)라고 부른다.

말한 적 없는 이름을 부르는 챗봇

이 원리를 조금 뒤집어 보자. 모델은 대화록에 적힌 걸 그대로 믿는다. 그 말을 정말 사용자가 했는지는 확인하지 않는다.

그러면 사용자가 말한 적 없는 것도 적어 둘 수 있다. 쇼핑몰 상담 챗봇이라면 고객 정보를 미리 넣어 두는 식이다.

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=(
        "너는 쇼핑몰 상담원이야.\n\n"
        "[고객 정보]\n"
        "이름: 영수\n"
        "최근 주문: 운동화 270 사이즈 (배송 중)"
    ),
    messages=[
        {"role": "user", "content": "내 주문 어떻게 됐어?"},
    ],
)

print(response.content[0].text)
# 영수 님, 주문하신 운동화(270)는 지금 배송 중이에요.

고객은 이름도, 발 사이즈도 말하지 않았다. 그래도 챗봇은 안다.

Claude Code가 며칠 전 잔소리를 기억하는 것도 같은 수법이다. 지난 세션에서 "커밋 메시지는 영어로 써줘"라고 했는데, 새 세션을 열어도 영어로 쓴다.

Claude Code는 세션을 시작할 때 프로젝트의 CLAUDE.md 파일과, 이전 세션에서 스스로 적어 둔 메모리 파일을 읽어서 컨텍스트에 넣는다. 「메멘토」로 치면 CLAUDE.md는 몸에 새긴 타투고, 메모리 파일은 주머니 속 폴라로이드다. 모델은 이번 대화록 맨 앞에서 지난번에 남긴 메모를 읽고 있을 뿐이다. 그래서 그 파일을 지우면 Claude Code도 깨끗하게 잊는다.

이름을 외우게 할 때도, 고객 정보를 넣을 때도, Claude Code가 메모를 읽어 올 때도 원리는 하나다. 대화 기록이든 시스템 프롬프트든 파일에서 읽어 온 것이든, 모델에게는 전부 같은 대화록에 적힌 글자다.

실제 상담 챗봇은 여기에 훨씬 많은 걸 넣는다. 주문 조회 도구의 설명서, 환불 규정, 도구를 돌려서 받은 결과까지 같은 곳에 쌓인다. 고객이 "그럼 환불되나요?"라고 물었을 때 모델이 받는 컨텍스트를 상자로 그려 보면 이렇다.

┌──────────────────────────────────────┐
│ 시스템 프롬프트                        │  너는 쇼핑몰 상담원이야...
│                                      │  [고객 정보] 이름: 영수 ...
├──────────────────────────────────────┤
│ 도구 정의                              │  get_order(order_id): 주문 조회...
├──────────────────────────────────────┤
│ 환불 규정 문서                          │  구매 후 7일 이내...
├──────────────────────────────────────┤
│ 이전 대화                              │  user: 주문한 게 안 왔어요
│                                      │  assistant: 주문 번호를 알려주세요
├──────────────────────────────────────┤
│ 도구 실행 결과                          │  {"status": "배송 중", ...}
├──────────────────────────────────────┤
│ 지금 질문                              │  user: 그럼 환불되나요?
└──────────────────────────────────────┘

위를 쉽게 상자라고 표현해보자. 문제는 모델이 이 상자를 너무 믿는다는 데 있다. 「메멘토」의 주인공이 폴라로이드에 적힌 글씨를 의심하지 않듯, 상자에 틀린 게 들어 있어도 믿는다.

주문 상태가 하루 늦게 반영돼서 "배송 중"으로 남아 있으면, 고객 현관 앞에 이미 놓인 운동화를 두고 곧 도착할 거라고 안심시킨다. 환불 규정이 작년 버전이면 작년 기준으로 당당하게 답하고, 규정이 아예 빠져 있으면 그럴듯한 규정을 즉석에서 창작한다.

모델이 기댈 수 있는 건 학습하면서 익힌 지식과 이 상자 하나다. 학습된 지식은 우리가 고칠 수 없으니, 챗봇을 더 낫게 만들고 싶을 때 손댈 수 있는 곳은 사실상 이 상자뿐이다.

서른 번째 메시지

챗봇이 잘 돌아간다. 그러다 한 고객이 배송 문의로 시작해서 교환, 쿠폰, 회원 등급, 그리고 왜 이 쇼핑몰 앱은 다크 모드가 없는지까지 서른 번 넘게 메시지를 보낸다.

여기서 두 가지 일이 생긴다.

수다에 드는 비용

컨텍스트 길이는 토큰(Token)으로 센다. 토큰은 모델이 텍스트를 쪼개 읽는 단위로, 한국어는 같은 내용이라도 영어보다 토큰이 더 드는 편이다. (같은 말을 해도 돈이 더 든다는 뜻이다.)

API 요금은 입력 토큰 수에 비례한다. 그리고 앞에서 본 것처럼 매번 대화 전체를 처음부터 다시 보낸다. 한 번 주고받을 때 500토큰씩 늘어난다고 가정하면 이렇다.

대화 횟수이번 호출에 보내는 토큰지금까지 보낸 토큰 합계
1번째500500
10번째5,00027,500
30번째15,000232,500

모델이 첫 인사부터 성실하게 다시 읽는 동안, 그 비용은 고스란히 우리에게 온다. 호출 한 번의 값이 오르고, 누적 비용은 그보다 훨씬 빨리 불어난다. 읽을 게 많으니 첫 글자가 나오기까지 기다리는 시간도 길어진다.

매번 똑같이 들어가는 앞부분, 시스템 프롬프트나 환불 규정 같은 건 프롬프트 캐싱(Prompt Caching)으로 아낄 수 있다. 바뀌지 않는 내용을 앞쪽에 모아 두고 캐시하면 다음 호출부터는 그 부분을 훨씬 싸고 빠르게 처리한다. 새로 나온 모델들은 캐싱처리가 잘 되어있는 편이다.

컨텍스트에는 상한선도 있다. 컨텍스트 윈도우(Context Window)라고 부르는데, 요즘 모델은 수십만에서 백만 토큰까지 받는다. 넉넉해 보이지만 선을 넘으면 무언가를 버려야 한다.

세 시간째 회의

중요한 건 품질이다. 대화가 길어지면 챗봇이 초반에 고객이 했던 말을 슬슬 놓친다.

세 시간째 이어지는 회의를 떠올려 보자. 회의실에는 다 앉아 있지만 첫 번째 안건을 기억하는 사람은 별로 없다. 백만 토큰을 받아 준다는 것과 백만 토큰을 고르게 잘 읽는다는 건 별개의 문제다.

2023년의 「Lost in the Middle」 연구에서는 같은 정보라도 긴 컨텍스트의 앞이나 끝보다 가운데에 있을 때 모델의 정답률이 떨어졌다. 2025년 Chroma가 18개 모델을 실험한 「Context Rot」 보고서에서도 입력이 길어질수록 성능이 고르지 않게 떨어졌다. 문장을 그대로 따라 쓰는 것처럼 아주 단순한 작업도 예외가 아니었다.

Anthropic은 이걸 Attention Budget 이라고 부른다(「Effective context engineering for AI agents」). 모델이 한 번에 쏟을 수 있는 주의력은 정해져 있고, 토큰이 하나 늘 때마다 그 예산을 조금씩 나눠 쓴다. 다크 모드 하소연 3천 토큰이 쌓여 있으면 그만큼 지금 환불 질문에 갈 주의력이 줄어든다.

택배 하나 찾는데 JSON 2만 토큰

이번엔 챗봇에게 권한을 더 준다. 주문 조회에서 그치지 않고 배송사에 문의하고, 재고를 확인하고, 교환 신청서까지 직접 넣게 한다. 랭체인과 랭그래프 글에서 본 에이전트다.

에이전트는 도구를 부를 때마다 결과를 컨텍스트에 쌓는다. 택배가 어디 있는지 물었을 뿐인데 배송사 API는 물류센터 이동 이력 전체를 JSON으로 돌려주고, 재고 시스템은 비슷한 운동화 목록 마흔 개를 보내 준다. 도구를 스무 번 부르면 고객과 나눈 대화보다 도구 결과가 훨씬 길어진다. 고객은 다섯 마디 했는데 상자는 이미 터지기 직전이다.

이쯤 되면 무엇을 넣을지보다 무엇을 빼고 어디에 둘지가 더 중요해진다. 앞의 Anthropic 글이 소개하는 방법을 이 상담 에이전트에 하나씩 붙여 보자.

고객과 오래 이야기했으면 지난 대화를 요약한다. "고객은 3일 전 주문한 운동화의 배송 지연으로 문의했고, 교환을 원함. 사이즈는 270" 정도만 남기고, 나머지 대화와 다 쓴 도구 결과는 버린다. 다크 모드 얘기도 이때 조용히 사라진다. Anthropic은 이걸 압축(Compaction)이라고 부르고, Claude Code도 대화가 길어지면 이렇게 한다. LangChain의 SummarizationMiddleware가 하는 일도 같다. 어려운 건 무엇을 남기느냐다. 너무 줄이면 나중에야 중요했다고 밝혀지는 정보를 잃는다.

상담이 며칠에 걸쳐 이어진다면 중요한 내용은 컨텍스트 바깥에 적어 둔다. 교환 진행 상황, 고객이 원하는 연락 시간 같은 것들이다. 다음 상담이 시작될 때 그 메모만 읽어 오면 된다(구조화된 메모, Structured Note-taking). 앞에서 본 Claude Code의 메모리 파일, 그러니까 폴라로이드가 바로 이 방식이다.

주문 이력 1년 치를 뒤지는 일은 하위 에이전트에게 맡긴다. 하위 에이전트는 깨끗한 컨텍스트에서 시작해 주문 수백 건을 뒤지고, 상담 에이전트에게는 "최근 3개월 내 같은 상품 교환 이력 1건" 같은 한 줄만 돌려준다. 수백 건을 읽느라 쌓인 피로는 에이전트의 역할이다.

환불 규정, 교환 규정, 배송 규정을 처음부터 다 넣어 두지도 않는다. 규정 문서가 어디 있는지만 알고 있다가 필요할 때 찾아 읽는다(Just-in-time). 코딩 에이전트가 프로젝트 파일을 전부 읽고 시작하는 대신 grep으로 필요한 부분만 찾는 것과 같다. 문서가 많아지면 이 찾아 읽기를 검색 시스템으로 만드는데, 그게 RAG(곧 블로그에 소개하겠다)다.

포인트는 이거다. 지금 이 순간 모델 앞에 무엇을 놓아야 하는가.

컨텍스트 엔지니어링

한동안 LLM을 잘 쓰는 법이라고 하면 프롬프트 엔지니어링을 말했다. "너는 20년 차 시니어 상담원이야"라고 역할을 주고, "단계별로 생각해"라고 시키고, 예시를 몇 개 넣었다. 잘 듣는 주문을 찾아 외우던 시절이다.

상담 챗봇이 커 온 과정을 돌아보면 그 주문은 상자 맨 위 한 칸이었다. 그 아래로 도구 정의, 문서, 대화 기록, 도구 결과가 쌓였고, 사고는 대부분 아래 칸에서 났다. 주문을 아무리 공들여 외워도 환불 규정이 빠져 있으면 챗봇은 규정을 창작한다.

컨텍스트 엔지니어링이 중요해진다. 매 호출마다 모델 앞에 무엇을 놓을지 고르고, 넣고, 줄이고, 버리는 일 전체를 잘 설계해야 된다. Anthropic은 그 목표를 이렇게 적었다.

원하는 결과를 얻을 가능성을 가장 높이는, 가장 작은 고신호(high-signal) 토큰의 집합을 찾는다.

챗봇이 이상한 답을 내놓으면 시스템 프롬프트의 주문부터 고치고 싶어진다. 그 전에 그 순간 모델이 받은 컨텍스트를 그대로 찍어서 한번 읽어 보자. 프레임워크가 몰래 붙인 메모리, 쓰지도 않는 도구 정의 열 개, 2만 토큰짜리 배송 이력이 쌓여 있을 지도 모른다.

참고 자료

Zero's Blog

소프트웨어를 만들며 배우고 인생을 살면서 느끼는 것들을 기록해요.

© 2026 Yeongsu Han (zero). All rights reserved.