연동 가이드
Python
Python 서버의 프로바이더 요청을 ABTO Gateway로 보내고 사용자와 기능 컨텍스트를 전달하는 SDK입니다.
서버 SDK백엔드에서 실행 (Calling Key)
Python SDK는 호출 시점의 사용자와 기능 컨텍스트를 게이트웨이 요청에 자동으로 실어 보냅니다. 토큰, 비용, 응답 속도와 요청 식별자는 게이트웨이가 기록합니다.
import os
from abto import init_abto
abto = init_abto( api_key=os.environ["ABTO_CALLING_KEY"], gateway_base_url="https://gateway.abto.app/v1", provider_keys={ "openai": os.environ["OPENAI_API_KEY"], # 프로젝트가 여러 provider로 라우팅되면 후보 키를 함께 전달합니다. # "anthropic": os.environ["ANTHROPIC_API_KEY"], # "gemini": os.environ["GEMINI_API_KEY"], },)
openai = abto.openai()
with abto.with_context( device_id="device-abc", feature_id="review.summary",): response = openai.chat.completions.with_raw_response.create( model="gpt-4.1-mini", messages=[{"role": "user", "content": "이 상품의 리뷰 12개를 세 줄로 요약해 줘."}], ) request_id = response.headers.get("x-abto-request-id") completion = response.parse()completion: 평소와 같은 OpenAI 응답 본문- raw response: Gateway가 발급한
x-abto-request-id를 읽는 자리 gateway_base_url: 필수. 생략하면ABTO_GATEWAY_BASE_URL환경 변수를 읽고, 둘 다 없으면ValueError
요청마다 전송되는 Gateway 헤더
섹션 제목: “요청마다 전송되는 Gateway 헤더”| SDK 입력 | Gateway 헤더 | 의미 |
|---|---|---|
api_key | Authorization: Bearer … | ABTO Calling Key |
provider_keys["openai"] | x-abto-key-openai | 직접 계약한 OpenAI provider key |
feature_id | x-abto-feature-id | 기능 ID |
device_id | x-abto-device-id | 사용자 기기 식별자 (선택) |
provider_keys의 성격과 취급:
- Gateway에 키를 등록하는 설정이 아니라, 서버에 보관한 credential을 요청마다 헤더로 실어 보내는 입력
- 요청 범위로만 전달. 호출 기록에는 미저장
- 라우팅된 provider의 키가 없으면 Gateway가 그 요청을 거절
- 문자열 대신 함수를 주면 요청마다 다시 평가. key rotation과 provider별 credential resolver에 사용
호출자가 넣은 헤더의 처리:
abto.openai()가 만든 client에서는extra_headers로x-abto-key-*를 덮어쓰지 마세요.- Python SDK가 호출자의
Authorization,x-abto-key-*,x-abto-feature-id,x-abto-device-id를 제거하고init_abto의 신뢰된 설정과 context로 다시 구성합니다. - Python SDK 없이 기존 OpenAI SDK를 직접 쓴다면 같은 헤더를 각 요청의
extra_headers에 직접 넣습니다. 직접 연결 예시를 참고하세요.
컨텍스트 필드
섹션 제목: “컨텍스트 필드”필드의 의미는 Node / Server JavaScript와 같습니다.
feature_id: 기능 ID(예:review.summary).x-abto-feature-id로 전송device_id:x-abto-device-id로 전송. 제품 행동과 잇기 위해 브라우저가 만든device_id를 백엔드로 받아 그대로 전달
식별자를 다루는 규칙:
- 클라이언트가 보낸
device_id,feature_id는 애플리케이션의 기존 요청 스키마로 검증 - Calling Key와 provider key는 클라이언트 요청에서 받지 않고 서버 환경 변수나 서버 전용 credential resolver에서만 읽기
응답을 브라우저·모바일 행동과 잇는 방법:
- 위 예제처럼
with_raw_response로x-abto-request-id를 읽기 - 백엔드 응답에 같은 헤더를 포함해 Browser 또는 Mobile SDK의 LLM trace에 연결
Gateway가 지원하는 OpenAI 요청
섹션 제목: “Gateway가 지원하는 OpenAI 요청”- 데이터 경로는 현재 OpenAI Chat Completions
user메시지의 인라인 base64 이미지와 PDF 지원- Streaming, tool calling, 원격 이미지 URL, audio 등 미지원 필드는 조용히 무시하지 않고
400으로 거절 - 정확한 필드 목록은 Gateway OpenAI 호환 범위 참고
재시도는 두 층에서 일어납니다
섹션 제목: “재시도는 두 층에서 일어납니다”재시도 층이 둘이라 max_retries만으로 provider 호출 횟수가 정해지지 않습니다.
| 층 | 무엇을 세는가 | 누가 정하는가 |
|---|---|---|
| 클라이언트 | 애플리케이션 → Gateway 왕복 횟수 | 공식 OpenAI SDK의 max_retries |
| Gateway | Gateway → provider 호출 횟수 | Gateway 내장 상한과 node 재시도 정책 |
클라이언트 층: max_retries
섹션 제목: “클라이언트 층: max_retries”openai = abto.openai(max_retries=2)- 공식 OpenAI 의미 그대로 최초 요청 이후의 재시도 횟수.
0은 왕복 1회,1은 왕복 2회 - Python SDK는 이 값을 덮어쓰지 않으며 별도의 fallback 재시도 설정도 미제공
- 설정하지 않으면 공식 OpenAI SDK의 기본값을 그대로 사용
- 그 밖의 공식 OpenAI option도 그대로 전달
api_key,base_url,http_client는 신뢰된 라우팅을 위해 ABTO가 소유. 넘기면 조용히 무시하지 않고ValueError발생
Gateway 층: 왕복 한 번 안에서의 재시도
섹션 제목: “Gateway 층: 왕복 한 번 안에서의 재시도”한 번의 왕복 안에서 Gateway가 같은 경로로 다시 시도합니다.
- 네트워크 재시도: 전송 전 unreachable이 확정된 경우. node 정책과 무관하게 항상, 최대 2회
- Provider 재시도:
429(rate limit),500,502,503,504,529. node 재시도 정책을 켠 경우에만, 최대 2회 - 두 예산은 독립 가산이므로 한 왕복의 provider 호출은 최대 5회(최초 1회 + 네트워크 2회 + provider 2회)
- 응답 헤더
x-abto-attempt가 몇 번째 시도의 결과인지 표시
재시도하지 않는 경우:
429중 크레딧 소진(insufficient_quota). 결정적 실패- timeout, 전송 후 단절, 본문 크기 초과, 취소. 이중 실행과 이중 과금 위험
501,505처럼 결정적인 그 밖의 상태
대기 시간:
- 지수 백오프 + full jitter. 네트워크는 50ms에서 250ms 상한, provider는 500ms에서 8초 상한
- provider가
Retry-After를 주면 그 값을 존중하고, 8초를 넘으면 기다리지 않고 즉시 오류를 표면화
Gateway 장애 시 OpenAI direct fallback
섹션 제목: “Gateway 장애 시 OpenAI direct fallback”ABTO 도입 이전에 쓰던 엔드포인트로 되돌아가는 비상 경로입니다.
그래서 목적지를 fallback.base_url에 직접 지정해야 하며, 기본값은 없습니다.
OpenAI에서 직접 키를 발급받아 공식 SDK를 쓰던 고객이라면 그 주소가 https://api.openai.com/v1입니다.
from abto import OpenAIDirectFallbackOptions, init_abto
abto = init_abto( api_key=os.environ["ABTO_CALLING_KEY"], gateway_base_url="https://gateway.abto.app/v1", provider_keys={"openai": os.environ["OPENAI_API_KEY"]}, fallback=OpenAIDirectFallbackOptions( # ABTO를 붙이기 전 이 코드가 호출하던 주소를 그대로 적습니다. base_url="https://api.openai.com/v1", timeout_seconds=30, on_timeout=False, ),)원본 Chat Completions body와 model을 그대로 그 주소로 보내며, Gateway의 provider/model 정책을 재현하지 않습니다.
현재 요청을 direct로 보내는 경우
- 연결 수립 전 실패
- provider 호출 전 admission
503
현재 요청을 폴백하지 않는 경우
- timeout과 전송 여부가 모호한 disconnect. Gateway가 이미 provider를 실행했을 가능성
- provider·transport·internal 오류, 결정적인
4xx와429, streaming 시작 이후 - 이때 direct circuit도 열지 않으며, 공식 OpenAI SDK가 재시도하면 다시 Gateway를 호출
설정
base_url: 필수. ABTO 이전에 쓰던 주소. OpenAI 요청 경로와Authorization: Bearer를 받는 엔드포인트여야 합니다. 이 값 없이 폴백을 켜면init_abto가ValueError를 발생시킵니다timeout_seconds: Gateway connection pool 대기, 연결, 쓰기, 응답 헤더 읽기 각 단계의 inactivity 상한. 헤더 이후 body와 direct 요청은abto.openai(timeout=...)값을 유지on_timeout=True: timeout 난 현재 요청까지 재전송. 중복 실행과 과금 위험을 감수하는 명시적 선택fallback=False: 기능 전체 해제
경계
- transport는 SDK attempt마다 Gateway 판단과 direct 전송을 각각 한 번만 수행
- direct 호출은 Gateway policy, ABTO telemetry,
request_id를 거치지 않음. model 은 그 엔드포인트가 지원하는 것으로 제한 - OpenAI에 필요한 header만 전달하고 Cookie, proxy credential, 사용자 정의 Gateway header는 제거
- direct 전환 뒤의 응답과 오류는 공식 OpenAI SDK로 그대로 반환하며 재시도 여부는 그 SDK 설정이 결정
- Anthropic과 Gemini의 네이티브 direct fallback은 현재 범위 밖