ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
"""
|
||||
Configuration for Multimodal Agent
|
||||
Supports multiple providers and extraction modes
|
||||
"""
|
||||
import os
|
||||
from typing import Optional, Dict, Any
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
def _openrouter_model_id(model) -> str:
|
||||
"""Map a provider-native model name to an OpenRouter model id, used by the
|
||||
universal OpenRouter fallback. An explicit OPENROUTER_MODEL env var wins.
|
||||
Vision-capable default (gpt-5.6-luna) so image analysis still works."""
|
||||
override = os.getenv("OPENROUTER_MODEL")
|
||||
if override:
|
||||
return override
|
||||
m = (model or "").strip()
|
||||
if not m:
|
||||
return "openai/gpt-5.6-luna"
|
||||
if "/" in m:
|
||||
return m
|
||||
ml = m.lower()
|
||||
if ml.startswith(("gpt-", "o1", "o3", "o4", "chatgpt")):
|
||||
return "openai/" + m
|
||||
if ml.startswith("claude-"):
|
||||
return "anthropic/claude-opus-4.8"
|
||||
if ml.startswith("gemini"):
|
||||
return "google/" + m # e.g. gemini-3.5-flash -> google/gemini-3.5-flash
|
||||
# Provider-native ids (doubao-*/qwen/...) -> a widely-available vision model.
|
||||
return "openai/gpt-5.6-luna"
|
||||
|
||||
|
||||
class ExtractionMode(Enum):
|
||||
"""Modes for multimodal content extraction"""
|
||||
NATIVE = "native" # Use model's native multimodal capabilities
|
||||
EXTRACT_TO_TEXT = "extract_to_text" # Convert multimodal to text first
|
||||
|
||||
|
||||
class Provider(Enum):
|
||||
"""Supported model providers"""
|
||||
GEMINI = "gemini"
|
||||
OPENAI = "openai"
|
||||
DOUBAO = "doubao"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModelConfig:
|
||||
"""Configuration for a specific model"""
|
||||
provider: Provider
|
||||
model_name: str
|
||||
api_key: str
|
||||
base_url: Optional[str] = None
|
||||
supports_native_multimodal: bool = True
|
||||
|
||||
|
||||
class Config:
|
||||
"""Main configuration class for multimodal agent"""
|
||||
|
||||
def __init__(self):
|
||||
# Load API keys from environment.
|
||||
# 兼容常见别名:Gemini 官方 SDK 用 GEMINI_API_KEY,旧文档用 GOOGLE_API_KEY,两者都接受;
|
||||
# 豆包/方舟(Ark)的 Key 环境变量常见为 DOUBAO_API_KEY 或 ARK_API_KEY。
|
||||
self.gemini_api_key = os.getenv("GOOGLE_API_KEY") or os.getenv("GEMINI_API_KEY", "")
|
||||
self.openai_api_key = os.getenv("OPENAI_API_KEY", "")
|
||||
self.doubao_api_key = os.getenv("DOUBAO_API_KEY") or os.getenv("ARK_API_KEY", "")
|
||||
|
||||
# Universal OpenRouter fallback: when a model's own provider key is
|
||||
# missing but OPENROUTER_API_KEY is present, route that model through
|
||||
# OpenRouter's OpenAI-compatible endpoint.
|
||||
self.openrouter_api_key = os.getenv("OPENROUTER_API_KEY", "")
|
||||
self.openrouter_base_url = "https://openrouter.ai/api/v1"
|
||||
|
||||
# Model configurations
|
||||
self.models = {
|
||||
"gemini-3.5-flash": ModelConfig(
|
||||
provider=Provider.GEMINI,
|
||||
model_name="gemini-3.5-flash",
|
||||
api_key=self.gemini_api_key,
|
||||
supports_native_multimodal=True
|
||||
),
|
||||
"gpt-5": ModelConfig(
|
||||
provider=Provider.OPENAI,
|
||||
model_name="gpt-5",
|
||||
api_key=self.openai_api_key,
|
||||
supports_native_multimodal=True
|
||||
),
|
||||
"gpt-5.6-luna": ModelConfig(
|
||||
provider=Provider.OPENAI,
|
||||
model_name="gpt-5.6-luna",
|
||||
api_key=self.openai_api_key,
|
||||
supports_native_multimodal=True
|
||||
),
|
||||
"doubao-1.6": ModelConfig(
|
||||
provider=Provider.DOUBAO,
|
||||
model_name=os.getenv("ARK_MODEL", "doubao-seed-1-6-250615"),
|
||||
api_key=self.doubao_api_key,
|
||||
base_url="https://ark.cn-beijing.volces.com/api/v3",
|
||||
supports_native_multimodal=True
|
||||
)
|
||||
}
|
||||
|
||||
# Default settings
|
||||
self.default_model = os.getenv("MULTIMODAL_MODEL", "doubao-1.6")
|
||||
self.default_mode = ExtractionMode.NATIVE
|
||||
self.enable_multimodal_tools = False
|
||||
|
||||
# File size limits (in MB)
|
||||
self.max_pdf_size_mb = 20
|
||||
self.max_image_size_mb = 20
|
||||
self.max_audio_size_mb = 25
|
||||
|
||||
# Whisper settings for audio transcription
|
||||
self.whisper_model = "whisper-1"
|
||||
|
||||
# Temperature settings
|
||||
self.temperature = 0.7
|
||||
self.max_tokens = 4096
|
||||
|
||||
def get_model_config(self, model_name: str) -> ModelConfig:
|
||||
"""Get configuration for a specific model"""
|
||||
if model_name not in self.models:
|
||||
raise ValueError(f"Unknown model: {model_name}")
|
||||
return self.models[model_name]
|
||||
|
||||
def validate_api_keys(self) -> Dict[str, bool]:
|
||||
"""Check which API keys are configured"""
|
||||
return {
|
||||
"gemini": bool(self.gemini_api_key),
|
||||
"openai": bool(self.openai_api_key),
|
||||
"doubao": bool(self.doubao_api_key),
|
||||
"openrouter": bool(self.openrouter_api_key)
|
||||
}
|
||||
|
||||
def has_provider_key(self, provider: 'Provider') -> bool:
|
||||
"""Whether the direct API key for a provider is configured."""
|
||||
if provider == Provider.OPENAI:
|
||||
return bool(self.openai_api_key)
|
||||
if provider == Provider.DOUBAO:
|
||||
return bool(self.doubao_api_key)
|
||||
if provider == Provider.GEMINI:
|
||||
return bool(self.gemini_api_key)
|
||||
return False
|
||||
|
||||
def use_openrouter(self, provider: 'Provider') -> bool:
|
||||
"""True when a model's own provider key is missing but OpenRouter is
|
||||
available -> the call should be routed through OpenRouter."""
|
||||
return (not self.has_provider_key(provider)) and bool(self.openrouter_api_key)
|
||||
|
||||
def openai_client_args(self, model_config: 'ModelConfig'):
|
||||
"""Return (client_kwargs, model_name) for an OpenAI-compatible call,
|
||||
applying the universal OpenRouter fallback when needed."""
|
||||
provider = model_config.provider
|
||||
_m = (model_config.model_name or "").lower()
|
||||
_prefer_or = bool(self.openrouter_api_key) and _m.startswith("gpt-5") # 直连 gpt-5.6 需组织实名,优先 OpenRouter
|
||||
if _prefer_or or self.use_openrouter(provider):
|
||||
return (
|
||||
{"api_key": self.openrouter_api_key, "base_url": self.openrouter_base_url},
|
||||
_openrouter_model_id(model_config.model_name),
|
||||
)
|
||||
if provider == Provider.DOUBAO:
|
||||
return {"api_key": self.doubao_api_key, "base_url": model_config.base_url}, model_config.model_name
|
||||
# OPENAI (and any GEMINI forced through the OpenAI-compatible path)
|
||||
return {"api_key": self.openai_api_key}, model_config.model_name
|
||||
Reference in New Issue
Block a user