0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Codex CLIでOpenAI / DeepSeekを切り替える方法

0
Posted at

TL;DR

  • Codex CLIのUIや操作感を変えずに、OpenAI / DeepSeekを切り替えて利用できるようにした
  • やり方は、CODEX_HOME をOpenAI用 / DeepSeek用に分離し、それぞれの設定・認証情報を独立して管理すること

背景・目的

  • Codexの利用制限に達したときの代替としてDeepSeekを使えるようにしたい。ただ、別のCLIへ乗り換えるのではなく、CodexのUIや操作感はそのまま使いたかったため、切り替える方法がないか調べてみた。
  • 調べた結果、CODEX_HOME を切り替えることで、Codexの設定や認証情報を接続先ごとに分離できることが分かったため、OpenAI用とDeepSeek用の環境を分け、Taskfileから簡単に切り替えられるように実装した。
  • この方法や具体的な実装例については、調べてもまとまった情報があまり見つからず、試行錯誤する中でCodexのトークンもかなり消費したため、同じことをもう一度調べ直さなくて済むよう、今回の構成と実装手順をメモとして残しておく。

前提

今回使用した環境は以下。

使用環境

  • Codex CLI v0.148.0
  • DeepSeek API
  • Python 3.x
  • uv
  • Task
  • Linux / WSL

ディレクトリ構成

<PROJECT_ROOT>/
├── .codex-home/
│   ├── main/
│   │   └── config.toml
│   └── deepseek/
│       ├── config.toml
│       └── models.json
└── scripts/
    └── switch_codex_profile.py

手順

1 OpenAI用 / DeepSeek用のCODEX_HOMEを作成

OpenAI用 / DeepSeek用にそれぞれ CODEX_HOME を作成し、配下に必要な設定ファイルを配置する。

OpenAI用config.tomlを作成

通常利用しているCodexの設定ファイルをOpenAI用の CODEX_HOME にコピーする。

mkdir -p .codex-home/main
cp ~/.codex/config.toml .codex-home/main/config.toml

DeepSeek用config.toml / models.jsonを作成

まずDeepSeek用の CODEX_HOME を作成する。

mkdir -p .codex-home/deepseek

.codex-home/deepseek/config.toml を作成し、DeepSeek用の設定を記載する。

model = "deepseek-v4-pro"
model_provider = "deepseek"

preferred_auth_method = "apikey"
forced_login_method = "api"
model_reasoning_effort = "high"
model_catalog_json = "<DeepSeek用CODEX_HOME>/models.json"

[model_providers.deepseek]
name = "deepseek"
base_url = "https://api.deepseek.com/"
wire_api = "responses"
experimental_bearer_token = "<DEEPSEEK_API_KEY>"
  • <DeepSeek用CODEX_HOME><DEEPSEEK_API_KEY> は、それぞれ実際のパスとDeepSeek APIキーに置き換える。
  • models.jsonDeepSeek公式ドキュメントで公開されているモデルカタログを配置する。
  • ※APIキーを含むため、.codex-home/ はGitの管理対象から除外することを推奨。

2 CODEX_HOMEを切り替えるスクリプトを作成

# scripts/switch_codex_profile.py
import argparse
import shutil
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parents[1]
CODEX_HOME_ROOT = PROJECT_ROOT / ".codex-home"


def get_codex_home(profile: str) -> Path:
    return CODEX_HOME_ROOT / profile


def set_profile(profile: str) -> None:
    codex_home = get_codex_home(profile)
    codex_home.mkdir(parents=True, exist_ok=True)

    if profile == "main":
        source = Path.home() / ".codex" / "config.toml"
        target = codex_home / "config.toml"

        if not source.exists():
            raise FileNotFoundError(f"OpenAI Codex config not found: {source}")

        shutil.copyfile(source, target)

    elif profile == "deepseek":
        config = codex_home / "config.toml"
        models = codex_home / "models.json"

        if not config.exists():
            raise FileNotFoundError(
                f"DeepSeek config not found: {config}\n"
                "Create the DeepSeek config.toml before switching."
            )

        if not models.exists():
            raise FileNotFoundError(
                f"DeepSeek models.json not found: {models}\n"
                "Create models.json from the DeepSeek Codex documentation."
            )


def main() -> None:
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(dest="command", required=True)

    set_parser = subparsers.add_parser("set")
    set_parser.add_argument("profile", choices=["main", "deepseek"])

    path_parser = subparsers.add_parser("path")
    path_parser.add_argument("profile", choices=["main", "deepseek"])

    args = parser.parse_args()

    if args.command == "set":
        set_profile(args.profile)

    elif args.command == "path":
        print(get_codex_home(args.profile))


if __name__ == "__main__":
    main()

OpenAI側へ切り替える場合。

uv run python scripts/switch_codex_profile.py set main
export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path main)"
codex

DeepSeek側へ切り替える場合。

uv run python scripts/switch_codex_profile.py set deepseek
export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path deepseek)"
codex

3 (Optional) Taskfileに起動コマンドを追加

毎回コマンドを入力するのが面倒なので、Taskfileから起動できるようにする。

version: "3"

env:
  UV_CACHE_DIR: "{{.TASKFILE_DIR}}/tmp/uv-cache"
  PLAYWRIGHT_BROWSERS_PATH: "{{.TASKFILE_DIR}}/tmp/playwright-browsers"

tasks:
  codex:codex:
    desc: Run Codex with OpenAI profile.
    cmds:
      - |
        uv run python scripts/switch_codex_profile.py set main
        export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path main)"
        codex {{.CLI_ARGS}}

  codex:deepseek:
    desc: Run Codex with DeepSeek profile.
    cmds:
      - |
        uv run python scripts/switch_codex_profile.py set deepseek
        export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path deepseek)"
        codex {{.CLI_ARGS}}

以下のように起動できる。

task codex:codex
task codex:deepseek

ハマったポイント

DeepSeekを指定してもOpenAIのモデルで起動する

最初はDeepSeek用の CODEX_HOME を指定しても、OpenAIのモデルで起動していた。

task codex:deepseek
# > model: gpt-5.6-sol

CODEX_HOME をDeepSeek用のディレクトリに切り替えるだけではなく、その配下にDeepSeek用の config.tomlmodels.json を事前に配置しておく必要がある。

そのため、DeepSeek用の設定ファイルを用意した上で、その CODEX_HOME を指定してCodexを起動することで解決した。

API key login is required で起動できない

DeepSeek用の設定を読み込めるようにしたところ、次のエラーが発生した。

API key login is required, but ChatGPT is currently being used. Logging out.

原因としては、DeepSeek用の CODEX_HOME にChatGPTの認証状態が残っていたことだった。

DeepSeek用の CODEX_HOME を指定してログアウトすることで解決した。

export CODEX_HOME="<DeepSeek用CODEX_HOME>"
codex logout

OpenAI側ではなく、DeepSeek側の CODEX_HOME を指定してログアウトする点に注意。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?