移行前後
典型的なOpenAIクライアントのPythonコードは以下の通りです:
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
r = client.chat.completions.create(
model="your-current-model",
messages=[{"role": "user", "content": "Draft a tense dialogue between two rivals."}],
)
そして同じクライアントが、無検閲の代替案を指し示しました:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.chatgptunfiltered.com/v1",
api_key=os.environ["UNFILTERED_API_KEY"],
)
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Draft a tense dialogue between two rivals."}],
)
コンストラクタで2行を変更し、呼び出しでモデル文字列を変更します。メッセージ形式、レスポンスオブジェクト、およびr.choices[0].message.contentの読み取り方は、以前と同じままです。この代替サービスは、独立したプロバイダが運用する別のモデルです。ChatGPTでもなく、OpenAIやその他の公式APIでもありません。
環境変数のみでの移行
最新の公式PythonおよびNode SDKは、引数なしでクライアントを作成する際にOPENAI_BASE_URLとOPENAI_API_KEYを読み取ります。つまり、アプリケーションコードを変更する必要はありません:
export OPENAI_BASE_URL="https://api.chatgptunfiltered.com/v1"
export OPENAI_API_KEY="YOUR_KEY"
python app.py
コードがmodel="uncensored"を渡すことを確認する必要があります。モデル名が多くの箇所でハードコードされている場合は、まず1つの設定値に抽出してください。この小さなリファクタリングにより、将来の切り替えがどちらの方向でも同様に低コストになります。
Nodeでも同じアイデアが適用できます:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.chatgptunfiltered.com/v1",
apiKey: process.env.UNFILTERED_API_KEY,
});
const r = await client.chat.completions.create({
model: "uncensored",
messages: [{ role: "user", content: "Give me five villain names." }],
});
console.log(r.choices[0].message.content);フレームワークとResponses形式
OpenAIクライアントをラップするライブラリは通常、base URL設定を公開しています。LangChainのOpenAIチャットラッパーでは次のようになります:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.chatgptunfiltered.com/v1",
api_key="YOUR_KEY",
)
print(llm.invoke("Name three moods for a chase scene.").content)
新しいResponses形式を使用する場合、POST /v1/responsesとPOST /v1/chat/completionsの両方がサポートされています。GET /v1/modelsはモデルを一覧表示し、キーとURLが正しいことを素早く確認できます。
期待される変更点
| 領域 | 気づく点 |
|---|---|
| 回答の意欲 | 法的な成人向け利用においてコンテンツ拒否なしで回答します。フィルタ付きモデルが拒否するプロンプトも通常は回答されます。 |
| 表現とスタイル | 異なるモデル、異なる声です。トーン、長さ、フォーマット習慣は以前のモデルと一致しません。 |
| モデルの選択 | 1つのモデル、IDはuncensoredです。選択できるティアはありません。 |
| 範囲 | テキストのみ:画像、音声、動画の生成、埋め込み、ファインチューニングはありません。 |
| コンテキスト | 100,000トークン、プロンプトとcompletionの両方。max_tokensはオプションです。 |
| 制限 | フルキー:並列8、1分間300。トライアルキー:並列2、1分間60。ボディ最大8 MB。 |
| エラー | HTTP 429エラー(コードrate_limitedまたはconcurrency);一時的な過負荷時にはRetry-After: 5ヘッダー付きの429を返します。 |
ストリーミング、ツール呼び出し、JSONモードはサポートされており、temperature、top_p、stop、seed、ペナルティも利用可能です。レスポンスヘッダーにはX-Request-Id、X-Balance-USD、X-RateLimit-Limit-Requests、X-RateLimit-Limit-Concurrencyが含まれます。詳細はドキュメントをご覧ください。
さらに2つの相違点に注意が必要です。まず、異なるモデルはトークンを異なる方法でカウントする可能性があるため、同じテキストのトークン数は旧プロバイダの報告と異なる場合があります。推定値ではなく、レスポンス内の使用量数値を使用してください。第二に、組み込みのウェブ検索やベンダー側のファイル保存など、ベンダーのホストツールに依存する機能はこのサービスには含まれません。ツール呼び出しは、関数を定義し、コードでそれらを実行するものです。
独自プロンプト用のパリティスクリプト
出力を視覚的に確認する代わりに、新しいエンドポイントでプロンプトセットをループ実行し、レビューに必要なものをすべて保存してください。
import csv, json
with open("prompts.json", encoding="utf-8") as f:
prompts = json.load(f) # a list of strings
with open("results.csv", "w", newline="", encoding="utf-8") as out:
w = csv.writer(out)
w.writerow(["prompt", "reply", "in_tokens", "out_tokens"])
for p in prompts:
r = client.chat.completions.create(
model="uncensored",
temperature=0.7,
messages=[{"role": "user", "content": p}],
)
w.writerow([p, r.choices[0].message.content, r.usage.prompt_tokens, r.usage.completion_tokens])
CSVを開き、列ごとにレビューします。トークン列は同じトラフィックのコスト予測を提供します:合計に1Mあたり$0.15と$0.50を掛けます。トライアルキーは1分間60リクエスト、同時2まで許可するため、ループを逐次実行すれば数百のプロンプトセットは数分で完了します。
短い移行チェックリスト
- キーを取得してください。APIキーページでGoogleまたはメールでサインアップし、$0.50の無料トライアルクレジットを受け取ってください。これは7日間有効で、カードは必要ありません。
- モデル名とURLを設定に移動します。1箇所にまとめ、環境変数から読み取ります。
- テストプロンプトを再実行します。以前のモデルが拒否したものを含む20〜50の実際の例を使用し、結果を確認します。
- システムプロンプトを調整します。フィルタ付きモデルを説得するためのテキストを削除します。役割、対象、フォーマットを説明するものを維持します。
- 429ハンドラを追加します。5秒待機して再試行します。キーに合わせて並列数を制限します。
- 使用状況を確認します。実際のトラフィック実行中にレスポンスの
X-Balance-USDを確認します。
ステップ5をカバーするリトライヘルパー:
import time
from openai import RateLimitError
def create_with_retry(**kwargs):
for _ in range(4):
try:
return client.chat.completions.create(**kwargs)
except RateLimitError:
time.sleep(5)
raise RuntimeError("rate limited after 4 tries")
旧モデルの保存済み出力を数週間保持してください。移行後にユーザーから違和感を訴えられた場合、旧モデルが何を出力していたかと比較し、その差がプロンプト、モデル、または入力に起因するものかを確認できます。
リスクのないロールアウト
すべてを一度に変更しないでください。プロバイダの選択を設定の背後に隠し、トラフィックの割合を移行し、数秒でロールバックできるようにします。
import os, random
from openai import OpenAI
old = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
new = OpenAI(base_url="https://api.chatgptunfiltered.com/v1", api_key=os.environ["UNFILTERED_API_KEY"])
SHARE = float(os.environ.get("NEW_SHARE", "0.05"))
def pick():
if random.random() < SHARE:
return new, "uncensored"
return old, os.environ["OLD_MODEL"]
5%から始めて、数日間エラー率、429応答の数、ユーザーフィードバックを監視し、その後引き上げます。ロールバックするにはNEW_SHAREを0に設定します。会話中に同じモデルに留める必要がある場合、チャット中にモデルを切り替えるとトーンが変わるため、リクエスト別ではなくユーザー別または機能別の選択の方が優れています。
コストと、そのままでよい場合
料金は入力トークン1Mあたり$0.15、出力トークン1Mあたり$0.50で、前払いクレジットから課金されます。入力1,500トークン、出力400トークンのリクエストの場合、1,500 x $0.15 / 1M = $0.000225、および400 x $0.50 / 1M = $0.0002となり、合計$0.000425、つまり1,000リクエストあたり$0.425です。他のベンダーについては、現在の料金ページをご確認ください。料率は変動するため、記憶に基づく比較はすぐに古くなります。チャージは$20から$500までの整数額で暗号資産で支払い、$50以上のボーナスが付きます。詳細は料金ページをご覧ください。
画像や埋め込みが必要、またはオーディエンスに厳格なモデレーションが必要、またはベンダー固有のモデルが必須の場合、現在のプロバイダを維持するのが適切です。このクラスのモデルに関する背景知識は、無検閲ChatGPTモデルの理解をお読みください。ハードリミットは変更されません:未成年者が関わる性的コンテンツは禁止されています。
両方のプロバイダーを並行して実行しても問題ありません。多くのチームは、通常のリクエストを1つのモデルにルーティングし、拒否応答が返されるリクエストを別のモデルにルーティングしています。どちらも同じフォーマットを使用するため、ルーティングは数行のコードと、どちらを使用するかを判断するルールで実現できます。
