요약
모델이 좋아져도 컨텍스트 문제는 사라지지 않고 새로운 실패로 모양을 바꿉니다.
개발자 드루 브루니그가 AGNTCon 발표 내용을 글로 옮겼습니다. 그는 모델이 사람과 다르게 만들어졌기 때문에, 모델이 똑똑해져도 깔끔한 지시를 건네는 일은 계속 어렵다고 봤습니다.
왜 중요한가
- 긴 컨텍스트 창이나 오래 혼자 일하는 에이전트가 문제를 끝내 주리라는 기대에, 해법마다 새 실패가 따라온다고 답한 글입니다.
- 하네스(모델에 도구와 기억을 붙여 돌리는 실행 틀)를 만들 때는 무엇을 코드로 고정하고 무엇을 모델에 맡길지가 핵심이라고 짚었습니다.
핵심 내용
- 2025년에 정리한 네 가지 실패로 오염, 산만, 혼동, 충돌을 다시 소개했습니다.
- Gemini 2.5 Pro는 원작 포켓몬 레드를 하면서 리메이크판 파이어레드에만 나오는 아이스티를 몇 시간 찾아다녔습니다.
- 올해 새로 보이는 실패로 학습된 습관이 낯선 도구 사용을 막는 현상과, 한 가설에만 매달리는 '컨텍스트 관성'을 꼽았습니다.
- 코딩 에이전트가 이상하면 먼저 컨텍스트 크기를 보고, 20만 토큰 안팎에서 새로 시작하라고 권했습니다.
- 개인 에이전트에 쌓인 기억이 서로 충돌하므로, 다음 과제는 '전략적 망각'이 될 것이라고 내다봤습니다.
HN 반응
- 아이스티 사례를 두고 원인이 가중치에 있는데 왜 컨텍스트 오염이냐는 지적과, 환각이 할 일 목록에 들어간 순간 오염이라는 반론이 맞섰습니다.
- 최신 모델은 70만~80만 토큰까지 괜찮다는 경험담과, 대화가 길어지면 모델이 둔해져 인수인계 파일을 쓰고 직접 초기화한다는 경험담이 엇갈렸습니다.
이 글이 "컨텍스트가 너무 길다"는 희생양식 진단을 넘어서 이야기해 주는 점이 좋습니다.
컨텍스트 분량을 줄이는 것만이 전부는 아닙니다. LLM의 어텐션 메커니즘은 서로 관련된 단어와 개념의 그래프를 찾는 방식으로 작동하는데, 관련된 요소들이 텍스트 안에서 가까이 붙어 있을 때 가장 잘 작동합니다. 길이도 중요하지만, 정보가 얼마나 잘 정리되어 있는지도 그만큼 중요합니다.
의존 길이(dependency length)라는 개념을 알아 두면 유용합니다. 이 이미지( https://benoitessiambre.com/img/dependencylength.png )의 두 문장은 단어도 뜻도 같지만, 문장 C는 서로 관련된 단어 사이의 거리를 최소화하도록 구성되어 있습니다.
이는 문단과 절에도 적용됩니다. 관련된 정보가 재귀적으로 더 가까워지도록 순서를 배치하면 AI가 더 잘 생각하게 됩니다(사람에게도 도움이 됩니다. 의존 길이 최소화, 즉 DLM은 심리언어학에서 나온 개념입니다).
점진적 공개(progressive disclosure)와 서브 에이전트가 중요한 이유 중 하나가 이것입니다. 불필요한 정보를 넣으면 주변 정보들이 서로 멀어지고, AI가 상황을 파악하기가 더 어려워집니다.
예를 들어 스킬을 최적화할 때는 더 중요한 정보를 스킬의 맨 아래에 두면 도움이 될 수 있습니다. 보통 스킬이 로드되고 나면 AI는 "생각"을 시작하고, 혼잣말을 하면서 문제를 추론해 나갑니다. 생각 블록은 자기와 가장 가까운 텍스트, 즉 스킬의 마지막 부분을 위쪽에 있는 정보보다 훨씬 쉽게 고려합니다.
생각 블록은 많은 텍스트를 만들어 낼 수 있고(사용자에게는 대부분 숨겨져 있는 경우가 많습니다), 이 역시 정보를 서로 떨어뜨려 놓습니다. 초반에 준 지시가 여전히 유효한데 그 뒤로 생각과 대화가 컨텍스트에 많이 쌓였다면, 초반 정보를 요약해서 다시 말해 주는 것이 좋을 때도 있습니다(다만 리마인더가 너무 많아도 다른 정보들이 서로 멀어진다는 점은 염두에 두세요). 그런데 LLM은 시스템 프롬프트를 무시하지 않도록 아주 앞부분 정보에 가중치를 과하게 두게끔 튜닝되어 있다고 생각합니다. 이를 이용해 중요한 사실 몇 가지를 대화 맨 처음에 두는 방법도 가능할 겁니다.
반복되는 블록을 인코딩하는 대신 참조하게 만드는 압축 알고리즘을 짜 보셨다면, 관련된 정보가 한데 모여 있을 때 압축이 더 잘 된다는 것을 아실 겁니다. 지능과 압축 사이의 유사성을 보여 주는 또 하나의 사례이고, DLM의 정보 이론적 측면을 암시하기도 합니다.
그렇다면 이 두 부분은 서로 모순되는 것 아닌가요?
제 느낌으로는 컨텍스트 윈도우 맨 앞부분의 아주 좁은 영역만 인위적으로 가중치가 올라가 있고, 그 뒤로는 DLM이 중요해집니다.
솔직히 말씀드리면 이 정보는 Claude에게서 얻은 겁니다. 얼마 전에 Claude와 DLM에 관한 제 생각을 논의했는데, 대체로 제 생각에 동의해 주면서도(아첨이었을 수도 있습니다) 거리에 따라 효과가 순수하게 감쇠하는 분포가 아니라, 컨텍스트 윈도우 맨 앞에 작은 가중치 상승이 있어서 U자 형태라고 말해 주었습니다.
아주 많은 걸 깨우쳐 주는 댓글이네요, 감사합니다!
저는 VictorTaelin의 UniiChat 1 아이디어가 마음에 듭니다. 모든 메시지를 한 줄로 요약하고, 그 위에 하위 레벨의 줄들을 합쳐 만든 이진 트리를 올립니다. 그러면 컨텍스트는 이 트리를 들여다본 모습이 되는데, 최근 메시지는 더 자세하게, 오래된 메시지는 덜 자세하게 보여 주고, 에이전트가 트리를 돌아다니며 메시지를 읽을 수 있게 해 주는
zoom도구도 붙어 있습니다.pi 하니스를 기반으로 이 아이디어를 구현한 것입니다: https://github.com/jonaslsaa/pi-optchat
이 대목은 사람의 기억이 불완전한 이유를 설명해 줍니다. 우리가 LLM에게 바라는 완벽한 기억은 오히려 창의성을 가로막고 적응에도 불리한 것 같습니다.
전략적 망각은 이 비결정적인 기계를 가장 잘 활용하는 데 도움이 됩니다. LLM에게 완벽한 기억은 필요하지 않습니다. 그건 컴퓨터가 알아서 맡아 주니까요.
루프 엔지니어링 같은 흐름 속에서도 컨텍스트 엔지니어링이라는, 한물간 듯한 용어가 여전히 의미가 있다는 점을 이 대목이 뒷받침해 줘서 좋습니다.
사실 에이전트는 아직 Zettelkasten 이후로 설계할 게 많다고 생각해요. 추가만 가능한(append-only) 정책을 두고, 정원 가꾸듯 손질하면서 지식을 통합한다는 개념이거든요. 어느 정도 나오긴 했지만 제 생각엔 아직 잠재력이 엄청나게 남아 있어요.
저는 가벼운 티켓 시스템을 씁니다. 계획 단계에서 인수 조건이 포함된 아주 상세한 티켓을 만듭니다. 구현이 끝나면 앞으로의 작업에 관련된 정보를 티켓에 댓글로 갱신합니다. 플래너는 과거의 함정을 피하기 위해서, 그리고 관련 있을 만한 정보를 자기 컨텍스트에 넣기 위해서 이전의 관련 작업을 검색합니다. 서브 에이전트들이 빠르게 일에 적응하는 데도 잘 맞습니다.
좋네요. 사람이 리뷰할 때도 유용한가요, 아니면 주로 에이전트가 다룰 적절한 추상화를 갖추게 하려는 용도인가요?
아주 유익한 글이지만, 왜 굳이 용어를 새로 만드는 걸까요? 이런 현상과 전략은 LLM에만 해당하는 게 아니라 컴퓨터 과학(과 심리학)의 다른 분야에서 이미 잘 알려진 것들입니다. 예를 들어 저라면 "오프로딩"은 그냥 "스와핑"이라고, "혼란"은 그냥 "오염"이라고 불렀을 겁니다.
적어도 최신 모델에서는 이 말이 맞지 않는다고 봅니다. 게다가 모델은 (아마 대부분 코드베이스를 훑어보느라) 250k까지 아주 빨리 차오르는데, 그 컨텍스트가 없으면 모델 성능이 나쁩니다. 저는 컨텍스트가 700~800k쯤 되기 전에는 큰 변화를 느끼지도 못하고, 그때조차 예전만큼 나쁘지 않습니다. (특히 코딩에서는) 장기 과제를 다루는 RLVR 학습이 이 부분을 꽤 개선해 줬을 거라고 짐작합니다.
grep 대신 에이전트가 찾는 걸 찾아낼 때 쓸 수 있는 코드 인덱스를 두면 효과가 엄청난 것 같아요.
그건 인덱스가 무엇을 해 주느냐에 크게 달려 있습니다. 무엇을 목표로 하시나요? 단순히 심볼 조회인가요? 아키텍처 정보인가요? 데이터 흐름 시스템인가요?
저한테는 18유로짜리 앤트로픽 요금제에서 최대한 많은 작업을 뽑아내는 게 관건이에요. 그래서 컨텍스트가 300k 정도를 넘지 않게 하려는 거죠.
저는 이렇게 가격을 표기하는 게 정말 싫어요. 실제로는 22.5유로잖아요. 우리는 부가세 포함 가격을 표시한다고요. 이런 오해를 부르는 미국식 헛짓거리는 그만했으면 좋겠어요.
음, 이건 완전히 다른 것들을 뒤섞는 것 아닌가요? 제가 알기로 오염된 컨텍스트는 컨텍스트 안에 있는, 모델이 제대로 동작하지 못하게 만드는 내용이거든요. 그런데 그게 가중치에 있다면 그건 그냥... 모델 문제잖아요.
차를 가져와야 한다는 생각이 컨텍스트에 들어갔고, 일단 거기 들어가자 모델은 (차가 맞는 음료인지 의심하는 대신) 거기에만 매달렸다는 거예요.
발표의 이 마지막 문장이 정말 마음에 듭니다. 이 문장을 읽으면서, 제가 어떤 작업에 AI를 언제 어떻게 쓸지 가늠할 때 써 온 핵심 원리 중 하나를 정확히 짚었다는 걸 깨달았습니다. 저는 A) AI에게 그 작업을 대신 시키는 게 나은지, B) 그 작업을 해 줄 무언가를 AI에게 만들게 하는 게 나은지 고민할 때가 많은데, 그 답의 큰 부분은 그 작업이 얼마나 결정적인지 혹은 확률적인지에 달려 있습니다.
정보가 가중치에 있었는데 왜 이걸 컨텍스트 오염이라고 부르는지 이해가 안 됩니다.
차를 가져와야 한다는 정보는 가중치에 있었던 거고(그리고 잘못된 정보였죠. 레모네이드를 꺼냈어야 했습니다).
그 정보를 꺼낸 뒤 "아이스티"를 할 일 목록에 추가했고, 그게 컨텍스트에 들어갑니다. 그러자 모델은 그 생각에서 벗어나지 못한 거죠.
컨텍스트에 있는 "아이스티"는 증상이었고, 하류에 영향을 줬을 수는 있지만 그걸 입증하기는 어렵습니다. 근본 문제는 가중치에 있었고요. 이걸 '컨텍스트 오염'이라고 부르는 건 우리의 추론 컨텍스트를 오염시키는 거예요 :)
두 가지 다른 것을 혼동하고 계시네요.
모델은 차가 필요하다고 환각을 일으켰습니다.
그 환각이 컨텍스트에 들어간 순간 컨텍스트가 오염된 거고요.
이걸 믿고 싶지 않으시다면 제가 억지로 믿게 할 수는 없죠. 믿고 싶은 대로 믿으세요.
하지만 저는 (그리고 글쓴이는) 환각이 컨텍스트에 들어가는, 원래 잘 알려진 문제를 설명하고 있는 겁니다.
제 요점은, 컨텍스트 오염이라고 부르는 게 두 가지 이유로 헷갈린다는 겁니다. 첫째, 하류에 얼마나 인과적으로 영향을 줬는지 입증하기 어렵습니다. 둘째, 컨텍스트를 비워도 해결되지 않습니다. 다음 라운드에서 다시 오염될 테니, 맞서려면 능동적인 조치가 필요합니다.
눈치채지 못하셨겠지만 약간은 농담조이기도 합니다. 이름만 보면 다른 뜻 같아도, 필요하다면 이 모든 걸 설명할 수는 있으니까요.
아직도 헷갈리고 계시네요.
다음 라운드에서는 레모네이드라고 제대로 판단할 가능성이 높습니다.
환각은 보통 이상치입니다. 열 번 중 한 번은 헷갈려서 차를 고르는 거죠. 그 열 번 중 한 번이 오염된 컨텍스트로 이어집니다.
모델은 설계상 결정적이지 않습니다. 같은 입력에도 다른 출력이 나옵니다. 그래서 나쁜 출력을 뽑으면 컨텍스트가 오염될 수 있습니다. 컨텍스트를 비우면 문제는 쉽게 해결됩니다(포켓몬 하니스처럼 이전 컨텍스트의 요약을 넘겨주는 경우는 예외지만요).
일화적인 이야기이긴 하지만(표본 수 1), 저는 컨텍스트가 길어질수록 모델이 멍청해지는 걸 봤습니다. 저는 하니스 같은 걸 쓰는 고급 사용자가 아니라, 그게 제가 감당할 수 있는 전부라서 채팅 인터페이스만 씁니다. 그래도 몇 턴만 지나면 모델이(OAI와 앤트로픽의 최신 모델 얘기입니다) 더 멍청한 짓을 하는 것 같습니다.
DeepSeek v4.1 flash는 컨텍스트가 길어지면 지금 하던 작업을 마무리하고 "다음 세션"(그게 무슨 뜻인지 모르겠지만)에 다시 시작하자거나, "컨텍스트 예산"이 거의 다 됐다거나, 기억나지 않는 다른 표현으로 말하기 시작하더라고요.
저는 그냥 직접 인수인계 파일을 쓰게 하고 컨텍스트를 완전히 비웁니다. 하니스가 해야 할 컴팩션을 사실상 수동으로 하는 셈이죠. 이상한 기분이지만 효과는 있습니다.
컴팩션 요약을 생성할 만큼 윈도우가 남아 있을 때 정지 토큰을 내보내도록 학습된 거라고 생각해요.
저는 하니스가 끝날 무렵 모델에게 알림을 보내는 거라고 생각합니다. 적어도 Claude Code는 도구 호출 결과에 리마인더를 붙여서, 하니스가 직접 모델을 살짝 유도하도록 설계되어 있습니다.
그 ~규칙이 뭔지, 어떻게 작동하게 되어 있는지 아시는 분 있나요? 제 하니스가 그걸 처리하게 연결할 수 있다면 더 잘 작동할 것 같은데, 감이 안 옵니다. 모델 스스로도 학습 내용에서 그걸 모르는 것 같았어요. 아직 많이 검색해 보지는 않았습니다.
그게 바로 LLM 모델의 lost-in-middle 문제라고 합니다. 큰 컨텍스트를 다루려면 map/reduce 같은 적절한 워크플로 패턴을 써야 합니다. 다만 먼저 데이터셋으로 실험해서 어떤 로직이 잘 되고 안정적인지 파악하세요. 안 되는 게 뭔지도요! 그리고 프로덕션에서 LLM의 확률적 문제를 줄이려면 그것들을 어떻게 조합할 수 있는지도 봐야 합니다.