본문으로 건너뛰기

[hermes-agent] Hermes Agent: 10배 빠른 프로젝트 그룹화 최적화 분석

PR 링크: NousResearch/hermes-agent#82472 상태: Merged | 변경: +82 / -1

들어가며

소프트웨어 개발 도구에서 '콜드 오픈(Cold Open)' 성능은 사용자 경험에 직결됩니다. NousResearch의 hermes-agent 프로젝트에서 데스크탑 사이드바의 프로젝트 그룹화 기능이 매번 수 초간 멈추는 현상이 발견되었습니다. 프로파일링 결과, 시스템은 이미 알고 있는 정보를 얻기 위해 수백 번의 git 서브프로세스를 메인 스레드에서 직렬로 실행하고 있었습니다. 본 글에서는 이 병목을 해결하여 빌드 속도를 3.3초에서 0.3초로 10배 이상 개선한 최적화 전략을 분석합니다.

코드 분석

1. tui_gateway/git_probe.py: 불필요한 Fork 방지

기존 코드에서는 존재하지 않는 디렉토리에 대해서도 git -C 명령을 실행하여 불필요한 프로세스 포크(fork)가 발생했습니다.

Before:

if not cwd:
    return ""
return bounded_git_probe(["git", "-C", cwd, *args], timeout=_GIT_TIMEOUT)

After:

if not cwd or not os.path.isdir(cwd):
    return ""
return bounded_git_probe(["git", "-C", cwd, *args], timeout=_GIT_TIMEOUT)

os.path.isdir 체크를 추가함으로써, 삭제된 워크트리나 존재하지 않는 경로에 대해 git 프로세스를 생성하지 않고 즉시 반환하도록 변경했습니다.

2. tui_gateway/server.py: 캐시 활용 및 데이터 로딩 최적화

프로젝트 트리 빌드 시, 모든 경로를 미리 '웜업(warm-up)'하여 직렬 호출을 방지하고, 데이터베이스에서 불필요한 대용량 데이터를 읽어오는 것을 방지했습니다.

Before:

# _project_tree_inputs 호출 시 모든 필드 로드

After:

compact_rows=True, # 필요한 필드만 선택하여 메모리 및 I/O 절약

또한, _build_project_tree 함수 내에서 git_probe.warm_roots를 호출하여 프로젝트 폴더와 발견된 리포지토리 루트를 미리 캐싱함으로써, 이후 발생하는 모든 git 조회가 캐시된 값을 사용하도록 개선했습니다.

왜 이게 좋은가

이번 최적화는 '불필요한 I/O를 줄이고, 직렬 작업을 병렬/캐싱 작업으로 전환'하는 고전적이면서도 강력한 원칙을 따릅니다.

  1. 성능 수치: 콜드 빌드 기준 3292ms에서 306ms로 약 10.7배의 성능 향상을 달성했습니다. 특히 메인 스레드에서 실행되던 219개의 직렬 git 호출이 16개로 줄어든 것이 핵심입니다.
  2. 교훈:
    • Lazy Evaluation의 함정: 모든 것을 필요할 때마다 호출하는 것은 직렬 병목을 유발합니다. 미리 필요한 경로를 파악해 캐시를 채우는(Warm-up) 전략이 효과적입니다.
    • System Call 비용: git과 같은 외부 프로세스 호출은 매우 비쌉니다. os.path.isdir과 같은 가벼운 시스템 콜로 무거운 프로세스 생성을 방지하는 것만으로도 큰 이득을 볼 수 있습니다.
    • 데이터베이스 최적화: 사용하지 않는 대용량 Blob 데이터를 쿼리하는 것은 메모리와 CPU를 낭비합니다. 필요한 필드만 선택하는 compact_rows 패턴은 데이터베이스 기반 애플리케이션에서 필수적입니다.

결론

이번 PR은 복잡한 알고리즘 변경 없이도, 시스템의 호출 흐름을 이해하고 불필요한 외부 의존성을 제거함으로써 극적인 성능 향상을 이뤄낸 훌륭한 사례입니다. 특히 회귀 테스트를 통해 최적화 과정에서 발생할 수 있는 로직 오류를 방지한 점은 시니어 엔지니어링의 모범을 보여줍니다.

참고 자료

⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.

댓글

관련 포스트

PR Analysis 의 다른글