Files
llm-intelligence/TECHNICAL_DESIGN.md
Your Name ba054f04cf feat(phase1): OpenRouter采集器接入PostgreSQL,数据链路闭环
- 将 fetch_openrouter.go 的 summarize() 实现为 PostgreSQL upsert
- 新增 -db 参数和 DATABASE_URL 环境变量支持
- 打通 models + model_prices 表的最小可运行链路
- 创建 llm_intelligence 数据库并运行 migration
- 前端 Explorer 验证 T-3.2~T-3.5 全部通过
- 日报生成器正常产出 Markdown 和 latest_models.json
2026-05-08 13:49:12 +08:00

53 KiB
Raw Blame History

LLM Intelligence Hub — 技术设计文档 v1.0

文档版本v1.0 日期2026-05-04 负责人宰相AI 辅助) 状态:初稿


一、系统架构概览

1.1 整体架构

┌──────────────────────────────────────────────────────────────────────┐
│                        LLM Intelligence Hub                         │
├──────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────────────────┐  │
│  │      报告    │   │   Web UI    │   │  AI Agent / MCP Client  │  │
│  │   Phase 2才推送│   │  (Explorer+报告)  │   │     (REST API / MCP)    │  │
│  └──────┬──────┘   └──────┬──────┘   └────────────┬────────────┘  │
│         │                 │                        │                │
│  ┌──────▼──────────────────▼────────────────────────▼────────────┐  │
│  │                      Service Layer (Python)                     │  │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌──────────┐  │  │
│  │  │  Report    │  │    API     │  │  Scheduler │  │ Notifier │  │  │
│  │  │  Generator │  │   Server   │  │  (cron)    │  │  (告警)  │  │  │
│  │  └────────────┘  └────────────┘  └────────────┘  └──────────┘  │  │
│  └───────────────────────────┬────────────────────────────────────┘  │
│                              │                                        │
│  ┌───────────────────────────▼────────────────────────────────────┐  │
│  │                    Data Access Layer (SQLAlchemy ORM)           │  │
│  └───────────────────────────┬────────────────────────────────────┘  │
│                              │                                        │
│  ┌───────────────────────────▼────────────────────────────────────┐  │
│  │              Storage Layer (PostgreSQL)                         │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │                    Data Collection Layer                        │  │
│  │  ┌─────────────┐  ┌──────────────┐  ┌──────────────────────┐   │  │
│  │  │ OpenRouter  │  │ Phase 2才扩充厂商/中转平台 │  │  中转平台采集器       │   │  │
│  │  │  Collector  │  │ (10家厂商)    │  │ (硅基流动等)         │   │  │
│  │  └─────────────┘  └──────────────┘  └──────────────────────┘   │  │
│  └────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────┘

1.2 各层职责

| 层级 | 职责 | 技术选型 | | 数据采集层 | 从 OpenRouter 抓取模型元数据、定价 | Python + requests | | 存储层 | 结构化数据持久化 + 数据库内任务队列 | PostgreSQL与立交桥技术栈统一 | | 服务层 | 报告生成、API 服务、调度 | Python 3.11 + FlaskPhase 1 API+ Jinja2报告模板 | | 前端层 | 静态 Web 页面展示Explorer / 报告) | 纯 HTML/CSS/JS + Bootstrap 5 + ECharts 5 |

1.3 技术架构决策(与立交桥技术栈统一)

核心约束与立交桥技术栈保持一致Phase 1 直接使用 PostgreSQL。

| 决策 | 选型 | 理由 | | 数据库 | PostgreSQL | 与立交桥统一;支持 JSONB/数组类型;数据库内队列替代第三方消息组件 | | API 框架 | Flask | 轻量1 进程运行 | | 前端 | 纯静态 HTML | 无需 Node.js 服务端渲染 | | 爬虫框架 | requests + BeautifulSoup | 成熟稳定 | | 调度 | 系统 cron + Python script | 无需 Celery/RQ | | 日志/监控 | 文件系统日志 | loguru 写入文件 | | 告警 | Phase 2 | 钉钉/飞书 Webhook 推送 |

Phase 1 单机部署拓扑

Phase 1 单机部署
├── PostgreSQL DB
├── 采集脚本cron 触发,直写 DB
├── 日报生成命令Markdown 输出)
└── 备份脚本Phase 2 才推送至 OSS

二、技术选型详解

2.1 语言与运行时

| 组件 | 选型 | 版本 | 依据 |

| 主力语言 | Python | 3.11+ | 爬虫/数据处理生态最成熟Flask/Jinja2 配套完善 | | 前端 | Vanilla JS + HTML5 | — | 无需 Node.js 构建链,静态文件 CDN 托管,降低成本 |

2.2 框架与工具库

| 用途 | 库/工具 | 用途说明 |

| HTTP 请求 | requests | 数据采集主库,轻量稳定 | | HTML 解析 | BeautifulSoup4 | 静态页面解析 | | 动态页面 | playwright | JavaScript 渲染页(如某些国内定价页) | | ORM | SQLAlchemy | 数据库抽象,直接对接 PostgreSQL | | API 框架 | Flask | 轻量 REST APIGunicorn 部署 | | 模板引擎 | Jinja2 | HTML 报告模板渲染 | | 图表 | ECharts | 前端可视化(价格趋势/排行榜) | | 调度 | APScheduler | Python 内置调度(辅助 cron | | 日志 | loguru | 结构化日志,低配置 | | 日期处理 | pandas | 数据清洗、价格计算 | | 货币换算 | forex-python | USD/CNY/EUR 汇率获取 |

2.3 数据库

Phase 1PostgreSQL

  • 与立交桥技术栈统一
  • 利用 PostgreSQL JSONB 存储灵活字段(如 capabilities 数组)
  • 使用 PostgreSQL job queue 表实现异步任务队列,无须第三方消息组件
  • Schema 设计直接以 PostgreSQL 语法编写

2.4 为什么不用这些

| 未选方案 | 原因 |

| SQLite | 不符合与立交桥技术栈统一的要求 | | FastAPI | Swagger UI 增加包体积Flask 在 Phase 1 足够轻量 | | Scrapy | 重量级框架Phase 1 采集规模不需要分布式 | | Celery + RabbitMQ | 增加运维复杂度,用 PostgreSQL job queue 替代 | | React/Vue | 需要 Node.js 构建链,增加部署复杂度 | | Deno/Bun | 生态不如 Python 成熟,数据处理库少 |


三、数据库设计DDL

以下 DDL 以 PostgreSQL 语法编写,与立交桥技术栈统一。

3.1 model_provider模型商

CREATE TABLE model_provider (
    id              BIGSERIAL PRIMARY KEY,
    name            TEXT NOT NULL UNIQUE,           -- "OpenAI", "百度", "DeepSeek"
    name_cn         TEXT,                            -- 中文名:"百度智能云"
    country         TEXT NOT NULL,                   -- "US" / "CN" / "EU"
    website         TEXT,                            -- 官网 URL
    founded_year    INTEGER,                         -- 成立年份
    description     TEXT,                            -- 简介
    logo_url        TEXT,                            -- 厂商 Logo
    status          TEXT NOT NULL DEFAULT 'active', -- active / deprecated
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_provider_country ON model_provider(country);
CREATE INDEX idx_provider_status ON model_provider(status);

3.2 model模型

CREATE TABLE model (
    id                  BIGSERIAL PRIMARY KEY,
    provider_id        INTEGER NOT NULL,
    name                TEXT NOT NULL,               -- "GPT-4o", "ERNIE-4.0"
    version             TEXT,                         -- "2025-12", "V3.2"
    modality            TEXT NOT NULL,               -- text / vision / audio / video / code
    context_length      INTEGER NOT NULL DEFAULT 0,  -- 上下文窗口0=未知
    capabilities        TEXT,                        -- JSON数组: ["function_calling","vision"]
    release_date        DATE,                        -- 发布日期
    status              TEXT NOT NULL DEFAULT 'active', -- active / deprecated / discontinued
    parent_model_id     INTEGER,                     -- 父模型ID区分 Turbo/Lite 变体)
    elo_score           REAL,                        -- ELO 分数OpenRouter
    benchmark_scores    TEXT,                        -- JSON: {"mmlu": 88.5, "humaneval": 90.2}
    source_url          TEXT,                        -- 来源 URL
    data_confidence     TEXT DEFAULT 'official',    -- official / inferred / unverified
    created_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (provider_id) REFERENCES model_provider(id) ON DELETE CASCADE,
    UNIQUE(provider_id, name, version)
);

CREATE INDEX idx_model_provider ON model(provider_id);
CREATE INDEX idx_model_modality ON model(modality);
CREATE INDEX idx_model_status ON model(status);
CREATE INDEX idx_model_name ON model(name);

3.3 operator运营商/云平台)

CREATE TABLE operator (
    id              BIGSERIAL PRIMARY KEY,
    name            TEXT NOT NULL UNIQUE,           -- "AWS Bedrock", "硅基流动"
    name_cn         TEXT,                            -- 中文名
    type            TEXT NOT NULL,                  -- cloud / reseller / official
    country         TEXT NOT NULL,                  -- 运营主体国籍
    website         TEXT,                           -- 控制台地址
    api_endpoint    TEXT,                           -- API 基础 URL
    auth_type       TEXT NOT NULL,                  -- api_key / oauth / sts
    is_cn_accessible BOOLEAN DEFAULT 1,              -- 国内是否可访问
    stability_grade TEXT DEFAULT 'B',               -- A/B/C/D 稳定性评级
    status          TEXT NOT NULL DEFAULT 'active', -- active / deprecated
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_operator_type ON operator(type);
CREATE INDEX idx_operator_country ON operator(country);

3.4 region_pricing区域定价

CREATE TABLE region_pricing (
    id                      BIGSERIAL PRIMARY KEY,
    operator_id             INTEGER NOT NULL,
    model_id                INTEGER NOT NULL,
    region                  TEXT NOT NULL DEFAULT 'GLOBAL', -- CN / US / EU / GLOBAL
    currency                TEXT NOT NULL,                    -- CNY / USD / EUR
    input_price_per_mtok    REAL NOT NULL,                   -- 元/百万Token
    output_price_per_mtok   REAL NOT NULL,
    unit                    TEXT DEFAULT 'per_mtok',         -- per_mtok / per_1k / per_token
    free_tier_id            INTEGER,                          -- 关联 free_tier 表
    rate_limit              TEXT,                             -- JSON: {"rpm": 60, "tpm": 100000}
    free_limitations        TEXT,                             -- JSON数组: ["仅限国内IP","新用户专享"]
    last_updated            DATE NOT NULL,
    source_url              TEXT,
    data_confidence         TEXT DEFAULT 'official',         -- official / inferred / expired
    created_at              TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at              TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (operator_id) REFERENCES operator(id) ON DELETE CASCADE,
    FOREIGN KEY (model_id) REFERENCES model(id) ON DELETE CASCADE,
    UNIQUE(operator_id, model_id, region, currency)
);

CREATE INDEX idx_pricing_operator ON region_pricing(operator_id);
CREATE INDEX idx_pricing_model ON region_pricing(model_id);
CREATE INDEX idx_pricing_region ON region_pricing(region);
CREATE INDEX idx_pricing_currency ON region_pricing(currency);
CREATE INDEX idx_pricing_input_cost ON region_pricing(input_price_per_mtok);

3.5 pricing_history价格历史

CREATE TABLE pricing_history (
    id                      BIGSERIAL PRIMARY KEY,
    region_pricing_id       INTEGER NOT NULL,
    model_id                INTEGER NOT NULL,
    operator_id             INTEGER NOT NULL,
    region                  TEXT NOT NULL,
    currency                TEXT NOT NULL,
    old_input_price         REAL,
    new_input_price         REAL NOT NULL,
    old_output_price        REAL,
    new_output_price        REAL NOT NULL,
    change_pct              REAL,                            -- 变动百分比(自动计算)
    change_type             TEXT NOT NULL,                   -- increase / decrease / new_model / discontinued
    recorded_at             DATE NOT NULL,                   -- 记录日期
    source_url              TEXT,
    created_at              TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (region_pricing_id) REFERENCES region_pricing(id) ON DELETE CASCADE,
    FOREIGN KEY (model_id) REFERENCES model(id) ON DELETE CASCADE,
    FOREIGN KEY (operator_id) REFERENCES operator(id) ON DELETE CASCADE
);

CREATE INDEX idx_history_model ON pricing_history(model_id);
CREATE INDEX idx_history_operator ON pricing_history(operator_id);
CREATE INDEX idx_history_recorded ON pricing_history(recorded_at);
CREATE INDEX idx_history_change_type ON pricing_history(change_type);

3.6 free_tier免费政策

CREATE TABLE free_tier (
    id                  BIGSERIAL PRIMARY KEY,
    operator_id         INTEGER NOT NULL,
    model_id            INTEGER,                          -- NULL表示该平台全部免费额度
    free_model_name     TEXT,                              -- 免费模型名称(展示用)
    quota_type          TEXT NOT NULL,                     -- daily / monthly / one_time / unlimited
    quota_amount        REAL,                              -- 配额数量
    quota_unit          TEXT,                              -- requests / tokens / minutes
    tpm_limit           INTEGER,                           -- tokens per minute 限制
    rpm_limit           INTEGER,                           -- requests per minute 限制
    daily_req_limit     INTEGER,                           -- 每日请求上限
    monthly_req_limit   INTEGER,                           -- 每月请求上限
    token_limit_per_req INTEGER,                           -- 单次请求Token上限
    requires_credit_card BOOLEAN DEFAULT 0,                -- 是否需要绑定信用卡
    requires_verification BOOLEAN DEFAULT 0,              -- 是否需要实名认证
    region_restrictions TEXT,                              -- JSON: ["仅限部分地区"]
    applicable_scenarios TEXT,                             -- JSON: ["仅限新用户"]
    special_notes       TEXT,                              -- 特殊说明
    effective_from       DATE,
    effective_until     DATE,                              -- NULL表示长期有效
    last_updated        DATE,
    source_url          TEXT,
    created_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (operator_id) REFERENCES operator(id) ON DELETE CASCADE,
    FOREIGN KEY (model_id) REFERENCES model(id) ON DELETE SET NULL
);

CREATE INDEX idx_free_operator ON free_tier(operator_id);
CREATE INDEX idx_free_model ON free_tier(model_id);
CREATE INDEX idx_free_quota_type ON free_tier(quota_type);

3.7 daily_report每日报告

CREATE TABLE daily_report (
    id              BIGSERIAL PRIMARY KEY,
    report_date     DATE NOT NULL UNIQUE,
    new_models      TEXT,                                 -- JSON数组新上线模型
    price_changes   TEXT,                                 -- JSON数组价格变动
    free_changes    TEXT,                                 -- JSON数组免费政策变更
    top_recommendations TEXT,                            -- JSON对象场景推荐
    cost_alerts     TEXT,                                 -- JSON数组成本告警
    html_content    TEXT,                                 -- 完整HTML报告内容
    summary_md      TEXT,                                 -- Markdown摘要
    status          TEXT NOT NULL DEFAULT 'generated',    -- generated / failed / partial
    generated_at    TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    error_message   TEXT
);

CREATE INDEX idx_report_date ON daily_report(report_date);
CREATE INDEX idx_report_status ON daily_report(status);

3.8 user_subscription用户订阅

CREATE TABLE user_subscription (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             TEXT NOT NULL,                    -- 统一用户ID
    email               TEXT,
    phone               TEXT,
    subscription_tier   TEXT NOT NULL DEFAULT 'free',     -- free / pro / team / enterprise
    subscription_start  DATE,
    subscription_end    DATE,
    notify_channels     TEXT,                             -- JSON: ["feishu","email","dingtalk"]
    feishu_webhook      TEXT,
    dingtalk_webhook    TEXT,
    email_webhook       TEXT,
    model_watchlist     TEXT,                             -- JSON数组关注模型
    operator_watchlist  TEXT,                             -- JSON数组关注平台
    price_alert_threshold REAL DEFAULT 10.0,             -- 告警阈值(%
    monthly_token_limit INTEGER,                          -- 月度Token限制
    monthly_token_used  INTEGER DEFAULT 0,
    stripe_customer_id  TEXT,
    created_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(email)
);

CREATE INDEX idx_sub_user ON user_subscription(user_id);
CREATE INDEX idx_sub_tier ON user_subscription(subscription_tier);

四、API 设计

4.1 内部采集 APICollector → Server

POST /api/v1/collect/push

采集器推送采集结果Phase 2 分布式采集节点使用)

Request:

{
  "batch": [
    {
      "provider_name": "OpenAI",
      "model_name": "GPT-4o",
      "version": "2025-01",
      "operator_name": "OpenRouter",
      "region": "GLOBAL",
      "currency": "USD",
      "input_price": 2.50,
      "output_price": 10.0,
      "context_length": 128000,
      "capabilities": ["vision", "function_calling", "json_mode"],
      "free_tier": null,
      "source_url": "https://openrouter.ai/api/v1/models"
    }
  ],
  "collected_at": "2026-05-04T08:00:00+08:00"
}

Response:

{
  "status": "ok",
  "inserted": 365,
  "updated": 12,
  "errors": 0
}

4.2 对外 REST API

GET /api/v1/models

查询模型列表

Query Parameters: | 参数 | 类型 | 默认值 | 说明 |

| provider | string | — | 模型商名称过滤 | | modality | string | — | text/vision/audio/video/code | | min_context | int | — | 最小上下文长度 | | max_input_price | float | — | 最大输入价格(/MTok | | has_free | bool | false | 仅显示有免费额的模型 | | search | string | — | 关键词搜索(模型名/capabilities | | sort | string | input_price | 排序字段 | | order | string | asc | asc/desc | | page | int | 1 | 页码 | | page_size | int | 20 | 每页数量max 100 |

Response:

{
  "total": 523,
  "page": 1,
  "page_size": 20,
  "models": [
    {
      "id": 42,
      "name": "DeepSeek V4-Flash",
      "provider": "DeepSeek",
      "provider_cn": "深度求索",
      "modality": "text",
      "context_length": 1048576,
      "capabilities": ["function_calling", "json_mode"],
      "status": "active",
      "lowest_price": {
        "operator": "硅基流动",
        "currency": "CNY",
        "input": 0.14,
        "output": 0.028,
        "region": "CN"
      }
    }
  ]
}

GET /api/v1/models/{id}

查询单个模型详情

Response:

{
  "id": 42,
  "name": "DeepSeek V4-Flash",
  "provider": {
    "id": 5,
    "name": "DeepSeek",
    "country": "CN"
  },
  "version": "V4-Flash",
  "modality": "text",
  "context_length": 1048576,
  "capabilities": ["function_calling", "json_mode"],
  "release_date": "2026-04-15",
  "status": "active",
  "elo_score": 1382.5,
  "pricing": [
    {
      "operator": "硅基流动",
      "region": "CN",
      "currency": "CNY",
      "input": 0.14,
      "output": 0.028,
      "source_url": "https://siliconflow.cn"
    },
    {
      "operator": "OpenRouter",
      "region": "GLOBAL",
      "currency": "USD",
      "input": 0.02,
      "output": 0.004
    }
  ],
  "free_tier": {
    "quota_type": "monthly",
    "quota_amount": 5000000,
    "quota_unit": "tokens",
    "requires_credit_card": false
  }
}

GET /api/v1/cost

成本计算器

Query Parameters: | 参数 | 类型 | 必填 | 说明 |

| input_tokens | int | 是 | 输入 Token 数 | | output_tokens | int | 否 | 输出 Token 数(默认=input_tokens×0.3 | | modality | string | 否 | 模态过滤 | | region | string | 否 | 区域CN/US/GLOBAL | | currency | string | CNY | 显示货币 | | top_n | int | 10 | 返回前N个最低价 |

Response:

{
  "input_tokens": 1000000,
  "output_tokens": 300000,
  "currency": "CNY",
  "results": [
    {
      "rank": 1,
      "model": "DeepSeek V4-Flash",
      "provider": "DeepSeek",
      "operator": "硅基流动",
      "input_cost": 0.14,
      "output_cost": 0.0084,
      "total_cost": 0.1484,
      "total_cost_usd": 0.020
    },
    {
      "rank": 2,
      "model": "Kimi K2.5",
      "provider": "Moonshot",
      "operator": "硅基流动",
      "input_cost": 0.23,
      "output_cost": 0.021,
      "total_cost": 0.251,
      "total_cost_usd": 0.034
    }
  ]
}

GET /api/v1/recommend

模型推荐

Query Parameters: | 参数 | 类型 | 必填 | 说明 |

| use_case | string | 是 | 场景coding/writing/reasoning/free/vision | | min_context | int | — | 最小上下文需求 | | budget | float | — | 预算上限(/MTok input | | region | string | CN | 区域偏好 | | limit | int | 5 | 返回数量 |

Response:

{
  "use_case": "coding",
  "recommendations": [
    {
      "rank": 1,
      "model": "Kimi K2.6",
      "provider": "Moonshot",
      "reason": "SWE-Bench Pro 超越 GPT-5.4,编码能力最强",
      "input_price": 0.95,
      "currency": "CNY",
      "free_option": null
    },
    {
      "rank": 2,
      "model": "GLM-5.1",
      "provider": "智谱",
      "reason": "编码能力接近 Opus 4.6,性价比高",
      "input_price": 1.40,
      "currency": "CNY",
      "free_option": null
    }
  ]
}

GET /api/v1/reports

每日报告列表

Query Parameters: | 参数 | 类型 | 默认值 | 说明 |

| from | date | 30天前 | 开始日期 | | to | date | 今天 | 结束日期 | | page | int | 1 | 页码 |

Response:

{
  "total": 30,
  "reports": [
    {
      "id": 30,
      "report_date": "2026-05-04",
      "status": "generated",
      "summary": "新上线3个模型价格变动2项免费政策更新1项",
      "generated_at": "2026-05-04T08:00:45+08:00"
    }
  ]
}

GET /api/v1/reports/{date}

获取指定日期报告内容

Response:

{
  "id": 30,
  "report_date": "2026-05-04",
  "html_content": "<html>...</html>",
  "new_models": [
    {"name": "xAI Grok 4.1 Fast", "provider": "xAI", "input_price": 0.20, "currency": "USD"}
  ],
  "price_changes": [
    {
      "model": "Claude Opus 4.6",
      "operator": "Anthropic",
      "old_price": 15.0,
      "new_price": 5.0,
      "change_pct": -66.7,
      "currency": "USD"
    }
  ],
  "free_changes": [
    {
      "model": "Gemini 2.5 Pro",
      "operator": "Google",
      "change": "免费层下线,需付费使用"
    }
  ],
  "top_recommendations": {
    "coding": {"model": "Kimi K2.6", "provider": "Moonshot"},
    "writing": {"model": "GLM-5.1", "provider": "智谱"},
    "free": {"model": "DeepSeek R1", "provider": "DeepSeek"},
    "cheapest": {"model": "Step 3.5 Flash", "provider": "字节"}
  }
}

GET /api/v1/health

健康检查

Response:

{
  "status": "ok",
  "version": "1.0.0",
  "db_record_count": {
    "models": 523,
    "providers": 22,
    "operators": 31,
    "pricing_records": 1847
  },
  "last_collect_time": "2026-05-04T08:00:12+08:00",
  "last_report_time": "2026-05-04T08:00:45+08:00"
}

五、数据采集 Pipeline

5.1 OpenRouter 采集流程

┌─────────────────┐
│  每日 08:00     │
│  cron 触发      │
└────────┬────────┘
         │
         ▼
┌─────────────────────────────────────────────────┐
│  GET https://openrouter.ai/api/v1/models        │
│  Headers: Authorization: Bearer <OPENROUTER_KEY>│
└────────┬────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────┐
│  解析响应 JSON                                   │
│  字段映射:                                       │
│    id → model.name (如 "anthropic/claude-3.5-sonnet")│
│    name → display_name                         │
│    pricing.input * 1e6 → input_price_per_mtok  │
│    pricing.output * 1e6 → output_price_per_mtok│
│    context_length → context_length             │
│    supported_parameters → capabilities          │
│    opensource → modality (text/vision/etc)     │
└────────┬────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────┐
│  识别 provider_name (从 id 前缀提取)             │
│  示例: "anthropic/claude-3.5-sonnet" →         │
│        provider="Anthropic", model="Claude 3.5 Sonnet"│
└────────┬────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────┐
│  Upsert:                                        │
│  INSERT OR REPLACE INTO model_provider (...)   │
│  INSERT OR REPLACE INTO model (...)             │
│  INSERT OR REPLACE INTO region_pricing (...)    │
└────────┬────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────┐
│  检测价格变动:                                   │
│  SELECT old_price FROM pricing_history          │
│  WHERE model_id = x AND operator_id = y         │
│  IF new_price != old_price:                     │
│    INSERT INTO pricing_history (...)            │
│    IF abs(change_pct) > 5%: 标记为高亮变动      │
└─────────────────────────────────────────────────┘

5.2 国内厂商采集流程 — Phase 2

每个国内厂商独立采集器(collectors/ 目录),统一接口输出:

# collectors/base.py
class BaseCollector:
    def collect(self) -> List[ModelRecord]:
        """返回标准化采集记录"""
        raise NotImplementedError

    def get_schedule(self) -> str:
        """返回 cron 表达式,如 "0 8 * * *" """
        return "0 8 * * *"

    def get_timeout(self) -> int:
        """超时秒数"""
        return 60

    def get_retry(self) -> int:
        """重试次数"""
        return 3

采集器清单Phase 1

统一字段映射

每个采集器输出标准化 CollectedRecord:

@dataclass
class CollectedRecord:
    provider_name: str           # "DeepSeek"
    provider_name_cn: str        # "深度求索"
    model_name: str              # "V4-Flash"
    model_version: str           # "V4-Flash"
    modality: str                # "text"
    context_length: int          # 1048576
    capabilities: List[str]    # ["function_calling", "vision"]
    operator_name: str          # "硅基流动"
    operator_type: str          # "reseller"
    region: str                 # "CN" / "US" / "GLOBAL"
    currency: str               # "CNY" / "USD"
    input_price_per_mtok: float
    output_price_per_mtok: float
    free_tier: Optional[FreeTierRecord] = None
    source_url: str
    collected_at: datetime

统一 ProviderMapper 将各厂商原始名称映射到标准名称:

PROVIDER_NAME_MAP = {
    # DeepSeek
    "deepseek-ai/DeepSeek-V3": {"provider": "DeepSeek", "model": "V3.2", "version": "2026-03"},
    "deepseek-ai/DeepSeek-V4": {"provider": "DeepSeek", "model": "V4", "version": "2026-04"},
    "deepseek-ai/DeepSeek-R1": {"provider": "DeepSeek", "model": "R1", "version": "2026-01"},
    # 阿里
    "qwen/Qwen3-VL-32B": {"provider": "阿里云", "model": "Qwen3-VL-32B", "version": "2026-03"},
    "qwen/Qwen3-VL-8B": {"provider": "阿里云", "model": "Qwen3-VL-8B", "version": "2026-03"},
    # Moonshot
    "moonshotai/Kimi-K2.6": {"provider": "Moonshot", "model": "K2.6", "version": "2026-04"},
    "moonshotai/Kimi-K2.5": {"provider": "Moonshot", "model": "K2.5", "version": "2026-03"},
    # 智谱
    "zhipuai/GLM-5.1": {"provider": "智谱", "model": "GLM-5.1", "version": "2026-03"},
    "zhipuai/GLM-4.7": {"provider": "智谱", "model": "GLM-4.7", "version": "2025-12"},
    # ... 其他厂商
}

5.3 每日调度设计

调度策略:系统 cron 统一调度,无外部消息队列依赖。

# /etc/crontab

# 每日 08:00 触发全量采集 + 报告生成
0 8 * * * root /opt/llm-hub/scripts/run_daily.sh >> /var/log/llm-hub/daily.log 2>&1

# 每日 09:00 触发数据备份
0 9 * * * root /opt/llm-hub/scripts/backup.sh >> /var/log/llm-hub/backup.log 2>&1
#!/bin/bash
# run_daily.sh

set -e

LOG_FILE="/var/log/llm-hub/daily.log"
echo "[$(date)] 开始每日采集任务" >> $LOG_FILE

# 1. 采集 OpenRouter海外模型优先级最高
cd /opt/llm-hub
python -m collectors.openrouter >> $LOG_FILE 2>&1

# 2. Phase 2 才并行采集国内厂商DeepSeek/阿里/Kimi/智谱等)

echo "[$(date)] 采集完成,开始生成报告" >> $LOG_FILE

# 3. 生成每日报告
python -m services.report_generator >> $LOG_FILE 2>&1

# 4. Phase 2 才检测价格变动并告警
echo "[$(date)] 每日任务完成" >> $LOG_FILE

5.4 失败重试 + 告警机制

# services/retry_handler.py

import time
import loguru
from functools import wraps
from typing import Callable, Any

logger = loguru.logger

def retry(max_attempts: int = 3, delay: int = 5, backoff: float = 2.0):
    """指数退避重试装饰器"""
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            attempt = 0
            while attempt < max_attempts:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    attempt += 1
                    wait = delay * (backoff ** (attempt - 1))
                    logger.warning(
                        f"Attempt {attempt}/{max_attempts} failed for {func.__name__}: {e}. "
                        f"Retrying in {wait}s..."
                    )
                    if attempt >= max_attempts:
                        logger.error(f"All {max_attempts} attempts failed for {func.__name__}")
                        raise
                    time.sleep(wait)
        return wrapper
    return decorator


# 采集器调用示例
@retry(max_attempts=3, delay=10, backoff=2.0)
def collect_with_retry(collector_name: str):
    collector = get_collector(collector_name)
    records = collector.collect()
    save_to_db(records)
    logger.info(f"{collector_name}: collected {len(records)} records")


# 告警触发逻辑
def check_and_alert_price_change(model_id: int, operator_id: int, new_price: float):
    old_price = get_last_price(model_id, operator_id)
    if old_price is None:
        return  # 首 次录入,不告警

    change_pct = (new_price - old_price) / old_price * 100

    if abs(change_pct) > 10:
        alert_msg = (
            f"⚠️ 价格变动告警\n"
            f"模型: {get_model_name(model_id)}\n"
            f"平台: {get_operator_name(operator_id)}\n"
            f"原价: {old_price}\n"
            f"新价: {new_price}\n"
            f"变动: {change_pct:+.1f}%"
        )
        send_dingtalk_alert(alert_msg)
        send_feishu_alert(alert_msg)
        logger.warning(alert_msg)

告警规则:

| 条件 | 动作 |

| 单个采集器失败 | 记录日志,保留旧数据,发送低优先级告警 | | 连续 3 天同一采集器失败 | 发送高优先级告警(钉钉/飞书) | | 价格变动 > 10% | 立即触发告警 | | 价格变动 > 20% | 立即触发告警 + 暂停该平台数据(人工确认) | | 报告生成失败 | 发送告警,保留前一天报告 | | 数据库写入失败 | 立即告警,回滚事务 |


六、前端架构

6.1 技术栈

| 组件 | 选型 | 理由 |

| 页面框架 | 纯 HTML5 + Bootstrap 5 | 无需 Node.js 构建CDN 托管,零运维 | | 图表库 | ECharts 5 | 免费,功能全面,支持中文,体积小(~1MB | | 图标 | Bootstrap Icons | 与 Bootstrap 5 原生集成 | | 搜索 | 前端 Fuse.js | 轻量模糊搜索,< 100KB无需服务端 | | 布局 | Bootstrap 5 响应式网格 | 移动端适配 | | 构建 | 无(纯静态文件) | Phase 2才引入 Nginx静态 CDN 托管 |

6.2 页面清单

| 页面 | 路径 | 功能说明 |

| 首页 / 报告列表 | / | 展示最新每日报告入口,显示近期报告摘要 | | 报告详情 | /reports/{date}.html | 单日报告完整内容(新模型/价格变动/推荐) | | 模型浏览器 | /explorer.html | 组合筛选 + 卡片/表格视图 + 搜索 | | 模型详情 | /model/{id}.html | 模型完整信息 + 全平台定价对比 | Phase 2|Phase 2 Phase 2Phase 2Phase 2Phase 2Phase 2成Phase 2本Phase 2计Phase 2算Phase 2器Phase 2Phase 2Phase 2Phase 2Phase 2 Phase 2|Phase 2 Phase 2Phase 2/Phase 2cPhase 2aPhase 2lPhase 2cPhase 2uPhase 2lPhase 2aPhase 2tPhase 2oPhase 2rPhase 2.Phase 2hPhase 2tPhase 2mPhase 2lPhase 2Phase 2 Phase 2|Phase 2 Phase 2TPhase 2oPhase 2kPhase 2ePhase 2nPhase 2 Phase 2用Phase 2量Phase 2 Phase 2→Phase 2 Phase 2多Phase 2平Phase 2台Phase 2成Phase 2本Phase 2对Phase 2比Phase 2排Phase 2行Phase 2 Phase 2|Phase 2 Phase 2Phase 2|Phase 2 Phase 2Phase 2Phase 2Phase 2Phase 2趋Phase 2势Phase 2图Phase 2Phase 2Phase 2Phase 2Phase 2 Phase 2|Phase 2 Phase 2Phase 2/Phase 2tPhase 2rPhase 2ePhase 2nPhase 2dPhase 2sPhase 2.Phase 2hPhase 2tPhase 2mPhase 2lPhase 2Phase 2 Phase 2|Phase 2 Phase 2价Phase 2格Phase 2/Phase 2模Phase 2型Phase 2能Phase 2力Phase 2历Phase 2史Phase 2趋Phase 2势Phase 2Phase 2EPhase 2CPhase 2hPhase 2aPhase 2rPhase 2tPhase 2sPhase 2Phase 2 Phase 2|Phase 2 Phase 2| 关于我们 | /about.html | 项目介绍、数据来源说明 |

6.3 与后端的数据交互

模式:纯前端 SPASingle Page Application通过 Fetch API 调用后端 REST API。

前端静态文件Phase 2才 Nginx 托管)
    │
    ├── GET /api/v1/models          → Flask API 返回 JSON
    ├── GET /api/v1/models/{id}    → 模型详情 JSON
    ├── GET /api/v1/cost           → 成本计算 JSON
    ├── GET /api/v1/recommend      → 推荐结果 JSON
    └── GET /api/v1/reports/{date} → 报告 JSON

前端数据层dataService.js

// 统一 API 调用封装
const API_BASE = '/api/v1';

async function apiGet(endpoint, params = {}) {
    const url = new URL(`${API_BASE}${endpoint}`, window.location.origin);
    Object.entries(params).forEach(([k, v]) => v != null && url.searchParams.set(k, v));
    const resp = await fetch(url);
    if (!resp.ok) throw new Error(`API error: ${resp.status}`);
    return resp.json();
}

// 主要接口封装
const api = {
    models: {
        list: (params) => apiGet('/models', params),
        detail: (id) => apiGet(`/models/${id}`)
    },
    cost: {
        calculate: (params) => apiGet('/cost', params)
    },
    recommend: (params) => apiGet('/recommend', params),
    reports: {
        list: (params) => apiGet('/reports', params),
        get: (date) => apiGet(`/reports/${date}`)
    }
};

6.4 模型浏览器页面结构

<!-- explorer.html -->

<!-- 筛选栏 -->
<div class="row mb-3">
    <div class="col-md-2">
        <select id="filter-provider" class="form-select">
            <option value="">全部厂商</option>
            <option value="DeepSeek">DeepSeek</option>
            <option value="阿里云">阿里云</option>
            <!-- ... -->
        </select>
    </div>
    <div class="col-md-2">
        <select id="filter-modality" class="form-select">
            <option value="">全部模态</option>
            <option value="text">文字</option>
            <option value="vision">视觉</option>
            <option value="code">代码</option>
        </select>
    </div>
    <div class="col-md-2">
        <input type="number" id="filter-max-price" class="form-control"
               placeholder="最大输入价(¥/MT)">
    </div>
    <div class="col-md-3">
        <input type="text" id="search-keyword" class="form-control"
               placeholder="搜索模型名称...">
    </div>
    <div class="col-md-3">
        <div class="btn-group" role="group">
            <button class="btn btn-outline-primary active" data-view="card">卡片</button>
            <button class="btn btn-outline-primary" data-view="table">表格</button>
        </div>
    </div>
</div>

<!-- 结果区域 -->
<div id="results" class="row">
    <!-- 动态渲染卡片或表格 -->
</div>

<!-- 分页 -->
<nav><ul class="pagination" id="pagination"></ul></nav>

七、部署架构

7.1 Docker 配置

# docker-compose.yml
version: '3.8'

services:
  # --- Phase 1 核心服务 ---

  collector:
    build:
      context: .
      dockerfile: Dockerfile.collector
    volumes:
      - ./data:/opt/llm-hub/data        # PostgreSQL 数据持久化
      - ./logs:/var/log/llm-hub        # 日志持久化
      - ./reports:/opt/llm-hub/reports # 报告输出
    env_file:
      - .env
    restart: unless-stopped
    networks:
      - llm-hub-net

  api:
    build:
      context: .
      dockerfile: Dockerfile.api
    ports:
      - "5000:5000"
    volumes:
      - ./data:/opt/llm-hub/data
      - ./reports:/opt/llm-hub/reports
    env_file:
      - .env
    restart: unless-stopped
    depends_on:
      - collector
    networks:
      - llm-hub-net

  # --- Phase 2 才引入 Nginx内网访问 + 静态文件服务)---

networks:
  llm-hub-net:
    driver: bridge

7.2 内网部署要求

部署前提

  • 一台可访问外网的服务器(境外更好,便于访问 OpenRouter
  • 域名(可选,用于 HTTPS + 钉钉/飞书 Webhook 回调)
  • Docker + Docker Compose

网络访问需求

| 目的地 | 用途 | 协议 |

| openrouter.ai | 采集海外模型数据 | HTTPS | | api.deepseek.com | 采集 DeepSeek 定价 | HTTPS | | dashscope.aliyuncs.com | 采集阿里云定价 | HTTPS | | api.moonshot.cn | 采集 Kimi 定价 | HTTPS | | open.bigmodel.cn | 采集智谱定价 | HTTPS | | api.siliconflow.cn | 采集硅基流动定价 | HTTPS | | oapi.dingtalk.com | Phase 2 钉钉告警 | HTTPS | | open.feishu.cn | Phase 2 飞书告警 | HTTPS | | 无需访问 | 国内云厂商定价页(如阿里云控制台) | — |

7.3 环境变量清单

# .env 文件Phase 1 最小配置)

# === 数据库 ===
DATABASE_URL=postgresql://user:pass@localhost:5432/llmhub

# === OpenRouter ===
OPENROUTER_API_KEY=sk-or-v1-xxxxx

# === 国内厂商 API Keys ===
DEEPSEEK_API_KEY=sk-xxxxx
DASHSCOPE_API_KEY=sk-xxxxx
MOONSHOT_API_KEY=sk-xxxxx
ZHIPU_API_KEY=xxxxx
MINIMAX_API_KEY=xxxxx
VOLCENGINE_API_KEY=xxxxx
VOLCENGINE_SECRET_KEY=xxxxx
TENCENT_SECRET_ID=xxxxx
TENCENT_SECRET_KEY=xxxxx
BAIDU_QIANFAN_API_KEY=xxxxx
BAIDU_QIANFAN_SECRET_KEY=xxxxx
SILICONFLOW_API_KEY=sk-xxxxx

# === 告警配置Phase 2 才启用)===
# DINGTALK_WEBHOOK=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
# FEISHU_WEBHOOK=https://open.feishu.cn/open-apis/bot/v2/hook/xxxxx
ALERT_THRESHOLD_PCT=10
ALERT_THRESHOLD_CRITICAL_PCT=20

# === 邮件配置(可选)===
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@example.com
SMTP_PASS=xxxxx

# === 备份配置 ===
BACKUP_OSS_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com
BACKUP_OSS_BUCKET=llm-hub-backup
BACKUP_OSS_KEY=xxxxx
BACKUP_OSS_SECRET=xxxxx

# === 系统 ===
LOG_LEVEL=INFO
TZ=Asia/Shanghai

7.4 Nginx 配置

# nginx.conf
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    keepalive_timeout 65;

    # --- 静态文件服务(前端)---
    server {
        listen 80;
        server_name _;

        root /usr/share/nginx/html;
        index index.html;

        # 前端静态页面
        location / {
            try_files $uri $uri/ /index.html;
        }

        # 每日报告 HTML
        location /reports/ {
            alias /usr/share/nginx/html/reports/;
            expires 7d;
            add_header Cache-Control "public, immutable";
        }

        # --- API 反向代理 ---
        location /api/ {
            proxy_pass http://api:5000/api/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_read_timeout 60s;
        }

        # 健康检查(无需认证)
        location /health {
            proxy_pass http://api:5000/api/v1/health;
            proxy_set_header Host $host;
        }
    }
}

八、Phase 1 技术路线3个月

8.1 Sprint 划分

| Sprint | 周期 | 目标 | 交付物 |

| Sprint 0 | Week 1 | 技术方案确认 + 环境搭建 | TECHNICAL_DESIGN.md 终稿;开发环境就绪 | | Sprint 1 | Week 2-3 | OpenRouter 采集器 + 数据库 Schema | 371 海外模型入库;数据库 DDL 可执行 | | Sprint 2 | Week 4-5 | PostgreSQL migration + 日报生成器 | 三张表落地Markdown 报告输出到 reports/daily/ | | Sprint 2 | Week 4-5 | 每日报告生成 + Explorer 页面 | Markdown 报告生成Explorer 页面上线Markdown 报告可输出到 reports/daily/ | | Sprint 4 | Week 8-9 | 模型浏览器 + 搜索筛选 | /explorer.html 上线;卡片/表格视图 | | Sprint 5 | Week 10-11 | Explorer 页面完善 + Dashboard 占位图 | 表格/筛选排序;价格趋势占位图 | | Sprint 6 | Week 12 | 收尾 + 部署 + 验证脚本 | Docker Compose 部署文档;验证脚本;备份策略 |

8.2 Sprint 1 详细任务OpenRouter 采集器)

Sprint 1 目标:从 OpenRouter API 采集 371 模型,建立基础数据库

任务分解:
├── T1.1 数据库 Schema 部署
│   ├── [ ] 创建所有 DDL 表model_provider/model/operator/region_pricing/...
│   ├── [ ] 编写 PostgreSQL Schema 部署脚本deploy.sh
│   └── [ ] 验证:查询所有表,返回空表,数量正确
│
├── T1.2 OpenRouter 采集器实现
│   ├── [ ] 实现 collectors/openrouter.py
│   │   ├── 调用 GET https://openrouter.ai/api/v1/models
│   │   ├── 解析 id/name/pricing/context_length/capabilities
│   │   ├── 从 id 前缀提取 provideranthropic/claude-3.5-sonnet → Anthropic
│   │   ├── 处理免费模型id 包含 :free 后缀)
│   │   └── 错误处理401/429/500
│   ├── [ ] 实现 base collector 抽象类
│   ├── [ ] 实现数据清洗逻辑(去除异常价格、统一单位)
│   └── [ ] 验证371 模型全部入库,无重复,数据正确
│
├── T1.3 数据映射 + Provider 标准化
│   ├── [ ] 建立 PROVIDER_NAME_MAPOpenRouter id → 标准厂商名)
│   ├── [ ] 验证:所有 provider 名称统一(无别名)
│   └── [ ] 补充 provider logo_url / description
│
├── T1.4 初始数据导入
│   ├── [ ] 运行 OpenRouter 采集器,导入 371 模型
│   ├── [ ] 质量检查:随机抽 10 条数据,验证价格/上下文长度
│   └── [ ] 导出数据字典文档
│
└── T1.5 采集脚本 + cron 配置
    ├── [ ] 编写 scripts/run_openrouter_collect.sh
    ├── [ ] 配置 crontab08:00 每日执行)
    ├── [ ] 编写失败重试逻辑
    └── [ ] 验证:手动运行脚本成功,数据入库

8.3 Phase 1 关键技术决策记录

| 决策 | 选型 | 记录时间 | 理由 |

| Phase 1 数据库用 PostgreSQL | 确认 | Sprint 0 | 与立交桥技术栈统一;支持 JSONB/数组类型;数据库内队列 | | 数据采集用 Python requests | 确认 | Sprint 0 | 生态成熟,内存占用低 | | 报告生成用 Jinja2 模板 | 确认 | Sprint 0 | 模板复用,减少前端维护成本 | | 告警用 Webhook 直推 | 确认 | Sprint 0 | 无需消息队列,降低复杂度 | | OpenRouter ELO 数据暂不采集 | ⚠️ 延期 | Sprint 1 | ELO API 可能收费Phase 1 跳过 | | 国内厂商优先级DeepSeek > 阿里 > Kimi > 智谱 > MiniMax > 火山 > 腾讯 > 百度 | 确认 | Sprint 2 | 按市场热度排序 |

8.4 质量检查清单Phase 1 上线前)

功能验证

  • OpenRouter 371 模型全部入库,覆盖率 100%

(Phase 2 才采集国内厂商)

  • 每日 08:00 cron 触发采集,报告自动生成
  • 报告内容包含:新模型、价格变动(>5% 高亮)、场景推荐
  • /explorer.html 搜索响应 < 500ms

(Phase 2 才实现告警推送)

数据质量验证

  • 每条数据有 source_url 来源标注
  • 置信度分级标注official / inferred / expired
  • 价格单位统一为 ¥/MTok 或 $/MTok
  • 同模型多源价格差异 > 20% 时标注"待核实"
  • 采集失败写入日志,保留旧数据

部署验证

  • docker-compose up 可正常启动所有服务
  • PostgreSQL 数据库持久化到 data/ 目录
  • 报告 HTML 生成到 reports/ 目录

Phase 2 才引入 Nginx

  • API /api/v1/health 返回 200
  • 备份脚本每日推送至 OSS 成功

性能验证

  • 371 模型采集完成 < 5 分钟
  • 报告生成 < 30 秒
  • API 查询响应 < 500ms/models, 20 条)
  • 并发 10 个采集器同时运行,内存 < 2GB

附录:目录结构

llm-intelligence/
├── TECHNICAL_DESIGN.md          # 本文档
├── PRD.md                        # 产品需求文档
├── FEATURE_LIST.md               # 功能清单
├── BUSINESS_MODEL.md             # 商业模式
├── MARKET_ANALYSIS.md            # 市场调研
│
├── Dockerfile.collector          # 采集器镜像
├── Dockerfile.api                # API 服务镜像
├── docker-compose.yml            # 容器编排
├── .env.example                  # 环境变量模板
├── nginx.conf                     # Nginx 配置
│
├── collectors/                    # 数据采集器
│   ├── __init__.py
│   ├── base.py                  # 采集器基类
│   ├── openrouter.py            # OpenRouter 采集器
│   ├── deepseek.py              # DeepSeek 采集器
│   ├── aliyun.py                # 阿里云 DashScope 采集器
│   ├── kimi.py                  # Moonshot/Kimi 采集器
│   ├── zhipu.py                 # 智谱 BigModel 采集器
│   ├── minimax.py               # MiniMax 采集器
│   ├── volcengine.py            # 火山引擎采集器
│   ├── tencent.py               # 腾讯云采集器
│   ├── baidu.py                 # 百度 Qianfan 采集器
│   └── siliconflow.py           # 硅基流动采集器
│
├── services/                     # 服务层
│   ├── __init__.py
│   ├── database.py               # SQLAlchemy 数据库连接
│   ├── models.py                # ORM 模型定义
│   ├── report_generator.py       # 每日报告生成器
│   ├── price_alert.py            # 价格告警服务
│   ├── notifier.py               # 钉钉/飞书推送
│   └── recommendation.py         # 模型推荐引擎
│
├── api/                          # REST API
│   ├── __init__.py
│   ├── app.py                    # Flask 应用入口
│   ├── routes/
│   │   ├── __init__.py
│   │   ├── models.py             # /models 路由
│   │   ├── cost.py               # /cost 路由
│   │   ├── recommend.py          # /recommend 路由
│   │   └── reports.py            # /reports 路由
│   └── schemas.py                # Pydantic 请求/响应模型
│
├── static/                       # 前端静态文件
│   ├── index.html                # 首页/报告列表
│   ├── explorer.html              # 模型浏览器
│   ├── calculator.html            # 成本计算器
│   ├── trends.html                # 趋势分析
│   ├── css/
│   │   └── style.css
│   └── js/
│       ├── dataService.js         # API 调用封装
│       ├── explorer.js            # 模型浏览器逻辑
│       ├── calculator.js           # 计算器逻辑
│       └── charts.js               # ECharts 封装
│
├── templates/                     # Jinja2 报告模板
│   └── report.html               # 每日报告 HTML 模板
│
├── reports/                       # 生成的报告 HTML 输出
│   └── 2026-05-04.html
│
├── scripts/                       # 运维脚本
│   ├── run_daily.sh               # 每日采集 + 报告脚本
│   ├── backup.sh                  # 数据库备份脚本
│   ├── migrate.sh                  # PostgreSQL Schema 部署脚本
│   └── init_db.py                  # 数据库初始化脚本
│
├── tests/                         # 单元测试
│   ├── test_collectors.py
│   ├── test_api.py
│   └── test_report.py
│
├── data/                          # PostgreSQL 数据目录(运行时生成)
│   └── llm_intelligence.db
│
└── logs/                          # 日志文件(运行时生成)
    ├── collector.log
    ├── api.log
    └── backup.log

文档状态: 设计修订完成

修订内容2026-05-06

  • SQLite → PostgreSQL与立交桥技术栈统一
  • 移除第三方消息组件依赖,改用 PostgreSQL 数据库内队列
  • 技术架构简洁化

下一步行动:

  • 技术负责人评审架构设计
  • 确认数据库选型(已确定为 PostgreSQL
  • 确认 OpenRouter API Key 获取方式
  • Sprint 1 任务分配

文档编制宰相AI 辅助) 基于 PRD.mdv0.3、FEATURE_LIST.mdv1.0、BUSINESS_MODEL.mdv1.0、MARKET_ANALYSIS.mdv3.0