メインコンテンツまでスキップ

OpenAI 互換 API

ChatWalaʻau はエージェントを OpenAI 互換エンドポイントとして公開するため、 OpenAI SDK を使う任意のアプリから利用でき ます。

API Keys 画面か、サーバー上で、responses スコープ(このエンドポイントにはこれで十分)の API キーを作ります (認証)。

chatwalaau keys create --name my-sdk-app --scope responses

SDK の base_url を自分のインスタンスに向けます:

from openai import OpenAI

client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="cwk_xxxxxxxx_...", # `keys create` が一度だけ表示する秘密の値
)

# 非ストリーミング
response = client.responses.create(
model="chatwalaau",
input="What is the weather in Tokyo?",
)

# ストリーミング
stream = client.responses.create(
model="chatwalaau",
input="Explain quantum computing.",
stream=True,
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
  • すべてのエージェントツール(天気、コーディング、画像生成)と Skills が利用可
  • previous_response_id によるマルチターン
  • API セッションはチャットサイドバーに API バッジ付きで表示
  • ストリーミング(SSE)と非ストリーミングの両モード

構造化出力​

エンドポイントは標準の OpenAI text.format フィールドを尊重するため、既存の SDK コードのまま回答を JSON または特定の JSON Schema に拘束できます。チャット UI と同じ プロバイダ seam で解決されるため、Azure OpenAI / Anthropic の両モデルで動作します。

# JSON Schema に拘束
response = client.responses.create(
model="chatwalaau",
input="Extract the city and the temperature unit from: weather in Tokyo in Celsius.",
text={
"format": {
"type": "json_schema",
"name": "extraction",
"schema": {
"type": "object",
"properties": {"city": {"type": "string"}, "unit": {"type": "string"}},
"required": ["city", "unit"],
"additionalProperties": False,
},
"strict": True,
}
},
)

# あるいは汎用 JSON を要求
response = client.responses.create(
model="chatwalaau",
input="List three primary colors as JSON.",
text={"format": {"type": "json_object"}},
)

通常の散文出力(既定)では text.format を省略します。チャット UI 側は モデルと推論 -> 構造化出力を 参照してください。

サンプリングオプション(temperature、top_p)​

temperature と top_p はどのリクエストでも受け付け、振り分け先のモデルごとに扱います。

振り分け先のモデルtemperature / top_p
Azure OpenAI、OpenAI(direct)、Microsoft Foundry適用される
Claude(Anthropic、direct または Foundry ホスト)無視される(v0.192.0 から)

v0.192.0 から Claude プロバイダは Anthropic SDK 1.x で動作し、この SDK はこれらの パラメータを受け付けません。リクエストは成功し、値は捨てられ、サーバーのログに Ignoring unsupported Anthropic sampling options が記録されます。adaptive thinking を使う 現行の Claude モデルは、もともとこれらを拒否していました。代わりにモデルの推論努力度を 使ってください(モデルと推論)。

/v1/responses は外部アプリ向けの設計のため、クライアントアドレスに関わらず常に API キー (どのスコープでも可)を要求します。認証を参照してください。外部の サーバーには、専用の responses スコープのキーを渡してください。このキーはこのエンドポイントにしか届きません。

運用者向けの制御​

v0.214.0 から、App Settings の OpenAI-compatible API グループにある3つの設定で、 このエンドポイントを制限できます。設定は次のリクエストから効き、影響するのは /v1/responses だけです。既定値は以前と同じ挙動です。

設定値(既定値)効果
モデル呼び出しごとの出力の上限0〜128000(0 は上限なし)max_output_tokens は、呼び出し側の値と上限の小さいほうになる。呼び出し側が送らなければ上限の値になる
応答に含めるツールの出力full / sources / none(full)sources と none は、ツールの呼び出しとツールの生の結果を応答から除く。sources は、rag_search が取り出した文書を annotation として付ける
受け付ける入力の rolepassthrough / user_only(passthrough)user_only では、user のメッセージ以外の input の項目(system、developer、assistant、ツールの項目)に 400 を返す

sources のとき、回答の本文の部分は次のようになります。

{
"type": "output_text",
"text": "Paid leave is 20 days.",
"annotations": [
{"type": "file_citation", "index": 22, "filename": "handbook.pdf", "page": 3, "distance": 0.12}
]
}
  • annotation は、そのターン中に文書が検索で取り出されたことを示すだけで、回答がそれを使ったことを 示すものではありません。
  • 上限はモデル呼び出し1回ごとにかかります。ツールを使うターンでは呼び出しが複数回になるので、 費用の上限にはなりません。費用を抑えるには利用上限を使います。推論モデルは考える分もこの上限に数えるので、上限が低すぎると 回答が空になることがあります。
  • user_only での会話の継続には previous_response_id を使います。履歴はサーバー側に保存されています。
  • 保存される会話は、どのモードでも同じです。

自社の文書だけで答える会社サイトのチャットにする場合は、サイトのキーを相談窓口のエージェントに 結びつけてください。文書の相談窓口 を参照してください。

利用上限​

v0.216.0 から、App Settings の OpenAI-compatible API: limits グループで、/v1/responses が使える量に上限をかけられます。呼び出し側のサイト(BFF)での回数制限は、そのサイトを通る経路しか 守りません。この上限は、キーが漏れた場合にも効きます。どの上限も既定値は 0(オフ)です。

設定効果
responses_requests_per_minute / _per_day / _per_month直近1分、1日、1か月に受け付けるリクエスト数
responses_input_tokens_per_day / _per_month入力トークン(responses_count_cache_reads をオフにしない限り、キャッシュ読み取りを含む)
responses_output_tokens_per_day / _per_month出力トークン(推論を含む)
responses_total_tokens_per_day / _per_month入力と出力の合計
responses_max_concurrent同時に処理するリクエスト数
responses_max_input_chars1リクエストの入力の文字数。保存済みの履歴を含む(超えると 400 input_too_large)
responses_limit_timezone日と月が切り替わる IANA タイムゾーン(既定値 UTC。例: Asia/Tokyo)

キーごとにも上限を持たせられます(1分・1日・1か月のリクエスト数、1日・1か月の合計トークン)。 API Keys 画面で設定します(認証)。厳しいほうの上限が先に断ります。

断られたリクエストは何も実行せず、OpenAI のエラーの形の 429 と、秒数の Retry-After を返します。

{"error": {"message": "The daily request limit for /v1/responses has been reached.",
"type": "insufficient_quota", "code": "requests_per_day", "param": null}}
typeいつBFF での表示の例
rate_limit_exceeded1分あたりの上限、または responses_max_concurrent「混み合っています。少し待ってからお試しください」
insufficient_quota1日・1か月の上限「本日の受付は終了しました」

code はどの上限かを示します(キーごとの上限は key_ で始まります)。メッセージにキーの名前は入りません。

注意点:

  • 上限は金額ではなくトークンで数えます。モデルが決まっていれば、入力と出力の上限で費用を追えます。
  • トークン数はターンが終わるまで分かりません。少しでも残りがあれば受け付けるので、処理中のターンは トークンの上限を超えて終わることがあります。responses_max_concurrent、responses_max_input_chars、 出力の上限を設定して、超える量を抑えてください。
  • カウンターはサーバーのプロセスごとにあり、再起動後はトークン台帳から作り直します。複数のインスタンスや ワーカーではそれぞれが別に数えるので、上限をインスタンス数で割るか、インスタンスを1つにしてください。
  • responses スコープのキーでは、これらの設定を変えられません。
  • 外側の防衛線として、提供元のクォータ(例: Azure OpenAI の1分あたりのトークン数)と、クラウドの予算アラートを 残してください。

文書の相談窓口​

v0.218.0 から、会社サイトのサーバー(BFF)は、専用のキーで、選んだ文書だけから答える相談窓口を動かせます。

  1. 検索範囲(検索してよいコレクションとオントロジー)を持つカスタムエージェントを、エージェントの編集画面か YAML で作ります(検索範囲)。ツールは必要なものだけ (rag_search、オントロジーを使うなら ontology_query)にし、grounding: strict と max_distance を設定します。
  2. API Keys 画面で、BFF のキーをそのエージェントに結びつけ、Conversations を Temporary にします (認証)。
  3. Tool output in responses は sources のまま、利用上限 も使い続けます。

結びつけたキーは、そのエージェントだけで動きます。使えるのはそのツールと検索範囲だけで、Web 検索はなく、 既定のモデルに回ることもありません。"model": "chatwalaau" を送ってください。

応答条件
400 model_not_allowed結びつけたキーがほかのモデル名を送った
503 agent_unavailable結びつけたエージェントが削除された、または警告がある。ほかのエージェントには回らない
400 storage_mismatchtemporary のリクエスト(または temporary のキー)が保存済みの会話を続けようとした
400 model_not_foundresponses_reject_unknown_model がオンのとき、結びつけていないキーが知らないモデルを送った

strict では、モデルを呼ぶ前にサーバーが文書を検索します。

  • max_distance 以内に何もなければ、決まった英語の文 "I could not find an answer to this question in the documents I can search. Please rephrase your question or contact the person in charge." を返し、モデルは呼びません。応答には "metadata": {"grounding": "no_match"} が付きます。
  • 見つかれば、渡した抜粋からモデルが答え、応答には "metadata": {"grounding": "grounded"} が付きます。 sources モードでは、抜粋が file_citation の注記として返ります。モデル自身が決まった文で答えたときも metadata.grounding は no_match です。
{"id": "resp_...", "output": [...], "metadata": {"grounding": "no_match"}}

続きのターンでは、最後の2つの user メッセージで検索するので、「では短時間勤務は?」でも主題が見つかります。

注意点:

  • strict が保証するのは「文書がなければ答えない」までです。抜粋から作った回答に独自の内容が混ざらないことは 証明できず、そこは指示文頼みのままです。
  • max_distance を設定してください。設定しないと、何か入っているコレクションは常に一番近い文を返すので、 no_match は空のコレクションのときにしか起きません。出典の distance を見て値を決めてください。
  • metadata が付くのは strict の実行と振り分けた実行だけです。それ以外の応答は変わりません。

会話:

  • temporary=true(または保存方法が Temporary のキー)の会話は、チャット一覧に出ません。v0.218.0 から temporary の会話も previous_response_id で続けられるので、BFF は responses_input_roles=user_only のまま 複数ターンの会話を扱えます。temporary の会話は TEMPORARY_CHAT_RETENTION_DAYS を過ぎると消えます。
  • 保存した API の会話には保存期間を設けられます。Keep API conversations (days) (responses_session_retention_days、既定 0=ずっと残す)。アプリのチャットには一切触れません。
  • previous_response_id は索引で引くので、会話が増えても遅くなりません。

質問を文書の分野に振り分ける​

v0.220.0 から、複数の業務分野を受け持つ窓口は、検索する前に質問を分類できます。決定モデル(カタログの決定モデル。 型付きの判定 を参照)がエージェントの route から1つを選び、 その route のコレクションとオントロジーだけを検索します。そのため、別の分野の「惜しい」文がモデルに渡りにくくなります。

  1. まだであれば、モデル提供カタログに決定モデルを登録します。
  2. 窓口のエージェントに route を2つ以上加えます。場所はエージェント編集画面の Knowledge > Routing、または YAML (routing ブロック)です。route ごとに、id、決定モデルが読む説明、 エージェント自身の検索先の一部を指定します。
  3. リクエストで "route": "auto" を送ります。
client.responses.create(model="chatwalaau", input="有給休暇は何日ありますか?",
extra_body={"route": "auto"})

動き:

判定検索する範囲route_reason
ある route が最低確率に達したその route の検索先だけmatched
どの route も達しないエージェントの検索先すべて。low_confidence: clarify なら、詳しく聞き返す固定文を返し、モデルは呼ばないlow_confidence
決定モデルが失敗した、時間切れ、未設定エージェントの検索先すべて。on_error: fail なら 503 routing_unavailableerror

結果は応答の metadata に入ります。値はすべて文字列です。

{"metadata": {"grounding": "grounded", "route": "leave", "route_reason": "matched", "route_probability": "0.87"}}

route は route の id です。すべての検索先を使ったときは all、聞き返し文のときは none になります。 route_probability は、呼び出しが失敗したときは付きません。BFF でこれらの値をログに残して振り分けの誤りを見つけ、 route の説明や最低確率を調整してください。

応答条件
400 invalid_routeroute が "auto" 以外
400 route_not_available結びつけていないキー、または route のないエージェントで "auto" を送った
503 routing_unavailable決定モデルが失敗し、エージェントが on_error: fail

補足:

  • route のないリクエストは今までどおりに動き、決定モデルは呼びません。
  • つなげたターンも毎回振り分け直します(1つ前の user メッセージも入力に含めます)。会話の途中で分野が変わっても 追従します。
  • 振り分けで検索先を絞ることはできても、増やすことはできません。
  • 振り分けるターンごとに、決定モデルを1回呼びます。待つのは最大で Routing timeout (seconds) (responses_route_timeout_seconds、既定 5)までで、再試行はしません。トークンは呼び出し元のキーの利用として記録され (目的 responses_route)、キーのトークン上限に数えます。リクエスト数は1件のままです。
  • 最低確率の既定は Routing minimum probability (%)(responses_route_min_probability_percent、既定 60)です。 エージェントごとに min_probability を指定することもできます。