diff --git a/drizzle/0044_add_anthropic_warmup_intercept.sql b/drizzle/0044_add_anthropic_warmup_intercept.sql
new file mode 100644
index 000000000..e87fb0f78
--- /dev/null
+++ b/drizzle/0044_add_anthropic_warmup_intercept.sql
@@ -0,0 +1,3 @@
+ALTER TABLE "system_settings"
+ADD COLUMN IF NOT EXISTS "enable_anthropic_warmup_intercept" boolean NOT NULL DEFAULT false;
+
diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json
index cc660ce02..0f81ea51d 100644
--- a/drizzle/meta/_journal.json
+++ b/drizzle/meta/_journal.json
@@ -309,6 +309,13 @@
       "when": 1767362174718,
       "tag": "0043_faithful_mother_askani",
       "breakpoints": true
+    },
+    {
+      "idx": 44,
+      "version": "7",
+      "when": 1767461538553,
+      "tag": "0044_add_anthropic_warmup_intercept",
+      "breakpoints": true
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/messages/en/dashboard.json b/messages/en/dashboard.json
index 2e64ac5e3..c395fb28b 100644
--- a/messages/en/dashboard.json
+++ b/messages/en/dashboard.json
@@ -127,6 +127,7 @@
       "nextPage": "Next Page",
       "blocked": "Blocked",
       "nonBilling": "Non-Billing",
+      "skipped": "Skipped",
       "times": "times",
       "loadedCount": "Loaded {count} records",
       "loadingMore": "Loading more...",
@@ -156,6 +157,7 @@
         "title": "Blocking Information",
         "type": "Blocking Type",
         "sensitiveWord": "Sensitive Word Blocking",
+        "warmupIntercept": "Warmup Intercept (CCH)",
         "word": "Sensitive Word",
         "matchType": "Match Type",
         "matchTypeContains": "Contains Match",
diff --git a/messages/en/settings.json b/messages/en/settings.json
index 6654ba5d1..4030ad8c8 100644
--- a/messages/en/settings.json
+++ b/messages/en/settings.json
@@ -102,6 +102,8 @@
       "verboseProviderErrorDesc": "When enabled, return detailed error messages when all providers are unavailable (including provider count, rate limit reasons, etc.); when disabled, only return a simple error code.",
       "enableHttp2": "Enable HTTP/2",
       "enableHttp2Desc": "When enabled, proxy requests will prefer HTTP/2 protocol. Automatically falls back to HTTP/1.1 on failure.",
+      "enableAnthropicWarmupIntercept": "Intercept Anthropic Warmup Requests",
+      "enableAnthropicWarmupInterceptDesc": "When enabled, CCH detects and short-circuits Claude/Anthropic warmup requests and returns a local short response to avoid unnecessary upstream calls.",
       "cleanupSchedule": "Cleanup Schedule",
       "cleanupScheduleDesc": "Select the execution schedule for automatic cleanup",
       "configUpdated": "System settings updated. The page will refresh to apply currency display changes.",
diff --git a/messages/ja/dashboard.json b/messages/ja/dashboard.json
index b1ca5e90d..397dd800a 100644
--- a/messages/ja/dashboard.json
+++ b/messages/ja/dashboard.json
@@ -127,6 +127,7 @@
       "nextPage": "次へ",
       "blocked": "ブロック済み",
       "nonBilling": "非課金",
+      "skipped": "スキップ",
       "times": "回",
       "loadedCount": "{count} 件のレコードを読み込みました",
       "loadingMore": "読み込み中...",
@@ -156,6 +157,7 @@
         "title": "ブロック情報",
         "type": "ブロックタイプ",
         "sensitiveWord": "機密語句ブロック",
+        "warmupIntercept": "Warmup 先行応答（CCH）",
         "word": "機密語句",
         "matchType": "一致タイプ",
         "matchTypeContains": "部分一致",
diff --git a/messages/ja/settings.json b/messages/ja/settings.json
index 23d7d5107..1d915c4f5 100644
--- a/messages/ja/settings.json
+++ b/messages/ja/settings.json
@@ -100,6 +100,8 @@
       "allowGlobalViewDesc": "無効にすると、一般ユーザーはダッシュボードで自分のキーの使用統計のみを表示できます。",
       "verboseProviderError": "詳細なプロバイダーエラー",
       "verboseProviderErrorDesc": "有効にすると、すべてのプロバイダーが利用不可の場合に詳細なエラーメッセージ（プロバイダー数、レート制限の理由など）を返します。無効の場合は簡潔なエラーコードのみを返します。",
+      "enableAnthropicWarmupIntercept": "Anthropic Warmup リクエストをインターセプト",
+      "enableAnthropicWarmupInterceptDesc": "有効にすると、CCH は Claude/Anthropic の Warmup リクエストを検出して上流への送信をスキップし、ローカルの短い応答を返します。",
       "cleanupSchedule": "クリーンアップスケジュール",
       "cleanupScheduleDesc": "自動クリーンアップの実行スケジュールを選択します",
       "configUpdated": "システム設定が更新されました。ページが更新され、通貨表示の変更が適用されます。",
diff --git a/messages/ru/dashboard.json b/messages/ru/dashboard.json
index f6f0b4737..87f8f7e6a 100644
--- a/messages/ru/dashboard.json
+++ b/messages/ru/dashboard.json
@@ -127,6 +127,7 @@
       "nextPage": "Следующая",
       "blocked": "Заблокировано",
       "nonBilling": "Не тарифицируется",
+      "skipped": "Пропущено",
       "times": "раз",
       "loadedCount": "Загружено {count} записей",
       "loadingMore": "Загрузка...",
@@ -156,6 +157,7 @@
         "title": "Информация о блокировке",
         "type": "Тип блокировки",
         "sensitiveWord": "Блокировка по ключевым словам",
+        "warmupIntercept": "Warmup перехвачен (CCH)",
         "word": "Ключевое слово",
         "matchType": "Тип совпадения",
         "matchTypeContains": "Содержит",
diff --git a/messages/ru/settings.json b/messages/ru/settings.json
index dd248698d..70c819333 100644
--- a/messages/ru/settings.json
+++ b/messages/ru/settings.json
@@ -100,6 +100,8 @@
       "allowGlobalViewDesc": "При отключении обычные пользователи могут видеть только статистику использования своих ключей на панели.",
       "verboseProviderError": "Подробные ошибки провайдеров",
       "verboseProviderErrorDesc": "При включении возвращает подробные сообщения об ошибках при недоступности всех провайдеров (количество провайдеров, причины ограничений и т.д.); при отключении возвращает только простой код ошибки.",
+      "enableAnthropicWarmupIntercept": "Перехватывать Anthropic Warmup-запросы",
+      "enableAnthropicWarmupInterceptDesc": "При включении CCH обнаруживает Warmup-запросы Claude/Anthropic, пропускает отправку вверх по цепочке и возвращает локальный короткий ответ.",
       "cleanupSchedule": "График очистки",
       "cleanupScheduleDesc": "Выбрать расписание автоматической очистки",
       "configUpdated": "Параметры системы обновлены. Страница обновится для применения изменений валюты.",
diff --git a/messages/zh-CN/dashboard.json b/messages/zh-CN/dashboard.json
index ff0730912..1a31c9a1b 100644
--- a/messages/zh-CN/dashboard.json
+++ b/messages/zh-CN/dashboard.json
@@ -127,6 +127,7 @@
       "nextPage": "下一页",
       "blocked": "被拦截",
       "nonBilling": "非计费",
+      "skipped": "已跳过",
       "times": "次",
       "loadedCount": "已加载 {count} 条记录",
       "loadingMore": "加载更多中...",
@@ -156,6 +157,7 @@
         "title": "拦截信息",
         "type": "拦截类型",
         "sensitiveWord": "敏感词拦截",
+        "warmupIntercept": "Warmup 抢答（CCH）",
         "word": "敏感词",
         "matchType": "匹配类型",
         "matchTypeContains": "包含匹配",
diff --git a/messages/zh-CN/settings.json b/messages/zh-CN/settings.json
index 9f2521247..2750ba22f 100644
--- a/messages/zh-CN/settings.json
+++ b/messages/zh-CN/settings.json
@@ -83,6 +83,8 @@
       "verboseProviderErrorDesc": "开启后，当所有供应商不可用时返回详细错误信息（包含供应商数量、限流原因等）；关闭后仅返回简洁错误码。",
       "enableHttp2": "启用 HTTP/2",
       "enableHttp2Desc": "启用后，代理请求将优先使用 HTTP/2 协议。如果 HTTP/2 失败，将自动降级到 HTTP/1.1。",
+      "enableAnthropicWarmupIntercept": "拦截 Anthropic Warmup 请求",
+      "enableAnthropicWarmupInterceptDesc": "开启后，CCH 将识别并拦截 Claude/Anthropic 的 Warmup 请求，直接返回简短响应，减少不必要的供应商调用。",
       "saveSettings": "保存设置",
       "keepDays": "保留天数",
       "keepDaysDesc": "清理超过此天数的历史日志",
diff --git a/messages/zh-TW/dashboard.json b/messages/zh-TW/dashboard.json
index 1e706ff67..d33eb3e75 100644
--- a/messages/zh-TW/dashboard.json
+++ b/messages/zh-TW/dashboard.json
@@ -127,6 +127,7 @@
       "nextPage": "下一頁",
       "blocked": "已攔截",
       "nonBilling": "非計費",
+      "skipped": "已跳過",
       "times": "次",
       "loadedCount": "已載入 {count} 筆記錄",
       "loadingMore": "載入更多中...",
@@ -156,6 +157,7 @@
         "title": "攔截資訊",
         "type": "攔截類型",
         "sensitiveWord": "敏感詞攔截",
+        "warmupIntercept": "Warmup 搶答（CCH）",
         "word": "敏感詞",
         "matchType": "匹配類型",
         "matchTypeContains": "包含匹配",
diff --git a/messages/zh-TW/settings.json b/messages/zh-TW/settings.json
index 258f023a9..33fbe5781 100644
--- a/messages/zh-TW/settings.json
+++ b/messages/zh-TW/settings.json
@@ -100,6 +100,8 @@
       "allowGlobalViewDesc": "關閉後，普通使用者在儀表板僅能查看自己金鑰的使用統計。",
       "verboseProviderError": "詳細供應商錯誤資訊",
       "verboseProviderErrorDesc": "開啟後，當所有供應商不可用時返回詳細錯誤資訊（包含供應商數量、限流原因等）；關閉後僅返回簡潔錯誤碼。",
+      "enableAnthropicWarmupIntercept": "攔截 Anthropic Warmup 請求",
+      "enableAnthropicWarmupInterceptDesc": "開啟後，CCH 會識別並攔截 Claude/Anthropic 的 Warmup 請求，直接回傳簡短回應，減少不必要的供應商呼叫。",
       "cleanupSchedule": "清理週期",
       "cleanupScheduleDesc": "選擇自動清理的執行週期",
       "configUpdated": "系統設定已更新，頁面將重新整理以應用貨幣顯示變更。",
diff --git a/src/actions/my-usage.ts b/src/actions/my-usage.ts
index 401aa7f0d..10b242f93 100644
--- a/src/actions/my-usage.ts
+++ b/src/actions/my-usage.ts
@@ -303,6 +303,7 @@ export async function getMyTodayStats(): Promise<ActionResult<MyTodayStats>> {
         and(
           eq(messageRequest.key, session.key.key),
           isNull(messageRequest.deletedAt),
+          sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
           gte(messageRequest.createdAt, timeRange.startTime),
           sql`${messageRequest.createdAt} < ${timeRange.endTime}`
         )
@@ -322,6 +323,7 @@ export async function getMyTodayStats(): Promise<ActionResult<MyTodayStats>> {
         and(
           eq(messageRequest.key, session.key.key),
           isNull(messageRequest.deletedAt),
+          sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
           gte(messageRequest.createdAt, timeRange.startTime),
           sql`${messageRequest.createdAt} < ${timeRange.endTime}`
         )
diff --git a/src/actions/system-config.ts b/src/actions/system-config.ts
index efa265586..f81ee833c 100644
--- a/src/actions/system-config.ts
+++ b/src/actions/system-config.ts
@@ -37,6 +37,7 @@ export async function saveSystemSettings(formData: {
   enableClientVersionCheck?: boolean;
   verboseProviderError?: boolean;
   enableHttp2?: boolean;
+  enableAnthropicWarmupIntercept?: boolean;
 }): Promise<ActionResult<SystemSettings>> {
   try {
     const session = await getSession();
@@ -57,6 +58,7 @@ export async function saveSystemSettings(formData: {
       enableClientVersionCheck: validated.enableClientVersionCheck,
       verboseProviderError: validated.verboseProviderError,
       enableHttp2: validated.enableHttp2,
+      enableAnthropicWarmupIntercept: validated.enableAnthropicWarmupIntercept,
     });
 
     // Invalidate the system settings cache so proxy requests get fresh settings
diff --git a/src/app/[locale]/dashboard/logs/_components/error-details-dialog.tsx b/src/app/[locale]/dashboard/logs/_components/error-details-dialog.tsx
index b365abe1c..258ec70b3 100644
--- a/src/app/[locale]/dashboard/logs/_components/error-details-dialog.tsx
+++ b/src/app/[locale]/dashboard/logs/_components/error-details-dialog.tsx
@@ -26,6 +26,7 @@ import {
 import { Link } from "@/i18n/routing";
 import { cn, formatTokenAmount } from "@/lib/utils";
 import { formatCurrency } from "@/lib/utils/currency";
+import { WARMUP_INTERCEPT_BLOCKED_BY } from "@/lib/utils/performance-formatter";
 import { formatProviderTimeline } from "@/lib/utils/provider-chain-formatter";
 import type { ProviderChainItem } from "@/types/message";
 import type { BillingModelSource } from "@/types/system-config";
@@ -272,7 +273,9 @@ export function ErrorDetailsDialog({
                   <Badge variant="outline" className="border-orange-600 text-orange-600">
                     {blockedBy === "sensitive_word"
                       ? t("logs.details.blocked.sensitiveWord")
-                      : blockedBy}
+                      : blockedBy === WARMUP_INTERCEPT_BLOCKED_BY
+                        ? t("logs.details.blocked.warmupIntercept")
+                        : blockedBy}
                   </Badge>
                 </div>
                 {parsedBlockedReason && (
diff --git a/src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx b/src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx
index 559adb6dc..9b4ed532e 100644
--- a/src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx
+++ b/src/app/[locale]/dashboard/logs/_components/usage-logs-table.tsx
@@ -21,6 +21,7 @@ import {
   calculateOutputRate,
   formatDuration,
   NON_BILLING_ENDPOINT,
+  WARMUP_INTERCEPT_BLOCKED_BY,
 } from "@/lib/utils/performance-formatter";
 import { formatProviderSummary } from "@/lib/utils/provider-chain-formatter";
 import type { UsageLogRow } from "@/repository/usage-logs";
@@ -89,7 +90,8 @@ export function UsageLogsTable({
               </TableRow>
             ) : (
               logs.map((log) => {
-                const isNonBilling = log.endpoint === NON_BILLING_ENDPOINT;
+                const isWarmupIntercept = log.blockedBy === WARMUP_INTERCEPT_BLOCKED_BY;
+                const isNonBilling = log.endpoint === NON_BILLING_ENDPOINT || isWarmupIntercept;
 
                 return (
                   <TableRow
@@ -302,7 +304,11 @@ export function UsageLogsTable({
                       </TooltipProvider>
                     </TableCell>
                     <TableCell className="text-right font-mono text-xs">
-                      {isNonBilling ? (
+                      {isWarmupIntercept ? (
+                        <span className="text-orange-700 dark:text-orange-300">
+                          {t("logs.table.skipped")}
+                        </span>
+                      ) : isNonBilling ? (
                         "-"
                       ) : log.costUsd ? (
                         <TooltipProvider>
diff --git a/src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx b/src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
index 0f27deffe..0e92daed8 100644
--- a/src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
+++ b/src/app/[locale]/dashboard/logs/_components/virtualized-logs-table.tsx
@@ -17,6 +17,7 @@ import {
   calculateOutputRate,
   formatDuration,
   NON_BILLING_ENDPOINT,
+  WARMUP_INTERCEPT_BLOCKED_BY,
 } from "@/lib/utils/performance-formatter";
 import { formatProviderSummary } from "@/lib/utils/provider-chain-formatter";
 import type { BillingModelSource } from "@/types/system-config";
@@ -250,7 +251,8 @@ export function VirtualizedLogsTable({
                 );
               }
 
-              const isNonBilling = log.endpoint === NON_BILLING_ENDPOINT;
+              const isWarmupIntercept = log.blockedBy === WARMUP_INTERCEPT_BLOCKED_BY;
+              const isNonBilling = log.endpoint === NON_BILLING_ENDPOINT || isWarmupIntercept;
 
               return (
                 <div
@@ -467,7 +469,11 @@ export function VirtualizedLogsTable({
 
                   {/* Cost */}
                   <div className="flex-[0.7] min-w-[60px] text-right font-mono text-xs px-1">
-                    {isNonBilling ? (
+                    {isWarmupIntercept ? (
+                      <span className="text-orange-700 dark:text-orange-300">
+                        {t("logs.table.skipped")}
+                      </span>
+                    ) : isNonBilling ? (
                       "-"
                     ) : log.costUsd ? (
                       <TooltipProvider>
diff --git a/src/app/[locale]/settings/config/_components/system-settings-form.tsx b/src/app/[locale]/settings/config/_components/system-settings-form.tsx
index aaf2ae203..af1fc97e6 100644
--- a/src/app/[locale]/settings/config/_components/system-settings-form.tsx
+++ b/src/app/[locale]/settings/config/_components/system-settings-form.tsx
@@ -29,6 +29,7 @@ interface SystemSettingsFormProps {
     | "billingModelSource"
     | "verboseProviderError"
     | "enableHttp2"
+    | "enableAnthropicWarmupIntercept"
   >;
 }
 
@@ -50,6 +51,9 @@ export function SystemSettingsForm({ initialSettings }: SystemSettingsFormProps)
     initialSettings.verboseProviderError
   );
   const [enableHttp2, setEnableHttp2] = useState(initialSettings.enableHttp2);
+  const [enableAnthropicWarmupIntercept, setEnableAnthropicWarmupIntercept] = useState(
+    initialSettings.enableAnthropicWarmupIntercept
+  );
   const [isPending, startTransition] = useTransition();
 
   const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
@@ -68,6 +72,7 @@ export function SystemSettingsForm({ initialSettings }: SystemSettingsFormProps)
         billingModelSource,
         verboseProviderError,
         enableHttp2,
+        enableAnthropicWarmupIntercept,
       });
 
       if (!result.ok) {
@@ -82,6 +87,7 @@ export function SystemSettingsForm({ initialSettings }: SystemSettingsFormProps)
         setBillingModelSource(result.data.billingModelSource);
         setVerboseProviderError(result.data.verboseProviderError);
         setEnableHttp2(result.data.enableHttp2);
+        setEnableAnthropicWarmupIntercept(result.data.enableAnthropicWarmupIntercept);
       }
 
       toast.success(t("configUpdated"));
@@ -192,6 +198,23 @@ export function SystemSettingsForm({ initialSettings }: SystemSettingsFormProps)
         />
       </div>
 
+      <div className="flex items-start justify-between gap-4 rounded-lg border border-dashed border-border px-4 py-3">
+        <div>
+          <Label htmlFor="enable-anthropic-warmup-intercept" className="text-sm font-medium">
+            {t("enableAnthropicWarmupIntercept")}
+          </Label>
+          <p className="text-xs text-muted-foreground mt-1">
+            {t("enableAnthropicWarmupInterceptDesc")}
+          </p>
+        </div>
+        <Switch
+          id="enable-anthropic-warmup-intercept"
+          checked={enableAnthropicWarmupIntercept}
+          onCheckedChange={(checked) => setEnableAnthropicWarmupIntercept(checked)}
+          disabled={isPending}
+        />
+      </div>
+
       <div className="flex justify-end">
         <Button type="submit" disabled={isPending}>
           {isPending ? tCommon("saving") : t("saveSettings")}
diff --git a/src/app/[locale]/settings/config/page.tsx b/src/app/[locale]/settings/config/page.tsx
index 000de838c..155a0f8a5 100644
--- a/src/app/[locale]/settings/config/page.tsx
+++ b/src/app/[locale]/settings/config/page.tsx
@@ -40,6 +40,7 @@ async function SettingsConfigContent() {
             billingModelSource: settings.billingModelSource,
             verboseProviderError: settings.verboseProviderError,
             enableHttp2: settings.enableHttp2,
+            enableAnthropicWarmupIntercept: settings.enableAnthropicWarmupIntercept,
           }}
         />
       </Section>
diff --git a/src/app/v1/_lib/proxy/guard-pipeline.ts b/src/app/v1/_lib/proxy/guard-pipeline.ts
index e807f65cd..27d65b9d5 100644
--- a/src/app/v1/_lib/proxy/guard-pipeline.ts
+++ b/src/app/v1/_lib/proxy/guard-pipeline.ts
@@ -10,6 +10,7 @@ import { ProxySensitiveWordGuard } from "./sensitive-word-guard";
 import type { ProxySession } from "./session";
 import { ProxySessionGuard } from "./session-guard";
 import { ProxyVersionGuard } from "./version-guard";
+import { ProxyWarmupGuard } from "./warmup-guard";
 
 // Request type classification for pipeline presets
 export enum RequestType {
@@ -31,6 +32,7 @@ export type GuardStepKey =
   | "version"
   | "probe"
   | "session"
+  | "warmup"
   | "requestFilter"
   | "sensitive"
   | "rateLimit"
@@ -91,6 +93,12 @@ const Steps: Record<GuardStepKey, GuardStep> = {
       return null;
     },
   },
+  warmup: {
+    name: "warmup",
+    async execute(session) {
+      return ProxyWarmupGuard.ensure(session);
+    },
+  },
   requestFilter: {
     name: "requestFilter",
     async execute(session) {
@@ -170,6 +178,7 @@ export const CHAT_PIPELINE: GuardConfig = {
     "version",
     "probe",
     "session",
+    "warmup",
     "requestFilter",
     "sensitive",
     "rateLimit",
diff --git a/src/app/v1/_lib/proxy/warmup-guard.ts b/src/app/v1/_lib/proxy/warmup-guard.ts
new file mode 100644
index 000000000..6b0151ffe
--- /dev/null
+++ b/src/app/v1/_lib/proxy/warmup-guard.ts
@@ -0,0 +1,102 @@
+import { db } from "@/drizzle/db";
+import { messageRequest } from "@/drizzle/schema";
+import { getCachedSystemSettings } from "@/lib/config";
+import { logger } from "@/lib/logger";
+import { SessionManager } from "@/lib/session-manager";
+import type { ProxySession } from "./session";
+import {
+  buildClaudeWarmupInterceptResponse,
+  getClaudeStreamFlag,
+  isClaudeWarmupRequestBody,
+  WARMUP_BLOCKED_BY,
+} from "./warmup-intercept";
+
+export class ProxyWarmupGuard {
+  static async ensure(session: ProxySession): Promise<Response | null> {
+    // 仅对 Claude/Anthropic 格式启用（“只针对 Anthropic 类型”的落地口径）
+    if (session.originalFormat !== "claude") {
+      return null;
+    }
+
+    const settings = await getCachedSystemSettings();
+    if (!settings.enableAnthropicWarmupIntercept) {
+      return null;
+    }
+
+    if (!isClaudeWarmupRequestBody(session.request.message)) {
+      return null;
+    }
+
+    const acceptHeader = session.headers.get("accept");
+    const stream = getClaudeStreamFlag(session.request.message, acceptHeader);
+    const model = session.request.model ?? "unknown";
+
+    const { response, responseBodyForStore, responseHeaders } = buildClaudeWarmupInterceptResponse({
+      model,
+      stream,
+    });
+
+    // 1) 存储响应体/头，确保 Session 详情可回放（即使不存 messages 也能看到 response）
+    if (session.sessionId) {
+      void SessionManager.storeSessionResponse(
+        session.sessionId,
+        responseBodyForStore,
+        session.requestSequence
+      ).catch((err) => {
+        logger.error("[WarmupGuard] Failed to store session response", { err });
+      });
+
+      void SessionManager.storeSessionResponseHeaders(
+        session.sessionId,
+        responseHeaders,
+        session.requestSequence
+      ).catch((err) => {
+        logger.error("[WarmupGuard] Failed to store session response headers", { err });
+      });
+
+      void SessionManager.storeSessionRequestHeaders(
+        session.sessionId,
+        session.headers,
+        session.requestSequence
+      ).catch((err) => {
+        logger.error("[WarmupGuard] Failed to store session request headers", { err });
+      });
+    }
+
+    // 2) 写入请求日志（不计费、不绑定 provider），但可审计可检索
+    try {
+      if (
+        session.authState?.success &&
+        session.authState.user &&
+        session.authState.apiKey &&
+        session.sessionId
+      ) {
+        await db.insert(messageRequest).values({
+          providerId: 0, // 特殊值：表示未选择供应商（本地抢答）
+          userId: session.authState.user.id,
+          key: session.authState.apiKey,
+          model: session.request.model ?? undefined,
+          sessionId: session.sessionId,
+          requestSequence: session.getRequestSequence(),
+          endpoint: session.getEndpoint() ?? undefined,
+          statusCode: 200,
+          durationMs: Math.max(0, Date.now() - session.startTime),
+          costUsd: "0", // 明确不计费
+          blockedBy: WARMUP_BLOCKED_BY, // 复用“拦截信息”展示区（但语义为本地抢答）
+          blockedReason: JSON.stringify({
+            type: "anthropic_warmup",
+            interceptedBy: "cch",
+            skippedUpstream: true,
+          }),
+          userAgent: session.userAgent ?? undefined,
+          messagesCount: session.getMessagesLength(),
+        });
+      }
+    } catch (error) {
+      // 失败不阻塞 warmup 抢答
+      logger.error("[WarmupGuard] Failed to log warmup intercept request", { error });
+    }
+
+    return response;
+  }
+}
diff --git a/src/app/v1/_lib/proxy/warmup-intercept.ts b/src/app/v1/_lib/proxy/warmup-intercept.ts
new file mode 100644
index 000000000..d7a4dc2e3
--- /dev/null
+++ b/src/app/v1/_lib/proxy/warmup-intercept.ts
@@ -0,0 +1,197 @@
+import crypto from "node:crypto";
+
+const WARMUP_TEXT = "Warmup";
+const WARMUP_RESPONSE_TEXT = "I'm ready to help you.";
+
+export const CCH_INTERCEPT_HEADER = "x-cch-intercepted";
+export const CCH_INTERCEPT_WARMUP_VALUE = "warmup";
+export const WARMUP_BLOCKED_BY = "warmup";
+
+type ClaudeTextContentBlock = {
+  type: "text";
+  text: string;
+};
+
+type ClaudeMessageUsage = {
+  input_tokens: number;
+  output_tokens: number;
+  cache_creation_input_tokens: number;
+  cache_read_input_tokens: number;
+};
+
+type ClaudeMessageResponse = {
+  model: string;
+  id: string;
+  type: "message";
+  role: "assistant";
+  content: ClaudeTextContentBlock[];
+  stop_reason: "end_turn";
+  stop_sequence: null;
+  usage: ClaudeMessageUsage;
+};
+
+function isRecord(value: unknown): value is Record<string, unknown> {
+  return !!value && typeof value === "object" && !Array.isArray(value);
+}
+
+export function isClaudeWarmupRequestBody(requestBody: unknown): boolean {
+  if (!isRecord(requestBody)) return false;
+
+  const messages = requestBody.messages;
+  if (!Array.isArray(messages) || messages.length !== 1) return false;
+
+  const message = messages[0];
+  if (!isRecord(message)) return false;
+
+  if (message.role !== "user") return false;
+
+  const content = message.content;
+  if (!Array.isArray(content) || content.length === 0) return false;
+
+  for (const item of content) {
+    if (!isRecord(item)) continue;
+    if (item.type !== "text") continue;
+    if (item.text !== WARMUP_TEXT) continue;
+
+    const cacheControl = item.cache_control;
+    if (!isRecord(cacheControl)) continue;
+    if (cacheControl.type !== "ephemeral") continue;
+
+    return true;
+  }
+
+  return false;
+}
+
+export function getClaudeStreamFlag(requestBody: unknown, acceptHeader: string | null): boolean {
+  if (isRecord(requestBody) && requestBody.stream === true) {
+    return true;
+  }
+
+  const accept = acceptHeader?.toLowerCase() ?? "";
+  return accept.includes("text/event-stream");
+}
+
+function buildWarmupMessageId(): string {
+  const rand = crypto.randomBytes(12).toString("hex");
+  return `msg_${rand}`;
+}
+
+export function buildClaudeWarmupMessageResponse(model: string): ClaudeMessageResponse {
+  return {
+    model,
+    id: buildWarmupMessageId(),
+    type: "message",
+    role: "assistant",
+    content: [
+      {
+        type: "text",
+        text: WARMUP_RESPONSE_TEXT,
+      },
+    ],
+    stop_reason: "end_turn",
+    stop_sequence: null,
+    usage: {
+      input_tokens: 0,
+      output_tokens: 0,
+      cache_creation_input_tokens: 0,
+      cache_read_input_tokens: 0,
+    },
+  };
+}
+
+export function buildClaudeWarmupSse(response: ClaudeMessageResponse): string {
+  const startEvent = {
+    type: "message_start",
+    message: {
+      id: response.id,
+      type: response.type,
+      role: response.role,
+      model: response.model,
+      content: [],
+      stop_reason: null,
+      stop_sequence: null,
+      usage: response.usage,
+    },
+  };
+
+  const contentBlockStart = {
+    type: "content_block_start",
+    index: 0,
+    content_block: { type: "text", text: "" },
+  };
+
+  const contentBlockDelta = {
+    type: "content_block_delta",
+    index: 0,
+    delta: { type: "text_delta", text: response.content[0]?.text ?? "" },
+  };
+
+  const contentBlockStop = { type: "content_block_stop", index: 0 };
+  const messageDelta = {
+    type: "message_delta",
+    delta: { stop_reason: response.stop_reason, stop_sequence: response.stop_sequence },
+    usage: response.usage,
+  };
+  const messageStop = { type: "message_stop" };
+
+  const lines: string[] = [];
+  const pushEvent = (event: string, data: unknown) => {
+    lines.push(`event: ${event}`);
+    lines.push(`data: ${JSON.stringify(data)}`);
+    lines.push("");
+  };
+
+  pushEvent("message_start", startEvent);
+  pushEvent("content_block_start", contentBlockStart);
+  pushEvent("content_block_delta", contentBlockDelta);
+  pushEvent("content_block_stop", contentBlockStop);
+  pushEvent("message_delta", messageDelta);
+  pushEvent("message_stop", messageStop);
+
+  // SSE 以空行作为事件分隔符
+  return `${lines.join("\n")}\n`;
+}
+
+export function buildClaudeWarmupInterceptResponse(params: { model: string; stream: boolean }): {
+  response: Response;
+  responseBodyForStore: string;
+  responseHeaders: Headers;
+} {
+  const payload = buildClaudeWarmupMessageResponse(params.model);
+
+  if (params.stream) {
+    const sseText = buildClaudeWarmupSse(payload);
+    const headers = new Headers({
+      "Content-Type": "text/event-stream; charset=utf-8",
+      "Cache-Control": "no-cache",
+      Connection: "keep-alive",
+      [CCH_INTERCEPT_HEADER]: CCH_INTERCEPT_WARMUP_VALUE,
+    });
+    const encoder = new TextEncoder();
+    const body = new ReadableStream<Uint8Array>({
+      start(controller) {
+        controller.enqueue(encoder.encode(sseText));
+        controller.close();
+      },
+    });
+
+    return {
+      response: new Response(body, { status: 200, headers }),
+      responseBodyForStore: sseText,
+      responseHeaders: headers,
+    };
+  }
+
+  const bodyText = JSON.stringify(payload);
+  const headers = new Headers({
+    "Content-Type": "application/json",
+    [CCH_INTERCEPT_HEADER]: CCH_INTERCEPT_WARMUP_VALUE,
+  });
+
+  return {
+    response: new Response(bodyText, { status: 200, headers }),
+    responseBodyForStore: bodyText,
+    responseHeaders: headers,
+  };
+}
diff --git a/src/drizzle/schema.ts b/src/drizzle/schema.ts
index 77dfbd041..c3b8bb467 100644
--- a/src/drizzle/schema.ts
+++ b/src/drizzle/schema.ts
@@ -462,6 +462,11 @@ export const systemSettings = pgTable('system_settings', {
   // 启用 HTTP/2 连接供应商（默认关闭，启用后自动回退到 HTTP/1.1 失败时）
   enableHttp2: boolean('enable_http2').notNull().default(false),
 
+  // 可选：拦截 Anthropic/Claude Warmup 请求并由 CCH 抢答（默认关闭）
+  enableAnthropicWarmupIntercept: boolean('enable_anthropic_warmup_intercept')
+    .notNull()
+    .default(false),
+
   createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
   updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
 });
diff --git a/src/lib/config/system-settings-cache.ts b/src/lib/config/system-settings-cache.ts
index 1004b747f..b370737d5 100644
--- a/src/lib/config/system-settings-cache.ts
+++ b/src/lib/config/system-settings-cache.ts
@@ -24,8 +24,9 @@ let cachedSettings: SystemSettings | null = null;
 let cachedAt: number = 0;
 
 /** Default settings used when cache fetch fails */
-const DEFAULT_SETTINGS: Pick<SystemSettings, "enableHttp2"> = {
+const DEFAULT_SETTINGS: Pick<SystemSettings, "enableHttp2" | "enableAnthropicWarmupIntercept"> = {
   enableHttp2: false,
+  enableAnthropicWarmupIntercept: false,
 };
 
 /**
@@ -54,6 +55,7 @@ export async function getCachedSystemSettings(): Promise<SystemSettings> {
 
     logger.debug("[SystemSettingsCache] Settings cached", {
       enableHttp2: settings.enableHttp2,
+      enableAnthropicWarmupIntercept: settings.enableAnthropicWarmupIntercept,
       ttl: CACHE_TTL_MS,
     });
 
@@ -84,6 +86,7 @@ export async function getCachedSystemSettings(): Promise<SystemSettings> {
       cleanupBatchSize: 10000,
       enableClientVersionCheck: false,
       enableHttp2: DEFAULT_SETTINGS.enableHttp2,
+      enableAnthropicWarmupIntercept: DEFAULT_SETTINGS.enableAnthropicWarmupIntercept,
       createdAt: new Date(),
       updatedAt: new Date(),
     } satisfies SystemSettings;
diff --git a/src/lib/utils/performance-formatter.ts b/src/lib/utils/performance-formatter.ts
index 53825dfef..3c9698042 100644
--- a/src/lib/utils/performance-formatter.ts
+++ b/src/lib/utils/performance-formatter.ts
@@ -1,4 +1,5 @@
 export const NON_BILLING_ENDPOINT = "/v1/messages/count_tokens";
+export const WARMUP_INTERCEPT_BLOCKED_BY = "warmup";
 
 /**
  * 格式化请求耗时
diff --git a/src/lib/validation/schemas.ts b/src/lib/validation/schemas.ts
index e71942a4b..c69af3b40 100644
--- a/src/lib/validation/schemas.ts
+++ b/src/lib/validation/schemas.ts
@@ -698,6 +698,8 @@ export const UpdateSystemSettingsSchema = z.object({
   verboseProviderError: z.boolean().optional(),
   // 启用 HTTP/2 连接供应商（可选）
   enableHttp2: z.boolean().optional(),
+  // 可选：拦截 Anthropic/Claude Warmup 请求并由 CCH 抢答（可选）
+  enableAnthropicWarmupIntercept: z.boolean().optional(),
 });
 
 // 导出类型推断
diff --git a/src/repository/_shared/transformers.ts b/src/repository/_shared/transformers.ts
index 9306dff76..9e34de907 100644
--- a/src/repository/_shared/transformers.ts
+++ b/src/repository/_shared/transformers.ts
@@ -151,6 +151,7 @@ export function toSystemSettings(dbSettings: any): SystemSettings {
     enableClientVersionCheck: dbSettings?.enableClientVersionCheck ?? false,
     verboseProviderError: dbSettings?.verboseProviderError ?? false,
     enableHttp2: dbSettings?.enableHttp2 ?? false,
+    enableAnthropicWarmupIntercept: dbSettings?.enableAnthropicWarmupIntercept ?? false,
     createdAt: dbSettings?.createdAt ? new Date(dbSettings.createdAt) : new Date(),
     updatedAt: dbSettings?.updatedAt ? new Date(dbSettings.updatedAt) : new Date(),
   };
diff --git a/src/repository/client-versions.ts b/src/repository/client-versions.ts
index 539f64021..03702b316 100644
--- a/src/repository/client-versions.ts
+++ b/src/repository/client-versions.ts
@@ -42,7 +42,12 @@ export async function getActiveUserVersions(days = 7): Promise<RawUserVersion[]>
       .from(messageRequest)
       .leftJoin(users, and(sql`${messageRequest.userId} = ${users.id}`, isNull(users.deletedAt)))
       .where(
-        and(gte(messageRequest.createdAt, cutoffDate), sql`${messageRequest.userAgent} IS NOT NULL`)
+        and(
+          isNull(messageRequest.deletedAt),
+          sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
+          gte(messageRequest.createdAt, cutoffDate),
+          sql`${messageRequest.userAgent} IS NOT NULL`
+        )
       )
       .groupBy(messageRequest.userId, users.name, messageRequest.userAgent)
       .orderBy(sql`MAX(${messageRequest.createdAt}) DESC`);
diff --git a/src/repository/key.ts b/src/repository/key.ts
index e72a0e604..f4ef238bc 100644
--- a/src/repository/key.ts
+++ b/src/repository/key.ts
@@ -563,6 +563,7 @@ export async function findKeysWithStatistics(userId: number): Promise<KeyStatist
         and(
           eq(messageRequest.key, key.key),
           isNull(messageRequest.deletedAt),
+          sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
           gte(messageRequest.createdAt, today),
           lt(messageRequest.createdAt, tomorrow)
         )
@@ -576,7 +577,13 @@ export async function findKeysWithStatistics(userId: number): Promise<KeyStatist
       })
       .from(messageRequest)
       .innerJoin(providers, eq(messageRequest.providerId, providers.id))
-      .where(and(eq(messageRequest.key, key.key), isNull(messageRequest.deletedAt)))
+      .where(
+        and(
+          eq(messageRequest.key, key.key),
+          isNull(messageRequest.deletedAt),
+          sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
+        )
+      )
       .orderBy(desc(messageRequest.createdAt))
       .limit(1);
 
@@ -592,6 +599,7 @@ export async function findKeysWithStatistics(userId: number): Promise<KeyStatist
         and(
           eq(messageRequest.key, key.key),
           isNull(messageRequest.deletedAt),
+          sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
           gte(messageRequest.createdAt, today),
           lt(messageRequest.createdAt, tomorrow),
           sql`${messageRequest.model} IS NOT NULL`
@@ -677,6 +685,7 @@ export async function findKeysWithStatisticsBatch(
       and(
         inArray(messageRequest.key, keyStrings),
         isNull(messageRequest.deletedAt),
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
         gte(messageRequest.createdAt, today),
         lt(messageRequest.createdAt, tomorrow)
       )
@@ -699,7 +708,13 @@ export async function findKeysWithStatisticsBatch(
     })
     .from(messageRequest)
     .innerJoin(providers, eq(messageRequest.providerId, providers.id))
-    .where(and(inArray(messageRequest.key, keyStrings), isNull(messageRequest.deletedAt)))
+    .where(
+      and(
+        inArray(messageRequest.key, keyStrings),
+        isNull(messageRequest.deletedAt),
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
+      )
+    )
     .orderBy(messageRequest.key, desc(messageRequest.createdAt));
 
   const lastUsageMap = new Map<string, { createdAt: Date | null; providerName: string | null }>();
@@ -725,6 +740,7 @@ export async function findKeysWithStatisticsBatch(
       and(
         inArray(messageRequest.key, keyStrings),
         isNull(messageRequest.deletedAt),
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
         gte(messageRequest.createdAt, today),
         lt(messageRequest.createdAt, tomorrow),
         sql`${messageRequest.model} IS NOT NULL`
diff --git a/src/repository/leaderboard.ts b/src/repository/leaderboard.ts
index 1035dc14d..b3a0178c9 100644
--- a/src/repository/leaderboard.ts
+++ b/src/repository/leaderboard.ts
@@ -170,7 +170,13 @@ async function findLeaderboardWithTimezone(
     })
     .from(messageRequest)
     .innerJoin(users, and(sql`${messageRequest.userId} = ${users.id}`, isNull(users.deletedAt)))
-    .where(and(isNull(messageRequest.deletedAt), buildDateCondition(period, timezone, dateRange)))
+    .where(
+      and(
+        isNull(messageRequest.deletedAt),
+        buildDateCondition(period, timezone, dateRange),
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
+      )
+    )
     .groupBy(messageRequest.userId, users.name)
     .orderBy(desc(sql`sum(${messageRequest.costUsd})`));
 
@@ -306,6 +312,7 @@ async function findProviderLeaderboardWithTimezone(
 ): Promise<ProviderLeaderboardEntry[]> {
   const whereConditions = [
     isNull(messageRequest.deletedAt),
+    sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
     buildDateCondition(period, timezone, dateRange),
     providerType ? eq(providers.providerType, providerType) : undefined,
   ];
@@ -405,6 +412,7 @@ async function findProviderCacheHitRateLeaderboardWithTimezone(
 
   const whereConditions = [
     isNull(messageRequest.deletedAt),
+    sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
     buildDateCondition(period, timezone, dateRange),
     cacheRequiredCondition,
     providerType ? eq(providers.providerType, providerType) : undefined,
@@ -547,7 +555,13 @@ async function findModelLeaderboardWithTimezone(
       )`,
     })
     .from(messageRequest)
-    .where(and(isNull(messageRequest.deletedAt), buildDateCondition(period, timezone, dateRange)))
+    .where(
+      and(
+        isNull(messageRequest.deletedAt),
+        buildDateCondition(period, timezone, dateRange),
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
+      )
+    )
     .groupBy(modelField)
     .orderBy(desc(sql`count(*)`)); // 按请求数排序
 
diff --git a/src/repository/message.ts b/src/repository/message.ts
index 712931bf3..28e2c7b48 100644
--- a/src/repository/message.ts
+++ b/src/repository/message.ts
@@ -296,20 +296,24 @@ export async function aggregateSessionStats(sessionId: string): Promise<{
   // 1. 聚合统计
   const [stats] = await db
     .select({
-      requestCount: sql<number>`count(*)::double precision`,
-      totalCostUsd: sql<string>`COALESCE(sum(${messageRequest.costUsd}), 0)`,
-      totalInputTokens: sql<number>`COALESCE(sum(${messageRequest.inputTokens})::double precision, 0::double precision)`,
-      totalOutputTokens: sql<number>`COALESCE(sum(${messageRequest.outputTokens})::double precision, 0::double precision)`,
-      totalCacheCreationTokens: sql<number>`COALESCE(sum(${messageRequest.cacheCreationInputTokens})::double precision, 0::double precision)`,
-      totalCacheReadTokens: sql<number>`COALESCE(sum(${messageRequest.cacheReadInputTokens})::double precision, 0::double precision)`,
-      totalDurationMs: sql<number>`COALESCE(sum(${messageRequest.durationMs})::double precision, 0::double precision)`,
+      // 用于判断 session 是否存在（包含 warmup 等被跳过的请求）
+      requestCountAll: sql<number>`count(*)::double precision`,
+
+      // 统计口径：排除 warmup（不计入任何统计数据）
+      requestCount: sql<number>`count(*) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision`,
+      totalCostUsd: sql<string>`COALESCE(sum(${messageRequest.costUsd}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'), 0)`,
+      totalInputTokens: sql<number>`COALESCE(sum(${messageRequest.inputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalOutputTokens: sql<number>`COALESCE(sum(${messageRequest.outputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalCacheCreationTokens: sql<number>`COALESCE(sum(${messageRequest.cacheCreationInputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalCacheReadTokens: sql<number>`COALESCE(sum(${messageRequest.cacheReadInputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalDurationMs: sql<number>`COALESCE(sum(${messageRequest.durationMs}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
       firstRequestAt: sql<Date>`min(${messageRequest.createdAt})`,
       lastRequestAt: sql<Date>`max(${messageRequest.createdAt})`,
     })
     .from(messageRequest)
     .where(and(eq(messageRequest.sessionId, sessionId), isNull(messageRequest.deletedAt)));
 
-  if (!stats || stats.requestCount === 0) {
+  if (!stats || stats.requestCountAll === 0) {
     return null;
   }
 
@@ -325,7 +329,8 @@ export async function aggregateSessionStats(sessionId: string): Promise<{
       and(
         eq(messageRequest.sessionId, sessionId),
         isNull(messageRequest.deletedAt),
-        sql`${messageRequest.providerId} IS NOT NULL`
+        sql`${messageRequest.providerId} > 0`,
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
       )
     );
 
@@ -337,7 +342,8 @@ export async function aggregateSessionStats(sessionId: string): Promise<{
       and(
         eq(messageRequest.sessionId, sessionId),
         isNull(messageRequest.deletedAt),
-        sql`${messageRequest.model} IS NOT NULL`
+        sql`${messageRequest.model} IS NOT NULL`,
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
       )
     );
 
@@ -349,7 +355,8 @@ export async function aggregateSessionStats(sessionId: string): Promise<{
       and(
         eq(messageRequest.sessionId, sessionId),
         isNull(messageRequest.deletedAt),
-        sql`${messageRequest.cacheTtlApplied} IS NOT NULL`
+        sql`${messageRequest.cacheTtlApplied} IS NOT NULL`,
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
       )
     );
 
@@ -448,13 +455,17 @@ export async function aggregateMultipleSessionStats(sessionIds: string[]): Promi
   const statsResults = await db
     .select({
       sessionId: messageRequest.sessionId,
-      requestCount: sql<number>`count(*)::double precision`,
-      totalCostUsd: sql<string>`COALESCE(sum(${messageRequest.costUsd}), 0)`,
-      totalInputTokens: sql<number>`COALESCE(sum(${messageRequest.inputTokens})::double precision, 0::double precision)`,
-      totalOutputTokens: sql<number>`COALESCE(sum(${messageRequest.outputTokens})::double precision, 0::double precision)`,
-      totalCacheCreationTokens: sql<number>`COALESCE(sum(${messageRequest.cacheCreationInputTokens})::double precision, 0::double precision)`,
-      totalCacheReadTokens: sql<number>`COALESCE(sum(${messageRequest.cacheReadInputTokens})::double precision, 0::double precision)`,
-      totalDurationMs: sql<number>`COALESCE(sum(${messageRequest.durationMs})::double precision, 0::double precision)`,
+      // 用于判断 session 是否存在（包含 warmup 等被跳过的请求）
+      requestCountAll: sql<number>`count(*)::double precision`,
+
+      // 统计口径：排除 warmup（不计入任何统计数据）
+      requestCount: sql<number>`count(*) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision`,
+      totalCostUsd: sql<string>`COALESCE(sum(${messageRequest.costUsd}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'), 0)`,
+      totalInputTokens: sql<number>`COALESCE(sum(${messageRequest.inputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalOutputTokens: sql<number>`COALESCE(sum(${messageRequest.outputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalCacheCreationTokens: sql<number>`COALESCE(sum(${messageRequest.cacheCreationInputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalCacheReadTokens: sql<number>`COALESCE(sum(${messageRequest.cacheReadInputTokens}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
+      totalDurationMs: sql<number>`COALESCE(sum(${messageRequest.durationMs}) FILTER (WHERE ${messageRequest.blockedBy} IS DISTINCT FROM 'warmup')::double precision, 0::double precision)`,
       firstRequestAt: sql<Date>`min(${messageRequest.createdAt})`,
       lastRequestAt: sql<Date>`max(${messageRequest.createdAt})`,
     })
@@ -478,7 +489,8 @@ export async function aggregateMultipleSessionStats(sessionIds: string[]): Promi
       and(
         inArray(messageRequest.sessionId, sessionIds),
         isNull(messageRequest.deletedAt),
-        sql`${messageRequest.providerId} IS NOT NULL`
+        sql`${messageRequest.providerId} > 0`,
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
       )
     );
 
@@ -508,7 +520,8 @@ export async function aggregateMultipleSessionStats(sessionIds: string[]): Promi
       and(
         inArray(messageRequest.sessionId, sessionIds),
         isNull(messageRequest.deletedAt),
-        sql`${messageRequest.model} IS NOT NULL`
+        sql`${messageRequest.model} IS NOT NULL`,
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
       )
     );
 
@@ -535,7 +548,8 @@ export async function aggregateMultipleSessionStats(sessionIds: string[]): Promi
       and(
         inArray(messageRequest.sessionId, sessionIds),
         isNull(messageRequest.deletedAt),
-        sql`${messageRequest.cacheTtlApplied} IS NOT NULL`
+        sql`${messageRequest.cacheTtlApplied} IS NOT NULL`,
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`
       )
     );
 
@@ -590,7 +604,7 @@ export async function aggregateMultipleSessionStats(sessionIds: string[]): Promi
     const userInfo = userInfoMap.get(sessionId);
 
     // 跳过没有数据的 session
-    if (!stats || !userInfo || stats.requestCount === 0) {
+    if (!stats || !userInfo || stats.requestCountAll === 0) {
       continue;
     }
 
diff --git a/src/repository/overview.ts b/src/repository/overview.ts
index 23d6d2976..6d8c1230b 100644
--- a/src/repository/overview.ts
+++ b/src/repository/overview.ts
@@ -39,6 +39,7 @@ export async function getOverviewMetrics(): Promise<OverviewMetrics> {
     .where(
       and(
         isNull(messageRequest.deletedAt),
+        sql`${messageRequest.blockedBy} IS DISTINCT FROM 'warmup'`,
         sql`(${messageRequest.createdAt} AT TIME ZONE ${timezone})::date = (CURRENT_TIMESTAMP AT TIME ZONE ${timezone})::date`
       )
     );
diff --git a/src/repository/statistics.ts b/src/repository/statistics.ts
index 899ba5a3c..1d1f56f26 100644
--- a/src/repository/statistics.ts
+++ b/src/repository/statistics.ts
@@ -46,6 +46,7 @@ export async function getUserStatisticsFromDB(timeRange: TimeRange): Promise<Dat
           LEFT JOIN message_request mr ON u.id = mr.user_id
             AND DATE_TRUNC('hour', mr.created_at AT TIME ZONE ${timezone}) = hr.hour
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           WHERE u.deleted_at IS NULL
           GROUP BY u.id, u.name, hr.hour
         )
@@ -82,6 +83,7 @@ export async function getUserStatisticsFromDB(timeRange: TimeRange): Promise<Dat
           LEFT JOIN message_request mr ON u.id = mr.user_id
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           WHERE u.deleted_at IS NULL
           GROUP BY u.id, u.name, dr.date
         )
@@ -118,6 +120,7 @@ export async function getUserStatisticsFromDB(timeRange: TimeRange): Promise<Dat
           LEFT JOIN message_request mr ON u.id = mr.user_id
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           WHERE u.deleted_at IS NULL
           GROUP BY u.id, u.name, dr.date
         )
@@ -154,6 +157,7 @@ export async function getUserStatisticsFromDB(timeRange: TimeRange): Promise<Dat
           LEFT JOIN message_request mr ON u.id = mr.user_id
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           WHERE u.deleted_at IS NULL
           GROUP BY u.id, u.name, dr.date
         )
@@ -230,6 +234,7 @@ export async function getKeyStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND DATE_TRUNC('hour', mr.created_at AT TIME ZONE ${timezone}) = hr.hour
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, hr.hour
         )
         SELECT
@@ -271,6 +276,7 @@ export async function getKeyStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, dr.date
         )
         SELECT
@@ -312,6 +318,7 @@ export async function getKeyStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, dr.date
         )
         SELECT
@@ -353,6 +360,7 @@ export async function getKeyStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, dr.date
         )
         SELECT
@@ -435,6 +443,7 @@ export async function getMixedStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND DATE_TRUNC('hour', mr.created_at AT TIME ZONE ${timezone}) = hr.hour
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, hr.hour
         )
         SELECT
@@ -465,6 +474,7 @@ export async function getMixedStatisticsFromDB(
           LEFT JOIN message_request mr ON DATE_TRUNC('hour', mr.created_at AT TIME ZONE ${timezone}) = hr.hour
             AND mr.user_id != ${userId}
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY hr.hour
         )
         SELECT
@@ -507,6 +517,7 @@ export async function getMixedStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, dr.date
         )
         SELECT
@@ -537,6 +548,7 @@ export async function getMixedStatisticsFromDB(
           LEFT JOIN message_request mr ON (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.user_id != ${userId}
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY dr.date
         )
         SELECT
@@ -579,6 +591,7 @@ export async function getMixedStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, dr.date
         )
         SELECT
@@ -609,6 +622,7 @@ export async function getMixedStatisticsFromDB(
           LEFT JOIN message_request mr ON (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.user_id != ${userId}
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY dr.date
         )
         SELECT
@@ -651,6 +665,7 @@ export async function getMixedStatisticsFromDB(
             AND mr.user_id = ${userId}
             AND (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY k.id, k.name, dr.date
         )
         SELECT
@@ -681,6 +696,7 @@ export async function getMixedStatisticsFromDB(
           LEFT JOIN message_request mr ON (mr.created_at AT TIME ZONE ${timezone})::date = dr.date
             AND mr.user_id != ${userId}
             AND mr.deleted_at IS NULL
+            AND mr.blocked_by IS DISTINCT FROM 'warmup'
           GROUP BY dr.date
         )
         SELECT
@@ -728,6 +744,7 @@ export async function sumUserCostToday(userId: number): Promise<number> {
     WHERE k.user_id = ${userId}
       AND (mr.created_at AT TIME ZONE ${timezone})::date = (CURRENT_TIMESTAMP AT TIME ZONE ${timezone})::date
       AND mr.deleted_at IS NULL
+      AND mr.blocked_by IS DISTINCT FROM 'warmup'
       AND k.deleted_at IS NULL
   `;
 
diff --git a/src/repository/system-config.ts b/src/repository/system-config.ts
index 73f1f7ddd..92cb4980b 100644
--- a/src/repository/system-config.ts
+++ b/src/repository/system-config.ts
@@ -86,6 +86,7 @@ function createFallbackSettings(): SystemSettings {
     enableClientVersionCheck: false,
     verboseProviderError: false,
     enableHttp2: false,
+    enableAnthropicWarmupIntercept: false,
     createdAt: now,
     updatedAt: now,
   };
@@ -110,6 +111,7 @@ export async function getSystemSettings(): Promise<SystemSettings> {
         enableClientVersionCheck: systemSettings.enableClientVersionCheck,
         verboseProviderError: systemSettings.verboseProviderError,
         enableHttp2: systemSettings.enableHttp2,
+        enableAnthropicWarmupIntercept: systemSettings.enableAnthropicWarmupIntercept,
         createdAt: systemSettings.createdAt,
         updatedAt: systemSettings.updatedAt,
       })
@@ -142,6 +144,7 @@ export async function getSystemSettings(): Promise<SystemSettings> {
         enableClientVersionCheck: systemSettings.enableClientVersionCheck,
         verboseProviderError: systemSettings.verboseProviderError,
         enableHttp2: systemSettings.enableHttp2,
+        enableAnthropicWarmupIntercept: systemSettings.enableAnthropicWarmupIntercept,
         createdAt: systemSettings.createdAt,
         updatedAt: systemSettings.updatedAt,
       });
@@ -165,6 +168,7 @@ export async function getSystemSettings(): Promise<SystemSettings> {
         enableClientVersionCheck: systemSettings.enableClientVersionCheck,
         verboseProviderError: systemSettings.verboseProviderError,
         enableHttp2: systemSettings.enableHttp2,
+        enableAnthropicWarmupIntercept: systemSettings.enableAnthropicWarmupIntercept,
         createdAt: systemSettings.createdAt,
         updatedAt: systemSettings.updatedAt,
       })
@@ -246,6 +250,11 @@ export async function updateSystemSettings(
       updates.enableHttp2 = payload.enableHttp2;
     }
 
+    // Warmup 拦截配置字段（如果提供）
+    if (payload.enableAnthropicWarmupIntercept !== undefined) {
+      updates.enableAnthropicWarmupIntercept = payload.enableAnthropicWarmupIntercept;
+    }
+
     const [updated] = await db
       .update(systemSettings)
       .set(updates)
@@ -263,6 +272,7 @@ export async function updateSystemSettings(
         enableClientVersionCheck: systemSettings.enableClientVersionCheck,
         verboseProviderError: systemSettings.verboseProviderError,
         enableHttp2: systemSettings.enableHttp2,
+        enableAnthropicWarmupIntercept: systemSettings.enableAnthropicWarmupIntercept,
         createdAt: systemSettings.createdAt,
         updatedAt: systemSettings.updatedAt,
       });
diff --git a/src/types/system-config.ts b/src/types/system-config.ts
index 484f442da..77158dbdc 100644
--- a/src/types/system-config.ts
+++ b/src/types/system-config.ts
@@ -29,6 +29,9 @@ export interface SystemSettings {
   // 启用 HTTP/2 连接供应商
   enableHttp2: boolean;
 
+  // 可选：拦截 Anthropic/Claude Warmup 请求并由 CCH 抢答
+  enableAnthropicWarmupIntercept: boolean;
+
   createdAt: Date;
   updatedAt: Date;
 }
@@ -58,4 +61,7 @@ export interface UpdateSystemSettingsInput {
 
   // 启用 HTTP/2 连接供应商（可选）
   enableHttp2?: boolean;
+
+  // 可选：拦截 Anthropic/Claude Warmup 请求并由 CCH 抢答（可选）
+  enableAnthropicWarmupIntercept?: boolean;
 }
diff --git a/tests/unit/proxy/session.test.ts b/tests/unit/proxy/session.test.ts
index 7e36327cd..3def5a08d 100644
--- a/tests/unit/proxy/session.test.ts
+++ b/tests/unit/proxy/session.test.ts
@@ -31,6 +31,7 @@ function makeSystemSettings(
     enableClientVersionCheck: false,
     verboseProviderError: false,
     enableHttp2: false,
+    enableAnthropicWarmupIntercept: false,
     createdAt: now,
     updatedAt: now,
   };
diff --git a/tests/unit/proxy/warmup-intercept.test.ts b/tests/unit/proxy/warmup-intercept.test.ts
new file mode 100644
index 000000000..8681fe7cd
--- /dev/null
+++ b/tests/unit/proxy/warmup-intercept.test.ts
@@ -0,0 +1,154 @@
+import { describe, expect, it } from "vitest";
+import {
+  CCH_INTERCEPT_HEADER,
+  CCH_INTERCEPT_WARMUP_VALUE,
+  buildClaudeWarmupInterceptResponse,
+  buildClaudeWarmupMessageResponse,
+  buildClaudeWarmupSse,
+  getClaudeStreamFlag,
+  isClaudeWarmupRequestBody,
+} from "@/app/v1/_lib/proxy/warmup-intercept";
+
+describe("warmup-intercept", () => {
+  describe("isClaudeWarmupRequestBody", () => {
+    it("应识别标准 Warmup 请求（user.content[].text=Warmup + cache_control.ephemeral）", () => {
+      const requestBody = {
+        model: "claude-sonnet-4-5-20250929",
+        messages: [
+          {
+            role: "user",
+            content: [
+              {
+                type: "text",
+                text: "Warmup",
+                cache_control: { type: "ephemeral" },
+              },
+            ],
+          },
+        ],
+        system: [{ type: "text", text: "You are Claude Code" }],
+      };
+
+      expect(isClaudeWarmupRequestBody(requestBody)).toBe(true);
+    });
+
+    it("messages 非单条消息时不应识别为 Warmup", () => {
+      const requestBody = {
+        messages: [
+          {
+            role: "user",
+            content: [{ type: "text", text: "Warmup", cache_control: { type: "ephemeral" } }],
+          },
+          { role: "assistant", content: [{ type: "text", text: "..." }] },
+        ],
+      };
+      expect(isClaudeWarmupRequestBody(requestBody)).toBe(false);
+    });
+
+    it("role 非 user 时不应识别为 Warmup", () => {
+      const requestBody = {
+        messages: [
+          {
+            role: "assistant",
+            content: [{ type: "text", text: "Warmup", cache_control: { type: "ephemeral" } }],
+          },
+        ],
+      };
+      expect(isClaudeWarmupRequestBody(requestBody)).toBe(false);
+    });
+
+    it("缺少 cache_control 或 cache_control.type 非 ephemeral 时不应识别为 Warmup", () => {
+      const missingCache = {
+        messages: [{ role: "user", content: [{ type: "text", text: "Warmup" }] }],
+      };
+      const wrongCache = {
+        messages: [
+          {
+            role: "user",
+            content: [{ type: "text", text: "Warmup", cache_control: { type: "persistent" } }],
+          },
+        ],
+      };
+      expect(isClaudeWarmupRequestBody(missingCache)).toBe(false);
+      expect(isClaudeWarmupRequestBody(wrongCache)).toBe(false);
+    });
+
+    it("text 非 Warmup 时不应识别为 Warmup", () => {
+      const requestBody = {
+        messages: [
+          {
+            role: "user",
+            content: [{ type: "text", text: "hello", cache_control: { type: "ephemeral" } }],
+          },
+        ],
+      };
+      expect(isClaudeWarmupRequestBody(requestBody)).toBe(false);
+    });
+  });
+
+  describe("getClaudeStreamFlag", () => {
+    it("body.stream=true 时应视为 stream", () => {
+      expect(getClaudeStreamFlag({ stream: true }, null)).toBe(true);
+    });
+
+    it("Accept 包含 text/event-stream 时应视为 stream", () => {
+      expect(getClaudeStreamFlag({}, "text/event-stream")).toBe(true);
+      expect(getClaudeStreamFlag({}, "text/event-stream; charset=utf-8")).toBe(true);
+    });
+
+    it("默认应为非 stream", () => {
+      expect(getClaudeStreamFlag({}, "application/json")).toBe(false);
+    });
+  });
+
+  describe("buildClaudeWarmupMessageResponse", () => {
+    it("应生成最小可用的 Claude message 响应结构", () => {
+      const res = buildClaudeWarmupMessageResponse("claude-test");
+      expect(res.type).toBe("message");
+      expect(res.role).toBe("assistant");
+      expect(res.model).toBe("claude-test");
+      expect(res.content[0]?.type).toBe("text");
+      expect(res.content[0]?.text).toContain("I'm ready to help you.");
+      expect(res.stop_reason).toBe("end_turn");
+      expect(res.usage.input_tokens).toBe(0);
+    });
+  });
+
+  describe("buildClaudeWarmupSse", () => {
+    it("应生成包含 message_start 与 content_block_delta 的 SSE 文本", () => {
+      const payload = buildClaudeWarmupMessageResponse("claude-test");
+      const sse = buildClaudeWarmupSse(payload);
+      expect(sse).toContain("event: message_start");
+      expect(sse).toContain("event: content_block_delta");
+      expect(sse).toContain("I'm ready to help you.");
+      expect(sse).toContain("event: message_stop");
+    });
+  });
+
+  describe("buildClaudeWarmupInterceptResponse", () => {
+    it("非 stream：应返回 JSON + 标记头", async () => {
+      const { response } = buildClaudeWarmupInterceptResponse({
+        model: "claude-test",
+        stream: false,
+      });
+      expect(response.status).toBe(200);
+      expect(response.headers.get("content-type")).toContain("application/json");
+      expect(response.headers.get(CCH_INTERCEPT_HEADER)).toBe(CCH_INTERCEPT_WARMUP_VALUE);
+      const body = await response.text();
+      expect(body).toContain("I'm ready to help you.");
+    });
+
+    it("stream：应返回 SSE + 标记头", async () => {
+      const { response } = buildClaudeWarmupInterceptResponse({
+        model: "claude-test",
+        stream: true,
+      });
+      expect(response.status).toBe(200);
+      expect(response.headers.get("content-type")).toContain("text/event-stream");
+      expect(response.headers.get(CCH_INTERCEPT_HEADER)).toBe(CCH_INTERCEPT_WARMUP_VALUE);
+      const body = await response.text();
+      expect(body).toContain("event: message_start");
+      expect(body).toContain("I'm ready to help you.");
+    });
+  });
+});
