お知らせ: GPT Image 2.6 Flare と Sunburst が新登場、期間限定で20%オフ、今すぐ体験
HiAPI
ブログ

チュートリアル

HiAPI API で kimi-k3.1-pro を呼び出す方法:curl、Python、そしてそのまま実行できるリクエスト

エンドポイント、リクエストパラメータ、ストリーミング、ツール呼び出し、エラー診断を網羅した実践的な統合ガイド

Nov 12, 2026
封面图:深墨绿底色上,两组扁平缎带呈经纬交错编织成规整的开放式网格,缎带为克制的黄铜色与暗绿色。
このページの内容

なぜ集約 API 経由で kimi-k3.1-pro を呼び出すのか

モデルの統合には、毎回同じ隠れたコストが伴います。初日は楽しくても、2 か月目にはメンテナンスになります。kimi-k3.1-pro をアプリに直接組み込むと、その提供元の認証方式、エラーセマンティクス、クォータモデル、リリースサイクルをそのまま引き継ぐことになります。単一モデルのプロトタイプなら問題ありません。しかし、2 つ目のモデル、2 つ目の環境、あるいはあるエンドポイントで障害が起きたときのフォールバック経路が欲しくなった瞬間に、それは摩擦に変わります。

集約 API はこうした差異を 1 つの契約に収束させます。HiAPI は kimi-k3.1-pro を OpenAI 互換のリクエスト形式で公開しています。つまり、ここで書くクライアントコードは使い捨てではありません。モデル識別子を差し替えるだけで、同じリクエスト構造をプラットフォーム上の他のモデルにも流用できます。同じヘッダー、同じメッセージ配列、同じストリーミングのラッパーです。

kimi-k3.1-pro に限って言えば、これには 3 つの実用的な意味があります。

  • 単一の認証面。 増え続ける提供元アカウント群ではなく、1 つの API キーと 1 つのベース URL を管理するだけで済みます。
  • 予測可能なペイロード。 リクエストとレスポンスのスキーマがモデル間で安定しているため、パース、リトライ、ログの各レイヤーは一度書けば済みます。
  • 低い移行コスト。 後である種の負荷に別のモデルが適していると分かっても、変更はペイロード内の 1 つの文字列だけで、トランスポート層のコードを書き直す必要はありません。

本ガイドの残りは統合そのものです。リクエストの解剖、そのままコピーできる curl 呼び出し、等価な Python クライアント、そして本番環境でもっとも問題になりやすい 2 つの機能——ストリーミングとツール呼び出し——、最後にエラー診断のチェックリストです。

始める前に用意するもの

  • HiAPI の API キー。プロジェクトでシークレットを保管している場所に保存します。
  • HiAPI コンソールから取得した、あなたのアカウントの API ベース URL。以下のすべての例では https://api.hiapi.ai/v1 をプレースホルダーのベースとして使います。本番前にコンソールで実際のホストを確認してください。
  • kimi-k3.1-pro のモデル識別子文字列。コンソールのモデル一覧からそのままコピーしてください。識別子は大文字小文字を区別します。
  • 最初のテスト用の curl、そしてクライアント例用に requests ライブラリを入れた Python 3.9 以上。

リクエストの形:エンドポイント、ヘッダー、モデルパラメータ

会話呼び出しは毎回同じ解剖構造に従います。一度すべての部分を理解すれば、その後はフィールドごとにデバッグする必要はありません。

エンドポイント

会話補完はベース URL 配下の単一パスにあります。

POST {BASE_URL}/chat/completions

本ガイドのすべての例に必要なエンドポイントはこれだけです。ストリーミングとツール呼び出しは独立したエンドポイントではなく、同じリクエストボディ上のオプションです。

ヘッダー

実際に効くヘッダーは 2 つだけです。

Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json

キーは Authorization ヘッダーに Bearer プレフィックス付きで入れます。URL、クエリパラメータ、リクエストボディには入れないでください。これら 3 つの方法はいずれもキーをログやエラーレポートに漏らします。Content-Type は明示的に設定してください。HTTP クライアントによっては推測してくれません。

本当に重要なリクエストボディのフィールド

最小のリクエストボディには意味のあるフィールドが 4 つあります。

  • model —— kimi-k3.1-pro の識別子。必須です。初回で最も書き間違えやすいフィールドで、完全一致が必要です。
  • messages —— 順序付きのオブジェクト配列で、各オブジェクトは role(system、user、assistant)と content を持ちます。必須かつ非空です。順序がそのまま会話履歴になります。モデルが見るのはこの配列だけであり、それ以外はありません。
  • stream —— ブール値で、デフォルトは false。true の場合、レスポンスは単一の JSON ボディではなくサーバー送信イベントとして届きます。専用のセクションを後述します。
  • temperature —— 任意のサンプリング制御です。低い値はより決定的な出力を、高い値はより多様な出力を生みます。ユースケースごとに一度決めたらそのままにし、リクエストごとに調整しないでください。

統合が成熟するにつれて追加できる任意フィールド:

  • max_tokens —— 生成長の上限。コストとレイテンシのガードレールとして使えます。これが制限するのは出力であり、入力ではない点に注意してください。
  • tools —— ツール定義の配列。後述します。
  • tool_choice —— モデルが提供したツールを呼ぶかどうか、またどう呼ぶかを制御します。
  • stop —— 生成を終了させる 1 つ以上のシーケンス。

期待すべきレスポンス

非ストリーミングのレスポンスは JSON オブジェクトを返し、その choices 配列には少なくとも 1 つのエントリーが含まれます。そのエントリー内には role と content を持つ message オブジェクトがあり、さらに生成がなぜ停止したかを示す finish_reason があります。常に finish_reason で分岐して処理し、内容が完全だと仮定しないでください。切り詰められたレスポンスにも内容はありますが、完全な答えではありません。

パーサーは文字列化されたレスポンスではなく、この構造に対して書いてください。そうすればプラットフォーム上でモデルをどう入れ替えても生き残ります。

実行可能な curl リクエスト

ここから始めてください。有効なレスポンスが返れば、キー、ベース URL、モデル識別子はすべて正しく、以降の問題は認証情報ではなくコード側にあります。

curl -sS "$HIAPI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kimi-k3.1-pro",
    "messages": [
      {"role": "system", "content": "あなたは簡潔な技術アシスタントです。"},
      {"role": "user", "content": "冪等キーとは何かを 2 文で説明してください。"}
    ],
    "temperature": 0.3,
    "max_tokens": 256
  }'

各フィールドの説明

  • -sS は curl の進捗表示を静かにしつつ、エラーは依然として表に出します。2 つ目の S がないと、失敗したリクエストが静かに終了し、デバッグの 1 ラウンドを無駄にします。
  • 環境変数 により、キーがシェル履歴やターミナルのスクロールバックバッファに残りません。シェルの設定ファイルまたは読み込まれた .env で HIAPI_BASE_URL と HIAPI_API_KEY をエクスポートしてください。
  • シングルクォートでリクエストボディを囲む のは POSIX シェルでは正しい方法ですが、ペイロードにシングルクォートが含まれない場合に限ります。シングルクォートが必要になったら、ボディをファイルに移し、-d @body.json で渡してください。これにより JSON のフォーマットエラーに見えるクォートのバグを一類回避できます。
  • system メッセージ は任意ですが、含める価値があります。トーンと出力フォーマットを固定する最も手軽な場所です。
  • max_tokens はこの例では意図的に控えめにしています。スモークテストのレイテンシとコストの両方を制限します。

結果の解釈

成功した呼び出しは HTTP 200 と JSON ボディを返します。先に進む前に 3 つを確認してください。

  1. choices が非空の配列である。
  2. choices[0].message.content に実際の答えが含まれている。
  3. choices[0].finish_reason が正常完了の値であり、長さによる切り詰めではない。

レスポンスボディがエラーオブジェクトなら、トラブルシューティングのセクションに進んでください。エラーメッセージは通常、問題のフィールドを具体的に指摘します。

再現性のためのヒント

その curl 呼び出しをリポジトリ内のシェルスクリプトとして保存してください。ライブ API に対する 1 コマンドのスモークテストは、「自分の統合が壊れた」のか「アカウントやキーが変わった」のかを切り分ける最速の方法です。何かおかしいと感じたら、まずこれを実行してください。

同じリクエストを Python で書く

Python 版は退屈に見えるべきです。それこそが目標です。興味深い判断(モデル識別子、ベース URL、タイムアウト)はすべて設定に置き、各呼び出し箇所に散らばめないでください。

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]
MODEL = os.environ.get("HIAPI_MODEL", "kimi-k3.1-pro")

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}


def chat(messages, temperature=0.3, max_tokens=512, timeout=60):
    payload = {
        "model": MODEL,
        "messages": messages,
        "temperature": temperature,
        "max_tokens": max_tokens,
    }
    resp = requests.post(
        f"{BASE_URL}/chat/completions",
        headers=HEADERS,
        json=payload,
        timeout=timeout,
    )
    resp.raise_for_status()
    data = resp.json()
    choice = data["choices"][0]
    return choice["message"]["content"], choice.get("finish_reason")


if __name__ == "__main__":
    text, reason = chat([
        {"role": "system", "content": "あなたは簡潔な技術アシスタントです。"},
        {"role": "user", "content": "冪等キーとは何かを 2 文で説明してください。"},
    ])
    print(reason)
    print(text)

このように構成する理由

  • data= ではなく json= を使う —— requests ライブラリが辞書をシリアライズし、コンテンツタイプを設定してくれます。手動シリアライズはエスケープミスを招きやすくなります。
  • 常に timeout=60 —— タイムアウト未設定は、ワーカープロセスがマネージャーに殺されるまでハングする最も一般的な原因です。サービス内のすべてのネットワーク呼び出しにタイムアウトを設定してください。
  • パース前に raise_for_status() —— これにより HTTP 層の失敗が呼び出し箇所で例外になり、不正なレスポンスボディが下流に流れるのを防ぎます。
  • MODEL を環境から取得 —— モデルを切り替えるとき、変わるのはモデル識別子だけです。これを設定に置くことで、切り替えはコード変更ではなくデプロイ変数になります。
  • finish_reason を返す —— 呼び出し側はほぼ常に、答えが切り詰められたかどうかを知る必要があります。

モデルをまたいで再利用可能に保つ

chat(messages, ...) のシグネチャは意図的にモデル固有のものを一切露出させていません。将来、より安価な負荷を別のモデルにルーティングするなら、明示的なモデル上書きパラメータを渡すか、異なる MODEL で 2 つ目のクライアントオブジェクトを構築するだけです。トランスポート、ヘッダー、リトライ戦略、エラー処理はすべてそのままです。

リトライに関する注意

chat() の内部で盲目的にリトライしないでください。その操作が安全に繰り返せるかどうかを知っているレイヤーでリトライしてください。失敗した補完は通常安全ですが、すでに下流の状態を変えたリクエストは安全ではありません。一時的なトランスポート失敗とレート制限のレスポンスに対してのみ、上限付きの指数バックオフでリトライしてください。

クライアントを壊さずにストリーミングする

ストリーミングは、チャット UI が即座に感じられるか、10 秒間空白になるかの差です。同時に最も多くの統合バグを持ち込みます。なぜなら、レスポンスがもはや 1 つの JSON ドキュメントではないからです。

有効化の方法

リクエストボディに "stream": true を加えます。リクエストの他の部分は変わりません。

with requests.post(
    f"{BASE_URL}/chat/completions",
    headers=HEADERS,
    json={"model": MODEL, "messages": messages, "stream": True},
    stream=True,
    timeout=120,
) as resp:
    resp.raise_for_status()
    for line in resp.iter_lines(decode_unicode=True):
        if not line or not line.startswith("data:"):
            continue
        chunk = line[len("data:"):].strip()
        if chunk == "[DONE]":
            break
        # chunk を JSON としてパースし、choices[0].delta.content を読む

実際に届くもの

レスポンスボディは一連のサーバー送信イベントです。各イベントは data: 行で、小さな JSON オブジェクトを運びます。choices[0] には message オブジェクトではなく delta オブジェクトが入っています。delta は通常 content の断片を含みますが、何も含まないこともあります。ストリームはセンチネル行 data: [DONE] で終わります。

4 つのルールでほぼすべての誤りをカバーできます。

  1. 置き換えずに蓄積する。 各 delta は断片です。delta.content をバッファに追加してください。完全な答えは各断片を順に連結したものです。
  2. 空の delta をスキップする。 最初と最後のイベントはしばしば内容を持ちません。None を追加しないようにしてください。
  3. [DONE] をデータではなく終端として扱う。 そこで読み取りを止めてください。それ以降の内容はレスポンスの一部ではありません。
  4. finish_reason を持つ最後のイベントから読む。 ストリーミングモードでは、完了状態はトップレベルのフィールドではなく、後方の delta に現れます。

名指しすべき落とし穴

  • クライアント呼び出しで stream=True を設定し忘れる。 ストリーム全体を 1 つのバッファとして受け取ることになり、目的に反し、非常に遅い非ストリーミングリクエストのように見えます。
  • タイムアウトを非ストリーミング用に設定する。 長い生成のストリーミングは短いリクエストより長く続きます。ストリーミング経路にはより寛容な読み取りタイムアウトを与え、選んだ間隔でバイトが届かない場合に中止するアイドルタイマーの検討もしてください。
  • プレフィックスを確認せずに行ごとにパースする。 すべての行がデータではありません。空行はイベントを区切ります。無視してください。
  • delta に content キーがあると仮定する。 ツール呼び出しのストリーミングでは delta に別のキーが入ります。常に防御的に読んでください。
  • クライアント側の消費者を忘れる。 サーバーがストリームをバッファに書き、終了時だけ出力するのは、技術的にはストリーミングでも実践的にはそうではありません。下流が断片の到着時にレンダリングすることを確認してください。

ストリーミングすべきでないとき

バッチ処理、バックグラウンド要約、そして出力が人間に見せるのではなくプログラムに消費されるものは、通常ストリーミングしないほうがシンプルです。非ストリーミングのレスポンスは 1 回のパースで済み、ログに取りやすく、スキーマ検証も容易です。レイテンシがユーザーに見える場所でストリーミングを使い、デフォルトではストリーミングしないでください。

フローにツール呼び出しを追加する

ツール呼び出しは、モデルが答えをでっち上げる代わりに、あなたのコードに操作の実行を要求できるようにします。プロトコルは 2 ラウンドの会話です。あなたがツールを宣言し、モデルが呼び出し要求で応答するかもしれず、あなたがそれを実行し、結果を送り返します。

ツールの宣言

リクエストに tools 配列を加えます。各エントリーは関数記述を包みます。

{
  "model": "kimi-k3.1-pro",
  "messages": [{"role": "user", "content": "リスボンの天気はどうですか?"}],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "指定した都市の現在の天気を返します。",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "都市名"}
          },
          "required": ["city"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

関数および各パラメータの description は飾りではありません。モデルがいつ、どうツールを呼ぶかを判断する唯一の手がかりです。新しい同僚に説明を書くように書いてください。

レスポンスのループ

  1. リクエストを送る。
  2. choices[0].finish_reason がツール呼び出しを示すなら、choices[0].message.tool_calls を読む。各エントリーには id、関数 name、そして arguments がある。arguments はオブジェクトではなく JSON エンコードされた文字列なので、パースする。
  3. 自分のコードで関数を実行する。パラメータに対して何か処理する前に検証する。モデルはもっともらしいがフィールドが欠けていたり型が誤っていたりするペイロードを生成することがある。
  4. アシスタントのメッセージ——その tool_calls を含めて——を自分の messages 配列に追加する。
  5. 一致する tool_call_id を持ち、結果を content とした、ロールが tool の新しいメッセージを追加する。
  6. リクエストを再度送る。モデルは今度はツール出力を使って最終的な答えを組み立てる。

ステップ 4 は皆が飛ばし、そして壊れるステップです。アシスタントのツール呼び出しラウンドを含めずにツール結果だけを送り返すと、会話に宙に浮いた参照が生まれ、モデルは自分が何を要求したかの記録を持ちません。

複数の呼び出しの処理

レスポンスは同じラウンドに複数のツール呼び出しを含むことがあります。1 つずつ実行し、各呼び出しに対してそれぞれ自分の tool_call_id を持つ tool メッセージを 1 つ返してください。それらを結合しないでください。

呼び出しの制御

tool_choice はあなたのポリシーレバーです。auto はモデルに任せ、特定のツールを要求すればその呼び出しを強制し、ツールを無効にすれば直接答えるよう指示します。予算を保ってください。ツールが失敗し続け、モデルがリトライし続けると、ツールループは長く走り続ける可能性があります。自分のループでイテレーション回数を制限し、上限に達したらリクエストをずるずる続けるのではなく明確なメッセージを返してください。

ツール出力を信頼できないものとして扱う

モデルはツール結果をテキストとして読みます。小さく、構造化され、命令を含まず、そしてパラメータをこちら側で検証してください。無制限のテキストを返すツールはコストの問題であると同時に正確性のリスクでもあります。

よくあるエラーのトラブルシューティング

統合の失敗のほとんどは 5 つのバケツに収まります。プロンプトを変える前に、このチェックリストをたどってください。

1. 認証と認可

  • 症状: HTTP ステータスが 401/403 の範囲。
  • 確認: キーが存在し、貼り付け時に前後の空白がなく、ちょうど Bearer プレフィックスが付いている。
  • 確認: ベース URL が HiAPI コンソールに表示されるものと一致している。古い、または貼り付けを誤ったホストは紛らわしい認証エラーを生みます。
  • 修正: 環境変数を再エクスポートし、コードに触る前に curl スモークテストを再実行する。

2. 不正なペイロード

  • 症状: とあるフィールドを名指しするリクエスト検証エラー、またはパースできないレスポンスボディ。
  • 確認: リクエストボディが有効な JSON である。手で構築するなら json.tool で一度素早く検証し、コードで構築するなら辞書が誤って余計にネストされていないことを確認する。
  • 確認: messages が非空で、各エントリーに role と content がある。
  • 確認: role の値がサポートされる集合にある。role: "human" のようなタイポは、クライアントによっては明らかなエラーではなく静かなエラーになります。
  • 確認: tools のエントリーに type: "function" とネストされた function オブジェクトがある。フラット化された定義は最もよくあるツール呼び出しの誤りです。

3. モデル識別子

  • 症状: 見つからない類のエラー、またはそのモデルがあなたのアカウントでは利用できないというメッセージ。
  • 確認: 識別子はコンソールからそのままコピーしたか。大文字小文字と区切り文字の両方が重要です。
  • 確認: モデルがあなたのキーで有効になっているか。識別子が有効でも、あなたのアカウントで呼べないモデルは依然として失敗します。

4. コンテキストと長さの制限

  • 症状: リクエストが最大コンテキストを超えたというエラー、または長さに関連する finish_reason で終わるレスポンス。
  • 確認: システムプロンプト、メッセージ履歴、そしていかなるツール定義の合計。ツールスキーマは予算に計上され、忘れられがちです。
  • 修正: 履歴を削る、初期ラウンドを要約する、またはタスクを分割する。出力の切り詰めについては、負荷が本当にそれを必要とするなら max_tokens を上げ、そうでなければ有界のままにする。

5. レート制限とタイムアウト

  • 症状: 負荷時のレート制限ステータス、またはクライアントの読み取りタイムアウト。
  • 確認: リトライがバックオフなしで発行されていないか。タイトなリトライループは短いレート制限を継続的なレート制限に変えます。
  • 修正: レスポンスが示すレート制限シグナルに従い、ジッター付きの上限付き指数バックオフを使い、キーごとの並行性を制御する。タイムアウトについては、まずクライアントのタイムアウト値を見る。クライアント制限がモデルの生成時間より短いと、まさにこの症状が生じます。

汎用のデバッグ規律

すべての失敗について 4 つを記録してください。HTTP ステータス、レスポンスボディ、モデル識別子、そして stream が設定されていたかどうか。この 4 つでほぼすべてのインシデントを説明できます。また、curl スモークテストを最新に保ってください。それが通り、あなたのアプリが失敗するとき、問題は認証情報ではなくコード側にあると分かります。

エラーメッセージを読む

集約レイヤーは通常、どのフィールドが拒否を引き起こしたかを明確に伝えます。プロンプトを書き換えたい衝動に抵抗してください。メッセージを読み、名指しされたフィールドを直し、1 回リトライしてください。同じエラーが続くなら、深掘りする前にスモークテストでリクエストを検証してください。

本番前に:プロダクションチェックリスト

「自分のターミナルでは動く」と「本番環境で動く」の間のギャップは、主に誰も書き留めていないチェックリストです。ここにコピーする価値のあるものを用意しました。

設定とシークレット

  • API キーはシークレットマネージャーに保管し、ソース管理にも URL にもログ行にも絶対に置かない。HTTP クライアントがデバッグレベルで Authorization ヘッダーを出力できないことを確認する。
  • ベース URL とモデル識別子は設定であり、コードベースに散らばった定数ではない。ベース URL はコンソールで確認する。
  • キーはスケジュールに従ってローテーションし、チームメンバーが退職した後は必ずローテーションする。クライアントコードは変更なしでローテーション後のキーを拾えるべきです。

リクエストの衛生

  • すべての送信呼び出しに明示的なタイムアウトがあり、ストリーミング経路にはより寛容なタイムアウトとアイドル中止ルールがある。
  • すべての呼び出し経路に max_tokens が設定されている。無制限の生成は無制限の請求です。
  • サンプリング設定はユースケースごとに固定され記録されているため、デバッグが必要になったとき結果を再現できる。

レスポンス処理

  • パーサーは finish_reason で分岐し、切り詰めを完全な答えではなく独立した結果として扱う。
  • ストリーミングの蓄積は短いレスポンスにも長いレスポンスにもテストされ、早期終了するレスポンスも含まれる。
  • ツール呼び出しのパラメータは使用前に検証され、アシスタントのツール呼び出しラウンドは常にメッセージ配列にエコーされる。
  • ツールループにはイテレーション上限と明確な失敗メッセージがある。

失敗時の挙動

  • リトライは有界で、ジッター付きの上限付き指数バックオフを使い、安全に繰り返せる操作にのみ適用される。
  • レート制限のレスポンスに従い、叩きつけない。
  • 失敗はステータス、レスポンスボディ、モデル識別子、stream フラグを記録する。この 4 つのフィールドこそが実際にインシデントを解決します。
  • curl スモークテストは CI 内またはスケジュールで実行され、認証情報やモデルの変更を顧客ではなくダッシュボードから知る。

コストと容量

  • 利用量がどう課金されるかを把握している。プラットフォームは処理されたトークンで課金するため、長いプロンプトも長い生成も重要です。現在の料金はコンソールの価格パネルで確認してください。
  • どの負荷が最大の消費者か、そしてそれがフルモデルを必要とするか、より軽量なモデルで足りるかを知っている。
  • フォールバック経路がある。ある呼び出しが繰り返し失敗するなら、アプリは静かにハングするのではなく明らかに縮退する。

最後の質問

問いかけてください。この統合を書いた人ではない人が、それを監視できるか。チームの開発者がスモークテスト、エラーログのフィールド、設定を読み、失敗をどう診断するかを理解できるなら、あなたは完了です。できなければ、チェックリストはまだ未完成です。

実行可能な curl 呼び出し、再利用可能な Python クライアント、そしてこのチェックリストがあれば、kimi-k3.1-pro は単につながっただけでなく、本当に統合されたと言えます。

永続的なAIアーティファクトで開発を始める

APIキーを取得して、タスクベースの1つのAPIで画像・動画・音声モデルを呼び出せます。

APIドキュメントを読む