코딩 에이전트에게 필요한 것은 더 큰 메모리가 아니라 연속성일지도 모릅니다
요약
코딩 에이전트의 성능 향상을 위해 단순히 컨텍스트 윈도우를 키우는 것보다 실행 이력을 구조화된 프로젝트 상태로 보존하는 '연속성'이 중요함을 강조합니다. 에이전트가 세션 간 맥락을 놓치지 않도록 리포지토리 자체를 상태 보존의 장소로 활용해야 합니다.
핵심 포인트
- 컨텍스트 윈도우 확장과 실행 연속성은 서로 다른 개념임
- 단순한 메모리 증설은 비싼 쓰레기통을 만드는 결과를 초래할 수 있음
- 실패한 명령어, 중단된 지점 등 실행 이력의 구조화가 핵심임
- 리포지토리를 에이전트의 상태 보존을 위한 적절한 장소로 활용해야 함
코딩 에이전트가 세션 사이의 맥락을 놓치는 이유와 왜 리포지토리(Repository) 자체가 이를 보존하기 위한 적절한 장소인지에 대한 실무적 성찰.
나는 예전에 그 문제가 메모리(Memory) 때문이라고 생각했습니다. 그것은 명백한 진단이었습니다.
모든 새로운 코딩 에이전트(Coding-agent) 세션은 똑같은 의식과 함께 시작되었습니다. 리포지토리(Repository)를 엽니다. README를 읽습니다. 프로젝트 구조를 조사합니다. 중요해 보이는 파일들을 검색합니다. 작업을 재구성합니다. 어떤 명령어가 중요했는지 추측합니다. 이미 시도했던 것이 무엇인지 다시 묻습니다. 그러고 나서 실제 작업을 수행합니다.
가끔은 말이죠.
왜냐하면 많은 작업이 실제 작업이 아니었기 때문입니다. 그것은 방향 설정(Orientation)이었습니다.
코딩 에이전트가 거대한 컨텍스트 윈도우(Context window)를 가지고 있더라도 운영상의 맥락(Operational thread)을 놓칠 수 있습니다. 채팅 기록(Chat history)을 가지고 있더라도 지난 실행에서 무엇이 일어났는지 알지 못할 수 있습니다. 벡터 스토어(Vector store)에서 의미론적으로 유사한 노트들을 검색할 수 있어도, 정작 중요한 단 하나의 사실을 놓칠 수 있습니다:
- 이 명령어는 이미 실패했다.
- 이전 세션은 여기서 중단되었다.
- 이 파일이 관련 있어 보였지만, 막다른 길이었다.
- 검증(Validation)이 실제로 실행되지 않았다.
어느 날 나는 이 문제를 "에이전트 메모리(Agent memory)"라고 생각하는 것을 그만두었습니다. 그 단어는 너무 광범위했습니다. 너무 매력적이었고, 너무 위험했습니다.
왜냐하면 일단 메모리라고 말하는 순간, 더 큰 것을 만들고 싶은 유혹에 빠지기 때문입니다.
더 큰 컨텍스트 윈도우(Context window). 더 큰 노트 저장소. 더 큰 벡터 데이터베이스(Vector database). 에이전트가 보고, 말하고, 만지고, 생성하거나 막연하게 암시했던 모든 것에 대한 더 큰 아카이브(Archive).
그것은 강력해 보이지만, 동시에 매우 비싼 쓰레기통을 만드는 방법이기도 합니다.
컨텍스트(Context)는 연속성(Continuity)이 아닙니다
컨텍스트(Context)는 에이전트가 지금 사용할 수 있는 것입니다.
연속성(Continuity)은 다음 실행이 이전에 실제로 일어났던 일로부터 계속 이어질 수 있게 해주는 것입니다.
이 둘은 같은 것이 아닙니다.
긴 컨텍스트(Long context)는 세션이 살아있는 동안에는 도움이 됩니다. 모델이 작업할 수 있는 더 많은 텍스트를 제공합니다. 더 많은 파일. 더 많은 이전 메시지. 더 많은 구현 세부 사항. 더 많은 공간을 제공합니다. 비록 그것이 매우 유용할지라도, 그것이 자동으로 연속성을 만들어내지는 않습니다.
세션이 종료되거나, 압축(compacted)되거나, 다른 도구로 이동하거나, 한 코딩 에이전트(coding agent)에서 다른 에이전트로 전환되거나, 혹은 단순히 내일 새로운 프롬프트(prompt)로 시작할 때, 문제는 다시 발생하며 동일한 질문들이 제기됩니다:
- 무엇이 활성화되어 있었는가?
- 무엇이 변경되었는가?
- 무엇이 실패했는가?
- 무엇이 검증되었는가?
- 무엇이 단지 가정되었는가?
- 이전 실행(run)이 해결되지 않은 채로 남겨둔 것은 무엇인가?
더 큰 컨텍스트 윈도우(context window)는 더 많은 텍스트를 담을 수 있지만, 실행 이력(execution history)을 구조화된 프로젝트 상태(project state)로 변환해주지는 않습니다.
문제는 단순히 충분한 정보를 불러오는 것이 아닙니다. 문제는 올바른 종류의 정보를 보존하는 것입니다.
잘못된 추상화: "모든 것을 기억하라"
에이전트 메모리(agent memory)의 단순한 버전은 다음과 같은 모습입니다:
repository
↓
chat history
...
이 방식은 한동안은 작동합니다. 그러다 곧 부패하기 시작합니다.
요약(summaries)은 너무 광범위해지고, 노트(notes)는 오래되어 쓸모없게 됩니다. 오래된 가정들이 검증된 사실과 뒤섞여 남아 있고, 실패한 접근 방식이 성공한 방식과 동일한 시각적 비중을 가진 채 나란히 놓이게 됩니다.
에이전트는 관련 있어 보이는 무언가를 검색(retrieve)해오지만, 그것이 최신인지, 유용한지, 모순되는지, 아니면 단지 세 번 전 세션에서 발생한 그럴싸해 보이는 환각(hallucination)인지 아무도 알 수 없습니다.
이 지점이 바로 "더 많은 메모리"가 메모리가 없는 것보다 더 나쁠 수 있는 이유입니다. 왜냐하면 에이전트에게 필요한 것은 단지 관련 있는 정보가 아니라, 운영상 신뢰할 수 있는 정보이기 때문입니다.
일반적인 개념은 같을지 몰라도, 유용성 측면에서 메모리 항목(memory item)과 연속성 기록(continuity record)의 차이는 매우 큽니다. 하나는 회상(recollection)이고, 다른 하나는 인수인계(handoff)입니다.
다음과 같은 메모리 항목은 취약합니다:
토크나이저(tokenizer)를 변경함으로써 아마도 파서(parser)를 수정했을 것입니다.
다음과 같은 연속성 기록은 훨씬 더 강력합니다:
작업(Task): 파서 엣지 케이스(edge case) 수정
수정된 파일(Files edited): src/parser/tokenizer.py, tests/test_parser.py
실행된 명령(Command run): pytest tests/test_parser.py
...
지침(Instructions), 벡터 메모리(vector memory), 그리고 채팅 이력(chat history)만으로는 부족합니다
**리포지토리 지침 파일(Repository instruction files)**은 코딩 에이전트에게 다음과 같이 말해줄 수 있기 때문에 유용합니다:
테스트를 실행하는 방법
따라야 할 스타일
주요 모듈이 위치한 곳
...
이는 좋은 프로젝트 컨텍스트 (Project context)입니다. 하지만 지침 (Instructions)은 대부분 정적 (Static)입니다.
그것들은 저장소 (Repository) 내에서 작업하는 방법을 설명합니다. 하지만 보통 10분 전에 무슨 일이 일어났는지는 알지 못합니다.
그들은 작업이 일시 중단되었는지, 혹은 마지막 검증 (Validation)이 실패했는지 알지 못합니다. 이전 시도가 잘못된 레이어 (Layer)를 수정했다는 사실도 알지 못합니다. 사용자가 세션 (Session)을 중단하고 범위를 좁혔다는 사실도 인지하지 못합니다.
코딩 에이전트 (Coding agent)에게는 두 가지가 모두 필요합니다: 안정적인 지침 (Stable instructions)과 변화하는 작업 상태 (Changing work state).
하나만 있고 다른 하나가 없다면 불완전합니다. 그것들은 서로 다른 역할을 수행합니다.
지침은 에이전트가 저장소 내에서 더 잘 행동하게 만들고, 연속성 (Continuity)은 에이전트가 저장소 내에서 작업을 더 잘 지속하게 만듭니다.
**벡터 데이터베이스 (Vector databases)**는 의미론적으로 유사한 청크 (Chunks)를 검색하는 데 능숙합니다. 이는 다음과 같은 문제 상황에서 가치가 있습니다:
관련 문서를 찾아줘.
유사한 과거 노트를 찾아줘.
이 질문과 일치하는 대규모 지식 베이스 (Knowledge base)의 청크를 찾아줘.
하지만 코딩 에이전트의 연속성은 단순히 의미론적 검색 (Semantic retrieval) 문제만이 아닙니다.
가장 중요한 지속 관련 사실들은 종종 작고, 지루하며, 운영적인 (Operational) 것들입니다:
npm test가 TS2322 오류로 실패함
pytest가 tests/test_parser.py에 대해서만 통과함
마이그레이션 (Migration) 파일이 검토되었으나 수정되지는 않음
...
벡터 저장소 (Vector store)는 관련된 무언가를 검색할 수 있습니다. 하지만 연관성만으로는 충분하지 않습니다.
다음 세션에는 출처 (Provenance)가 필요합니다.
- 이것은 관찰된 것인가?
- 이것은 추론된 것인가?
- 이것은 에이전트에 의해 주장된 것인가?
- 이것은 검증되었는가?
- 이것은 나중에 모순되었는가?
- 이것은 여전히 최신 상태인가?
이 지점에서 일반적인 메모리 (Generic memory)는 취약해집니다. 의미론적 검색이 나쁘기 때문이 아니라, 실행 연속성 (Execution continuity)에는 라이프사이클 (Lifecycle), 타임스탬프 (Timestamps), 품질 신호 (Quality signals), 그리고 명시적인 증거 경계 (Explicit evidence boundaries)가 필요하기 때문입니다.
벡터 데이터베이스는 더 큰 시스템의 일부가 될 수 있지만, 그것을 시스템 그 자체로 오해해서는 안 됩니다.
**대화 기록 (Chat history)**은 지도의 또 다른 조각입니다. 대화 내용을 포함하고 있기 때문에 연속성처럼 느껴질 수도 있지만, 이 또한 충분하지 않습니다.
대화는 실행 상태 (Execution state)가 아니기 때문입니다.
그것은 유용한 사실들을 포함합니다, 맞습니다. 하지만 다음과 같은 것들도 포함합니다:
버려진 아이디어 (abandoned ideas)
중간 추론 (intermediate reasoning)
오래된 계획 (outdated plans)
...
다음 에이전트는 이 모든 것을 읽을 수 있지만, 여전히 무엇이 현재 사실인지 알지 못할 수 있습니다.
더 심각한 것은, 채팅 기록 (chat history)은 종종 하나의 제공자 (provider), 하나의 도구 (tool), 하나의 계정 (account), 하나의 세션 (session), 또는 하나의 UI에 종속된다는 점입니다.
하지만 리포지토리 (repositories)는 채팅보다 더 오래 지속됩니다.
중요한 상태 (state)는 프로젝트와 함께 존재해야 합니다.
연속성 (Continuity)은 대화에만 속해서는 안 됩니다. 그것은 리포지토리에 속해야 합니다.
리포지토리는 자연스러운 경계입니다
코딩 에이전트에게 리포지토리는 이미 운영 단위 (operational unit)입니다.
그 안에는 코드, 테스트, 빌드 시스템, 컨벤션 (conventions), 현재 브랜치 (current branch), 디프 (diff), 파일 구조, 명령어, 실패 사례, 그리고 작업의 결과물 (artifacts) 등이 포함되어 있습니다...
따라서 리포지토리는 연속성이 거주하기에도 적절한 장소로 보입니다.
연속성은 숨겨진 클라우드 메모리나 특정 제공자 전용의 블랙박스 (black box)가 되어서는 안 됩니다.
연속성은 로컬의 검사 가능한 결과물 (inspectable artifacts)로서 존재해야 합니다.
그것은 몇 가지 장점을 가집니다.
- 사용자가 이를 검토할 수 있습니다.
- 다른 호환 가능한 에이전트가 이를 읽을 수 있습니다.
- 연속성 계층 (continuity layer)을 정리, 수정, 압축하거나 무시할 수 있습니다.
- 메모리가 더 이상 하나의 채팅 세션 안에 갇혀 있지 않습니다.
- 시스템은 로컬 전용 운영 상태 (operational state)와 Git을 통해 공유될 수 있는 더 안전하고 이식 가능한 하위 집합 (portable subset)을 구분할 수 있습니다 (이는 팀 단위 작업에서 중요합니다).
코딩 에이전트가 세션 사이에 실제로 필요로 하는 것
대규모 프로덕션 코드베이스에서 리포지토리 로컬 연속성 런타임 (repo-local continuity runtime)을 여러 차례 반복하여 작업해 본 결과, 유용한 요소들이 훨씬 더 명확해졌습니다.
새로운 세션에는 회고록 (memoir)이 필요한 것이 아니라, 압축된 실행 표면 (execution surface)이 필요합니다.
다음과 같은 형태 말입니다:
재개 (resume)
-> 활성 작업 상태 (active work state)
-> 관련 결정 사항 (relevant decisions)
...
그다음 에이전트가 작업을 수행합니다.
그리고 마지막으로 에이전트는 해당 세션에서 중요한 사항들을 기록합니다:
작업 (work)
-> 수정된 파일 (files touched)
-> 실행된 명령어 (commands executed)
...
그러면 다음 세션은 그 지점부터 재개됩니다.
단순한 느낌(vibes)이 아닙니다. "우리가 인증(auth) 관련 작업을 하고 있었던 것 같아요"라는 식의 기억도 아닙니다. 40개의 메시지가 쌓인 채팅 기록도 아닙니다.
명시적인 운영 연속성 (operational continuity)을 통해, 루프는 다음과 같이 단순해집니다:
재개 (resume) -> 작업 (work) -> 마무리 (finalize) -> 재개 (resume)
이 루프는 그 어떤 개별적인 메모리 기능보다 더 중요하다는 것이 밝혀졌습니다.
생명 주기 (lifecycle)가 없다면, 메모리는 수동적입니다. 기다리고, 축적될 뿐입니다... 결국 고고학 유물이 되어버립니다.
생명 주기가 있다면, 메모리는 실행 (execution)의 일부가 됩니다.
에이전트는 제한된 상태 (bounded state)에서 시작하여, 작업을 수행한 뒤, 다음 실행을 위한 사실적 근거 (factual evidence)를 기록합니다.
이것이 문제의 형태를 바꿉니다.
유용한 메모리는 작다
이것은 직관에 반하는 것이었습니다.
연속성 계층 (continuity layer)이 개선될수록, 저는 오히려 더 적은 양의 정보를 반환하기를 원했습니다.
처음에는 결정 사항, 인수인계 (handoffs), 파일, 노트 등 모든 것을 더 많이 불러오려는 본능이 있었습니다... 컨텍스트 (context)가 다시 무겁게 느껴질 때까지 말이죠. 포장 방식만 다를 뿐, 문제는 동일했습니다.
그래서 목표가 바뀌었습니다.
연속성 계층은 쓸데없는 재발견 (rediscovery)을 최소화해야 합니다.
즉, 최적의 재개 페이로드 (resume payload)는 가장 큰 것이 아닙니다. 에이전트가 아무런 준비 없이 시작하는 것 (starting cold)을 방지할 수 있을 만큼 충분한 운영적 근거 (operational grounding)를 제공하는 것입니다.
좋은 재개 정보는 다음 질문에 답할 수 있어야 합니다:
무엇이 활성화되어 있는가? (What is active?)
어디서 시작해야 하는가? (Where should I start?)
무엇을 반복하지 말아야 하는가? (What should I avoid repeating?)
...
그게 전부입니다. 나머지는 필요할 때 (on demand) 사용할 수 있습니다.
에이전트는 파일 하나를 건드리기 전에 전체 기억의 궁전 (memory palace)을 가질 필요가 없습니다. 적절한 문 (the right door)이 필요할 뿐입니다.
연속성에는 출처 (provenance)가 필요하다
가장 강력한 교훈 중 하나는 연속성의 품질이 메모리의 양보다 중요하다는 것입니다.
진실의 원천 (source of truth)은 메모리, 오래된 인수인계 정보, 또는 이전 에이전트의 요약에 의존해서는 안 됩니다.
만약 연속성 계층이 "이것은 오래되었습니다", "이것은 검증되지 않았습니다", "이것은 등급이 낮아졌습니다", 또는 "이것은 검증 근거가 부족합니다"라고 말할 수 없다면, 그것은 너무 신뢰에 의존하는 것이며 위험합니다.
더 강력한 모델은 증거 가중 연속성 (evidence-weighted continuity)입니다:
런타임 (runtime)에서 이를 관찰함
에이전트가 이를 주장함
검증 (validation)이 이를 뒷받침함
...
그러한 프레이밍은 에이전트의 목표를 '메모리를 믿는 것'에서 '적절한 가중치를 가지고 사용하는 것'으로 변화시키기 때문에, 메모리와 에이전트의 관계를 변화시킵니다.
훌륭한 연속성 계층 (continuity layer)은 불확실성 (uncertainty)을 가시화해야 합니다. 왜냐하면 숨겨진 불확실성이야말로 잘못된 연속성이 시작되는 지점이기 때문입니다.
이를 구축하려 했을 때 무엇이 변했는가
이 도구는 처음부터 완전한 연속성 런타임 (continuity runtime)으로 시작된 것이 아닙니다. 더 단순한 아이디어에서 시작되었습니다:
재사용 가능한 컨텍스트 (context)를 프롬프트 (prompt) 밖으로 이동시킨다.
그 후 각 계층은 이전 계층의 약점을 드러냈습니다. 문제는 기능을 추가하는 것이 아니라, 어떤 종류의 상태 (state)가 실제로 중요한지를 발견하는 것이었습니다:
- 외부 메모리 (External memory)는 반복을 해결했지만, 노이즈 (noise)를 유발했습니다.
- 구조화된 컨텍스트 (Structured context)는 노이즈를 줄였지만, 여전히 실행 상태 (execution state)가 부족했습니다.
- 실패 메모리 (Failure memory)는 고통스러운 지점을 포착했지만, 활성 작업 (active work)을 포착하지는 못했습니다.
- 작업 상태 (Work State)는 활성 작업을 포착했지만, 검증 의미론 (validation semantics)이 필요했습니다.
- 실행 계약 (Execution contracts)은 가이던스 (guidance)를 추가했지만, 품질 및 준수 신호 (quality and compliance signals)가 필요했습니다.
- MCP는 접근성을 개선했지만, 안전 경계 (safety boundaries)가 필요했습니다.
- 가드레일 (Guardrails)은 행동 경계 (action boundaries)에서 도움이 되었지만, 컴팩트 (compact)하게 유지되어야 했습니다.
시간이 흐르면서 방향은 더 명확해졌습니다:
덜 일반적인 메모리 (less generic memory)
더 운영적인 연속성 (more operational continuity)
더 적은 숨겨진 상태 (less hidden state)
...
이것이 핵심적인 아키텍처적 교훈입니다.
실패 메모리가 첫 번째 진정한 전환점이었습니다
성공적인 작업을 기억하는 것보다 실패를 기억하는 것이 종종 더 유용합니다.
코딩 에이전트는 그럴듯한 실수를 반복함으로써 많은 시간을 낭비합니다.
- 이름이 맞는 것처럼 보여서 잘못된 파일을 엽니다.
- 이전에 실패했던 동일한 명령어를 실행합니다.
- 에러 메시지가 흔한 것과 유사하다는 이유로 동일한 수정 시도를 합니다.
- 두 세션 전에 포기했던 경로를 따릅니다.
실패 메모리 계층은 이를 변화시킵니다.
"다시는 이렇게 하지 마"라고 말함으로써가 아니라, 다음과 같이 말함으로써 말입니다:
이것은 이전에 실패했습니다.
여기에 명령어가 있습니다.
여기에 에러가 있습니다.
...
마지막 문장이 중요한 이유는 실패 메모리가 에이전트를 리포지토리 (repo)에 대해 두렵게 만들어서는 안 되기 때문입니다. 대신 에이전트를 덜 순진하게 (less naive) 만들어야 합니다.
이 둘 사이에는 차이가 있습니다.
Work State가 모델을 변화시킵니다
실패 메모리 (failure memory)가 반복되는 마찰을 처리한다면, Work State는 완료되지 않은 작업을 처리합니다.
그 차이는 필수적입니다.
인수인계 요약 (handoff summary)은 유용하지만, 그것이 활성 작업 (active task)과 동일한 것은 아닙니다.
결정 기록 (decision record)은 유용하지만, 그것이 중단된 실행 (suspended execution)과 동일한 것은 아닙니다.
실패 패턴 (failure pattern)은 유용하지만, 그것이 "우리는 현재 이 변경 사항의 중간 단계에 있으며 검증이 아직 대기 중이다"라는 것과 동일한 것은 아닙니다.
Work State는 살아있는 스레드 (live thread)를 보존해야 합니다:
task (작업)
hypothesis (가설)
relevant files (관련 파일)
...
이 지점에서 연속성 (continuity)은 기록용이 아닌 운영적인 (operational) 느낌을 주기 시작합니다.
실행 계약 (Execution contracts)은 관료주의가 아닙니다
연속성은 과거를 설명하는 것 이상의 역할을 해야 합니다. 그것은 다음 실행을 형성해야 합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기