Wu Xianzhi API移行ガイド
API 中継ステーション移行ガイド:OpenAI、OpenRouter から無検閲 API へ
現在プロジェクトが OpenAI、OpenRouter、または API 中継ステーションを利用しており、合法なリクエストを拒否しない無検閲 API へ移行したい場合、実際には 3 つの設定のみを変更すれば十分です。base_url、API キー、モデル名の変更です。本稿ではまず中継ステーションと専用無検閲モデルの違いを明確にし、パラメータ対照表、環境変数を用いた新旧インターフェースの並行実行方法、デプロイ前の切り替えチェックリスト、移行時に陥りやすい失敗例について解説します。
更新日:
ポイント
- 中継ステーションは元メーカーのモデルを転売しており、コンテンツポリシーは不変。拒答問題を解決するには専用無検閲モデルが必要
- 移行は 3 箇所のみ変更:base_url を https://api.wuxianzhiapi.com/v1,密钥,模型名 uncensored に
- embeddings、画像、音声、ファインチューニングは非対応。これらの機能は元のサービスを引き続きご利用ください
- 環境変数による段階的切り替えを行い、問題発生時は変数一つの変更でロールバック可能
API 中継ステーションと専用無検閲モデルの違い
まず概念を明確にしておかないと、移行時に方向性を誤りやすくなります。一般的な API 中継ステーションは、本質的に大手メーカーのモデル呼び出し枠を転売または集約しており、OpenAI 互換のエンドポイントを提供することで、同じ SDK を用いて異なるモデルを切り替え可能にしています。これは「アクセスと支払い」の問題を解決するもので、統一されたエントリポイントや請求書を提供しますが、モデル自体は変わらず、メーカーのコンテンツポリシーはそのまま維持されます。拒答されるべき話題は変わらず拒答され、中継先アドレスを変えてもこれは変わりません。
専用無検閲モデルは別問題です。他モデルを転送するのではなく、独自に提供されるモデルです。合法的な成人向けコンテンツ、フィクション、論争のある話題でも拒否されません。Wu Xianzhi APIは1つのモデルのみを提供し、モデル名はuncensoredです。OpenAI互換のAPI形式を採用しているため移行コストは低いですが、明確な境界があります。テキストのみで、画像・音声・ベクトル・ファインチューニングは非対応です。未成年者関連の性的コンテンツはフィクションでも403エラーでブロックされます。
したがって移行前に自問してください。「インターフェースの不安定さや高コスト」の問題か、それとも「モデルが合法なリクエストを常に拒否する」問題か。後者であれば、中継ステーションへの変更は意味が薄く、専用無検閲 API への変更が効果的です。多くのチームは両方を併用しています。汎用タスクは元のインターフェースを通し、無検閲出力が必要なリクエストのみをこちらへルーティングします。具体的な方法は後述します。
OpenAI または OpenRouter からの移行で変更すべき 3 箇所
OpenAI公式、OpenRouterなどの集約API、またはAPI中継のいずれを使用していた場合でも、OpenAI互換SDKを使用しているコードであれば、変更すべき点は3つだけです。base_urlをhttps://api.wuxianzhiapi.com/v1に変更し、api_keyを/get-api-key/で取得したAPIキーに置き換え、modelをuncensoredに統一します。他のモデルは選択できず、GET /v1/modelsにもこの1つしか表示されません。
import os
from openai import OpenAI
messages = [{"role": "user", "content": "你好"}]
# 迁移前(示意):
# client = OpenAI(api_key=os.environ["OLD_API_KEY"], base_url="旧地址")
# resp = client.chat.completions.create(model="旧模型名", messages=messages)
# 迁移后:只动 base_url、api_key、model 这三处
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
resp = client.chat.completions.create(model="uncensored", messages=messages, max_tokens=100)
print(resp.choices[0].message.content)Node.jsでも同様です。new OpenAI({...})内のbaseURLとapiKeyを変更してください。プロジェクトが直接HTTPリクエストを使用している場合は、リクエスト先をhttps://api.wuxianzhiapi.com/v1/chat/completionsに変更し、リクエストヘッダーはAuthorization: Bearer <密钥>のまま維持してください。Python、Node.js、cURLの完全な実装例はコード例で確認できます。
curl https://api.wuxianzhiapi.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WUXIANZHI_API_KEY" \
-d '{"model":"uncensored","messages":[{"role":"user","content":"你好"}],"max_tokens":50}'
パラメータ対照:利用可能か、非対応か
以下の表では、移行時に頻繁に遭遇するフィールドを確認します。原則として、会話関連の OpenAI 形式のコアフィールドはそのまま使用可能です。一方、「他のモデルや他のモーダリティ」に関連する機能はここでは提供されていません。
| 従来の使用方法 | 本サービスでの処理方法 |
|---|---|
model(各種GPTモデルなど) | uncensoredに変更する必要があります |
messages(system / user / assistant / tool) | フォーマットは一致しており、そのまま使用可能 |
max_tokens | デフォルト 2048、最大 32,000。超過時は 400 エラー |
stream: true | サポート。最後に使用量ブロックが自動付加されます |
tools / tool_choice | サポート。OpenAI 形式 |
| コンテキストウィンドウ | プロンプトと出力の合計 100,000 トークン |
| リクエストボディサイズ | 8 MB 以下 |
| レート | API キーあたり 1 分間 300 リクエスト |
| ベクトル embeddings | 非対応 |
| 画像生成 / 画像認識、音声、動画 | 非対応。テキストのみ処理 |
| ファインチューニング | サポートしていません |
| 複数のモデルに切り替える | モデルは1つだけで、切り替え可能なリストはありません |
表にリストされていない他のオプションフィールドは、デフォルトで元のメーカーの仕様に従うとは限りません。安全な方法は、テスト環境で個別に実行し、動作が期待どおりであることを確認してからリリースすることです。具体的なサポート状況はAPIドキュメントをご参照ください。
持っていない機能の場合:ベクトル、画像、音声の代替案
既存のプロジェクトで会話とベクトル検索の両方を同時に使用している場合、移行時に「すべてを移行する」と考えないでください。ここではテキスト会話のみを提供しているため、ナレッジベースの検索や意味的な重複排除など、embeddingsに関連するコードは既存のベクトルサービスを引き続き使用するか、独自にデプロイしたベクトルソリューションに置き換える必要があります。会話部分はここに切り替え、検索部分はそのままにしておけば、両者は互いに影響を与えず、これが最も手間のかからない分離方法です。
画像や音声についても同様です。例えば、プロダクトが「テキスト+画像」の形式である場合、テキスト生成はここで処理し、画像生成は既存の画像APIを引き続き使用します。音声読み上げが必要な場合は、テキスト生成の後に既存の音声サービスに渡してください。「テキスト生成」のステップを独立した関数として抽出しておけば、他の機能を後でどのように組み合わせても、修正範囲は小さくて済みます。
また、コード内で複数のモデルを分担して使用している場合もあります。例えば、安価なモデルで分類を行い、高価なモデルで創作を行うケースです。ここでは1つのモデルしか利用できないため、分類タスクもそのモデルで実行する必要があります。幸い、トークン100万あたりの価格は$0.25であり、出力が短い分類タスクのコストは非常に低く抑えられます。max_tokensを小さく設定すれば、コストはほぼ無視できるレベルになります。価格の詳細は価格ページをご覧ください。
並列実行:環境変数を使って2つのAPI間で切り替える
移行で最も恐れるべきは「一律の切り替え」です。より確実な方法は、コードに薄いラッパー層を追加し、環境変数でどちらのAPIにリクエストを送るかを決めることです。これにより、一部のトラフィックや機能のみを新しいAPIに切り替え、問題が発生した場合は変数を1つ変更するだけで元に戻すことができます。両方ともOpenAI互換の形式であるため、ラッパーの実装は非常に簡単です。
import os
from openai import OpenAI
PROVIDERS = {
"old": {
"base_url": os.environ.get("OLD_BASE_URL", ""),
"api_key": os.environ.get("OLD_API_KEY", ""),
"model": os.environ.get("OLD_MODEL", ""),
},
"wuxianzhi": {
"base_url": "https://api.wuxianzhiapi.com/v1",
"api_key": os.environ.get("WUXIANZHI_API_KEY", ""),
"model": "uncensored",
},
}
def get_client(name=None):
name = name or os.environ.get("LLM_PROVIDER", "old")
cfg = PROVIDERS[name]
return OpenAI(base_url=cfg["base_url"], api_key=cfg["api_key"]), cfg["model"]
def chat(messages, provider=None, **kwargs):
client, model = get_client(provider)
return client.chat.completions.create(model=model, messages=messages, **kwargs)
# 通用任务走旧接口,需要无审查输出的请求显式指定新接口
resp = chat([{"role": "user", "content": "写一个黑色幽默的短故事"}],
provider="wuxianzhi", max_tokens=800)
print(resp.choices[0].message.content)切り替えの粒度は3段階あります:環境別(テスト環境から先に切り替える)、機能別(創作系のAPIのみを切り替える)、ユーザー別(一部のアカウントのみをグレーリリース)。どのレイヤーであっても、ログに記録される provider フィールドを残しておくことをお勧めします。これにより、差異が発生した際に照合してトラブルシューティングを行うことができます。会話履歴も標準的な messages 配列として統一して保存することをお勧めします。そうすれば、同じセッションを両方のAPI間でシームレスに継続できます。
切り替えチェックリスト
以下の順序で確認すれば、基本的に見落としはありません:
- /get-api-key/ で登録し、API キーを取得します。$0.50 の無料トライアルクレジット(7日間有効)で検証できます。事前にチャージする必要はありません。
curl /v1/modelsを使用して、API キーが有効であり、ネットワークに到達可能であることを確認します。base_url、api_key、modelの3項目を環境変数で制御するように変更し、API キーをコードリポジトリにコミットしないようにします。- コード内のハードコードされたモデル名、
max_tokensの値、および embeddings 呼び出しを検索します。 - ストリーミング処理コードを確認し、最後の
choicesが空のときの使用量ブロックに互換性があるか確認してください。 - 429と503には指数バックオフの再試行を追加し、402と403には明確なエラー表示分岐を追加します。
- 実際のプロンプトで回帰テストを実行し、特に以前拒否されていた部分が正常に出力されるかどうかを重点的に確認します。
- まず少量のトラフィックでグレーリリースを行い、使用量とレイテンシを比較します。問題がなければ、範囲を拡大します。
- プロダクトの対象が成年ユーザーであり、用途が合法であることを確認してください。これが本APIの利用前提条件です。
移行時に最もよくある失敗例
モデル名の変更忘れ。旧コードの gpt 形式のモデル名や、ある集約プラットフォームのモデルパスをそのまま送信すると、エラーレスポンスが返されます。モデル名をグローバルに検索し、最終的に送信されるのが uncensored であることを確認してください。
max_tokens の上限超過。モデルに長く書かせるために、max_tokens を 32000 やそれ以上に設定しているプロジェクトがあります。ここでは1回のリクエストで最大 32,000 までであり、それを超えると 400 エラーが返されます。また、プロンプトに max_tokens を追加した場合、合計で 100,000 トークンを超えないようにしてください。入力が長い場合は、出力の上限を相应に下げる必要があります。
ストリーミングのusageブロック。ストリーミング終了前に、サーバーは usage を含むブロックを自動的に追加します。このブロックの choices は空の配列です。もし解析コードが chunk.choices[0] で直接値を取得するようになっていると、最後のステップでエラーが発生します。また、一部の旧コードでは用量を取得するために stream_options を手動で送信することがありますが、ここでは不要です。
「無検閲」を「境界なし」と誤解する。合法な成人向けコンテンツ、フィクション、論争のある話題は拒否されませんが、未成年者の性的コンテンツは常にブロックされます(フィクションやロールプレイも含む)。その場合、403 content_blocked が返されます。プロダクト側で成年ユーザーのアクセス制御を適切に行う必要があります。
残高とトライアルの有効期限。トライアルクレジットは7日後に失効し、残高が枯渇すると 402 エラーが発生し、エラーコードは no_credit です。アプリケーション内でこのエラーをユーザーにわかりやすいメッセージに変換し、単に「サービスエラー」と表示するのではなくしてください。具体的なユースケースの設計については ユースケース を参照してください。
よくある質問
移行後、既存のプロンプトを再作成する必要がありますか?
フォーマットの変更は不要で、messages 構造は完全に一致します。ただし、以前拒否を回避するために書かれていた「ジェイルブレイク」的な前書きは削除し、役割とタスクを明確に記述してください。これによりトークンを節約でき、より安定します。
移行期間中に新旧APIを同時に維持できますか?
可能です。むしろ推奨されます。環境変数を使って base_url、API キー、モデル名を制御し、一部機能または一部のユーザーのみを新しいAPIに切り替えます。問題が発生した場合は変数を1つ変更するだけで元に戻せます。
旧APIの embeddings 呼び出しを移行するとどうなりますか?
ここでは embeddings API がないため、リクエストは 404 を返します。ベクトル検索部分は既存のサービスを継続して使用し、会話リクエストのみを切り替えてください。
移行後にパフォーマンスが向上したかどうかをどう判断すればよいですか?
以前拒否または改変された実際のプロンプトのサンプルを準備して回帰比較を行い、拒否率、応答の長さ、usage内のトークン数を記録します。サンプルはネット上の一般的なテストセットではなく、自社のビジネスデータから取得してください。