作業開始前のチェックリスト
先に目を通しておけば、途中で戻ってくる手間が省けます。
- 登録に使えるメールボックス。
- ローカル環境に以下のいずれかのランタイムがインストールされていること:Python 3、JDK 15 以降(テキストブロックを使用)、Go、または curl 拡張機能付きの PHP。
- 18 歳以上の成人であることを確認してください。本サービスは成人ユーザーのみを対象としています。
- 純粋なテキスト対話が必要であることを理解してください。ここではモデルが一つだけで、ベクトル検索、画像、音声、ファインチューニングは提供していません。
- キーは環境変数に保存し、ソースコードにハードコードしたり、リポジトリにコミットしたりしないでください。
API の仕様はシンプルです:エンドポイント URL は https://api.wushenchaapi.com/v1 で、OpenAI のチャット補完 API と互換性があります。そのため、以前書いたリクエストボディをほぼそのまま流用できます。
所要時間の目安:登録は 1 分、環境構築は環境によりますが、初回リクエスト自体は 30 秒以内です。これより時間がかかる場合は、ネットワークまたはキーの問題である可能性が高いため、末尾のトラブルシューティングリストに直接ジャンプしてください。順序は崩さないでください:まず models、次に chat、同期から始めて、その後ストリーミングへ。各ステップを確認してから次に進んでください。
登録してキーを取得
/get-api-key/ にアクセスし、メールアドレスとパスワードで登録します。登録完了後、キーが即座に表示されるので、コピーしてください。いくつかの注意点:
- アカウントごとにキーは一つだけです。
- キーの再生成は可能ですが、旧キーは即座に無効になります。本番環境でキーを変更する前に、新しい値をデプロイしてください。
- 新規アカウントには $0.50 の試用クレジットが付与され、7 日間有効です。支払い情報の入力は不要です。
- 試用期間が終了するかクレジットが枯渇すると、リクエストは 402 を返し、エラーコードは
no_creditになります。前払いクレジットにチャージすれば利用を継続できます。サブスクリプションではなく、残有效期限はありません。
キーを環境変数に設定します:macOS / Linux では export API_KEY=YourKey、Windows PowerShell では $env:API_KEY="YourKey" を実行します。以降の例ではすべて API_KEY から読み取ります。
ステップ 1:/v1/models で接続を確認する
すぐにチャットを送信しないでください。まずコストゼロの GET リクエストを送信し、アドレス、ネットワーク、キーの 3 点がすべて正常であることを確認してください。
curl https://api.wushenchaapi.com/v1/models \
-H "Authorization: Bearer $API_KEY"200 とモデルリスト(uncensored のみ)が返れば接続成功です。401 が返った場合はキーの不備または未設定、タイムアウトの場合はローカルネットワークとプロキシを確認してください。接続性とリクエストボディの問題を分離して調査することは、接続段階で最も時間を節約する習慣です。
Python:requests
SDK不要です。requests.post 1つで十分です。3点注意してください:timeout を設定すること、r.ok を確認してからchoices にアクセスすること、エラー時は{"error":{"code":...,"message":...}} の形式であることです。
import os
import requests
url = "https://api.wushenchaapi.com/v1/chat/completions"
headers = {
"Authorization": "Bearer " + os.environ["API_KEY"],
"Content-Type": "application/json",
}
payload = {
"model": "uncensored",
"messages": [{"role": "user", "content": "用两句话描述一场雨夜里的追逐戏。"}],
"max_tokens": 300,
}
r = requests.post(url, headers=headers, json=payload, timeout=120)
print(r.status_code)
data = r.json()
if r.ok:
print(data["choices"][0]["message"]["content"])
print(data["usage"])
else:
print(data["error"]["code"], data["error"]["message"])成功時はusage にprompt_tokensとcompletion_tokensが含まれます。開発中は毎回ログ出力し、コストを把握することをお勧めします。
リクエストボディのフィールドを分解して確認
4 言語すべてで送信される JSON は同じです。これを理解しておけば、どの言語で書いても単なる翻訳作業になります。
| フィールド | 必須 | 説明 |
|---|---|---|
| model | 必須 | 固定値はuncensored です。 |
| messages | 必須 | 配列。各要素は role と content を含み、role は system、user、assistant のいずれかを取ります。 |
| max_tokens | 任意 | デフォルトは2048、コンテキストウィンドウの単一リクエスト上限は16,000です。長文の生成には手動で増やす必要があります。 |
| temperature / top_p / stop | 任意 | 標準的なサンプリングパラメータであり、そのまま渡されます。 |
| stream | いいえ | true の場合、SSE ストリーミングが有効になります。 |
レスポンスで最も頻繁に確認すべき箇所は3つです。choices[0].message.contentは本文、choices[0].finish_reasonは正常終了かトークン長で切り捨てられたかを示し、usageは今回のトークン使用量です。これら3つを確認して、接続が完了したと判断してください。
また、2つのハード制限を覚えておいてください。リクエストボディは8 MB以下、APIキー1つあたり毎分300リクエストまでです。バッチ処理では無制限に同時リクエストを送らず、適切な同時実行数の上限を設定してください。
Java:java.net.http
JDK 11 以降には HttpClient が標準搭載されており、依存ライブラリは不要です。以下では JDK 15 のテキストブロック機能で JSON を記述していますが、旧版 JDK では文字列連結に変更するか、お好みの JSON ライブラリでシリアライズしてください。
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class Demo {
public static void main(String[] args) throws Exception {
String key = System.getenv("API_KEY");
String body = """
{"model":"uncensored",
"messages":[{"role":"user","content":"写一段两百字以内的悬疑小说开头。"}],
"max_tokens":400}
""";
HttpRequest req = HttpRequest.newBuilder(
URI.create("https://api.wushenchaapi.com/v1/chat/completions"))
.timeout(Duration.ofSeconds(120))
.header("Authorization", "Bearer " + key)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.statusCode());
System.out.println(resp.body());
}
}ヒント:本文に中国語が含まれる場合、BodyPublishers.ofString はデフォルトでUTF-8エンコーディングを使用するため、追加処理は不要です。本番環境では、HttpClient をシングルトンとして再利用し、リクエストごとに新規作成しないようにしてください。
Go:net/http
Goの標準ライブラリでも十分対応可能です。重要なのは、デフォルトのhttp.DefaultClientを使用する際にタイムアウトを設定し、サーバー側で応答が止まった際にgoroutineがリークして固まらないようにすることです。
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"time"
)
func main() {
body := []byte(`{"model":"uncensored","messages":[{"role":"user","content":"给一个反派角色写三句独白。"}],"max_tokens":300}`)
req, err := http.NewRequest("POST", "https://api.wushenchaapi.com/v1/chat/completions", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 120 * time.Second}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(out))
}レスポンスボディは io.ReadAll で読み込み、解析を行ってください。構造化処理が必要な場合は、対応するstructを定義し、encoding/json で逆シリアライズしてください。フィールドは choices、message、content、usage です。
PHP:curl
PHPではcurl拡張を使用します。json_encode 呼び出し時には JSON_UNESCAPED_UNICODE フラグを指定してください。これを指定しないと中国語が \uXXXX にエスケープされ、動作には問題ありませんがデバッグ時に可読性が低下します。
<?php
$payload = [
"model" => "uncensored",
"messages" => [["role" => "user", "content" => "写一首八行的现代诗,主题是末班地铁。"]],
"max_tokens" => 300,
];
$ch = curl_init("https://api.wushenchaapi.com/v1/chat/completions");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$res = curl_exec($ch);
if ($res === false) {
die("curl 错误: " . curl_error($ch) . "\n");
}
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, "\n";
$data = json_decode($res, true);
echo $data["choices"][0]["message"]["content"] ?? $res, "\n";2種類の失敗を区別してください。curl_exec が false を返す場合はネットワーク層の問題です。内容が返されたがステータスコードが200ではない場合はAPI層の問題であり、error.code を確認する必要があります。
初回呼び出しでよくある失敗例
- 401:Header が
Authorization: 密钥となっており、Bearerプレフィックスが抜けている、または環境変数が新しいターミナルで有効になっていない。 - 404:パスに
/v1が不足している、またはchat/completionsのスペルミスがある。 - 400:JSONが不正、またはプロンプトとmax_tokensのトークン数の合計が100,000の上限を超えています。
- 402:残高が枯渇した、または試用期間が終了した。
- 出力が切り捨てられる:
max_tokensのデフォルトは2048で、最大16,000まで設定可能です。長文を生成する場合は明示的に値を増やしてください。 - ストリーミングを有効にする:リクエストボディに
"stream": trueを追加してください。レスポンスはSSE形式となり、最後にusageデータブロックが自動的に付加されます。
接続完了後、プロンプトの書き方で出力品質を向上させ、エラー時はエラーコードトラブルシューティングガイドを確認してください。パラメータ詳細はドキュメント、価格は価格ページをご覧ください。
動作確認ができたら、本番環境へのデプロイ前に以下の3点を追加してください
チュートリアルのサンプルは最小限の動作保証版です。実際のサービスに組み込む場合は、少なくとも以下の3項目を追加してください。
- タイムアウト。サンプルでは長文生成の遅延を考慮し、一律で120秒が設定されています。同期待機を行う場合は、許容範囲に合わせてタイムアウト値を短縮し、ストリーミング出力と組み合わせることで、ユーザーが先に文字を表示させることができます。
- エラーの振り分け。401、402、403 は再試行しても解決しないエラーであり、アラート通知またはユーザーへの表示が必要です。429 と 503 のみ、バックオフ再試行の対象となります。具体的な実装は排障マニュアルに記載していますので、ここでは割愛します。
- 使用量の記録。毎回のレスポンスの usage をログに記録してください。記録するのは数値のみとし、ユーザーのコンテンツをログに含めないでください。月末の請求書確認や異常な使用量の調査に役立ちます。
鍵の管理について一言補足します。API キーは1つしか存在せず、漏洩した場合は再発行するしかありません。再発行すると、使用中のすべてのサービスが同時に切断されます。そのため、複数のスクリプトや複数のサーバーの設定ファイルに鍵を散在させず、一元管理された鍵設定場所に集中配置してください。これにより、変更時に抜け漏れを防ぐことができます。
最後にコンテンツの境界について:成人向けコンテンツ、小説のフィクション、論争のあるトピックは拒否されませんが、未成年者に関連する性的コンテンツはすべてブロックされ、403が返されます。フィクションやロールプレイも例外ではありません。あなたのアプリケーションが成人ユーザーを対象とする場合は、登録フローに年齢確認を追加することを推奨します。
最後に自己チェックの順序を提示します。モニターの横に貼っておいても構いません:API キーが環境変数に含まれているか、models エンドポイントが通るか、リクエストボディが有効なJSONか、model が uncensored であるか、max_tokens が十分か、レスポンスの finish_reason が stop か length か、usage が記録されているか。これら7項目がすべて緑(正常)であれば、接続完了です。