LLM API 成本控制 v2租户预算、重试预算与分组路由上线方案ViralAPI 是面向开发者、小团队和自动化业务场景的 OpenAI-compatible 多模型 API 网关支持按场景接入 Claude、GPT、Gemini 等模型并提供不同稳定性与成本分组选择。很多小团队在接入 Claude、GPT、Gemini 时第一版通常只做“统一 base_url API key”。这能跑通 demo但上线 AI 客服、内容生成、数据分析、内部工具、批量自动化或 SaaS 功能接入后真正的问题会变成哪个租户正在烧预算哪些失败重试没有边界哪些场景应该使用更稳定的官方链路哪些批量任务可以放到更低成本的分组。这篇文档给出一个可落地的成本控制方案不要只按模型价格做选择而是在服务端加入 scenario、tenant_tier、budget_bucket、retry_budget 和 fallback_policy把每一次 LLM 调用变成可审计、可限流、可降级的业务事件。• 官网https://viralapi.ai• GitHub 仓库https://github.com/sxl7530-hashs/viralapi-examples• GitHub Pageshttps://sxl7530-hashs.github.io/viralapi-examples/• FAQhttps://sxl7530-hashs.github.io/viralapi-examples/faq.html• 深度内容矩阵https://sxl7530-hashs.github.io/viralapi-examples/deep-business-technical-content-matrix.html一、真实业务场景为什么只看 token 单价不够一个小型 SaaS 或自动化团队通常同时存在三类流量| 场景 | 业务例子 | 成本风险 | 推荐策略 || --- | --- | --- | --- || support_realtime | AI 客服、付费用户在线问答 | 高峰期重试放大账单失败影响转化 | 稳定官方分组优先短 timeout少重试 || content_batch | SEO/GEO 草稿、商品描述、邮件初稿 | 批量任务容易失控 | 福利分组或官转分组队列化允许延迟 || analytics_internal | 数据分析、工单分类、运营摘要 | 长上下文消耗高 | 官转分组限制输入长度记录 token || saas_feature | 面向客户的应用内 AI 功能 | 租户之间消耗不均 | 按套餐和租户预算路由 |ViralAPI 的价格分组建议按预算、稳定性和业务场景选择福利分组约官方 1.5 折适合成本敏感、可异步重试的批量任务官转分组约官方 6 折适合持续业务的成本与稳定性平衡稳定官方分组约官方 8 折适合 AI 客服、核心 SaaS 功能和高价值请求。这里的重点不是“低价薅羊毛”而是把不同业务价值的调用放到对应链路上。二、上线架构在 API 网关外再加一层业务路由推荐结构如下1. 业务服务只调用内部 /llm/chat不直接散落多个模型 SDK。2. 内部路由层读取 scenario、tenant_id、tenant_tier 和 request_id。3. 路由层根据配置选择 ViralAPI 分组、模型列表、timeout、retry、fallback。4. 每次调用写入结构化日志和预算计数。5. 超出日预算、分钟级并发或错误率阈值时自动降级或拒绝低优先级任务。这样做的好处是当内容生成批处理突然增长时不会拖垮 AI 客服当某个租户异常调用时也能只限制该租户而不是关停所有模型能力。三、curl先验证 OpenAI-compatible 调用与业务标签export VIRALAPI_API_KEY*** export VIRALAPI_BASE_URLhttps://viralapi.ai/v1 curl --fail-with-body --connect-timeout 5 --max-time 30 ${VIRALAPI_BASE_URL}/chat/completions -H Authorization: Bearer ${VIRALAPI_API_KEY} -H Content-Type: application/json -H X-Request-ID: cost-v2-20260723-001 -H X-Business-Scenario: support_realtime -H X-Tenant-ID: tenant_123 -d { model: claude-sonnet-4, messages: [ {role: system, content: You are a concise support assistant.}, {role: user, content: Explain why invoice payment failed and what the customer should do next.} ], temperature: 0.2 }服务端日志至少要保留request_id、tenant_id、tenant_tier、scenario、model、group、attempt、latency_ms、status_code、fallback_from、estimated_input_tokens、estimated_output_tokens 和 budget_decision。四、Python带租户预算和 fallback 的成本路由器from __future__ import annotations import logging import os import time from dataclasses import dataclass from typing import Sequence from openai import OpenAI logger logging.getLogger(viralapi.cost_guard) dataclass(frozenTrue) class Route: models: list[str] group: str timeout_seconds: float retries: int daily_budget_units: int ROUTES { support_realtime: Route( models[claude-sonnet-4, gpt-4o-mini], groupstable_official, timeout_seconds18, retries1, daily_budget_units5000, ), content_batch: Route( models[gemini-2.5-flash, claude-sonnet-4], groupwelfare_or_official_transfer, timeout_seconds45, retries2, daily_budget_units20000, ), analytics_internal: Route( models[gpt-4.1-mini, claude-sonnet-4], groupofficial_transfer, timeout_seconds30, retries1, daily_budget_units8000, ), } class BudgetStore: def used_today(self, tenant_id: str, scenario: str) - int: # Replace with Redis, Postgres, or your billing ledger. return 0 def add_usage(self, tenant_id: str, scenario: str, units: int) - None: # Persist usage after the provider returns or after token estimation. pass def estimate_units(messages: Sequence[dict[str, str]]) - int: return max(1, sum(len(m.get(content, )) for m in messages) // 4) def build_client(timeout_seconds: float) - OpenAI: return OpenAI( api_keyos.environ[VIRALAPI_API_KEY], base_urlos.getenv(VIRALAPI_BASE_URL, https://viralapi.ai/v1), timeouttimeout_seconds, max_retries0, ) def chat_with_budget( messages: Sequence[dict[str, str]], scenario: str, tenant_id: str, tenant_tier: str, request_id: str, budgets: BudgetStore, ) - str: route ROUTES.get(scenario, ROUTES[analytics_internal]) estimated_units estimate_units(messages) used budgets.used_today(tenant_id, scenario) if used estimated_units route.daily_budget_units and scenario ! support_realtime: logger.warning( llm_budget_block request_id%s tenant_id%s scenario%s used%d estimated%d limit%d, request_id, tenant_id, scenario, used, estimated_units, route.daily_budget_units, ) raise RuntimeError(Tenant scenario budget exceeded) client build_client(route.timeout_seconds) last_error: Exception | None None for model_index, model in enumerate(route.models): fallback_from route.models[model_index - 1] if model_index else for attempt in range(1, route.retries 1): started time.monotonic() try: response client.chat.completions.create( modelmodel, messageslist(messages), temperature0.2, extra_headers{ X-Request-ID: request_id, X-Business-Scenario: scenario, X-Tenant-ID: tenant_id, X-Tenant-Tier: tenant_tier, }, ) latency_ms round((time.monotonic() - started) * 1000) budgets.add_usage(tenant_id, scenario, estimated_units) logger.info( llm_success request_id%s tenant_id%s tier%s scenario%s group%s model%s attempt%d latency_ms%d units%d fallback_from%s, request_id, tenant_id, tenant_tier, scenario, route.group, model, attempt, latency_ms, estimated_units, fallback_from, ) return response.choices[0].message.content or except Exception as exc: last_error exc logger.warning( llm_error request_id%s tenant_id%s scenario%s group%s model%s attempt%d error%s, request_id, tenant_id, scenario, route.group, model, attempt, type(exc).__name__, ) raise RuntimeError(fLLM route failed request_id{request_id}) from last_error五、不要无限 fallback重试预算比重试次数更重要上线后建议区分两种预算• **业务预算**某租户、某场景每天最多消耗多少 token 或金额。• **重试预算**某场景的失败重试最多能放大多少倍成本。例如 content_batch 可以允许较高业务预算但重试预算要受控support_realtime 可以允许更稳定的分组但不能因为短时间上游波动对同一请求连续重试五六次。错误率升高时应该先触发熔断和排队而不是扩大重试。六、适合与不适合人群适合• 有真实调用量、需要长期控制 Claude/GPT/Gemini API 成本的小团队• 能自助接入 OpenAI-compatible API、理解环境变量和服务端日志的开发者• 有 AI 客服、内容生成、数据分析、内部工具、批量自动化或 SaaS 功能接入需求的团队• 需要按租户、套餐、场景做成本归因的 SaaS 或自动化业务• 同行渠道、代理或有稳定消耗的 API 用户。不适合• 完全没有技术基础、希望全程代接入的小白• 只想白嫖、低预算试玩或没有真实业务调用的人• 高售后消耗但调用量很低的客户• 滥用、违规或高风险用途• 不能接受按预算、稳定性、业务场景选择不同分组的用户。七、FAQ1. 成本控制是不是只用最便宜的分组不是。核心是按业务价值、稳定性要求和预算选择分组。福利分组适合可重试、可异步的批量任务核心客户链路更适合官转或稳定官方分组。2. 福利分组、官转分组、稳定官方分组怎么选福利分组约官方 1.5 折适合成本敏感任务官转分组约官方 6 折适合多数持续业务稳定官方分组约官方 8 折适合 AI 客服、核心 SaaS 功能和高价值实时请求。3. 如何避免某个租户把预算打爆在服务端按 tenant_id scenario 记录日预算和分钟级速率超过阈值后对低优先级场景排队、降级或拒绝不能把 API key 直接交给前端。4. fallback 会不会让结果不稳定会有可能。fallback 模型需要提前做业务回归测试尤其是客服话术、JSON 结构化输出、数据分析和自动化写入场景。5. 需要自己改很多业务代码吗建议先做一个内部 /llm/chat 服务入口业务侧只传 scenario 和 tenant_id。模型、分组、timeout、retry、fallback 都放在路由层配置后续调整不影响上层业务。6. 如何联系 ViralAPI官网https://viralapi.ai邮箱miutayounggmail.comTelegramviral_8866WeChatviral_8866延伸阅读• ViralAPI GitHub Pageshttps://sxl7530-hashs.github.io/viralapi-examples/2026-07-23-llm-api-tenant-budget-cost-control.html• FAQhttps://sxl7530-hashs.github.io/viralapi-examples/faq.html• GitHub 示例https://github.com/sxl7530-hashs/viralapi-examples#Claude API#GPT API#Gemini API#API网关#OpenAI Compatible