
【#3】Hermes Agent 분석하기
요약
Hermes Agent의 상태 관리와 컨텍스트 압축(Compaction) 메커니즘을 분석합니다. SQLite를 활용한 세션 영속화와 CJK 지원 검색, 그리고 대화의 맥락을 유지하며 중반부를 요약하는 효율적인 컨텍스트 관리 전략을 다룹니다.
핵심 포인트
- SQLite WAL 모드와 지터 재시도를 통한 안정적인 병렬 데이터 처리
- CJK 언어 지원을 위한 FTS5 trigram 인덱스 활용
- 컨텍스트 윈도우 유지를 위한 Head/Tail 보호 및 Middle 요약 방식
- 세션 계보 체인(Parent-Child)을 통한 비파괴적 압축 구현
연재 「Hermes Agent 분석하기」 제3회.
연재 「Hermes Agent 분석하기」 전 10회
- [제1회 전체상과 읽는 법]
- [제2회 코어 대화 루프]
[제3회 상태 관리와 컴팩션 (Compaction)] (본 기사) - [제4회 기억 아키텍처와 인격]
- [제5회 툴 시스템]
- [제6회 멀티 에이전트 병렬]
- [제7회 Kanban 영속 태스크 보드]
- [제8회 접속층과 인터페이스 총람]
- [제9회 확장 운용]
- [제10회 보안과 안전 운용]
지난 회차의 루프는 1회 주기로 상태를 「영속화 (Persistence)」하고 있었다. 그 영속화 대상이 hermes_state.py이다. 그리고 루프 내의 「압축 (Compression)」이 context_compressor.py이다. 이 두 가지는 표리일체로, 긴 대화를 파괴하지 않고 컨텍스트 윈도우 (Context Window)에 계속 담아두는 난제를 분담하고 있다.
Hermes는 세션을 SQLite에 저장한다. 동시 액세스에 대비한 장치가 이중으로 적용되어 있다.
- WAL 모드로 「병렬 리더 + 단일 라이터」를 실현. 읽기는 막히지 않게 하고, 쓰기는 하나로 집중시킨다. 쓰기 경합에는 지터 (Jitter)를 포함한 재시도로 대응 (일제 재시도로 인한 충돌을 분산함).
검색은 FTS5의 이중 인덱스를 사용한다. 영어용 표준 토크나이저(Tokenizer) 외에, CJK(한중일)를 위한 trigram 인덱스 (messages_fts_trigram)를 별도로 생성한다. 일본어, 중국어처럼 공백으로 단어가 구분되지 않는 언어에서도 전체 텍스트 검색(Full Text Search)이 작동하도록 하는 장치다 (hermes_state.py:345 부근에서 실재 확인).
나아가, 스토어를 NFS / SMB 상에 두었을 경우의 폴백 (Fallback) 기능을 갖추고 있다. 네트워크 파일 시스템에서는 SQLite의 WAL이 제대로 작동하지 않을 수 있기 때문에, 해당 환경에서는 DELETE 저널 모드로 퇴각한다 (hermes_state.py:42 부근). NAS에 홈 디렉토리를 두는 운용을 실제로 상정한 구현으로, 나처럼 Synology를 병용하는 사람에게는 반가운 배려다.
컨텍스트 (Context)는 무한하지 않다. Hermes는 임계치를 넘으면 대화의 중반부를 요약하여 압축한다.
- 발화 임계치: 컨텍스트 길이의 약 50% (
threshold_percent = 0.50). 단, 하한선인 64,000 토큰 (MINIMUM_CONTEXT_LENGTH = 64_000) 밑으로는 내려가지 않는다 (context_compressor.py:587/model_metadata.py:133). - 스래싱 (Thrashing) 방지: 압축 직후에 다시 바로 임계치를 넘어 재압축되는... 식의 진동을 피하기 위한 가드를 갖추고 있다.
「50%」라는 빠른 발화 시점이 효과적이다. 컨텍스트가 가득 찬 후에 서둘러 압축하는 것이 아니라, 절반인 시점에서 여유 있게 압축한다. 하한선 64K는 작은 컨텍스트 모델에서 과도하게 압축되는 것을 막기 위한 바닥이다.
압축 방식은 Head / Tail을 보호하고 Middle을 요약하는 방식이다.
도입부(태스크의 전제)와 말미(최근 문맥)는 남기고, 중반부만 요약으로 대체한다. 그리고 최신 사용자 메시지는 반드시 Tail에 남긴다 —— 이것을 압축하면 「지금 무엇을 요청받고 있는가」가 사라지기 때문이다.
압축은 파괴적인 작업이다. 원래의 대화를 덮어써 버리면 나중에 「압축 전에는 무엇이었나」를 추적할 수 없다. Hermes는 이를 피한다.
압축할 때마다 새로운 session_id를 생성하고, 이전 세션에 parent_session_id로 링크한다. 압축 후의 세션은 새로운 ID를 가지면서도 부모를 가리킨다. 결과적으로 압축을 반복할수록 부모 → 자식 → 손자... 식의 **계보 체인 (Lineage Chain)**이 늘어난다. 원래의 대화는 사라지지 않으며, 필요하다면 거슬러 올라갈 수 있다.
이 설계는 제4회의 기억론과도 맞닿아 있다. 압축은 「망각」이지만, 계보 체인을 통해 「잊힌 사실에 대한 참조」는 유지된다.
툴 호출(Tool Call)과 결과는 한 쌍이다. tool_use (호출)와 tool_result (결과)는 API 상에서 쌍을 이루어야 한다. 압축으로 중반부를 압축하면 이 쌍이 깨지는 경우가 있다 —— 호출만 남고 결과가 사라지거나, 그 반대의 경우 말이다.
Hermes는 API에 전달하기 전에 **고아가 된 도구 결과(orphan tool results)를 제거하거나 스텁화(stubbing)**한다. 한쪽 편만 남은 상태로 API에 보내면 프로바이더(provider) 측에서 에러가 발생하기 때문이다. 앞서 언급한 "원본은 건드리지 않고 전송용 복사본을 가공한다"는 설계가 여기서 빛을 발한다. 압축된 결과 쌍이 깨지더라도 원본은 무사하며, 전송용 복사본 측에서만 논리적 일관성을 맞춘다.
다음 회차는 드디어 하이라이트다. 압축을 통해 무언가를 "잊어버리는" 에ージェント가 어떻게 연속적인 인격(personality)을 유지할 수 있는가. 기억 아키텍처(memory architecture)와 명제 인격 = 지능 × 기억을 다룬다.
대응 맵 장: §2.3, §13.2-4 / 행 번호는 hermes update 시 어긋날 수 있음
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기