exo:models
Exoエージェントのモデルとプロバイダーを設定する際に使用します。モデル文字列、プロバイダーの選択、APIキー、ベースURL、ModelConfig、カスタムプロバイダー、get_provider()、model_registry、コンテキストウィンドウ、トークンカウント、メディア生成ツール、マルチモーダルコンテンツ、プロバイダー固有のオプションに対応しています。model、provider、openai、anthropic、gemini、vertex、api_key、base_url、ModelConfig、get_provider、model_registry、MODEL_CONTEXT_WINDOWS、ModelResponse、StreamChunk、ModelError、custom provider、media tools、dalle、imagen、veo、context window、temperature、max_tokens、TokenCounter、count_tokensといったキーワードで自動的にトリガーします。
description の原文を見る
Use when configuring Exo agent models and providers — model strings, provider selection, API keys, base URLs, ModelConfig, custom providers, get_provider(), model_registry, context windows, token counting, media generation tools, multimodal content, provider-specific options. Triggers on: model, provider, openai, anthropic, gemini, vertex, api_key, base_url, ModelConfig, get_provider, model_registry, MODEL_CONTEXT_WINDOWS, ModelResponse, StreamChunk, ModelError, custom provider, media tools, dalle, imagen, veo, context window, temperature, max_tokens, TokenCounter, count_tokens.
SKILL.md 本文
ブランチ: これらのスキルは
rename/orbiter-to-exoブランチ用に作成されています。ここで参照する Exo API は他のブランチで異なる可能性があります。
Exo Models — プロバイダーとモデル設定
このスキルを使用する場合
開発者が以下を必要とする場合にこのスキルを使用します:
- エージェントが使用する LLM モデルとプロバイダーを設定する
"provider:model"文字列形式を理解する- API キー、ベース URL、タイムアウト、または再試行ポリシーを設定する
- カスタムプロバイダーを登録する
- プロバイダー固有オプション (Vertex AI 認証情報、OpenAI プロキシ) を使用する
ModelResponse、StreamChunk、またはModelError型を使用する- メディア生成ツール (DALL-E、Imagen、Veo) を追加する
- コンテキストウィンドウサイズとトークン制限を理解する
- プロバイダー間のマルチモーダルコンテンツを処理する
判断ガイド
- どのモデル文字列を使用するか? →
"provider:model_name"(例:"openai:gpt-4o"、"anthropic:claude-sonnet-4-20250514") - モデル文字列にコロンがない? → OpenAI にデフォルト (例:
"gpt-4o"→"openai:gpt-4o") - プロバイダーインスタンスが直接必要か? →
get_provider("openai:gpt-4o", api_key=..., base_url=...) - 再試行/タイムアウトをカスタマイズする必要があるか? →
max_retriesとtimeoutの kwargs をget_provider()に渡す - Vertex AI を使用するか? →
GOOGLE_CLOUD_PROJECT環境変数 + ADC またはgoogle_service_account_base64のいずれかを設定 - カスタムプロバイダーを構築するか? →
ModelProviderをサブクラス化し、complete()+stream()を実装し、model_registryに登録 - 画像/動画生成が必要か? →
dalle_generate_image、imagen_generate_image、またはveo_generate_videoツールを使用 - コンテキストウィンドウサイズが必要か? →
MODEL_CONTEXT_WINDOWS辞書をチェック - 送信前にトークンをカウントする必要があるか? →
count_tokens(text, model="openai:gpt-4o")または一括カウント用のTokenCounter(model)を使用
リファレンス
モデル文字列形式
形式: "provider:model_name"
# 明示的なプロバイダー
agent = Agent(name="bot", model="openai:gpt-4o")
agent = Agent(name="bot", model="anthropic:claude-sonnet-4-20250514")
agent = Agent(name="bot", model="gemini:gemini-2.0-flash")
agent = Agent(name="bot", model="vertex:gemini-2.5-pro")
# 短形式 — コロンなしは OpenAI にデフォルト
agent = Agent(name="bot", model="gpt-4o") # "openai:gpt-4o" と同等
パース (exo.config.parse_model_string):
from exo.config import parse_model_string
parse_model_string("openai:gpt-4o") # → ("openai", "gpt-4o")
parse_model_string("gpt-4o") # → ("openai", "gpt-4o")
parse_model_string("anthropic:claude-sonnet-4-20250514") # → ("anthropic", "claude-sonnet-4-20250514")
組み込みプロバイダー
| プロバイダー文字列 | クラス | SDK | API キーの環境変数 |
|---|---|---|---|
"openai" | OpenAIProvider | openai (AsyncOpenAI) | OPENAI_API_KEY |
"anthropic" | AnthropicProvider | anthropic (AsyncAnthropic) | ANTHROPIC_API_KEY |
"gemini" | GeminiProvider | google-genai | GEMINI_API_KEY |
"vertex" | VertexProvider | google-genai (vertexai=True) | GCP ADC またはサービスアカウント |
エージェントモデルパラメーター
from exo import Agent
agent = Agent(
name="assistant",
model="openai:gpt-4o", # モデル文字列 (デフォルト: "openai:gpt-4o")
temperature=0.7, # サンプリング温度 0.0-2.0 (デフォルト: 1.0)
max_tokens=4096, # 最大出力トークン (デフォルト: None → プロバイダーのデフォルト)
planning_model="anthropic:claude-sonnet-4-20250514", # オプション: プランニングフェーズ用の別モデル
)
エージェントは初期化時にプロバイダーをインスタンス化せず、モデル文字列を保存し、run() 中に get_provider() 経由で遅延解決します。
get_provider() — 直接プロバイダーのインスタンス化
from exo.models import get_provider
# 基本
provider = get_provider("openai:gpt-4o")
# 明示的な API キーとカスタムベース URL (例: プロキシ)
provider = get_provider(
"openai:gpt-4o",
api_key="sk-...",
base_url="https://my-proxy.com/v1",
)
# 再試行/タイムアウトのカスタマイズ
provider = get_provider(
"anthropic:claude-sonnet-4-20250514",
api_key="sk-ant-...",
max_retries=5,
timeout=60.0,
)
# Vertex AI とサービスアカウント
provider = get_provider(
"vertex:gemini-2.5-pro",
google_project="my-gcp-project",
google_location="us-central1",
google_service_account_base64="eyJ0eXBlIjoi...",
)
内部的な動作:
- モデル文字列をパース →
(provider_name, model_name) model_registryでプロバイダークラスを検索MODEL_CONTEXT_WINDOWSからコンテキストウィンドウを検索 (オプション)- 提供されたすべてのパラメーターで
ModelConfigを作成 - プロバイダーをインスタンス化して返す
発生例外: プロバイダーが登録されていない場合 ModelError (エラーメッセージに利用可能なプロバイダーを含む)。
ModelConfig
from exo.config import ModelConfig
config = ModelConfig(
provider="openai", # プロバイダー名
model_name="gpt-4o", # モデル識別子
api_key="sk-...", # API キー (None → SDK が環境変数を読み込む)
base_url="https://proxy.com/v1", # カスタムベース URL (None → プロバイダーのデフォルト)
max_retries=3, # 一時的エラー時の再試行 (デフォルト: 3)
timeout=30.0, # リクエストタイムアウト秒数 (デフォルト: 30.0)
context_window_tokens=128000, # コンテキストウィンドウオーバーライド (None → レジストリから自動)
)
ModelConfig は extra = "allow" を持つ — プロバイダー固有の kwargs は属性として保存されます:
config = ModelConfig(
provider="vertex",
model_name="gemini-2.5-pro",
google_project="my-project", # Vertex 固有
google_location="europe-west1", # Vertex 固有
google_service_account_base64="...", # Vertex 固有
)
ModelProvider ABC
すべてのプロバイダーはこのインターフェースを実装します:
from exo.models.provider import ModelProvider
from exo.models.types import ModelResponse, StreamChunk
from exo.types import Message
class ModelProvider:
def __init__(self, config: ModelConfig) -> None:
self.config = config
async def complete(
self,
messages: list[Message],
*,
tools: list[dict] | None = None,
temperature: float | None = None,
max_tokens: int | None = None,
) -> ModelResponse: ...
async def stream(
self,
messages: list[Message],
*,
tools: list[dict] | None = None,
temperature: float | None = None,
max_tokens: int | None = None,
) -> AsyncIterator[StreamChunk]: ...
レスポンス型
ModelResponse (complete() から):
class ModelResponse(BaseModel):
id: str = "" # プロバイダー相関 ID
model: str = "" # このレスポンスを生成したモデル
content: str = "" # テキスト出力
tool_calls: list[ToolCall] = [] # リクエストされたツール呼び出し
usage: Usage = Usage() # トークン使用状況 (入力、出力、合計)
finish_reason: FinishReason = "stop" # "stop" | "tool_calls" | "length" | "content_filter"
reasoning_content: str = "" # チェーンオブソート (o1/o3、Claude 思考)
StreamChunk (stream() から):
class StreamChunk(BaseModel):
delta: str = "" # 増分テキスト
tool_call_deltas: list[ToolCallDelta] = [] # 増分ツール呼び出しフラグメント
finish_reason: FinishReason | None = None # 最終チャンクでのみ非 None
usage: Usage = Usage() # 通常は最終チャンクのみ
ToolCallDelta:
class ToolCallDelta(BaseModel):
index: int = 0 # マルチツール呼び出しレスポンス内の位置
id: str | None = None # ツール呼び出し ID (最初のチャンクのみ)
name: str | None = None # ツール名 (最初のチャンクのみ)
arguments: str = "" # 増分 JSON フラグメント
FinishReason 正規化 — すべてのプロバイダーは以下にマップします: "stop" | "tool_calls" | "length" | "content_filter"
ModelError
from exo.models.types import ModelError
# プロバイダーが失敗時に発生させる
class ModelError(ExoError):
def __init__(self, message: str, *, model: str = "", code: str = "") -> None:
self.model = model # 例: "openai:gpt-4o"
self.code = code # 例: "context_length"、"rate_limit"
環境変数
| 変数 | プロバイダー | 目的 |
|---|---|---|
OPENAI_API_KEY | OpenAI | API 認証 (SDK が自動読み込み) |
ANTHROPIC_API_KEY | Anthropic | API 認証 (SDK が自動読み込み) |
GEMINI_API_KEY | Gemini | API 認証 (api_key が渡されない場合のフォールバック) |
GOOGLE_API_KEY | Gemini メディアツール | imagen_generate_image が使用 |
GOOGLE_CLOUD_PROJECT | Vertex AI | GCP プロジェクト ID (必須) |
GOOGLE_CLOUD_LOCATION | Vertex AI | GCP リージョン (デフォルト: "us-central1") |
GOOGLE_SERVICE_ACCOUNT_BASE64 | Vertex AI | Base64 エンコードされたサービスアカウント JSON |
コンテキストウィンドウ
from exo.models import MODEL_CONTEXT_WINDOWS
# 既知のモデルとそのコンテキストウィンドウサイズ (トークン):
# gpt-4o: 128,000
# gpt-4o-mini: 128,000
# o1: 200,000
# claude-sonnet-4-6: 200,000
# claude-opus-4-6: 200,000
# claude-haiku-4-5-20251001: 200,000
# gemini-2.0-flash: 1,048,576
# gemini-1.5-pro: 2,097,152
get_provider() によって自動的に使用され、ModelConfig.context_window_tokens を入力します。
トークンカウント
呼び出し前のトークン推定には、TokenCounter または count_tokens() 便利関数を使用します。これらは tiktoken をプロバイダー対応エンコーディング選択で使用します。
from exo import TokenCounter, count_tokens
# クイックカウント (モデル文字列ごとにカウンターをキャッシュ)
n = count_tokens("Hello, world!", model="anthropic:claude-sonnet-4-6")
# 再利用可能なカウンター
counter = TokenCounter("openai:gpt-4o")
n = counter.count("Some text to count")
# チャットメッセージをカウント (メッセージごとのオーバーヘッドを含む)
total = counter.count_messages([
{"role": "user", "content": "Hello"},
])
# トークン ↔ 文字変換 (エンコーディング対応比率)
chars = counter.tokens_to_chars(4096)
tokens = counter.chars_to_tokens(10000)
精度: OpenAI モデルの場合は正確 (tiktoken は彼らのトークナイザー)。Anthropic の場合は ~95%、Gemini/Vertex の場合は ~85-90% (利用可能な最良のローカル近似)。
呼び出し後の使用状況: LLM 呼び出し後に実際に消費されたトークンについては、ModelResponse.usage または RunResult.usage を使用します — これらはプロバイダーが報告したものであり、常に正確です。
model_registry — プロバイダー登録
from exo.models.provider import model_registry
# 登録されたすべてのプロバイダーをリストします
model_registry.list_all() # ["openai", "anthropic", "gemini", "vertex"]
# プロバイダークラスを取得
provider_cls = model_registry.get("openai") # → OpenAIProvider
# カスタムプロバイダーを登録
model_registry.register("my_provider", MyProviderClass)
メディア生成ツール
画像/動画生成用の事前構築 @tool 関数:
from exo.models import dalle_generate_image, imagen_generate_image, veo_generate_video
agent = Agent(
name="creative",
tools=[dalle_generate_image, imagen_generate_image, veo_generate_video],
)
dalle_generate_image(prompt, size="1024x1024", quality="standard", style="vivid")
- 必須:
OPENAI_API_KEY - 戻り値:
list[ImageURLBlock]
imagen_generate_image(prompt, aspect_ratio="1:1", number_of_images=1)
- 必須:
GOOGLE_API_KEY - 戻り値:
list[ImageDataBlock](base64 PNG)
veo_generate_video(prompt, duration_seconds=5, aspect_ratio="16:9")
- 必須:
GOOGLE_CLOUD_PROJECT+ GCP 認証 - 戻り値:
list[VideoBlock]
マルチモーダルコンテンツサポート
Exo は、マルチモーダルメッセージに ContentBlock 型を使用します。プロバイダーのサポートは異なります:
| コンテンツ型 | OpenAI | Anthropic | Gemini/Vertex |
|---|---|---|---|
TextBlock | あり | あり | あり |
ImageURLBlock | あり | あり | あり |
ImageDataBlock | あり | あり | あり |
AudioBlock | あり | なし (警告) | あり |
VideoBlock | なし (警告) | なし (警告) | あり |
DocumentBlock | なし (警告) | あり | あり |
サポートされていない型は警告をログし、スキップされます — エラーは発生しません。
パターン
特定のモデルを持つ基本エージェント
from exo import Agent, run
agent = Agent(
name="assistant",
model="anthropic:claude-sonnet-4-20250514",
temperature=0.7,
instructions="You are a helpful assistant.",
)
result = await run(agent, "Hello!")
print(result.output)
直接プロバイダー使用 (エージェントなし)
from exo.models import get_provider
from exo.types import SystemMessage, UserMessage
provider = get_provider("openai:gpt-4o", api_key="sk-...")
response = await provider.complete([
SystemMessage(content="You are helpful."),
UserMessage(content="What is 2+2?"),
])
print(response.content) # "4"
print(response.usage) # Usage(input_tokens=..., output_tokens=..., total_tokens=...)
print(response.finish_reason) # "stop"
直接プロバイダーでのストリーミング
from exo.models import get_provider
from exo.types import UserMessage
provider = get_provider("anthropic:claude-sonnet-4-20250514")
async for chunk in provider.stream([UserMessage(content="Tell me a story")]):
if chunk.delta:
print(chunk.delta, end="", flush=True)
if chunk.finish_reason:
print(f"\n[Finished: {chunk.finish_reason}]")
OpenAI 互換プロキシ (例: Azure、LiteLLM、vLLM)
agent = Agent(
name="bot",
model="openai:my-deployment", # プロキシが期待するモデル名
)
provider = get_provider(
"openai:my-deployment",
api_key="your-proxy-key",
base_url="https://your-proxy.com/v1",
)
result = await run(agent, "Hello", provider=provider)
Vertex AI とサービスアカウント
import base64, json
service_account = json.dumps({
"type": "service_account",
"project_id": "my-project",
# ... サービスアカウント JSON の残り
})
provider = get_provider(
"vertex:gemini-2.5-pro",
google_project="my-project",
google_location="europe-west1",
google_service_account_base64=base64.b64encode(service_account.encode()).decode(),
)
カスタムプロバイダー登録
from exo.models.provider import ModelProvider, model_registry
from exo.models.types import ModelResponse, StreamChunk
from exo.config import ModelConfig
class MyProvider(ModelProvider):
def __init__(self, config: ModelConfig) -> None:
super().__init__(config)
# ここでクライアントを初期化
async def complete(self, messages, *, tools=None, temperature=None, max_tokens=None):
# メッセージを変換、API を呼び出し、ModelResponse を返す
return ModelResponse(
content="response text",
model=self.config.model_name,
usage=Usage(input_tokens=10, output_tokens=5, total_tokens=15),
)
async def stream(self, messages, *, tools=None, temperature=None, max_tokens=None):
# ストリーミング API を呼び出し、StreamChunk オブジェクトをイールド
yield StreamChunk(delta="Hello ")
yield StreamChunk(delta="world!", finish_reason="stop")
# 登録
model_registry.register("my_llm", MyProvider)
# 使用
agent = Agent(name="bot", model="my_llm:my-model-v1")
プランニングと実行で異なるモデル
agent = Agent(
name="researcher",
model="openai:gpt-4o", # メイン実行モデル
planning_enabled=True,
planning_model="anthropic:claude-sonnet-4-20250514", # プランニング用の安いモデル
planning_instructions="Create a research plan with clear steps.",
)
エラーハンドリング
from exo.models.types import ModelError
try:
result = await run(agent, "Hello", provider=provider)
except ModelError as e:
print(f"Model: {e.model}") # "openai:gpt-4o"
print(f"Code: {e.code}") # "rate_limit"、"context_length" など
print(f"Message: {e}") # "[openai:gpt-4o] Rate limit exceeded"
プロバイダー固有の注釈
OpenAI
- デフォルト max_tokens:
None(OpenAI が独自のデフォルトを適用) - ストリーミングは
stream_options={"include_usage": True}経由で使用状況を含める model_extra経由で o1/o3 モデルレスポンスからreasoning_contentを抽出base_urlはプロキシ、Azure OpenAI、vLLM、LiteLLM などを有効にする
Anthropic
- デフォルト max_tokens: 4096 (ハードコード — Anthropic はこのフィールドを要求)
- システムメッセージを
system=kwarg に抽出 (メッセージリストにはない) - 連続した
ToolResultメッセージは単一のユーザーメッセージにマージ (Anthropic API 要件) thinkingブロックからreasoning_contentを抽出- ツール形式は OpenAI の
parametersではなくinput_schemaを使用
Gemini
api_keyが提供されない場合GEMINI_API_KEY環境変数にフォールバック- API が省略した場合、合成ツール呼び出し ID (
call_0、call_1) を生成 - システムメッセージは
system_instruction設定経由で渡される、メッセージ内にはない - セーフティフィルター理由は
"content_filter"finish reason にマップ
Vertex AI
- Gemini と同じメッセージ/ツール形式 (共有 Google SDK)
GOOGLE_CLOUD_PROJECT環境変数またはgoogle_projectkwarg が必須- 位置のデフォルトは
"us-central1"—GOOGLE_CLOUD_LOCATIONまたはgoogle_locationでオーバーライド - 認証情報: サービスアカウント base64 →
google.oauth2.service_account.Credentials、または GCP ADC フォールバック
落とし穴
- モデル文字列にコロンがない → OpenAI と想定 —
"gpt-4o"は動作しますが、"anthropic:"プレフィックスなしの"claude-sonnet-4-20250514"は OpenAI モデルとして見つけようとし、失敗します - API キーはデフォルトで環境変数 —
api_key=Noneの場合、各プロバイダーの SDK は自動的に独自の環境変数を読み込みます。明示的にオーバーライドする場合にのみapi_keyを渡します。 - Anthropic は max_tokens=4096 をハードコード — OpenAI/Gemini と異なり、Anthropic は
max_tokensを要求します。指定しない場合、プロバイダーは 4096 にデフォルト設定します。max_tokensを Agent またはcomplete()/stream()で渡してオーバーライドします。 - Vertex AI は GCP 認証が必要 — ADC を設定 (
gcloud auth application-default login) するか、google_service_account_base64を渡す ModelConfig.extra = "allow"— プロバイダー固有の kwargs (google_projectなど) は静かに保存されます。タイプミスはエラーを発生させません。- コンテキストウィンドウは参考情報 —
MODEL_CONTEXT_WINDOWSはコンテキスト管理 (要約、ウィンドウイング) で使用されますが、プロバイダーは適用しません。それを超過するとプロバイダー側エラーが発生します。 - プロバイダーのインスタンス化は遅延 —
Agent(model="openai:gpt-4o")はrun()が呼ばれるまでプロバイダーを作成しません。無効なモデル文字列は初期化時に失敗しません。 - エージェントの温度デフォルトは 1.0 — しかし
complete()/stream()を直接呼び出すときプロバイダーにNoneが渡され、プロバイダー独自のデフォルトを使用 - メディアツールはスタンドアロン — 内部的に独自の SDK クライアントを作成し、エージェントのプロバイダーを使用しません。環境変数を直接読み込みます。
- サポートされていないコンテンツ型はエラーを発生させない —
AudioBlockを Anthropic に送信すると、警告をログし、ブロックを静かにスキップ FinishReasonは正規化される — すべてのプロバイダーは 4 つの値にマップします:"stop"、"tool_calls"、"length"、"content_filter"。プロバイダー固有の理由は失われます。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- midsphere-ai
- リポジトリ
- midsphere-ai/exo
- ライセンス
- MIT
- 最終更新
- 2026/4/13
Source: https://github.com/midsphere-ai/exo / ライセンス: MIT