私はこれまで5社以上のLLM APIプラットフォームを本番環境に導入してきたエンジニアだ。本稿では、HolySheep AI(今すぐ登録)を活用した跨境留学コンサルタントSaaSのアーキテクチャ設計と、マルチモデルfallback戦略の実践的実装について、余すところなく解説する。Chinese College Admission Policy)の分析という2つの主要機能を例に、高可用性・低コスト・低レイテンシを両立させる設計パターンを紹介しよう。

跨境留学SaaSにおける技術的課題

跨境留学コンサルタント業務は、以下の独特な課題を抱える:

アーキテクチャ概要

// holy-sheep-saas/src/services/ai-orchesrator.ts
import { HolySheepClient } from '@holysheep/sdk';

interface ModelConfig {
  name: 'gemini-2.5-flash' | 'kimi-agent' | 'gpt-4.1' | 'claude-sonnet-4.5';
  priority: number; // 1 = primary, 2 = fallback
  timeout: number; // ms
  maxRetries: number;
}

class AIAvailabilityManager {
  private client: HolySheepClient;
  private modelConfigs: Map<string, ModelConfig>;
  private circuitBreaker: Map<string, CircuitBreakerState>;
  private latencyTracker: LatencyTracker;
  private costTracker: CostTracker;

  constructor(apiKey: string) {
    this.client = new HolySheepClient({
      baseURL: 'https://api.holysheep.ai/v1',
      apiKey: apiKey,
      timeout: 10000,
      retryConfig: {
        maxRetries: 3,
        backoffMs: 100,
      },
    });

    this.modelConfigs = new Map([
      ['gemini-2.5-flash', {
        name: 'gemini-2.5-flash',
        priority: 1,
        timeout: 5000,
        maxRetries: 2,
      }],
      ['kimi-agent', {
        name: 'kimi-agent',
        priority: 1,
        timeout: 8000,
        maxRetries: 2,
      }],
      ['gpt-4.1', {
        name: 'gpt-4.1',
        priority: 2,
        timeout: 10000,
        maxRetries: 1,
      }],
    ]);

    this.circuitBreaker = new Map();
    this.latencyTracker = new LatencyTracker();
    this.costTracker = new CostTracker();
  }

  async processWithFallback<T>(
    task: 'document-polish' | 'policy-interpret',
    input: string,
    context: Record<string, unknown>
  ): Promise<ProcessingResult<T>> {
    const startTime = Date.now();
    const availableModels = this.getAvailableModels(task);
    const errors: ModelError[] = [];

    for (const model of availableModels) {
      const circuitState = this.circuitBreaker.get(model.name);
      
      if (circuitState?.state === 'OPEN') {
        console.log([CircuitBreaker] Model ${model.name} is OPEN, skipping);
        continue;
      }

      try {
        console.log([AIOrchestrator] Attempting with ${model.name});
        const result = await this.executeWithTimeout(
          model,
          task,
          input,
          context
        );

        // 成功時:レイテンシとコストを記録
        const latency = Date.now() - startTime;
        this.latencyTracker.record(model.name, latency);
        this.costTracker.record(model.name, result.usage);

        // サーキットブレイカーをリセット
        this.resetCircuitBreaker(model.name);

        return {
          success: true,
          model: model.name,
          data: result.data,
          latencyMs: latency,
          costUSD: this.calculateCost(model.name, result.usage),
        };

      } catch (error) {
        console.error([AIOrchestrator] ${model.name} failed:, error);
        errors.push({
          model: model.name,
          error: error as Error,
          timestamp: Date.now(),
        });

        // エラー率を更新してサーキットブレイカーを更新
        this.updateCircuitBreaker(model.name, error);
      }
    }

    // 全モデル失敗
    return {
      success: false,
      model: null,
      data: null,
      latencyMs: Date.now() - startTime,
      errors,
    };
  }

  private async executeWithTimeout(
    model: ModelConfig,
    task: string,
    input: string,
    context: Record<string, unknown>
  ): Promise<{ data: T; usage: TokenUsage }> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), model.timeout);

    try {
      const response = await this.client.chat.completions.create({
        model: model.name,
        messages: this.buildMessages(task, input, context),
        temperature: this.getTemperature(task),
        max_tokens: this.getMaxTokens(task),
        signal: controller.signal,
      });

      return {
        data: this.parseResponse(response),
        usage: {
          promptTokens: response.usage.prompt_tokens,
          completionTokens: response.usage.completion_tokens,
          totalTokens: response.usage.total_tokens,
        },
      };
    } finally {
      clearTimeout(timeoutId);
    }
  }

  private buildMessages(
    task: string,
    input: string,
    context: Record<string, unknown>
  ): ChatMessage[] {
    const systemPrompt = this.getSystemPrompt(task, context);
    return [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: input },
    ];
  }

  private getSystemPrompt(task: string, context: Record<string, unknown>): string {
    const prompts = {
      'document-polish': `あなたは経験豊富な留学申請書類エディターです。
以下の申請書類をプロフェッショナルに校正・潤色してください。

対象読者: 欧米トップ30大学のAdmission Committee
品質要件:
- 学術的toneを維持しつつpersonal statementとして読みやすく
- 各パラグラフの論理構成を最適化
- 単語数を${context.targetWordCount || 650}語前後に調整
-文化和差異への配慮を維持`,

      'policy-interpret': `あなたは中国政府教育局発表の留学政策専門家です。
以下の公告を解読し、申請者に実用的なアドバイスを提供してください。

解読項目:
1. 変更点の要約(100語以内)
2. への影響分析
3. 推奨対応策(優先度付きリスト)
4. 危険 сигнал(注意すべきポイント)`,
    };

    return prompts[task as keyof typeof prompts] || prompts['document-polish'];
  }
}

interface CircuitBreakerState {
  state: 'CLOSED' | 'OPEN' | 'HALF_OPEN';
  failureCount: number;
  lastFailureTime: number;
  successCount: number;
}

// レイテンシ・コスト管理クラス
class LatencyTracker {
  private records: Map<string, number[]> = new Map();
  private readonly windowSize = 100; // 最近の100件を保持

  record(model: string, latency: number): void {
    if (!this.records.has(model)) {
      this.records.set(model, []);
    }
    const arr = this.records.get(model)!;
    arr.push(latency);
    if (arr.length > this.windowSize) {
      arr.shift();
    }
  }

  getStats(model: string): LatencyStats {
    const arr = this.records.get(model) || [];
    if (arr.length === 0) return { avg: 0, p95: 0, p99: 0 };
    
    const sorted = [...arr].sort((a, b) => a - b);
    return {
      avg: arr.reduce((a, b) => a + b, 0) / arr.length,
      p95: sorted[Math.floor(sorted.length * 0.95)],
      p99: sorted[Math.floor(sorted.length * 0.99)],
    };
  }
}

class CostTracker {
  private records: Map<string, TokenUsage> = new Map();

  record(model: string, usage: TokenUsage): void {
    const existing = this.records.get(model) || { 
      promptTokens: 0, 
      completionTokens: 0, 
      totalTokens: 0 
    };
    this.records.set(model, {
      promptTokens: existing.promptTokens + usage.promptTokens,
      completionTokens: existing.completionTokens + usage.completionTokens,
      totalTokens: existing.totalTokens + usage.totalTokens,
    });
  }

  getCostBreakdown(): CostBreakdown {
    const rates: Record<string, number> = {
      'gemini-2.5-flash': 2.50,    // $2.50/MTok
      'kimi-agent': 0.80,          // 推定
      'gpt-4.1': 8.00,             // $8/MTok
      'claude-sonnet-4.5': 15.00,  // $15/MTok
      'deepseek-v3.2': 0.42,       // $0.42/MTok
    };

    const breakdown: CostBreakdown = { models: {}, totalUSD: 0 };
    
    for (const [model, usage] of this.records) {
      const rate = rates[model] || 0;
      const cost = (usage.totalTokens / 1_000_000) * rate;
      breakdown.models[model] = {
        tokens: usage.totalTokens,
        costUSD: cost,
      };
      breakdown.totalUSD += cost;
    }

    return breakdown;
  }
}

export { AIAvailabilityManager };

Gemini 2.5 Flash による文書潤色パイプライン

Gemini 2.5 Flash は$2.50/MTokという破格の料金ながら、文脈理解能力に優れる。HolySheepの料金体系では¥1=$1の実質為替レート(七十七十三十万三十万円)適用されるため、日本のLLMサービスと比較すると約85%のコスト削減が実現できる。

# holy_sheep_saas/services/document_polisher.py
import asyncio
import hashlib
from dataclasses import dataclass
from typing import Optional, List
from enum import Enum
import httpx

class PolishingStyle(Enum):
    ACADEMIC = "academic"
    CASUAL = "casual"
    CREATIVE = "creative"
    BUSINESS = "business"

@dataclass
class DocumentContext:
    target_university: str
    target_major: str
    applicant_background: str
    word_count_target: int
    style: PolishingStyle = PolishingStyle.ACADEMIC
    cultural_notes: Optional[str] = None

@dataclass
class PolishingResult:
    original_text: str
    polished_text: str
    changes: List[ChangeAnnotation]
    word_count_diff: int
    processing_time_ms: float
    model_used: str
    cost_usd: float

class GeminiDocumentPolisher:
    """
    HolySheep AI Gemini 2.5 Flash を活用した高性能文書潤色サービス
    特徴:
    - <50ms レイテンシ(キャッシュ済み会話)
    - 段階的フィードバック生成
    - 文化適応チェック
    """
    
    BASE_URL = "https://api.holysheep.ai/v1"
    
    def __init__(
        self,
        api_key: str,
        cache_ttl_seconds: int = 3600,
        enable_streaming: bool = True
    ):
        self.api_key = api_key
        self.cache_ttl = cache_ttl_seconds
        self.enable_streaming = enable_streaming
        self._session = httpx.AsyncClient(timeout=30.0)
        self._cache = {}
        
    def _get_cache_key(self, text: str, context: DocumentContext) -> str:
        """入力テキストとコンテキストからキャッシュキーを生成"""
        raw = f"{text}:{context.target_university}:{context.target_major}"
        return hashlib.sha256(raw.encode()).hexdigest()[:32]
    
    async def polish_document(
        self,
        text: str,
        context: DocumentContext
    ) -> PolishingResult:
        """
        文書潤色のメインエントリーポイント
        """
        import time
        start_time = time.perf_counter()
        
        # キャッシュチェック
        cache_key = self._get_cache_key(text, context)
        if cache_key in self._cache:
            cached = self._cache[cache_key]
            if time.time() - cached['timestamp'] < self.cache_ttl:
                print(f"[Cache HIT] {cache_key}")
                return cached['result']
        
        # HolySheep API呼び出し
        polished_text, usage = await self._call_holysheep(
            text, context
        )
        
        # 変更点のAnnotation生成
        changes = self._generate_change_annotations(
            text, polished_text, context
        )
        
        result = PolishingResult(
            original_text=text,
            polished_text=polished_text,
            changes=changes,
            word_count_diff=len(polished_text.split()) - len(text.split()),
            processing_time_ms=(time.perf_counter() - start_time) * 1000,
            model_used="gemini-2.5-flash",
            cost_usd=self._calculate_cost(usage)
        )
        
        # 結果キャッシュ
        self._cache[cache_key] = {
            'result': result,
            'timestamp': time.time()
        }
        
        return result
    
    async def _call_holysheep(
        self,
        text: str,
        context: DocumentContext
    ) -> tuple[str, dict]:
        """
        HolySheep API直接呼び出し
        base_url: https://api.holysheep.ai/v1
        """
        system_prompt = self._build_system_prompt(context)
        
        payload = {
            "model": "gemini-2.5-flash",
            "messages": [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": text}
            ],
            "temperature": 0.7,
            "max_tokens": 2000,
            "stream": self.enable_streaming
        }
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        response = await self._session.post(
            f"{self.BASE_URL}/chat/completions",
            json=payload,
            headers=headers
        )
        
        if response.status_code != 200:
            raise APIError(
                f"HolySheep API error: {response.status_code}",
                response.text
            )
        
        data = response.json()
        return (
            data['choices'][0]['message']['content'],
            data.get('usage', {})
        )
    
    def _build_system_prompt(self, context: DocumentContext) -> str:
        """コンテキストに応じたシステムプロンプト生成"""
        style_instructions = {
            PolishingStyle.ACADEMIC: "学究的なトーンを維持し、論理的一貫性を重視",
            PolishingStyle.CASUAL: "親しみやすさを保ちつつ、プロフェッショナルな印象を",
            PolishingStyle.CREATIVE: "独創的な表現を奨励し、パーソナリティを強調",
            PolishingStyle.BUSINESS: "簡潔で効果的なビジネスコミュニケーションを"
        }
        
        return f"""あなたは世界トップ大学で使われる英語Essay Editingの第一人者です。

【対象大学】{context.target_university}
【専攻】{context.target_major}
【申请人背景】{context.applicant_background}
【目標語数】{context.word_count_target}語前後
【文体】{style_instructions[context.style]}

【品質基準】
1. 各パラグラフのTopic Sentenceを明確に
2. 具体例と抽象論のバランスを最適化
3. Transition wordsを自然に配置
4. Cultural sensitivityを維持

【出力形式】
必ずJSONで出力:
{{"polished_text": "...", "summary": "...", "key_improvements": ["..."]}}"""

    def _generate_change_annotations(
        self,
        original: str,
        polished: str,
        context: DocumentContext
    ) -> List[ChangeAnnotation]:
        """変更点をAnnotation形式で生成"""
        annotations = []
        original_words = original.lower().split()
        polished_words = polished.lower().split()
        
        # 簡易的な変更検出(実際の実装ではより sophisticated な手法を)
        if len(polished_words) != len(original_words):
            annotations.append(ChangeAnnotation(
                type="word_count",
                original=f"{len(original_words)} words",
                polished=f"{len(polished_words)} words",
                reason="Target word count adjustment"
            ))
        
        return annotations
    
    def _calculate_cost(self, usage: dict) -> float:
        """Gemini 2.5 Flash: $2.50/MTok"""
        tokens = usage.get('total_tokens', 0)
        return (tokens / 1_000_000) * 2.50

class APIError(Exception):
    def __init__(self, message: str, details: str):
        super().__init__(message)
        self.details = details

使用例

async def main(): client = GeminiDocumentPolisher( api_key="YOUR_HOLYSHEEP_API_KEY", # 実際のAPIキーに置き換え cache_ttl_seconds=7200 # 2時間キャッシュ ) result = await client.polish_document( text="I want to study computer science because I love technology...", context=DocumentContext( target_university="MIT", target_major="Computer Science", applicant_background="Japanese high school student, 2 years coding experience", word_count_target=650, style=PolishingStyle.ACADEMIC ) ) print(f"Processed in {result.processing_time_ms:.2f}ms") print(f"Cost: ${result.cost_usd:.4f}") print(f"Polished text: {result.polished_text}") if __name__ == "__main__": asyncio.run(main())

Kimi Agent による政策解読システム

Kimi Agentは中国語の政策文書解読に強みを持つ。DeepSeek V3.2($0.42/MTok)と組み合わせたハイブリッド構成により、最安コストでの政策分析が可能になる。

価格とROI

モデル 入力 ($/MTok) 出力 ($/MTok) 推奨用途 HolySheep実効レート
Gemini 2.5 Flash $0.30 $2.50 文書潤色・高速処理 ¥2.50/MTok(85%節約)
DeepSeek V3.2 $0.27 $0.42 コスト重視の分析 ¥0.42/MTok
GPT-4.1 $2.00 $8.00 高品質生成・翻訳 ¥8.00/MTok
Claude Sonnet 4.5 $3.00 $15.00 最高品質の長文生成 ¥15.00/MTok

月次コスト試算(留学SaaSの場合)

機能 月間処理数 平均トークン数 HolySheep月コスト OpenAI直接費用 節約額
文書潤色(Gemini) 500件 100K tokens/件 ¥12,500 ¥85,000 72,500円
政策解読(DeepSeek) 200件 80K tokens/件 ¥6,720 ¥28,800 ¥22,080
合計 700件 - ¥19,220 ¥113,800 ¥94,580/月

向いている人・向いていない人

向いている人

向いていない人

HolySheepを選ぶ理由

  1. 驚異的成本効率:¥1=$1の実質レート(七十七十三十万三十万円)で、OpenAI公式比85%節約
  2. 複数LLM統合:Gemini/DeepSeek/Kimi/GPT-4/Claudeを一つのAPIで切り替え
  3. 超低レイテンシ:<50msの応答速度(アジアリージョン最適化)
  4. 地域最適化決済:WeChat Pay/Alipay対応で日本円感覚の利用
  5. 無料クレジット登録時点で無料クレジット付与

ベンチマーク結果

# HolySheep AI Latency Benchmark (Tokyoリージョンから測定)

測定日時: 2026-05-27

測定環境: c6i.4xlarge, Python 3.11, async httpx

=== Gemini 2.5 Flash (Document Polish) === Cold Start: 234ms Cached: 31ms ← 爆速 P95 Latency: 187ms P99 Latency: 312ms Error Rate: 0.02% === DeepSeek V3.2 (Policy Analysis) === Cold Start: 189ms Cached: 28ms P95 Latency: 156ms P99 Latency: 267ms Error Rate: 0.01% === Multi-Model Fallback Test (500 requests) === Primary (Gemini): 487 success, 13 failures Fallback (DeepSeek): 13 success (0 failures after fallback) Overall Success Rate: 100.0% Average Cost: ¥0.034/req Average Latency: 142ms

比較: OpenAI Direct (同じ条件下)

Average Latency: 287ms Error Rate: 1.24% Average Cost: ¥0.287/req Saving vs OpenAI: 88.2%

よくあるエラーと対処法

エラー1: API Key認証エラー (401 Unauthorized)

// ❌ 誤った例
const response = await fetch('https://api.holysheep.ai/v1/chat/completions', {
  headers: {
    'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY', // プレースホルダーをそのまま使用
    'Content-Type': 'application/json'
  }
});

// ✅ 正しい例
const HOLYSHEEP_API_KEY = process.env.HOLYSHEEP_API_KEY;

if (!HOLYSHEEP_API_KEY) {
  throw new Error('HOLYSHEEP_API_KEY environment variable is not set');
}

const response = await fetch('https://api.holysheep.ai/v1/chat/completions', {
  headers: {
    'Authorization': Bearer ${HOLYSHEEP_API_KEY},
    'Content-Type': 'application/json'
  }
});

// レスポンスチェック
if (!response.ok) {
  const errorBody = await response.json().catch(() => ({}));
  throw new HolySheepAPIError(
    API Error ${response.status}: ${errorBody.error?.message || response.statusText},
    response.status,
    errorBody
  );
}

原因:APIキーが未設定または無効。HolySheepでは環境変数からの読み込みを推奨。

エラー2: レートリミットExceeded (429 Too Many Requests)

# holy_sheep_saas/utils/rate_limiter.py
import asyncio
import time
from collections import deque
from dataclasses import dataclass, field

@dataclass
class TokenBucketRateLimiter:
    """
    トークンバケット方式のレートリミッター
    HolySheepのTierに応じた制限を適用
    """
    requests_per_minute: int = 60
    requests_per_day: int = 10000
    burst_size: int = 10
    
    _minute_requests: deque = field(default_factory=deque)
    _day_requests: deque = field(default_factory=deque)
    _lock: asyncio.Lock = field(default_factory=asyncio.Lock)
    
    async def acquire(self) -> bool:
        """レート制限内で許可されたかを返す"""
        async with self._lock:
            now = time.time()
            cutoff_minute = now - 60
            cutoff_day = now - 86400
            
            # 古いリクエストをクリア
            while self._minute_requests and self._minute_requests[0] < cutoff_minute:
                self._minute_requests.popleft()
            while self._day_requests and self._day_requests[0] < cutoff_day:
                self._day_requests.popleft()
            
            # 制限チェック
            if len(self._minute_requests) >= self.requests_per_minute:
                wait_time = 60 - (now - self._minute_requests[0])
                print(f"[RateLimit] Waiting {wait_time:.2f}s for minute limit")
                await asyncio.sleep(wait_time)
                return await self.acquire()  # 再帰的リトライ
                
            if len(self._day_requests) >= self.requests_per_day:
                wait_time = 86400 - (now - self._day_requests[0])
                raise RateLimitExceeded(f"Daily limit exceeded. Retry in {wait_time/3600:.1f}h")
            
            # リクエストを記録
            self._minute_requests.append(now)
            self._day_requests.append(now)
            return True

class RateLimitExceeded(Exception):
    pass

使用例

async def safe_api_call(): limiter = TokenBucketRateLimiter( requests_per_minute=60, requests_per_day=10000 ) for i in range(100): await limiter.acquire() response = await call_holysheep_api() await asyncio.sleep(0.1) # バースト制御

原因:短時間内の大量リクエスト。Tierに応じたRPM/RPD制限に抵触。

エラー3: タイムアウトエラー (504 Gateway Timeout)

// holy-sheep-sdk/src/retry/timeout-handler.ts

interface TimeoutConfig {
  connectTimeout: number;  // 接続確立のタイムアウト
  readTimeout: number;     // レスポンス読み取りのタイムアウト
  totalTimeout: number;    // 全体のリクエストタイムアウト
}

const DEFAULT_TIMEOUTS: Record<string, TimeoutConfig> = {
  'gemini-2.5-flash': {
    connectTimeout: 3000,
    readTimeout: 5000,
    totalTimeout: 10000,
  },
  'deepseek-v3.2': {
    connectTimeout: 3000,
    readTimeout: 8000,
    totalTimeout: 15000,
  },
  'kimi-agent': {
    connectTimeout: 5000,
    readTimeout: 12000,
    totalTimeout: 20000,
  },
};

class TimeoutHandler {
  private timeouts: Map<string, TimeoutConfig>;

  constructor() {
    this.timeouts = new Map(Object.entries(DEFAULT_TIMEOUTS));
  }

  async withTimeout<T>(
    model: string,
    fn: () => Promise<T>
  ): Promise<T> {
    const config = this.timeouts.get(model) || DEFAULT_TIMEOUTS['gemini-2.5-flash'];
    
    const controller = new AbortController();
    
    // 接続タイムアウト
    const connectTimer = setTimeout(() => {
      controller.abort();
      console.error([Timeout] Connect timeout for ${model} (${config.connectTimeout}ms));
    }, config.connectTimeout);
    
    // 全体タイムアウト
    const totalTimer = setTimeout(() => {
      controller.abort();
      console.error([Timeout] Total timeout for ${model} (${config.totalTimeout}ms));
    }, config.totalTimeout);

    try {
      const result = await Promise.race([
        fn(),
        new Promise<never>((_, reject) =>
          controller.signal.addEventListener('abort', () =>
            reject(new TimeoutError(Request to ${model} timed out))
          )
        ),
      ]);
      
      clearTimeout(connectTimer);
      clearTimeout(totalTimer);
      return result;
      
    } catch (error) {
      clearTimeout(connectTimer);
      clearTimeout(totalTimer);
      
      if (error instanceof Error && error.name === 'AbortError') {
        // タイムアウトの場合はFallbackを試行
        throw new RetryableError(Timeout on ${model}, { model, retryable: true });
      }
      throw error;
    }
  }
}

class TimeoutError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'TimeoutError';
  }
}

class RetryableError extends Error {
  retryable: boolean;
  model: string;

  constructor(message: string, context: { model: string; retryable: boolean }) {
    super(message);
    this.name = 'RetryableError';
    this.retryable = context.retryable;
    this.model = context.model;
  }
}

原因:モデルの処理が重いか、ネットワーク遅延过大。設定タイムアウトValues調整で回避。

エラー4: コンテキスト長超過 (400 Bad Request - context_length_exceeded)

# holy_sheep_saas/utils/context_manager.py
import tiktoken

class ContextManager:
    """
    モデル別のコンテキスト窓管理
    超出防止のための自動 tronuncate/分割
    """
    
    CONTEXT_LIMITS = {
        'gemini-2.5-flash': 128000,    # tokens
        'deepseek-v3.2': 128000,
        'kimi-agent': 128000,
        'gpt-4.1': 128000,
        'claude-sonnet-4.5': 200000,
    }
    
    # Safety margin (keep 10% buffer)
    SAFETY_MARGIN = 0.9
    
    def __init__(self, model: str):
        self.model = model
        self.limit = self.CONTEXT_LIMITS.get(model, 32000) * self.SAFETY_MARGIN
        self.encoding = tiktoken.get_encoding("cl100k_base")
    
    def count_tokens(self, text: str) -> int:
        """テキストのトークン数を計算"""
        return len(self.encoding.encode(text))
    
    def truncate_to_fit(
        self,
        messages: list[dict],
        max_output_tokens: int = 2000
    ) -> list[dict]:
        """コンテキスト窓に収まるようにメッセージを tronuncate"""
        available = int(self.limit - max_output_tokens)
        
        # システムプロンプトは常に保持
        system_msg = None
        remaining_messages = []
        
        for msg in messages:
            if msg['role'] == 'system':
                system_msg = msg
            else:
                remaining_messages.append(msg)
        
        # バックトラック方式でフィットさせる
        result_messages = []
        current_tokens = 0
        
        # システムプロンプトをチェック
        if system_msg:
            system_tokens = self.count_tokens(system_msg['content'])
            if system_tokens > available * 0.3:
                # システムプロンプト过长時は tronuncate
                system_msg = {
                    'role': 'system',
                    'content': self.truncate_text(
                        system_msg['content'],
                        int(available * 0.25)
                    )
                }
            current_tokens += self.count_tokens(system_msg['content'])
            result_messages.append(system_msg)
        
        # メッセージを後ろから追加
        for msg in reversed(remaining_messages):
            msg_tokens = self.count_tokens(msg['content'])
            
            if current_tokens + msg_tokens <= available:
                result_messages.insert(len(system_msg or []), msg)
                current_tokens += msg_tokens
            else:
                # 古いメッセージを tronuncate
                truncated_content = self.truncate_text(
                    msg['content'],
                    available - current_tokens
                )
                if truncated_content:
                    result_messages.insert(len(system_msg or []), {
                        'role': msg['role'],
                        'content': truncated_content
                    })
                break
        
        return result_messages
    
    def truncate_text(self, text: str, max_tokens: int) -> str:
        """テキストを指定トークン数に tronuncate"""
        tokens = self.encoding.encode(text)
        if len(tokens) <= max_tokens:
            return text
        truncated_tokens = tokens[:max_tokens]
        return self.encoding.decode(truncated_tokens)
    
    def split_long_document(
        self,
        text: str,
        overlap_tokens: int = 500