Codex의 모델 요청을 외부 서비스로 보내려면 API 키보다 먼저 프로토콜 계약을 확인해야 합니다. 어떤 서비스가 OpenAI-compatible이라고 설명해도 /v1/chat/completions만 구현했을 수 있습니다. Codex가 요구하는 Responses API와 스트리밍 형식이 없다면 URL 끝에 /responses를 붙여도 호환성이 생기지 않습니다.
또한 이 작업은 MCP 연결이 아닙니다. MCP는 Codex에 데이터베이스, 브라우저, 사내 시스템 같은 도구를 추가합니다. custom model provider는 Codex가 추론을 요청하는 모델 backend를 바꿉니다. “외부 API 연동”이라는 표현이 같아도 설정, 인증, 오류 소유자가 다릅니다.

공급자 문서에서 먼저 답을 찾아야 하는 질문
설정 파일을 열기 전에 다음 네 항목을 공급자의 공식 문서와 console에서 확인합니다.
- Responses API endpoint가 명시되어 있는가?
- 그 endpoint에서 사용할 정확한 모델 ID가 무엇인가?
- Bearer token인지, 별도 header나 query parameter가 필요한가?
- 스트리밍과 Codex가 필요한 tool 요청을 지원하는가?
OpenAI의 현재 Codex Configuration Reference는 custom provider의 wire_api로 responses만 지원한다고 명시합니다. Chat Completions SDK 예제가 성공했다는 사실은 첫 번째 질문의 증거가 아닙니다.
계정 경계도 분리합니다. ChatGPT에 로그인되어 있거나 플랜 한도가 남아 있어도 제3자 provider의 잔액, 모델 권한, rate limit을 증명하지 못합니다. 모델 요청이 제3자에게 가면 과금, 로그, 보존 정책, 지역 제한, 지원 책임도 해당 서비스 계약을 따릅니다.
기본 설정을 덮어쓰지 않는 방식
Provider와 인증 설정은 machine-local입니다. Project의 .codex/config.toml에 model_provider나 model_providers를 넣으면 Codex가 무시합니다. 사용자 ~/.codex/config.toml 또는 같은 디렉터리의 독립 profile에 둬야 합니다.
처음에는 ~/.codex/third-party.config.toml로 분리하면 공식 경로를 보존할 수 있습니다.
tomlmodel = "provider-model-id" model_provider = "acme" [model_providers.acme] name = "Acme Model API" base_url = "https://api.example.com/v1" env_key = "ACME_API_KEY" wire_api = "responses"
위 URL과 모델 ID는 예시입니다. 공급자의 Responses 문서에 적힌 값을 그대로 사용해야 합니다. 로컬 ID acme는 model_provider와 table 이름에서 일치해야 합니다. openai, ollama, lmstudio는 예약된 ID라 custom 정의로 덮어쓸 수 없습니다. Custom provider와 profile의 현재 형식은 OpenAI의 Advanced Configuration에서 확인할 수 있습니다.
키는 config 값이 아니라 환경 변수로 전달
env_key = "ACME_API_KEY"는 실제 키가 아니라 Codex가 읽을 환경 변수의 이름입니다. macOS, Linux, WSL에서는 같은 shell에서 설정하고 실행합니다.
bashexport ACME_API_KEY="실제-키" codex --profile third-party
PowerShell 현재 세션에서는 다음과 같습니다.
powershell$env:ACME_API_KEY = "실제-키" codex --profile third-party
키를 TOML, dotfiles 저장소, .env.example, 화면 캡처, 지원 로그에 넣지 마세요. 공식 reference는 literal token을 넣는 experimental_bearer_token보다 env_key 사용을 권장합니다. 공급자가 특수 header를 요구하면 해당 서비스의 공식 형식에 따라 env_http_headers, http_headers, query_params 중 필요한 것만 사용합니다.
CLI는 되는데 Desktop이나 IDE에서 키를 찾지 못할 수 있습니다. 터미널에서 임시로 export한 값은 Dock, 시작 메뉴, 다른 IDE process에 자동 전달되지 않을 수 있기 때문입니다. 이 경우 endpoint를 바꾸기 전에 실제 실행 process의 환경을 확인합니다.
UI의 모델 이름만 믿지 않는 검증

화면에 custom 모델이 보이면 profile을 읽었다는 뜻입니다. 요청이 의도한 provider로 갔다는 증거는 아닙니다. 민감한 파일이 없는 빈 디렉터리에서 codex --profile third-party를 시작하고, 파일 읽기나 tool이 필요 없는 고정된 짧은 문자열만 응답하도록 요청합니다.
성공 판정에는 세 가지가 함께 필요합니다.
- 현재 Codex 세션의 모델 ID가 의도와 일치한다.
- 응답이 stream parse 오류나 반복 reconnect 없이 완료된다.
- 같은 시각에 provider 또는 gateway console에 해당 모델의 요청, status, usage가 나타난다.
가능하면 request ID와 시각을 기록하되 키와 불필요한 prompt 본문은 남기지 않습니다. DeepSeek처럼 서비스가 자체 Codex 연동 문서에서 Responses 지원을 명시하면 그 경로의 일차 근거가 됩니다. 다른 gateway의 호환성까지 대신 증명하지는 않습니다.
첫 오류가 가리키는 위치
| 증상 | 소유 경계 | 먼저 확인할 것 |
|---|---|---|
| 알 수 없는 설정 key, TOML 오류 | Codex 버전 또는 구문 | codex --version, table 이름, 따옴표, 최신 reference |
| 환경 변수를 찾지 못함 | 실행 process | 같은 shell 실행 또는 Desktop/IDE 환경 설정 |
| 401 / 403 | key, header, provider project 권한 | console에서 key 상태와 모델 권한 확인 |
| 404 / model not found | base URL 또는 모델 매핑 | 정확한 Responses 경로와 공급자 모델 ID 비교 |
| 연결 직후 response parse 실패 | protocol 형식 | Chat Completions-only endpoint 사용 중단 |
| 출력 중단, reconnect 반복 | SSE, proxy timeout, upstream | 중단 시각과 request ID를 양쪽 log에서 대조 |
| 429 | provider 계정, gateway, 모델 한도 | status를 실제 반환한 시스템의 잔액과 제한 확인 |
429가 확정되면 Codex 429 한도 진단, 응답이 멈추면 Codex 시간 초과 진단, 설정 layer가 충돌하면 config.toml 경계 안내를 이어서 확인할 수 있습니다.
짧은 텍스트 응답 성공은 기능 동등성을 뜻하지 않습니다. Custom provider의 standalone web search 지원은 기본값이 false이고, capability flag만으로 provider endpoint, 모델, runtime, policy의 부족을 해결할 수 없습니다. 이미지 입력, tool calls, reasoning summary, WebSocket, plugin, cloud 기능도 실제 필요한 항목을 별도로 검증해야 합니다.
외부 provider를 가끔 쓴다면 profile을 유지하는 편이 명확합니다. 공식 경로로 돌아갈 때 custom 세션을 종료하고 --profile third-party 없이 Codex를 실행합니다. 기본 config를 직접 수정했다면 추가한 model, model_provider, 해당 provider table만 제거하세요. ~/.codex 전체 삭제는 호환성 문제를 고치지 못한 채 로그인, MCP, rules, profiles, history까지 없앨 수 있습니다.



