- Rename package directory and all references from sage_datamark to sage_datamart - Add 3 ETL cron dspy files (sync/aggregate/provider_cost) for scheduled data pipelines - Add 5 stat UI files (total_users/fail_calls/success_rate/avg_ttft/total_calls) - Register j2_ template functions in init.py for UI rendering - Move j2_avg_ttft SQL to dashboards.py for DRY - Clean unused imports (getConfig/DBPools/exception) - Update git remote to sage_datamart.git
149 lines
5.3 KiB
Markdown
149 lines
5.3 KiB
Markdown
# Sage DataMart — 数据集市模块
|
||
|
||
模型性能监控、供应商性价比分析、多维度数据下钻。
|
||
|
||
## 数据来源
|
||
|
||
| 数据源 | 模块 | 表 | 说明 |
|
||
|--------|------|-----|------|
|
||
| 模型调用记录 | llmage | `llmusage` | 每次 API 调用详细日志 |
|
||
| 模型定义 | llmage | `llm` | 模型名、catelog、供应商、owner |
|
||
| 定价 | pricing | `pricing_program_timing` | 各模型供应商定价数据 |
|
||
| 供应链关系 | supplychain | `distribution_agreements` | 分销商(reseller) → 二级分销商(sub_reseller) |
|
||
| 供应链关系 | supplychain | `product_org_auth` | 产品授权 org 关联链 |
|
||
| 组织架构 | rbac | `organization` | org 基础信息(名称、类型、parentid) |
|
||
|
||
### 维度层级(从供应链模块获取)
|
||
|
||
```
|
||
分销商(distributor, org_type='reseller')
|
||
└─ 供应商/二级分销商(sub_reseller, org_type='sub_reseller')
|
||
└─ 客户(customer, org_type='customer')
|
||
```
|
||
|
||
- 分销商与二级分销商关系:`distribution_agreements`(reseller_id → sub_reseller_id)
|
||
- 二级分销商与客户关系:`organization.parentid` 或 `product_org_auth` 授权链
|
||
- **注意**: 不能用 `organization.parentid` 递归到顶来获取分销商,因为 parentid 是组织管理层级,不代表供应链业务关系。分销商归属必须从 `supplychain` 模块获取。
|
||
|
||
## 集市表
|
||
|
||
| 表名 | 说明 | 粒度 |
|
||
|------|------|------|
|
||
| `dm_model_call_fact` | 模型调用事实表 | 每次调用 |
|
||
| `dm_model_perf_daily` | 模型性能天汇总 | 天/模型/组织 |
|
||
| `dm_provider_cost_daily` | 供应商性价比天汇总 | 天/模型/供应商 |
|
||
|
||
## 取数频率
|
||
|
||
| ETL 任务 | 频率 | 说明 |
|
||
|----------|------|------|
|
||
| `sync_call_fact` | 每 5 分钟 | 增量同步 llmusage → dm_model_call_fact |
|
||
| `aggregate_daily_perf` | 每小时 | 聚合当天 dm_model_call_fact → dm_model_perf_daily |
|
||
| `aggregate_provider_cost` | 每天 1 次 | 聚合同模型供应商性价比 → dm_provider_cost_daily |
|
||
|
||
## 业务指标
|
||
|
||
### 性能指标
|
||
- **TTFT** (Time To First Token): 首 Token 响应时间,来源 `llmusage.responsed_seconds`
|
||
- **TTOT** (Time To Output Total): 完成时间,来源 `llmusage.finish_seconds`
|
||
- **成功率**: `status='SUCCEEDED'` / 总调用数
|
||
- **失败率**: `status='FAILED'` / 总调用数
|
||
- **并发度**: 同一时间窗口内活跃请求数
|
||
|
||
### 性价比
|
||
- **单价**: `total_amount / total_tokens`,按模型+供应商维度对比
|
||
- **TTFT × 单价**:综合性价比排序
|
||
|
||
### 多维度
|
||
|
||
- **分销商(reseller)** → **二级分销商(sub_reseller)** → **客户(customer)**
|
||
- 层级关系来自 `supplychain` 模块:`distribution_agreements` + `product_org_auth`
|
||
- 每层独立统计:用量、模型分布、性能、费用
|
||
|
||
## Dashboard 看板
|
||
|
||
### 统一数据看板 `/sage_datamart/index.ui`
|
||
- 6 个统计卡片:今日调用、今日金额、成功率、失败数、平均TTFT、总用户
|
||
- 模型性能排行 + 供应商性价比对比(双栏)
|
||
- 热门模型 / 用户排行 / 供应商排行(三栏)
|
||
- 数据来源全部从集市表 `dm_model_call_fact` / `dm_model_perf_daily` / `dm_provider_cost_daily`
|
||
|
||
### 供应商性价比看板 `/sage_datamart/provider_roi.ui`
|
||
- 同模型不同供应商对比:单价(¥/token)、TTFT、调用次数、总费用
|
||
|
||
## API 接口
|
||
|
||
| 端点 | 说明 | 替代 dashboard_for_sage |
|
||
|------|------|------------------------|
|
||
| `/sage_datamart/api/stats.dspy` | 统计卡片 | get_today_usage/amount, active_users |
|
||
| `/sage_datamart/api/model_perf.dspy` | 模型性能 | - (新增) |
|
||
| `/sage_datamart/api/provider_roi.dspy` | 供应商性价比 | - (新增) |
|
||
| `/sage_datamart/api/top_models.dspy` | 热门模型排行 | get_top_models |
|
||
| `/sage_datamart/api/top_providers.dspy` | 供应商排行 | get_top_providers_combined |
|
||
| `/sage_datamart/api/top_users.dspy` | 用户排行 | get_top_users_combined |
|
||
| `/sage_datamart/api/customer_models.dspy` | 客户今日+当月用量 | get_customer_daily/monthly_models |
|
||
| `/sage_datamart/api/daily_trend.dspy` | 7天趋势 | - (新增) |
|
||
| `/sage_datamart/api/hourly_concurrency.dspy` | 每小时并发 | - (新增) |
|
||
|
||
### model_perf.dspy
|
||
```json
|
||
// 请求
|
||
{"date": "2026-07-17", "model": "qwen3-max"}
|
||
|
||
// 响应
|
||
[{
|
||
"model": "qwen3-max",
|
||
"avg_ttft_ms": 320.5,
|
||
"avg_ttot_ms": 2100.3,
|
||
"success_rate": 98.5,
|
||
"total_calls": 12340,
|
||
"success_calls": 12155,
|
||
"fail_calls": 185,
|
||
"total_amount": 246.80
|
||
}]
|
||
```
|
||
|
||
### provider_roi.dspy
|
||
```json
|
||
// 请求
|
||
{"model": "qwen3-max"}
|
||
|
||
// 响应
|
||
[{
|
||
"model": "qwen3-max",
|
||
"providerid": "aliyun",
|
||
"total_calls": 5000,
|
||
"total_tokens": 5000000,
|
||
"total_amount": 10.00,
|
||
"unit_price": 0.000002,
|
||
"avg_ttft_ms": 280.5
|
||
}]
|
||
```
|
||
|
||
## 部署
|
||
|
||
```bash
|
||
cd ~/sage/pkgs
|
||
git clone git@git.opencomputing.cn:yumoqing/sage_datamart.git
|
||
cd sage_datamart && pip install .
|
||
py3/bin/python scripts/load_path.py
|
||
|
||
# 添加 ETL cron 任务(在 Sage start.sh 或系统 cron)
|
||
# 每 5 分钟同步
|
||
*/5 * * * * cd ~/sage && py3/bin/python -c "
|
||
from sage_datamart.etl import run_etl_sync
|
||
from sqlor.dbpools import DBPools
|
||
from appPublic.jsonConfig import getConfig
|
||
import asyncio
|
||
config = getConfig('.')
|
||
db = DBPools(config.databases)
|
||
async def go():
|
||
env_dbname = ServerEnv().get_module_dbname('sage_datamart')
|
||
async with db.sqlorContext(env_dbname) as sor:
|
||
await run_etl_sync(sor)
|
||
asyncio.run(go())
|
||
"
|
||
|
||
# 重启 Sage,访问 /sage_datamart/index.ui
|
||
```
|