425 lines
13 KiB
Markdown
425 lines
13 KiB
Markdown
# 自定义 API 数据源与 LLM 映射系统 — 实施计划
|
||
|
||
**状态**:规划中
|
||
**创建日期**:2026-04-28
|
||
**核心原则**:LLM 辅助生成映射配置;生产采集使用确定性转换引擎
|
||
|
||
## 已确认决策
|
||
|
||
| 项目 | 决策 |
|
||
|-----|------|
|
||
| 自定义 API 的定位 | 作为内置数据源的补充入口,不直接等同于 Earth 新功能 |
|
||
| LLM 的职责 | 探索未知 API、分析样本 JSON、生成 mapping 草案 |
|
||
| 采集时是否调用 LLM | 不调用;采集链路必须确定性、可审计、可复现 |
|
||
| 自定义数据如何进入 Earth | 必须映射到已支持的目标 schema,或先进入通用数据沉淀 |
|
||
| 外部凭证放置位置 | Settings / 外部集成统一管理 provider token;DataSources 引用 provider profile |
|
||
| TimescaleDB | 放入 TODO;高频时序数据稳定后再评估迁移 |
|
||
|
||
---
|
||
|
||
## 一、背景与问题
|
||
|
||
当前系统已经有 `datasource_configs`,可以配置自定义数据源的 endpoint、auth、headers、config,也已经有部分 collector 会读取这些配置。但这只能解决“怎么请求数据”,还没有解决以下问题:
|
||
|
||
- API 返回 JSON 后,如何转换成系统已有领域模型。
|
||
- 自定义数据源是补充已有能力,还是全新数据沉淀。
|
||
- 转换规则由谁生成、谁校验、谁执行。
|
||
- 未知数据是否能自动在 Earth 上展示。
|
||
- 外部 token 是放在全局配置中心,还是放在每个 datasource 下。
|
||
|
||
专业做法是把“请求配置”“外部凭证”“目标 schema”“字段映射”“采集执行”拆开:
|
||
|
||
- Settings 管外部集成凭证,例如 AI Provider、BarentsWatch、未来付费 AIS API。
|
||
- DataSources 管具体数据源实例,例如 endpoint、调度频率、目标 schema、mapping 版本。
|
||
- LLM 只在配置阶段辅助生成 mapping,不进入生产采集链路。
|
||
- Earth 只消费明确 schema 的数据,不消费任意未知 JSON。
|
||
|
||
---
|
||
|
||
## 二、目标架构
|
||
|
||
### 2.1 自定义 API 数据源生命周期
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A[配置 endpoint/auth/request] --> B[抓取 sample JSON]
|
||
B --> C[选择目标 schema]
|
||
C --> D[LLM 生成 mapping 草案]
|
||
D --> E[确定性 mapping engine 预览]
|
||
E --> F[schema validation]
|
||
F --> G[保存 mapping version]
|
||
G --> H[scheduler 执行 mapped collector]
|
||
H --> I[写入目标表或 generic_records]
|
||
```
|
||
|
||
### 2.2 目标 schema 分层
|
||
|
||
| schema | 用途 | Earth 可视化 |
|
||
|-------|------|-------------|
|
||
| `vessel_ais` | 船只 AIS 位置、航速、航向、MMSI 等 | 进入船舶图层 |
|
||
| `geo_points` | 通用点位数据,包含经纬度、名称、类型、时间 | 进入通用 geo layer(TODO) |
|
||
| `news_events` | 新闻/事件类数据,带时间、地点、摘要、来源 | 复用新闻/事件链路 |
|
||
| `compute_centers` | 算力中心、机房、数据中心数据 | 复用算力中心图层 |
|
||
| `generic_records` | 未知结构化数据沉淀 | 不直接展示 |
|
||
|
||
v1 建议优先实现:
|
||
|
||
- `vessel_ais`
|
||
- `geo_points`
|
||
- `generic_records`
|
||
|
||
其他 schema 可先在 registry 中预留名称,但不承诺完整落库与可视化。
|
||
|
||
### 2.3 LLM 的边界
|
||
|
||
LLM 可以做:
|
||
|
||
- 根据 API 文档或 sample JSON 解释字段含义。
|
||
- 推荐目标 schema。
|
||
- 生成 mapping JSON 草案。
|
||
- 给出字段置信度和需要人工确认的字段。
|
||
- 帮用户发现分页、数组路径、时间字段、坐标字段。
|
||
|
||
LLM 不应该做:
|
||
|
||
- 在正式采集时参与每批数据转换。
|
||
- 生成并执行 Python/JavaScript 代码。
|
||
- 接触 API key、bearer token、basic auth password。
|
||
- 自动创建新的 Earth 图层或数据库表。
|
||
|
||
---
|
||
|
||
## 三、后端实施计划
|
||
|
||
### Phase 1 — Target Schema Registry
|
||
|
||
新增代码级 registry,统一描述系统支持的目标数据类型。
|
||
|
||
每个 target schema 至少包含:
|
||
|
||
- `key`:例如 `vessel_ais`。
|
||
- `label`:前端展示名称。
|
||
- `description`:适用场景。
|
||
- `fields`:字段名、类型、是否必填、说明、示例。
|
||
- `validator`:Pydantic 或等价校验器。
|
||
- `destination`:写入目标,例如 vessel 表、generic_records、future geo layer。
|
||
|
||
示例概念:
|
||
|
||
```json
|
||
{
|
||
"key": "vessel_ais",
|
||
"fields": [
|
||
{"name": "mmsi", "type": "integer", "required": true},
|
||
{"name": "lat", "type": "float", "required": true},
|
||
{"name": "lon", "type": "float", "required": true},
|
||
{"name": "sog", "type": "float", "required": false},
|
||
{"name": "cog", "type": "float", "required": false},
|
||
{"name": "received_at", "type": "datetime", "required": false}
|
||
]
|
||
}
|
||
```
|
||
|
||
### Phase 2 — Mapping Template Model
|
||
|
||
新增 mapping 配置持久化表,建议命名为 `datasource_mapping_templates`。
|
||
|
||
关键字段:
|
||
|
||
- `id`
|
||
- `datasource_config_id`
|
||
- `target_schema`
|
||
- `mapping_json`
|
||
- `sample_payload_hash`
|
||
- `validation_status`
|
||
- `version`
|
||
- `is_active`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
`mapping_json` 是声明式 DSL,不允许任意代码执行。
|
||
|
||
示例:
|
||
|
||
```json
|
||
{
|
||
"source": {
|
||
"items_path": "$.data.vessels[*]"
|
||
},
|
||
"fields": {
|
||
"mmsi": {"path": "$.mmsi", "type": "integer"},
|
||
"lat": {"path": "$.latitude", "type": "float"},
|
||
"lon": {"path": "$.longitude", "type": "float"},
|
||
"sog": {"path": "$.speedOverGround", "type": "float", "default": null},
|
||
"received_at": {"path": "$.timestamp", "type": "datetime"}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Phase 3 — Deterministic Mapping Engine
|
||
|
||
实现独立 mapping engine,输入 sample/raw payload 和 mapping JSON,输出目标 schema 记录。
|
||
|
||
v1 支持能力:
|
||
|
||
- JSONPath/JMESPath 风格路径提取。
|
||
- 数组展开。
|
||
- 默认值。
|
||
- 基础类型转换:string、integer、float、boolean、datetime。
|
||
- 坐标范围校验。
|
||
- 简单枚举映射。
|
||
- 错误收集:缺字段、类型转换失败、路径不存在。
|
||
|
||
明确不支持:
|
||
|
||
- 任意表达式执行。
|
||
- 用户提交脚本。
|
||
- LLM runtime 修复。
|
||
|
||
### Phase 4 — LLM Mapping Assistant API
|
||
|
||
新增配置阶段 API:
|
||
|
||
- `POST /api/v1/datasources/custom/sample`
|
||
- 按 datasource 请求配置抓取 sample JSON。
|
||
- `GET /api/v1/datasources/target-schemas`
|
||
- 返回可选目标 schema 和字段说明。
|
||
- `POST /api/v1/datasources/mappings/propose`
|
||
- 输入 sample JSON + target schema,调用 AI provider 生成 mapping 草案。
|
||
- `POST /api/v1/datasources/mappings/preview`
|
||
- 使用确定性 mapping engine 预览转换结果。
|
||
- `POST /api/v1/datasources/mappings`
|
||
- 保存 mapping 版本。
|
||
- `PUT /api/v1/datasources/mappings/{id}`
|
||
- 更新 mapping,生成新版本或覆盖草稿。
|
||
- `POST /api/v1/datasources/{id}/run-mapped`
|
||
- 手动触发一次 mapped collector。
|
||
|
||
安全要求:
|
||
|
||
- `propose` 请求发送给 LLM 前必须脱敏 sample。
|
||
- auth headers、token、password 不进入 prompt。
|
||
- LLM 返回结果必须再经过 mapping schema 校验。
|
||
|
||
### Phase 5 — Generic Mapped HTTP Collector
|
||
|
||
新增通用 collector:
|
||
|
||
- 读取 `DataSourceConfig` 请求配置。
|
||
- 读取 active mapping template。
|
||
- 拉取 API 数据。
|
||
- 使用 mapping engine 转换。
|
||
- 使用 target schema validator 校验。
|
||
- 调用 destination handler 写入目标表或 generic storage。
|
||
- 将失败记录写入错误日志或 dead-letter 结构。
|
||
|
||
对于 `generic_records`:
|
||
|
||
- 保存 datasource id。
|
||
- 保存 target schema。
|
||
- 保存 normalized JSON。
|
||
- 保存 raw payload 摘要或 raw reference。
|
||
- 保存采集时间、source timestamp、mapping version。
|
||
|
||
---
|
||
|
||
## 四、前端实施计划
|
||
|
||
### Phase 1 — Settings 外部集成
|
||
|
||
Settings 中保留统一外部集成配置:
|
||
|
||
- AI Provider:base URL、model、API key。
|
||
- BarentsWatch:client id/client secret 或 bearer token。
|
||
- 未来付费接口:AISHub、MarineTraffic、VesselFinder 等 provider profile。
|
||
|
||
DataSources 不直接管理全局 secret,只引用 provider profile。
|
||
|
||
### Phase 2 — DataSources 自定义源向导
|
||
|
||
自定义数据源配置改成向导或右侧 drawer:
|
||
|
||
1. Request
|
||
- endpoint
|
||
- method
|
||
- auth profile
|
||
- headers
|
||
- query/body config
|
||
- schedule
|
||
2. Sample
|
||
- 点击抓取 sample
|
||
- 展示 JSON tree
|
||
- 支持选择数组根路径
|
||
3. Target Schema
|
||
- 选择 `vessel_ais`、`geo_points`、`generic_records`
|
||
- 展示该 schema 必填字段
|
||
4. Mapping Proposal
|
||
- 调用 LLM 生成 mapping 草案
|
||
- 显示字段匹配置信度
|
||
- 标出需要人工确认的字段
|
||
5. Preview
|
||
- 用确定性 engine 预览前 N 条转换结果
|
||
- 展示校验错误
|
||
6. Save & Enable
|
||
- 保存 mapping version
|
||
- 启用调度或仅保存草稿
|
||
|
||
### Phase 3 — 运维视图
|
||
|
||
为 mapped datasource 展示:
|
||
|
||
- 上次运行时间。
|
||
- 成功记录数。
|
||
- 失败记录数。
|
||
- 当前 mapping version。
|
||
- 目标 schema。
|
||
- 最近错误。
|
||
- 手动运行按钮。
|
||
|
||
---
|
||
|
||
## 五、数据库与存储策略
|
||
|
||
### v1:继续使用 PostgreSQL
|
||
|
||
PostgreSQL 可以承载当前规模的采集、关系查询、JSONB 沉淀和基础时序查询。v1 不必因为“时序数据”立刻引入 TimescaleDB。
|
||
|
||
适合继续用 PostgreSQL 的场景:
|
||
|
||
- 数据量可控。
|
||
- 最近状态查询为主。
|
||
- 历史保留窗口较短。
|
||
- 查询模式还没稳定。
|
||
- 需要快速迭代 schema 与 mapping。
|
||
|
||
### TODO:TimescaleDB
|
||
|
||
以下条件满足后,再评估 TimescaleDB:
|
||
|
||
- AIS、遥测、轨迹类数据达到高频持续写入。
|
||
- 需要按时间窗口做聚合、降采样、retention policy。
|
||
- 单表时间序列查询明显成为瓶颈。
|
||
- 历史轨迹保留从 24h 扩展到数周或数月。
|
||
|
||
候选迁移对象:
|
||
|
||
- `vessel_position`
|
||
- future telemetry tables
|
||
- future generic time-series records
|
||
|
||
备选方案:
|
||
|
||
- PostgreSQL 原生按天/月分区。
|
||
- TimescaleDB hypertable。
|
||
- 热数据 PostgreSQL,冷数据对象存储。
|
||
|
||
---
|
||
|
||
## 六、安全与治理
|
||
|
||
### Secret 管理
|
||
|
||
- Settings 中保存 provider credentials。
|
||
- API 返回配置时必须 mask secret。
|
||
- LLM prompt 只能包含脱敏 sample 和 schema 说明。
|
||
- 后续 TODO:引入字段级加密或 KMS。
|
||
|
||
### Mapping 治理
|
||
|
||
- 每次 mapping 变更保留版本。
|
||
- active mapping 只能有一个。
|
||
- 允许保存 draft mapping。
|
||
- 运行记录关联 mapping version。
|
||
- 校验失败不能自动启用。
|
||
|
||
### 错误处理
|
||
|
||
常见错误类型:
|
||
|
||
- API 401/403:凭证错误或过期。
|
||
- API 429:限流,需要调整 schedule。
|
||
- JSON path 不存在:上游结构变化。
|
||
- 类型转换失败:mapping 规则错误。
|
||
- schema validation failed:转换结果不满足目标模型。
|
||
|
||
每次运行需要记录:
|
||
|
||
- datasource id。
|
||
- mapping version。
|
||
- started_at / finished_at。
|
||
- fetched count。
|
||
- mapped count。
|
||
- written count。
|
||
- failed count。
|
||
- error summary。
|
||
|
||
---
|
||
|
||
## 七、测试计划
|
||
|
||
### Backend Unit Tests
|
||
|
||
- mapping engine:
|
||
- path 提取。
|
||
- 数组展开。
|
||
- 默认值。
|
||
- 类型转换。
|
||
- datetime parse。
|
||
- 枚举映射。
|
||
- 缺字段错误。
|
||
- target schema registry:
|
||
- `vessel_ais` 必填字段校验。
|
||
- `geo_points` 经纬度范围校验。
|
||
- `generic_records` 接受未知结构。
|
||
- LLM assistant:
|
||
- mock provider 返回 mapping。
|
||
- 验证 secret 不进入 prompt。
|
||
- 验证非法 mapping 被拒绝。
|
||
|
||
### Backend Integration Tests
|
||
|
||
- sample JSON -> propose mapping -> preview -> save mapping。
|
||
- mapped collector 使用保存的 mapping 写入 `generic_records`。
|
||
- `vessel_ais` sample 写入船舶相关目标结构。
|
||
- 上游 JSON 结构变化时,运行失败并记录错误。
|
||
|
||
### Frontend Tests
|
||
|
||
- 自定义数据源向导完整流程。
|
||
- 未配置 AI Provider 时,提示去 Settings 配置,但允许手写 mapping。
|
||
- LLM 返回不完整 mapping 时,Preview 阶段显示校验错误。
|
||
- 保存 mapping 后展示 active version 和运行状态。
|
||
|
||
---
|
||
|
||
## 八、分期工作量
|
||
|
||
| 阶段 | 内容 | 估算 |
|
||
|-----|------|------|
|
||
| Phase 0 | 完成本规划、确认 schema registry 设计 | 0.5 天 |
|
||
| Phase 1 | target schema registry + mapping template model | 1–2 天 |
|
||
| Phase 2 | deterministic mapping engine | 2–3 天 |
|
||
| Phase 3 | sample/propose/preview/save API | 2–3 天 |
|
||
| Phase 4 | DataSources 自定义源向导 | 3–5 天 |
|
||
| Phase 5 | generic mapped collector + run history | 2–4 天 |
|
||
| Phase 6 | vessel_ais / geo_points destination handler | 2–4 天 |
|
||
|
||
---
|
||
|
||
## 九、当前差距与下一步
|
||
|
||
当前差距:
|
||
|
||
- `datasource_configs` 只描述请求配置,不描述目标 schema 和 mapping。
|
||
- 自定义源没有 sample -> schema -> mapping -> preview -> save 的闭环。
|
||
- 生产采集还没有通用 mapped collector。
|
||
- Settings 与 DataSources 的职责边界需要在 UI 上进一步明确。
|
||
- Earth 还没有通用 `geo_points` 图层。
|
||
|
||
下一步建议:
|
||
|
||
1. 先实现 target schema registry 和 mapping engine,不急着接 LLM。
|
||
2. 用固定 sample JSON 做 `vessel_ais` 和 `generic_records` 的单元测试。
|
||
3. 再接 LLM propose API,让 LLM 产出的只是 mapping 草案。
|
||
4. 最后做前端向导,把人工确认和 preview 放到启用之前。
|