Files
label_ai_service/specs/001-ai-service-requirements/data-model.md

168 lines
5.3 KiB
Markdown
Raw Normal View History

# Data Model: AI 服务
**Branch**: `001-ai-service-requirements` | **Date**: 2026-04-10
---
## 实体定义
### TripleItem文本三元组
从文档中提取的一条知识关系。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| subject | string | 非空 | 主语实体 |
| predicate | string | 非空 | 谓语/关系 |
| object | string | 非空 | 宾语实体 |
| source_snippet | string | 非空 | 原文中的证据片段(直接引用) |
| source_offset.start | int | ≥0 | 证据片段在全文中的起始字符偏移 |
| source_offset.end | int | >start | 证据片段在全文中的结束字符偏移 |
**状态转换**: 无(只读输出)
---
### QuadrupleItem图像四元组
从图像中提取的一条知识关系,带图像位置信息。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| subject | string | 非空 | 主体实体 |
| predicate | string | 非空 | 关系/属性 |
| object | string | 非空 | 客体实体 |
| qualifier | string | 可为空 | 修饰信息(时间、条件、场景) |
| bbox.x | int | ≥0 | 边界框左上角 x 像素坐标 |
| bbox.y | int | ≥0 | 边界框左上角 y 像素坐标 |
| bbox.w | int | >0 | 边界框宽度(像素) |
| bbox.h | int | >0 | 边界框高度(像素) |
| cropped_image_path | string | 非空 | 裁剪图在 RustFS 中的存储路径 |
**派生规则**: `cropped_image_path = "crops/{task_id}/{item_index}.jpg"`,由 image_service 自动生成并上传
---
### QAPair文本问答对
由文本三元组生成的训练候选问答对。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| question | string | 非空 | 问题文本 |
| answer | string | 非空 | 答案文本 |
---
### ImageQAPair图像问答对
由图像四元组生成的训练候选图文问答对。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| question | string | 非空 | 问题文本 |
| answer | string | 非空 | 答案文本 |
| image_path | string | 非空 | 对应裁剪图的存储路径(来源于 QuadrupleItem.cropped_image_path |
---
### FrameInfo视频帧信息
视频帧提取任务中单帧的元数据。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| frame_index | int | ≥0 | 帧在视频中的原始帧序号 |
| time_sec | float | ≥0.0 | 帧对应的时间点(秒) |
| frame_path | string | 非空 | 帧图在 RustFS 中的存储路径 |
**派生规则**: `frame_path = "frames/{source_id}/{upload_index}.jpg"`
---
### VideoJobCallback视频任务回调
异步视频任务完成后发送给 Java 后端的通知载荷。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| job_id | int | 非空 | 由 Java 后端分配的任务 ID |
| status | string | SUCCESS \| FAILED | 任务最终状态 |
| frames | FrameInfo[] \| null | 仅帧提取时非 null | 提取的帧列表(可为空列表) |
| output_path | string \| null | 仅视频转文本时非 null | 输出文字描述的存储路径 |
| error_message | string \| null | 仅 FAILED 时非 null | 错误描述 |
---
### FinetuneJob微调任务
微调任务的状态快照。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| job_id | string | 非空 | 由 ZhipuAI 平台分配的任务 ID如 "glm-ft-xxxxxx" |
| status | string | RUNNING \| SUCCESS \| FAILED | 当前状态 |
| progress | int \| null | 0-100 \| null | 完成百分比ZhipuAI 支持时) |
| error_message | string \| null | 仅 FAILED 时非 null | 错误描述 |
**状态映射**:
```
ZhipuAI "running" → RUNNING
ZhipuAI "succeeded" → SUCCESS
ZhipuAI "failed" → FAILED
其他 → RUNNING保守处理
```
---
## RustFS 存储路径规范
| 资源类型 | 存储桶 | 路径格式 |
|----------|--------|----------|
| 上传文本文件 | `source-data` | `text/{年月}/{source_id}.txt` |
| 上传图片 | `source-data` | `image/{年月}/{source_id}.jpg` |
| 上传视频 | `source-data` | `video/{年月}/{source_id}.mp4` |
| 视频帧图 | `source-data` | `frames/{source_id}/{upload_index}.jpg` |
| 视频转译文本 | `source-data` | `video-text/{source_id}/{timestamp}.txt` |
| 图像/帧 bbox 裁剪图 | `source-data` | `crops/{task_id}/{item_index}.jpg` |
| 导出 JSONL 文件 | `finetune-export` | `export/{batchUuid}.jsonl` |
---
## 配置模型
### config.yaml非敏感提交 git
```yaml
server:
port: 8000
log_level: INFO
storage:
buckets:
source_data: "source-data"
finetune_export: "finetune-export"
backend: {} # callback_url 由 .env 注入
video:
frame_sample_count: 8 # 视频转文本时均匀采样帧数
max_file_size_mb: 200 # 视频大小上限(可通过 MAX_VIDEO_SIZE_MB 覆盖)
models:
default_text: "glm-4-flash"
default_vision: "glm-4v-flash"
```
### 环境变量覆盖映射
| 环境变量 | YAML 路径 | 说明 |
|----------|-----------|------|
| ZHIPUAI_API_KEY | zhipuai.api_key | 必填 |
| STORAGE_ACCESS_KEY | storage.access_key | 必填 |
| STORAGE_SECRET_KEY | storage.secret_key | 必填 |
| STORAGE_ENDPOINT | storage.endpoint | RustFS 地址 |
| BACKEND_CALLBACK_URL | backend.callback_url | Java 后端回调接口 |
| LOG_LEVEL | server.log_level | 日志级别 |
| MAX_VIDEO_SIZE_MB | video.max_file_size_mb | 视频大小上限 |