자격 증명 풀
자격 증명 풀(credential pool)은 같은 제공자에 대해 여러 API 키 또는 OAuth 토큰을 등록하게 해 줍니다. 한 키가 속도 제한(rate limit)이나 결제 할당량에 걸리면 Hermes는 자동으로 다음 정상 키로 순환합니다. 제공자를 바꾸지 않고도 현재 세션을 계속 유지할 수 있습니다.
이는 대체 제공자와 다릅니다. 대체 제공자는 완전히 다른 제공자로 전환하지만, 자격 증명 풀은 같은 제공자 안에서 키를 바꿉니다. Hermes는 먼저 풀을 시도하고, 풀의 모든 키를 소진한 뒤에야 대체 제공자를 활성화합니다.
동작 방식
사용자 요청
-> 풀에서 키 선택(round_robin / least_used / fill_first / random)
-> 제공자로 전송
-> 429 속도 제한?
-> 같은 키로 한 번 재시도(일시적 오류로 간주)
-> 두 번째 429 -> 다음 풀 키로 순환
-> 모든 키 소진 -> fallback_model(다른 제공자)
-> 402 결제 오류?
-> 즉시 다음 풀 키로 순환(24시간 쿨다운)
-> 401 인증 만료?
-> 토큰 갱신 시도(OAuth)
-> 갱신 실패 -> 다음 풀 키로 순환
-> 성공 -> 정상 진행
빠른 시작
이미 .env에 API 키가 설정되어 있다면 Hermes는 이를 키 1개짜리 풀로 자동 발견합니다. 풀링의 이점을 얻으려면 키를 더 추가하세요.
# 두 번째 OpenRouter 키 추가
hermes auth add openrouter --api-key sk-or-v1-your-second-key
# 두 번째 Anthropic 키 추가
hermes auth add anthropic --type api-key --api-key sk-ant-api03-your-second-key
# Anthropic OAuth 자격 증명 추가(Claude Max 플랜 + 추가 사용 크레딧 필요)
hermes auth add anthropic --type oauth
# OAuth 로그인을 위해 브라우저 열기
풀 상태를 확인합니다.
hermes auth list
출력 예:
openrouter (자격 증명 2개):
#1 OPENROUTER_API_KEY api_key env:OPENROUTER_API_KEY <- selected
#2 backup-key api_key manual
anthropic (자격 증명 3개):
#1 hermes_pkce oauth hermes_pkce <- selected
#2 claude_code oauth claude_code
#3 ANTHROPIC_API_KEY api_key env:ANTHROPIC_API_KEY
<- selected는 현재 선택된 자격 증명을 나타냅니다.
대화형 관리
하위 명령 없이 hermes auth를 실행하면 대화형 마법사가 열립니다.
hermes auth
마법사는 전체 풀 상태를 보여 주고 다음 메뉴를 제공합니다.
무엇을 할까요?
1. 자격 증명 추가
2. 자격 증명 제거
3. 제공자의 쿨다운 초기화
4. 제공자의 순환 전략 설정
5. 종료
API 키와 OAuth를 모두 지원하는 제공자(Anthropic, Nous, Codex)의 경우, 추가 흐름에서 자격 증명 유형을 묻습니다.
anthropic은 API 키와 OAuth 로그인을 모두 지원합니다.
1. API 키(제공자 대시보드의 키 붙여넣기)
2. OAuth 로그인(브라우저로 인증)
유형 [1/2]:
CLI 명령
| 명령 | 설명 |
|---|---|
hermes auth | 대화형 풀 관리 마법사 |
hermes auth list | 모든 풀과 자격 증명 표시 |
hermes auth list <provider> | 특정 제공자의 풀 표시 |
hermes auth add <provider> | 자격 증명 추가. 유형과 키를 프롬프트로 입력 |
hermes auth add <provider> --type api-key --api-key <key> | API 키를 비대화형 방식으로 추가 |
hermes auth add <provider> --type oauth | 브라우저 로그인으로 OAuth 자격 증명 추가 |
hermes auth remove <provider> <index> | 1부터 시작하는 인덱스로 자격 증명 제거 |
hermes auth reset <provider> | 모든 쿨다운/소진 상태 초기화 |
순환 전략
hermes auth의 "Set rotation strategy" 메뉴에서 설정하거나 config.yaml에 직접 설정합니다.
credential_pool_strategies:
openrouter: round_robin
anthropic: least_used
| 전략 | 동작 |
|---|---|
fill_first(기본값) | 첫 번째 정상 키가 소진될 때까지 사용한 뒤 다음 키로 이동 |
round_robin | 키를 고르게 순환하며 매 선택 후 다음 키로 이동 |
least_used | 요청 횟수가 가장 낮은 키를 항상 선택 |
random | 정상 키 중에서 무작위 선택 |
오류 복구
풀은 오류 종류에 따라 다르게 대응합니다.
| 오류 | 동작 | 쿨다운 |
|---|---|---|
| 429 속도 제한 | 같은 키를 한 번 재시도합니다. 일시적 오류로 간주합니다. 연속 두 번째 429부터 다음 키로 순환합니다. | 1시간 |
| 402 결제/할당량 | 즉시 다음 키로 순환합니다. | 24시간 |
| 401 인증 만료 | 먼저 OAuth 토큰 갱신을 시도합니다. 갱신이 실패한 경우에만 순환합니다. | - |
| 모든 키 소진 | 설정되어 있다면 fallback_model로 넘어갑니다. | - |
has_retried_429 플래그는 성공한 API 호출마다 재설정됩니다. 따라서 일시적인 429 한 번만으로는 키 순환이 발생하지 않습니다.
사용자 정의 엔드포인트 풀
OpenAI 호환 사용자 정의 엔드포인트(Together.ai, RunPod, 로컬 서버)는 자체 풀을 가집니다. 풀 키는 config.yaml의 custom_providers에 있는 엔드포인트 이름을 기준으로 합니다.
hermes model로 사용자 정의 엔드포인트를 설정하면 Hermes는 "Together.ai" 또는 "Local (localhost:8080)" 같은 이름을 자동 생성합니다. 이 이름이 풀 키가 됩니다.
# hermes model로 사용자 정의 엔드포인트를 설정한 뒤:
hermes auth list
# 표시 예:
# Together.ai (자격 증명 1개):
# #1 config key api_key config:Together.ai <- selected
# 같은 엔드포인트에 두 번째 키 추가:
hermes auth add Together.ai --api-key sk-together-second-key
사용자 정의 엔드포인트 풀은 auth.json의 credential_pool 아래에 custom: 접두사와 함께 저장됩니다.
{
"credential_pool": {
"openrouter": [...],
"custom:together.ai": [...]
}
}
자동 발견
Hermes는 시작 시 여러 소스에서 자격 증명을 자동 발견하고 풀의 시드로 사용합니다.
| 소스 | 예시 | 자동 시드 여부 |
|---|---|---|
| 환경 변수 | OPENROUTER_API_KEY, ANTHROPIC_API_KEY | 예 |
OAuth 토큰(auth.json) | Codex 디바이스 코드, Nous 디바이스 코드 | 예 |
| Claude Code 자격 증명 | ~/.claude/.credentials.json | 예(Anthropic) |
| Hermes PKCE OAuth | ~/.hermes/auth.json | 예(Anthropic) |
| 사용자 정의 엔드포인트 설정 | config.yaml의 model.api_key | 예(사용자 정의 엔드포인트) |
| 수동 항목 | hermes auth add로 추가 | auth.json에 지속 저장 |
자동 시드된 항목은 풀을 로드할 때마다 업데이트됩니다. 예를 들어 환경 변수를 제거하면 해당 풀 항목도 자동으로 정리됩니다. 수동 항목, 즉 hermes auth add로 추가한 항목은 자동으로 제거되지 않습니다.
위임 및 서브에이전트 공유
에이전트가 delegate_task로 서브에이전트를 생성하면 부모의 자격 증명 풀이 서브에이전트와 자동 공유됩니다.
- 같은 제공자 - 서브에이전트는 부모의 전체 풀을 받아 속도 제한 발생 시 키 순환을 사용할 수 있습니다.
- 다른 제공자 - 서브에이전트는 해당 제공자의 자체 풀을 로드합니다. 설정되어 있는 경우에 한합니다.
- 풀이 설정되지 않음 - 서브에이전트는 상속된 단일 API 키를 사용합니다.
즉 서브에이전트도 추가 설정 없이 부모와 같은 속도 제한 회복력을 얻습니다. 작업별 자격 증명 임대(per-task credential leasing)는 여러 서브에이전트가 동시에 키를 순환하더라도 서로 충돌하지 않도록 합니다.
스레드 안전성
자격 증명 풀은 모든 상태 변경(select(), mark_exhausted_and_rotate(), try_refresh_current(), mark_used())에 스레딩 락을 사용합니다. 게이트웨이가 여러 채팅 세션을 동시에 처리할 때도 안전한 동시 접근을 보장합니다.
아키텍처
전체 데이터 흐름 다이어그램은 저장소의 docs/credential-pool-flow.excalidraw를 참고하세요.
자격 증명 풀은 제공자 해석 계층에 통합됩니다.
agent/credential_pool.py- 풀 관리자: 저장, 선택, 순환, 쿨다운hermes_cli/auth_commands.py- CLI 명령과 대화형 마법사hermes_cli/runtime_provider.py- 풀을 인식하는 자격 증명 해석run_agent.py- 오류 복구: 429/402/401 -> 풀 순환 -> 페일오버
저장소
풀 상태는 ~/.hermes/auth.json의 credential_pool 키 아래에 저장됩니다.
{
"version": 1,
"credential_pool": {
"openrouter": [
{
"id": "abc123",
"label": "OPENROUTER_API_KEY",
"auth_type": "api_key",
"priority": 0,
"source": "env:OPENROUTER_API_KEY",
"access_token": "sk-or-v1-...",
"last_status": "ok",
"request_count": 142
}
]
},
}
전략은 auth.json이 아니라 config.yaml에 저장됩니다.
credential_pool_strategies:
openrouter: round_robin
anthropic: least_used