1편에서 에이전트 메모리를 끝까지 파기로 다짐한 이야기를 적었습니다. 이번 편은 만든 이야기입니다. 그리고 만든 것들이 부서진 이야기입니다.

모든 에이전트가 배운 것을 공유한다면

만들기로 했으니 시장부터 봤습니다. 생각보다 제품이 많았습니다. 나온 지 몇 년 된 것도 있었습니다. 차별점이 필요했고, 그러다 이런 상상을 했습니다. 모든 에이전트가 자기가 배운 것을 서로 공유할 수 있다면? 그 효과를 상상하니 심장이 뛰기 시작했습니다. 바로 작업에 들어갔습니다. 에이전트끼리 메모리를 공유하는 플랫폼, Memory Network. 줄여서 모넷입니다.

밤낮없이 만들었습니다. 집 작업 머신에, 코다에, 회사에까지 설치하고 도그푸딩을 시작했습니다. 파일 기반 메모리와는 질이 다른 느낌이었습니다. 만족스러웠지만 조금 부족했고, 제품과 하네스를 조금씩 고치며 완성해 갔습니다.

그러다 갑자기 의문이 들었습니다. 기억을 다른 사람과 공유한다? 물론 에이전트가 쓰는 메모리입니다. 근데 그 기억은 나와 에이전트가 주고받은 상호작용의 기록이기도 합니다. 코다가 저장한 메모리를 보면 더욱 그랬고, 회사와 집의 업무용 메모리에도 나에 대한 기록이 여기저기 있었습니다. 공유의 효과에만 눈이 가서, 다른 것을 보지 못하고 있던 겁니다.

켄을 만나다

모넷을 다 만들고 써줄 사람들을 찾아다녔습니다. 소개글 올릴 곳을 찾다 Dev.to에 글을 올렸고, 거기서 LLM 메모리에 진심인 켄(Ken W Alger)의 을 읽었습니다. 댓글로 대화가 시작됐는데, 뎁스가 점점 깊어졌습니다.

주제는 지금 챗 제품들의 태생적인 구조였습니다. 대화 기록 전체를 매 턴 모델에 다시 보내는, 트랜스크립트 기반 구조. 그 스레드에서 저는 이렇게 적었습니다. 에이전트에게 넘겨야 할 것은 말해진 것이 아니라 지금 알고 있는 것이다(“not what was said, but what is now known”). 켄의 답은 짧았습니다. “Exactly right.”

사람의 대화가 그렇습니다. 우리는 상대의 단어를 하나하나 곱씹으며 대화하지 않습니다. 이해한 것을 저장하고, 그걸 바탕으로 답합니다. 그래서 가설이 하나 섰습니다. 대화를 메모리로 정리해 저장하고 필요할 때 그 스테이트를 모델에 주면, 노이즈가 줄고 엉뚱한 답도 줄 것이다.

아무것도 하지 않는 메인 에이전트

정말 궁금했습니다. 바로 실험에 들어갔습니다. 당장 스테이트 코드를 만들 수는 없어도, 스테이트 기반 하네스는 만들 수 있었습니다. 메인 에이전트는 스테이트와 메모리만 맡습니다. 전체 업무의 스테이트, 서브에이전트들의 작업 스테이트, 작업 중에 나오는 기억 조각들. 실제 작업은 딱 필요한 컨텍스트만 받은 서브에이전트가 합니다. 이 실험에서 중요한 건 메인 에이전트가 정말 아무 작업도 안 하는 것이었습니다.

결과는 생각보다 좋았습니다. 작업의 경중에 따라 모델을 골라 쓰니 비용도 크게 줄었습니다. 확신이 들었고, 접어뒀던 Brain_DB가 다시 떠올랐습니다. Brain_DB가 메모리가 되고 하네스가 스테이트 모델이 되면, 스테이트 기반의 새로운 코딩 에이전트를 만들 수 있겠다.

2주 만에 나온 새 모넷

일단 Brain_DB를 쓴 메모리 제품부터 만들기로 했습니다. 공유는 미래 기능으로 미뤄두고 기존 모넷을 정리했습니다. Brain_DB 컨셉의 엔진을 만들고 그 위에 MCP를 붙였습니다. 마침 나온 Claude의 새 모델 Fable의 도움으로, 2주 만에 실제로 쓸 수 있는 제품이 나왔습니다. 기존 모넷의 기억은 전부 이식했고, 하네스도 더 날카롭게 손봤습니다. 메인 에이전트의 이름은 Stig로 지었습니다.

첫인상은 놀라웠습니다. 세션 컨텍스트 사용량이 30%를 넘으면 일부러 새 세션을 열었습니다. 그만큼 메모리에 자신이 있었습니다. 대부분의 작업은 사용량 20% 안에서 끝났습니다. 그렇게 도그푸딩이 다시 시작됐고, 제품이 마음에 들었습니다.

회사에서는 아무것도 동작하지 않았다

그 무렵 회사에서는 큰 프로젝트가 하나 마무리됐고, 팀 리더가 자신의 세컨 브레인을 팀에 소개했습니다. 에이전트가 지난 세션을 읽고 의미 있는 내용을 md 문서로 정리해 깃으로 공유하는 방식이었습니다. 이미 많은 문서가 쌓여 있었고, 누구든 그 리포를 받아 에이전트가 읽게 하면 됐습니다. 모넷의 공유 기능은 뾰족한 수가 없던 차였는데, 깃에 md를 올려 공유하는 이 방식이 생각보다 효과적이었습니다.

그래서 md 파일을 읽어 모넷의 메모리로 처리하는 기능을 만들기로 했습니다. 이건 선택이 아니라 필수였습니다. 그래야 에이전트가 모넷 하나로 기존 메모리와 md에 있던 정보를 같이 읽을 수 있으니까요. 빠르게 디자인을 끝내고 작업에 들어갔습니다. 대체로 순조로웠지만 생각보다 더뎠고, 이상하게 토큰이 녹고 있다는 느낌이 들었습니다. 2주 가까이 걸려 작업을 마쳤고, 회사에 설치해서 리더의 세컨 브레인을 연결했습니다.

집에서는 제 옵시디언 리포로 대략 작동하는 것까지 보고 릴리즈한 터였습니다. 회사에서는 아예 작동하지 않았습니다. 몇 번의 코드 수정 끝에 연결은 됐지만, 연결 다음으로 동작하는 것이 하나도 없었습니다.

문제는 한 곳이 아니었다

그때부터 여기저기서 문제가 보이기 시작했습니다. Kiro는 몇 턴 전에 한 지시를 기억하지 못했고, 시킨 일을 정확히 이해하지 못한 채 엉뚱한 결과물을 내놨습니다. 집에서도 에이전트가 토큰만 태우고 결과물이 나쁘다는 확신이 강해졌습니다. 그 무렵 코덱스만 써서 이런저런 제품을 만들어보고 있었는데, 하나같이 쓸 수 없는 물건이 나오고 있었습니다.

무엇이 문제인지 곰곰이 따져봤습니다. 처음 보인 것은 Stig의 하네스였습니다. 모넷 사용법, 일을 진행하는 정형화된 루프, 서브에이전트별 사용법. 복잡하고 긴 프롬프트가 자리를 잡고 있었고, 작업의 경중과 상관없이 매번 그 무거운 루프를 돌고 있었습니다. 모델은 똑똑해져서 한 번에 더 많은 일을 처리할 수 있는데, 제 하네스는 몇 세대 전 모델에 맞춰 만들어진 채 굳어 있었습니다. 그러니 모델이 복잡한 절차만 따르면서, 제가 원한 제품이 아니라 엔지니어링적으로 흠잡을 데 없는 코딩에만 집중한 제품을, 엄청난 토큰을 써가며 만들고 있던 겁니다.

모넷의 결과물도 예상대로였습니다. 그간 추가한 기능들이 정리 안 된 채 덕지덕지 붙어서, 매 세션 시작부터 컨텍스트를 더럽히고 있었습니다. 모델은 무엇에 집중해야 하고 무엇이 노이즈인지 분간하지 못한 채, 동전 던지기처럼 운에 기대 일하고 있었습니다.

저장은 되고 있었습니다. 회수도 되고 있었습니다. 그런데 결과물은 나빠지고 있었습니다. 문제는 저장이 아니었습니다. 그럼 메모리는 대체 왜 필요한 걸까요. 3편은 그 질문에서 다시 시작합니다. 그리고 유니콘이 나옵니다.