# 语言及多模态理解模型精调数据格式

> 全部文档的索引见 [llms.txt](https://ark.volcengine.com/llms.txt)；在任一文档页面地址后追加 `.md` 可获取该页的 Markdown 版本。

进行模型精调前，需要准备符合模型类别和精调方法要求的训练集与验证集。数据集采用 JSONL 格式，每行包含一个完整的 JSON 对象。

> **注意**
>
> 精调 JSONL 文件绝对路径不可包含以下特殊字符：`*`、`?`、`[`、`]`。

本文适用于以文本作为输出的语言及多模态理解模型。训练样本可以只包含文本，也可以混合使用 `image_url`、`audio_url`、`video_url` 等输入；同一条样本可按模型能力组合多种模态。音频输入支持 SFT、DPO、CPT，不支持 GRPO、PPO 等 RL 训练。

## 支持模型

| 模型 | 版本 | 输入模态 | 支持特性 | SFT | DPO | GRPO | 精调后推理 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `doubao-seed-2-0-mini` | 260428（推荐） | 文本、图片；SFT、DPO、CPT 支持音频；RL 不支持音频；视频以控制台可选能力为准 | thinking：enabled、disabled、reasoning_effort；支持 Function Calling | 全量、LoRA | 全量、LoRA | 全量、LoRA | 模型单元、批量推理窗口与基础模型一致；LoRA 按 token 推理为基础模型 2 倍价格，窗口 256k，最大回答和思维链 32k |
| `doubao-seed-2-0-lite` | 260428（推荐） | 文本、图片；SFT、DPO、CPT 支持音频；RL 不支持音频；视频以控制台可选能力为准 | thinking：enabled、disabled、reasoning_effort；支持 Function Calling | 全量、LoRA | 全量、LoRA | 全量、LoRA | LoRA 按 token 推理为基础模型 2 倍价格，窗口 256k，最大回答和思维链 32k；其他方式以控制台为准 |

thinking 模式详情请参见 [深度思考能力支持情况](/docs/multimodal-fine-tuning-data-format#c680ed77)，Function Calling 详情请参见[Function Calling（函数调用）](/docs/function-calling)。

> **说明**
>
> 音频输入支持范围与模型版本及训练方式有关：
> * SFT、DPO 和 CPT 支持通过 `audio_url` 传入音频。
> * GRPO、PPO 等 RL 训练不支持音频输入。

<span id="multimodal-sft"></span>
## SFT 精调

<span id="a881aec9"></span>

语言及多模态理解模型支持多模态混排的对话数据格式，核心基于 JSONL 文件规范，在文本对话基础上扩展了图片、音频、视频 / 视频抽帧等多模态数据支持。以下是完整的格式示例、说明及字段定义。

<span id="3227d669"></span>
### 格式示例

样本格式：为 JSONL 文件（**JSON Lines**，轻量级文本格式，核心规则：**每一行对应一个独立的、合法的 JSON 对象**），需确保**单个对话样本独占一行**。

```JSON
{"messages":[{"role":"system","content":"请描述图片中的物体及场景"},{"role":"user","content":[{"type":"image_url","image_url":{"url":"tos://bucketname/image/desk.png"}},{"type":"text","text":"这张图片里有什么？"}]},{"role":"assistant","reasoning_content":"用户让我描述图片中的物体和场景，首先看图片内容：画面中有一张木质书桌，上面放着笔记本电脑、咖啡杯和绿植，背景是白色墙壁和窗户，光线明亮。需要准确列出物体，描述场景氛围，保持简洁明了。","content":"图片中展示了一个整洁的办公场景：一张木质书桌上放置着笔记本电脑、白色咖啡杯和一盆绿色多肉植物，背景是带有窗户的白色墙壁，自然光线充足，整体氛围清新舒适。","loss_weight":1.0}],"extra":{"sample_id":"sample-001","metadata":{"source":"user"}},"thinking":{"type": "enabled"}}
{"messages":[{"role":"user","content":[{"type":"text","text":"计算图片中物体的数量"},{"type":"image_url","image_url":{"url":"data:image/jpeg;base64,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"}},{"type":"image_url","image_url":{"url":"file:./image/books.png"}}]},{"role":"assistant","content":"图片中包含3个主要物体：1台笔记本电脑、1个咖啡杯、1盆绿植，共3个物体。"}]}
{"messages":[{"role": "user","content": [{"type": "image_url","image_url": {"url": "file:./image/doubao_logo.jpeg"}},{"type": "text","text": "What’s in this image?"}]},{"role": "assistant","content": "It is the logo of Doubao LLM model."}]}
{"messages":[{"role":"user","content":[{"type":"text","text":"请将这段客服通话转写为文字，并总结客户诉求。"},{"type":"audio_url","audio_url":{"url":"tos://bucketname/audio/customer_call.wav"}}]},{"role":"assistant","content":"转写：客户咨询订单配送延迟的问题，并提供了订单号。总结：客户希望确认延迟原因和预计送达时间。","loss_weight":1.0}]}
{"messages":[{"role":"user","content":[{"type":"text","text":"请根据视频画面和声音判断这段素材是否适合用于产品介绍。"},{"type":"video_url","fps":1,"video_url":{"url":"tos://bucketname/video/product_intro.mp4"}}]},{"role":"assistant","content":"这段视频画面清晰，讲解声音完整，适合用于产品介绍。","loss_weight":1.0}]}
```

#### 纯文本任务示例

仅训练纯文本任务时，也使用语言及多模态理解模型格式。将用户输入作为 `text` 类型内容传入，模型回复仍写入 `assistant.content`。

```JSON
{"messages":[{"role":"system","content":[{"type":"text","text":"请根据古诗内容，仅回复作者的名字。"}]},{"role":"user","content":[{"type":"text","text":"姑苏城外寒山寺，夜半钟声到客船"}]},{"role":"assistant","reasoning_content":"用户让我根据古诗内容回复作者名字，诗句是“姑苏城外寒山寺，夜半钟声到客船”。这句诗出自张继的《枫桥夜泊》。用户要求仅回复作者名字，所以直接回复。","content":"张继","loss_weight":1}]}
{"messages":[{"role":"user","content":[{"type":"text","text":"什么时候需要 SFT？"}]},{"role":"assistant","content":"当 prompt engineering 无法稳定解决问题，或模型输出需要满足固定格式但仍有部分 case 不符合要求时，可以考虑使用 SFT。SFT 也可用于减少 prompt 中的复杂约束，降低线上推理耗时。","loss_weight":1}]}
```

<span id="e504998a"></span>
### 格式说明

将 JSONL 文件中的一条数据展开，清晰展示字段层级关系：

```JSON
{
    "messages": [
        {
            "role": "system",
            "content": "请描述图片中的物体及场景"  // 本示例中system角色使用文本内容
        },
        {
            "role": "user",
            "content": [  // user角色支持数组格式，混排文本、图片、音频、视频
                {
                    "type": "image_url",  // 内容类型：图片
                    "image_url": {
                      "url": "tos://bucketname/image/desk.png"  // 图片地址（TOS/base64/相对路径）
                    }
                },
                {
                    "type": "text",  // 内容类型：文本
                    "text": "这张图片里有什么？"
                },
                {
                    "type": "audio_url",  // 内容类型：音频
                    "audio_url": {
                      "url": "tos://bucketname/audio/customer_call.wav"  // 音频地址（TOS）
                    }
                },
                {
                    "type": "video_url",  // 内容类型：视频，支持视频内嵌音频
                    "fps": 1,  // 视频抽帧帧率，表示每秒抽取的帧数
                    "video_url": {
                      "url": "tos://bucketname/video/product_intro.mp4"  // 视频地址（TOS 或 Base64）
                    }
                }
            ]
        },
        {
            "role": "assistant",
            "reasoning_content": "用户让我描述图片中的物体和场景，首先看图片内容：画面中有一张木质书桌，上面放着笔记本电脑、咖啡杯和绿植，背景是白色墙壁和窗户，光线明亮。需要准确列出物体，描述场景氛围，保持简洁明了。",
            "content": "图片中展示了一个整洁的办公场景：一张木质书桌上放置着笔记本电脑、白色咖啡杯和一盆绿色多肉植物，背景是带有窗户的白色墙壁，自然光线充足，整体氛围清新舒适。",
            "loss_weight": 1.0  // 训练权重，默认1.0
        }
    ],
    "extra": {
        "sample_id": "sample-001",
        "metadata": {
            "source": "user"
        }
    },
    "thinking": {"type": "enabled"}  // 深度思考能力控制字段
}
```

**字段说明**
每行一条 JSON 格式数据，核心字段如下：

|字段名 |||类型 |是否必填 |说明 |
|---|---|---|---|---|---|
|messages | | |list |是 |对话列表，包含多轮角色交互 |
| |role | |str |是 |角色类型，支持`system`/`user`/`assistant`/`tool` 中的一个 | \
| | | | | |- `system`：支持文本、图片、音频、视频混排 | \
| | | | | |- `user`：支持文本、图片、音频、视频混排 | \
| | | | | |- `assistant`：仅支持文本内容 | \
| | | | | |- `tool`：如希望提升模型的Function Calling能力，需选择支持Function Calling训练的模型并提供包含Function Calling格式数据的训练集用于精调，格式可参考 [Function Calling 样本要求](/docs/multimodal-fine-tuning-data-format#7bbc7eed) |
| |content | |str/list |是 |对话内容： | \
| | | | | |- 当role为`assistant`：字符串格式 | \
| | | | | |- 当role为`user`/`system`：数组格式，支持`text`、`image_url`、`audio_url`、`video_url`子类型 |
| | |type |str |条件必选 |子内容类型，可选`text`（文本）、`image_url`（图片）、`audio_url`（音频）或`video_url`（视频） | \
| | | | |当role为`user`时 | |
| | |text |str |条件必选 |文本内容，不能为空字符串 | \
| | | | |type为`text`时 | |
| | |image_url |dict |条件必选 |图片信息，包含`url`字段（图片地址）。 | \
| | | | |type为`image_url`时 |参考：[图片文件要求](/docs/multimodal-fine-tuning-data-format#94dd94ae) |
| | |audio_url |dict |条件必选 |音频信息，包含`url`字段，支持 TOS 地址和 Base64。 | \
| | | | |type为`audio_url`时 |参考：[音频/视频文件要求](/docs/multimodal-fine-tuning-data-format#a59f2e98) |
| | |video_url |dict |条件必选 |视频信息，支持 TOS 地址和 Base64，包含`url`字段，支持视频内嵌音频。 | \
| | | | |type为`video_url`时 |参考：[音频/视频文件要求](/docs/multimodal-fine-tuning-data-format#a59f2e98) |
| | |fps |float |否 |视频抽帧帧率，表示每秒抽取的帧数。 | \
| | | | |type为`video_url`时 |不填时使用模型默认抽帧策略；建议根据视频时长和任务效果按需配置 |
| |loss_weight | |float |否 |仅 `assistant` 角色支持配置该字段，默认 1.0，取值范围 [0.0,1.0]。`system` 和 `user` 角色不支持该字段。 |
| |reasoning_content | |str |否 |深度思考内容，**仅允许最后一个`assistant`角色携带**。 | \
| | | | | | | \
| | | | | |* 如有优化多轮对话场景下深度思考能力的精调需求，请参考 [多轮 reasoning_content 样本文件拆分](/docs/multimodal-fine-tuning-data-format#c84133a4)。 | \
| | | | | |* 如多轮对话场景训练时仅最后一轮对话携带reasoning_content，模型将学习到在中间对话轮次不进行thinking，影响模型thinking效果。 |
|`extra` | | |dict |否 |样本顶层的用户自定义扩展字段。`extra`中的 `key` 必须为 `string` 类型，`value` 类型不限制。 |
|thinking | | |object |否 |深度思考能力控制： | \
| | | | | | | \
| | | | | |* 部分模型精调支持该字段。 |
| |`type` | |str |否 |枚举值：`enabled`/`disabled`/`auto`/`custom`（不同模型支持范围不同，详情请参见 [深度思考能力支持情况](/docs/multimodal-fine-tuning-data-format#c680ed77)）。 |

<span id="multimodal-dpo"></span>
## 直接偏好学习（DPO）

<span id="eaa330e8"></span>

语言及多模态理解模型支持多模态混排的对话数据格式，核心基于 JSONL 文件规范，在文本对话基础上扩展了图片、音频、视频 / 视频抽帧等多模态数据支持。以下是完整的格式示例、说明及字段定义。
数据格式支持提供多个模型回复列表，通过 score 来指定对回复的偏好。训练过程将根据 score 的大小自动生成两两对比的偏序对进行训练，注意：score 相同的两个回复不会生成相应的偏序对。

<span id="8e20ec92"></span>
### 格式示例

样本格式：为JSONL文件（ **JSON Lines**，是一种轻量级的文本文件格式，核心规则 **每一行对应一个独立的、合法的 JSON 对象**），需确保**单个对话样本独占一行**，示例如下。

```JSON
{"messages":[{"role":"system","content":[{"type":"text","text":"你是一名多模态质检助手，需要结合文本、图片、音频和视频判断回复质量。"}]},{"role":"user","content":[{"type":"text","text":"请根据工单截图、客服通话和处理录屏，判断哪个质检结论更准确。"},{"type":"image_url","image_url":{"url":"tos://bucketname/image/ticket.png"}},{"type":"audio_url","audio_url":{"url":"tos://bucketname/audio/customer_call.wav"}},{"type":"video_url","video_url":{"url":"tos://bucketname/video/operation_record.mp4"}}]},{"role":"assistant","choices":[{"content":"客服准确解释了配送延迟原因，并在录屏中完成了补偿流程，结论完整。","score":1.0,"lm_loss_mask":1.0},{"content":"客服没有解决用户问题，建议直接判定为不合格。","score":0.2,"lm_loss_mask":0.0}]}],"thinking":{"type":"disabled"}}
```

<span id="84593217"></span>
### 格式说明

为便于展示各个字段关系，将JSON格式文件的一条数据展开，如下：

```Plain Text
{
  "messages": [
    {
      "role": "system",
      "content": [
        {
          "type": "text",
          "text": "你是一名多模态质检助手，需要结合文本、图片、音频和视频判断回复质量。"
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "请根据工单截图、客服通话和处理录屏，判断哪个质检结论更准确。"
        },
        {
          "type": "image_url",
          "image_url": {
             "url": "tos://bucketname/image/ticket.png"
          }
        },
        {
          "type": "audio_url",
          "audio_url": {
             "url": "tos://bucketname/audio/customer_call.wav"
          }
        },
        {
          "type": "video_url",
          "video_url": {
             "url": "tos://bucketname/video/operation_record.mp4"
          }
        }
      ]
    },
    {
      "role": "assistant",            # 最后一个message的role必须为assistant
      "choices": [                    # 可以有多个response
        {
          "content": "客服准确解释了配送延迟原因，并在录屏中完成了补偿流程，结论完整。",
          "score": 1.0,               # 该response的得分
          "lm_loss_mask": 1.0         # 这个response是否计算 sft loss，默认为0.0
        },
        {
          "content": "客服没有解决用户问题，建议直接判定为不合格。",
          "score": 0.2,
          "lm_loss_mask": 0.0         # 这个response是否计算 sft loss，默认为0.0
        }
      ]
    }
  ],
  "thinking": {
    "type": "disabled"
  }
}
```

每行一条JSON格式的数据：

|字段名 |||类型 |是否必填 |说明 |
|---|---|---|---|---|---|
|`messages` | | |list |是 |对话列表，包含多轮角色交互 |
| |`role` | |str |是 |角色类型，支持`system`/`user`/`assistant`/`tool`，其中： | \
| | | | | |- `system`：支持文本、图片、音频、视频混排 | \
| | | | | |- `user`：支持文本、图片、音频、视频混排 | \
| | | | | |- `assistant`：仅支持文本内容 |
| |`content` | |str/list |是 |*非最后一轮的对话内容* | \
| | | | | |- 当role为`assistant`：字符串格式 | \
| | | | | |- 当role为`system`/`user`：数组格式，支持`text`、`image_url`、`audio_url`、`video_url`子类型 |
| | |`type` |str |是（ 当role为`user`时） |子内容类型，可选`text`（文本）、`image_url`（图片）、`audio_url`（音频）或`video_url`（视频） |
| | |`text` |str |是（type=text 时） |文本内容，不能为空字符串 |
| | |`image_url` |dict |是（type=image_url 时） |图片信息，包含`url`字段（图片地址）。 | \
| | | | | |参考：[图片文件要求](/docs/multimodal-fine-tuning-data-format#94dd94ae) |
| | |`audio_url` |dict |是（type=audio_url 时） |音频信息，包含`url`字段，支持 TOS 地址和 Base64。参考：[音频/视频文件要求](/docs/multimodal-fine-tuning-data-format#a59f2e98) |
| | |`video_url` |dict |是（type=video_url 时） |视频信息，支持 TOS 地址和 Base64，包含`url`字段，支持视频内嵌音频。参考：[音频/视频文件要求](/docs/multimodal-fine-tuning-data-format#a59f2e98) |
| | |`fps` |float |否 |视频抽帧帧率，表示每秒抽取的帧数。仅在 type=video_url 时生效，不填时使用模型默认抽帧策略。 |
| |`choices` | |list |是 |仅可以在最后一轮对话中填写，且 list 长度在 1～5 之间。为生成有效偏序对，建议提供至少 2 个 `score` 不同的回复。 |
| | |`content` |str/list |是 | - 字符串格式：文本内容 | \
| | | | | | - 数组格式：仅支持type为text |
| | |`reasoning_content` |str |否 |深度思考内容，**仅允许最后一个`assistant`角色携带**。 | \
| | | | | | | \
| | | | | |* 如果打开 lm_loss_mask，则需要注意将非最后一轮的 assistant 对话 loss_weight 置为 0，否则将影响模型的深度思考能力 |
| | |`score` |float |否 |偏好值，默认为 0.0，范围为 [0.0,1.0]，值越高表示越偏好。包含多个回复时，所有 `score` 不可完全相同。 |
| | |`lm_loss_mask` |float |否 |该条消息是否计算 SFT loss，默认为 0.0，即不计算 SFT loss。建议将 `score` 最大的回复设为 1.0；如果全为 0.0，可能导致模型训练不稳定、泛化能力变差。 |
| |`loss_weight` | |float |否 |仅 `assistant` 角色支持配置该字段，默认 1.0，取值范围 [0.0,1.0]。 |
|`thinking` | | |object |否 |深度思考能力控制。支持该参数的模型选填，不支持的模型禁填。 |
| |`type` | |str |否 |枚举值：`enabled`/`disabled`/`auto`/`custom`（不同模型支持范围不同，详情请参见 [深度思考能力支持情况](/docs/multimodal-fine-tuning-data-format#c680ed77)）。 |

<span id="multimodal-grpo-ppo"></span>
## 强化学习（GRPO/PPO）

<span id="7cf8d0a9"></span>

语言及多模态理解模型支持多模态混排的对话数据格式，核心基于 JSONL 文件规范，在文本对话基础上扩展了图片、视频 / 视频抽帧等多模态数据支持。以下是完整的格式示例、说明及字段定义。

> **注意**
>
> GRPO、PPO 等 RL 训练不支持音频输入，数据中不得使用 `audio_url`。

<span id="b29f4847"></span>
### 格式示例

样本格式：为JSONL文件（ **JSON Lines**，是一种轻量级的文本文件格式，核心规则 **每一行对应一个独立的、合法的 JSON 对象**），需确保**单个对话样本独占一行**，示例如下。

```JSON
{"messages": [{"role": "user","content": [{"type": "text","text": "\nLet's think step by step and output the final answer within \\boxed{}."},{"type": "image_url","image_url": {"url": "data:image/{image_extension};base64,{image_base64}"}},{"type":"video_url","video_url":{"url":"tos://bucketname/video/question.mp4"}}]}],"extra": {"answer": "A"},"thinking": {"type": "enabled"}}
```

<span id="c0e1f1f5"></span>
### 格式说明

```JSON
{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "\nLet's think step by step and output the final answer within \\boxed{}."
        },
        {
          "type": "image_url",
          "image_url": {
              "url": "data:image/{image_extension};base64,{image_base64}"
          }
        },
        {
          "type": "video_url",
          "video_url": {
              "url": "tos://bucketname/video/question.mp4"
          }
        }
      ]
    }
  ],
  "extra": {
    "answer": "A"
  },
  "thinking": {"type": "enabled"}
}
```

每一条JSON格式的数据：

|字段名 |||类型 |是否必填 |说明 |
|---|---|---|---|---|---|
|`messages` | | |list |是 |对话列表，包含多轮角色交互 |
| |`role` | |str |是 |角色类型，支持`system`/`user`/`assistant`/`tool`，其中： | \
| | | | | |- `system`：支持文本、图片、视频混排 | \
| | | | | |- `user`：支持文本、图片、视频混排 | \
| | | | | |- `assistant`：仅支持文本内容 | \
| | | | | |- `tool`：如希望提升模型的Function Calling能力，需选择支持Function Calling训练的模型并提供包含Function Calling格式数据的训练集用于精调，格式可参考 [Function Calling 样本要求](/docs/multimodal-fine-tuning-data-format#7bbc7eed) | \
| | | | | |**最后一个message的role必须是user或tool** |
| |`content` | |str/list |是 |对话内容： | \
| | | | | |- 当role为`assistant`：字符串格式 | \
| | | | | |- 当role为`system`/`user`：数组格式，支持`text`、`image_url`、`video_url`子类型 |
| | |`type` |str |是（ 当role为`user`时） |子内容类型，可选`text`（文本）、`image_url`（图片）或`video_url`（视频） |
| | |`text` |str |是（type=text 时） |文本内容，不能为空字符串 |
| | |`image_url` |dict |是（type=image_url 时） |图片信息，包含`url`字段（图片地址）。 | \
| | | | | |参考：[图片文件要求](/docs/multimodal-fine-tuning-data-format#94dd94ae) |
| | |`video_url` |dict |是（type=video_url 时） |视频信息，支持 TOS 地址和 Base64，包含`url`字段，支持视频内嵌音频。参考：[音频/视频文件要求](/docs/multimodal-fine-tuning-data-format#a59f2e98) |
| | |`fps` |float |否 |视频抽帧帧率，表示每秒抽取的帧数。仅在 type=video_url 时生效，不填时使用模型默认抽帧策略。 |
|`extra` | | |dict |否 |样本顶层的用户自定义扩展字段，可用于携带 reward function 与 custom rollout 所需的信息。`extra`中的 `key` 必须为 `string` 类型，`value` 类型不限制。 |
|`thinking` | | |object |否 |深度思考能力控制。支持该参数的模型选填，不支持的模型禁填。 |
| |`type` | |str |否 |枚举值：`enabled`/`disabled`/`auto`/`custom`（不同模型支持范围不同，详情请参见 [深度思考能力支持情况](/docs/multimodal-fine-tuning-data-format#c680ed77)）。 |

<span id="multimodal-continued-pretraining"></span>
## 继续预训练

<span id="6f7330dd"></span>

继续预训练支持以下几类样本组织方式：
* 纯文本：适用于标准文本继续预训练。
* 分段 content[]：适用于需要显式保留内容片段边界的场景。
* 多模态 content[]：适用于图文、音频、视频等继续预训练样本。

<span id="8233434b"></span>
### **格式示例**

样本格式：为JSONL文件（ **JSON Lines**，是一种轻量级的文本文件格式，核心规则 **每一行对应一个独立的、合法的 JSON 对象**），需确保**单个样本独占一行**，示例如下。

```Plain Text
{"text": "火山方舟通过稳定可靠的安全互信方案，保障模型提供方的模型安全与模型使用者的信息安全，加速大模型能力渗透到千行百业，助力模型提供方和使用者实现商业新增长。"}
{"content":[{"type":"text","text":"支持运行超大规模的分布式任务，"},{"type":"text","text":"包含多种预置算法框架和自定义算法框架。"}]}
{"content":[{"type":"image_url","image_url":{"url":"tos://bucketname/image/figure.jpeg"},"loss_weight":0.0},{"type":"text","text":"学习这张图片对应的描述方式。","loss_weight":1.0}]}
{"content":[{"image_url":{"url": "data:image\/jpeg;base64,xx"}, "type": "image_url","loss_weight":0.0},{"type": "text", "text": "今天天气很好", "loss_weight": 1.0}]}
{"content":[{"type":"audio_url","audio_url":{"url":"tos://bucketname/audio/customer_call.wav"},"loss_weight":0.0},{"type":"text","text":"这是一段客服通话音频，可用于学习语音转写、说话人意图识别与问题摘要的表达方式。","loss_weight":1.0}]}
{"content":[{"type":"video_url","video_url":{"url":"tos://bucketname/video/demo.mp4"},"loss_weight":0.0},{"type":"text","text":"学习这段视频中画面与声音的联合描述方式。","loss_weight":1.0}]}

```

<span id="3b716e16"></span>
### 格式说明

为便于展示各个字段关系，将 JSONL 格式文件中的几类典型样本展开如下：

```Plain Text
{
    "text": "火山引擎机器学习平台是面向机器学习应用开发者，提供【开发机】和【自定义训练】等丰富建模工具、多框架高性能模型推理服务的企业级开发平台，支持从数据托管、代码开发、模型训练、模型部署的全生命周期工作流。"
}
{
    "content": [
        {
            "type": "text",
            "text": "支持运行超大规模的分布式任务，",
            "loss_weight": 1.0
        },
        {
            "type": "text",
            "text": "包含多种预置算法框架和自定义算法框架。",
            "loss_weight": 1.0
        }
    ]
}
{
    "content": [
        {
            "type": "image_url",
            "image_url": {
                "url": "tos://bucketname/image/figure.jpeg"
            },
            "loss_weight": 0.0
        },
        {
            "type": "text",
            "text": "学习该图片所对应的描述内容。",
            "loss_weight": 1.0
        }
    ]
}
{
    "content": [
        {
            "type": "audio_url",
            "audio_url": {
                "url": "tos://bucketname/audio/customer_call.wav"
            },
            "loss_weight": 0.0
        },
        {
            "type": "text",
            "text": "这是一段客服通话音频，可用于学习语音转写、说话人意图识别与问题摘要的表达方式。",
            "loss_weight": 1.0
        }
    ]
}
{
    "content": [
        {
            "type": "video_url",
            "video_url": {
                "url": "tos://bucketname/video/demo.mp4"
            },
            "loss_weight": 0.0
        },
        {
            "type": "text",
            "text": "学习这段视频中画面与声音的联合描述方式。",
            "loss_weight": 1.0
        }
    ]
}
```

每行一条JSON格式的数据：

|字段名 |类型 |是否必填 |说明 |
|---|---|---|---|
|text |str |与 content 二选一 |纯文本样本。每条样本不限制 text 长度，如果超长将自动根据模型最大支持的 token 拆成多个样本，因此样本总数可能会超过数据行数。 |
|content |list |与 text 二选一 |分段内容列表，支持文本或多模态内容混排。 |
|content[].type |str |是 |子内容类型，可选 text、image_url、audio_url、video_url。 |
|content[].text |str |type=text 时必填 |文本内容。 |
|content[].image_url |dict |type=image_url 时必填 |图片信息，包含 url 字段或者base64信息。 |
|content[].audio_url |dict |type=audio_url 时必填 |音频信息，包含 url 字段，支持 TOS 地址和 Base64。 |
|content[].video_url |dict |type=video_url 时必填 |视频信息，支持 TOS 地址和 Base64，包含 url 字段，支持视频内嵌音频。 |
|content[].fps |float |否 |视频抽帧帧率，表示每秒抽取的帧数。仅在 type=video_url 时生效，不填时使用模型默认抽帧策略。 |
|content[].loss_weight |float |否 |当前内容片段的训练权重。`text` 类型默认为 1.0；`image_url`、`audio_url`、`video_url` 类型默认为 0.0，且只允许设置为 0.0。 |

> **说明**
>
> 继续预训练的多模态样本沿用统一的 content[] 结构：
> * 纯文本：{"text":"..."}
> * 分段纯文：{"content":[{"type":"text","text":"..."}, ...]}
> * 图文：{"content":[{"type":"image_url",...},{"type":"text","text":"..."}]}
> * 音频 / 视频：{"content":[{"type":"audio_url",...},{"type":"video_url",...},{"type":"text","text":"..."}]}

<span id="94dd94ae"></span>
## 图片文件要求

<span id="6b653397"></span>
#### 图片格式要求

* **数据集文件大小**：单数据集文件大小需控制在 2G 以下。
* **图片规格**：单张图片大小限制在 10M 以内，长宽比要小于 200。单图最大支持 5120 tokens，若超出此数值则会被采样到最大值（图片 token = 长像素 * 宽像素 / 784）。
* **样本长度**：单样本长度若超过模型训练窗口会被截断，图片按单张整体截断。不同模型的窗口大小，参考 [选择模型](/docs/fine-tuning-overview#d3ef4388)。

* **支持的图片格式**：参见下表。

|**图片格式** |**文件扩展名** |内容格式 Content Type |
|---|---|---|
|JPEG |.jpg, .jpeg |image/jpeg |
|PNG |.apng, .png |image/png |
|GIF |.gif |image/gif |
|WEBP |.webp |image/webp |
|BMP |.bmp |image/bmp |
|TIFF |.tiff, .tif |image/tiff |
|ICO |.ico |image/x-icon |
|DIB |.dib |image/bmp |
|SGI |.sgi |image/sgi |
|JPEG2000 |.j2c, .j2k, .jp2, .jpc, .jpf, .jpx |image/jp2 |

<span id="09e24972"></span>
#### 图片传入方式

在视觉理解模型的数据输入中，图片的传入方式有多种，以满足不同场景的需求，以下是具体介绍。

> **说明**
>
> `image_url.url` 支持 `tos://`、`data:` Base64 和 `file:` 相对路径，不支持 HTTP(S) 地址。

<span id="c1c92310"></span>
##### **1.（推荐）使用 TOS 存储图片**

1. 创建存储桶（Bucket）用于存储文件（Object），例如创建如下结构。

创建存储桶详细步骤可见 [对象存储控制台快速入门](https://docs.volcengine.com/docs/6349/74830?lang=zh)。

```Bash
bucketname    #桶名称
├── sample  #桶内文件夹名称
    ├── data.jsonl
└── image   #桶内文件夹名称
    ├── xxx.png
    └── xxxx.png
```

2. jsonl文件中在URL内以“`tos://${bucket}/${object}`”的形式填入TOS对象地址。**注意，TOS URL所引用的图片需与JSONL文件处于同一个桶内**。这种格式能够加快数据处理速度、减少多角色传输所耗费的时间，进而提高训练效率。以上步骤完成后，**精调任务进行数据配置时选择 从TOS中导入方式 仅上传jsonl文件即可**。

```JSON
{
  "messages": [
    {
      "role": "user",
      "content": [
         {
          "type": "image_url",
          "image_url": {
            "url": "tos://bucketname/image/xxx.png"
          }
        },
        {
          "type": "text",
          "text": "What’s in this image?"
        }
      ]
    },
    {
      "role": "assistant",
      "content": "It is the logo of Doubao LLM model."
    }
  ]
}
```

<span id="ceb3e8cc"></span>
##### **2.  图片使用**base64编码

<span id="e5810bc8"></span>
###### **格式示例**

将图片进行 base64 编码后填入 jsonl 文件中，需确保**单个样本独占一行**，示例如下。您也可以 [下载样例文件](https://arkdocs.tos-cn-beijing.volces.com/files/training/vlm_data.jsonl) 参考。

```JSON
{"messages":[{"role":"user","content":[{"type":"text","text":"What’s in this image?"},{"type":"image_url","image_url":{"url":"data:image/jpeg;base64,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"}}]},{"role":"assistant","content":"It is the logo of Doubao LLM model."}]}
{"messages":[{"role":"user","content":[{"type":"text","text":"What’s in this image?"},{"type":"image_url","image_url":{"url":"data:image/jpeg;base64,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"}}]},{"role":"assistant","content":"It is the logo of Doubao APP."}]}
```

**格式说明**
为便于展示各个字段关系，将JSONL格式文件的一条数据展开，如下：

```JSON
{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "image_url",
          "image_url": {
            "url": "data:image/{image_extension};base64,{image_base64}"
          }
        },
        {
          "type": "text",
          "text": "What’s in this image?"
        }
      ]
    },
    {
      "role": "assistant",
      "content": "It is a cat."
    }
  ]
}
```

* 支持在 user role 内混排图文，图文顺序无限制，训练按样本中的顺序进行。
* 支持多轮对话和单轮对话多图。
* text 字段不能为空字符串。
* 支持在创建精调任务时上传或选择多个文件或数据集，**单数据文件大小限制在 2G 以下，大文件可拆分为多个小文件**。

<span id="ef90707e"></span>
###### **附：图片编码方法**

以下是Python对图片进行 base64 编码的代码示例。

```Python
import base64

# 将结果填入 url 字段内
def encode_image(image_path):
    extension = image_path.split(".")[-1]
    with open(image_path, "rb") as image_file:
        base64_image = base64.b64encode(image_file.read()).decode('utf-8')
        return f"data:image/{extension};base64,{base64_image}"
```
<span id="4e4da83f"></span>
##### 3. 图片使用相对路径

<span id="6bcdfa14"></span>
###### **格式示例**

以下为 jsonl 文件中使用图片相对路径的格式示例。
1. 创建目录结构如下：

    ```Bash
    vlm
    ├── data.jsonl
    └── image
        ├── doubao_app_logo.jpeg
        └── doubao_logo.jpeg
    ```

2. 则对应的数据示例如下：JSONL 文件中需确保**单个样本独占一行**

    ```JSON
    {"messages": [{"role": "user","content": [{"type": "image_url","image_url": {"url": "file:./image/doubao_logo.jpeg"}},{"type": "text","text": "What’s in this image?"}]},{"role": "assistant","content": "It is the logo of Doubao LLM model."}]}
    ```

<span id="8dff679e"></span>
###### 格式说明

为便于展示各个字段关系，将JSONL格式文件的一条数据展开，如下：

```JSON
{
    "messages": [
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "file:./image/doubao_logo.jpeg"
                    }
                },
                {
                    "type": "text",
                    "text": "What’s in this image?"
                }
            ]
        },
        {
            "role": "assistant",
            "content": "It is the logo of Doubao LLM model."
        }
    ]
}
```

**注意：这种格式仅支持文件夹内图片数量少于 1000 张，大于该规模仍建议使用 TOS 存储图片**。
* 具体操作：创建文件夹，将图片和对应的 jsonl 文件按照上述格式要求进行整理后放入该文件夹中。 如在控制台页面进行精调数据配置**需将创建的文件夹拖拽到上传框内**，暂不支持点击上传框后选择文件夹。例如：上方目录结构需把`vlm`文件夹拖拽上传。对于 tos 数据集文件夹路径，可以在控制台直接点击选择。
* 支持图片和 jsonl 文件分别存放在同一文件夹中，通过相对路径在 jsonl 文件中指向图片（暂不支持绝对路径 tos url），文件夹内可包含多个 jsonl 文件，但要求 jsonl 文件位于文件夹根路径。

<span id="f729cfda"></span>
#### **视频抽帧图片序列**

视觉理解模型精调支持用户将视频抽帧为图片后，将时间戳和图片按顺序编排到训练集中。可参考 [附3：对视频内容进行抽帧](/docs/multimodal-fine-tuning-data-format#72d61a86)。

> **注意**
>
> doubao-seed-1.8 / 2.0 模型抽帧策略与doubao-seed-1.8 之前的模型有所不同，详情请参见 [抽帧策略](/docs/video-understanding#203baa92)。

**格式示例**
样本格式：为JSONL文件（ **JSON Lines**，是一种轻量级的文本文件格式，核心规则 **每一行对应一个独立的、合法的 JSON 对象**），需确保**单个样本独占一行，** 示例如下：

```JSON
{"messages": [{"role": "user","content": [{"type": "text","text": "你觉得这个恐怖吗？"},{"type": "text","text": "[0.0 second]"},{"type": "image_url","image_url": {"url": "base64/相对路径"}},{"type": "text","text": "[1.0 second]"},{"type": "image_url","image_url": {"url": "base64/相对路径"}},{"type": "text","text": "[2.0 second]"},{"type": "image_url","image_url": {"url": "base64/相对路径"}}]}]}
```

为便于展示各个字段关系，将JSONL格式文件的一条数据展开，如下：

```JSON
{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "你觉得这个恐怖吗？"
        },
        {
          "type": "text",
          "text": "[0.0 second]"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "base64/相对路径"
          }
        },
        {
          "type": "text",
          "text": "[1.0 second]"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "base64/相对路径"
          }
        },
        {
          "type": "text",
          "text": "[2.0 second]"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "base64/相对路径"
          }
        }
      ]
    }
  ]
}
```

<span id="a59f2e98"></span>
## 音频/视频文件要求

以下要求仅适用于语言及多模态理解模型的音频、视频输入。视频生成模型的输入素材限制，请参见[全模态输入](/docs/video-generation-tutorial#63a97f09)。

音频和视频支持使用 `tos://` TOS 地址或 `data:` Base64 内嵌方式传入，不支持 HTTP(S) 地址、`file:` 相对路径或 File API 的 `file_id`。通过 TOS 地址传入时，音频或视频对象需要与 JSONL 文件处于同一个桶内。视频文件沿用现有 `messages[].content[]` 或 `content[]` 多模态结构，通过 `video_url` 传入；如需控制视频抽帧帧率，可在 `type` 为 `video_url` 的同级对象中配置 `fps` 字段。

> **说明**
>
> `audio_url` 支持用于 SFT、DPO、CPT，不支持用于 GRPO、PPO 等 RL 训练。`video_url` 需要在支持视频输入的模型和训练方式中使用。详情请参见 [选择模型](/docs/fine-tuning-overview#d3ef4388)。

**音频文件限制**
* 支持 WAV、MP3、M4A、AAC 格式，具体以创建精调任务时的数据校验结果为准。
* 单个音频文件大小不超过 512 MB。
* 纯音频训练不做音频时长限制。
* 音频文件应保证可正常解码，避免空音轨、损坏文件或无法识别的编码格式。

Base64 内嵌示例：

```JSON
{
  "type": "audio_url",
  "audio_url": {
    "url": "data:audio/wav;base64,<BASE64_ENCODING>"
  }
}
```

**视频文件输入方式（视频内嵌音频文件）**

视频输入沿用现有多模态 `content[]` 结构：

```JSON
{
  "content": [
    {
      "type": "video_url",
      "fps": 1,
      "video_url": {
        "url": "tos://bucket/video/demo.mp4"
      }
    },
    {
      "type": "text",
      "text": "请你描述下视频中的人物的一系列动作。"
    }
  ]
}
```

视频地址支持：
* TOS 地址：`tos://bucket/video/demo.mp4`
* Base64：`data:video/mp4;base64,...`

暂不支持 HTTP(S) 地址、`file:` 相对路径，以及通过 File API 上传后使用 `file_id` 或文件引用方式传入视频。

**视频文件限制**
* 支持格式：
  * MP4：`video/mp4`
  * AVI：`video/x-msvideo`
  * MOV：
    * 通过 URL 传入视频时，对象存储请设置 Content-Type 为 `video/quicktime`。
    * 通过 Base64 编码传入视频时，请使用 `video/mov`，即 `data:video/mov;base64,<BASE64_ENCODING>`。
* 单个视频文件大小不超过 512 MB。
* 视频内嵌音频经预处理后，音轨和纯音频文件使用一致的 token 计量规则。
* 如需使用视频内嵌音频进行训练，请确保视频文件包含可正常解码的音轨。

**具体操作**：
1. 创建存储桶（Bucket）用于存储文件（Object），创建存储桶详细步骤可见 [对象存储控制台快速入门](https://docs.volcengine.com/docs/6349/74830?lang=zh)。例如创建如下结构：

    ```Bash
    bucketname    #桶名称
    ├── sample  #桶内文件夹名称
        ├── data.jsonl
    ├── audio   #桶内文件夹名称
        ├── xxx.wav
        └── xxxx.mp3
    └── video   #桶内文件夹名称
        ├── xxx.mp4
        └── xxxx.mp4
    ```

2. jsonl文件中在URL内以“`tos://${bucket}/${object}`”的形式填入TOS对象地址，例如上方结构URL则为“`tos://bucketname/audio/xxx.wav`”或“`tos://bucketname/video/xxx.mp4`”。**注意，TOS URL所引用的音频或视频需与JSONL文件处于同一个桶内**。这种格式能够加快数据处理速度、减少多角色传输所耗费的时间，进而提高训练效率。以上步骤完成后，**精调任务进行数据配置时选择 从TOS中导入方式 仅上传jsonl文件即可**。

<span id="9656cd75"></span>
## 数据集 Thinking 字段处理工具

您可以通过脚本将不含`thinking`的数据集转换为含`thinking`的数据集：
* 对于数据集中不含`reasoning_content`的样本，将`thinking`赋值为`disabled`。
* 含`reasoning_content`的样本，则赋值为`enabled`。

您可下载 [此脚本](https://arkdocs.tos-cn-beijing.volces.com/files/training/dataset_converter.zip) 对数据集进行转换，使您的数据集符合精调模型数据格式规范。

<span id="c84133a4"></span>
## 多轮 reasoning_content 样本文件拆分

您可参照以下脚本，将一条携带多轮reasoning_content的样本拆分为多条仅最后一轮对话携带reasoning_content的样本。
* 代码实现：输入一个JSONL样例文件，输出处理好的训练数据到指定文件夹。
* 使用示例：python main.py --input test.jsonl --output res-folder

    ```Python
    import json
    import os
    import argparse
    from process import process_sample
    from typing import List, Dict, Any

    def process_sample(sample: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        处理单个样例数据，根据规则生成一组处理后的样例

        参数:
            sample: 包含消息的字典，格式如案例所示

        返回:
            处理后的样例列表
        """
        messages = sample["messages"]

        # 用于存储处理后的消息
        message_result_list = []
        processed_messages = []
        not_set_loss_weight_index = []

        for i in range(0, len(messages)):
            current = messages[i]

            # 最后一个消息不需要处额外理
            if i == len(messages) - 1:
                processed_messages.append(current)
                message_result_list.append(processed_messages.copy())
                break

            # 只处理role为assistant的消息
            if current.get("role") == "assistant":
                # 检查是否存在loss_weight: 0
                has_loss_weight_zero = "loss_weight" in current and current["loss_weight"] == 0
                # 检查是否存在reasoning_content
                has_reasoning_content = "reasoning_content" in current

                # 情况1: 不存在loss_weight:0, 且存在reasoning_content
                if not has_loss_weight_zero and has_reasoning_content:
                    # 拆分出当前消息, 并添加到消息列表中
                    previous_messages = [msg.copy() for msg in processed_messages]
                    previous_messages.append(current.copy())
                    message_result_list.append(previous_messages.copy())

                    # 处理当前消息, 不保留reasoning_content, 并记录loss_weight:0
                    new_assistant_msg = current.copy()
                    del new_assistant_msg["reasoning_content"]
                    new_assistant_msg["loss_weight"] = 0

                    # 将处理后的消息段保存下来，用于后续使用
                    processed_messages.append(new_assistant_msg)
                    current = []

                    # 处理之前未设置loss_weight的消息，确保每条消息只被用于一次训练
                    for idx in not_set_loss_weight_index:
                        processed_messages[idx]["loss_weight"] = 0
                    not_set_loss_weight_index = []

                # 情况2: 存在loss_weight:0
                elif has_loss_weight_zero:
                    # 不做拆分，不保留reasoning_content
                    new_assistant_msg = current.copy()
                    if "reasoning_content" in new_assistant_msg:
                        del new_assistant_msg["reasoning_content"]

                    processed_messages.append(new_assistant_msg)
                # 情况3: 不存在reasoning_content
                else:
                    processed_messages.append(current)
                    # 记录下当前未设置loss_weight的消息
                    not_set_loss_weight_index.append(i)
            else:
                # 非assistant角色的消息直接添加
                processed_messages.append(current)

        # 生成最终的样例列表
        processed_samples = []
        for messages in message_result_list:
            processed_sample = sample.copy()
            processed_sample["messages"] = messages
            processed_samples.append(processed_sample)

        return processed_samples

    def main():
        parser = argparse.ArgumentParser(description='处理JSONL样例数据并输出到文件夹')
        parser.add_argument('--input', required=True, help='输入的JSONL文件路径')
        parser.add_argument('--output', required=True, help='输出文件夹路径')

        args = parser.parse_args()

        # 读取JSONL文件
        samples = []
        try:
            with open(args.input, 'r', encoding='utf-8') as f:
                for line in f:
                    if line.strip():  # 跳过空行
                        samples.append(json.loads(line))
        except FileNotFoundError:
            print(f"错误: 找不到输入文件 {args.input}")
            return

        # 处理所有样例
        all_processed_samples = []
        for sample in samples:
            processed_samples = process_sample(sample)
            all_processed_samples.extend(processed_samples)

        # 写入JSONL文件到文件夹
        os.makedirs(args.output, exist_ok=True)

        try:
            # 确保输出目录存在
            os.makedirs(args.output, exist_ok=True)

            # 构建完整输出路径
            output_path = os.path.join(args.output, f"result.jsonl")

            # 将所有样本写入JSONL文件
            with open(output_path, 'w', encoding='utf-8') as f:
                for sample in all_processed_samples:
                    f.write(json.dumps(sample, ensure_ascii=False) + '\n')

            print(f"处理完成，已生成JSONL文件，包含 {len(all_processed_samples)} 个样本，保存在 {output_path}")
        except Exception as e:
            print(f"错误: 写入文件失败 - {e}")

    if __name__ == "__main__":
        main()
    ```

<span id="72d61a86"></span>
## 对视频内容进行抽帧处理

当您需要对视频内容进行理解时，可以对视频进行抽帧，生成若干图片后，再将图片结合文本作为提示词内容，请求视频理解的模型服务。下面是使用 Python 脚本实现的方案，供您参考。

> **注意**
>
> doubao-seed-1.8 / 2.0 模型抽帧策略与doubao-seed-1.8 之前的模型有所不同，详情请参见 [抽帧策略](/docs/video-understanding#203baa92)。

<span id="b0e9d867"></span>
### 代码流程

1. 视频文件读取：从本地路径读取视频文件。
2. 对视频进行抽帧，可以支持 2 种策略：

    1. `CONSTANT_INTERVAL`：固定时间间隔抽帧，如 1s 一帧，时间间隔可以调整。

    2. `EVEN_INTERVAL`：固定总帧数均匀抽帧，如不管视频时长，总共抽 20 帧，抽取的总帧数可以调整。
3. 压缩帧图像：为了降低网络传输时延，以及减少 token 用量，将图像等比例压缩至 640*480 以内。
4. 请求视觉理解模型：组装请求体，包含提示词（Prompt）及所有帧图像的 Base64，并使用方舟`ChatCompletion` 接口调用模型服务。

<span id="d3ba8d6a"></span>
### 示例代码

<span id="003350ad"></span>
#### 环境配置

在运行脚本前，您需要配置好 API Key、获取Model ID，具体方法请参见：

> **说明**
>
> 方舟平台的新用户？获取 API Key 及 开通模型等准备工作，请参见 [快速入门](/docs/quick-start)。

> 创建推理接入点时，请选择支持视觉理解的大模型，具体可参见 [视觉理解能力](/docs/model-list#76df97c8)。

运行脚本前，请先在终端中安装依赖包。

```Bash
pip install opencv-contrib-python
pip install arkruntime
```

<span id="a8e78432"></span>
#### 实现脚本以及配置

配置您的变量，包括：
* `<VIDEO_FILE_PATH>`替换您的视频文件的路径。
* `<MODEL>`替换为模型的Model ID。
* `prompt = "描述视频内容"`配置您的文本提示，这里仅做示例使用。
* 选择您的抽帧策略。

```Python
...
# 1. CONSTANT_INTERVAL：固定时间间隔抽帧，可以调整时间间隔
# 2. EVEN_INTERVAL：固定总帧数均匀抽帧，可以调整总帧数
        extraction_strategy=Strategy.CONSTANT_INTERVAL,
        # extraction_strategy=Strategy.EVEN_INTERVAL,
...
```
<span id="a72e86f2"></span>
#### 完整的 Python 脚本

```Python
from typing import Optional
# Import the OpenCV library for video processing
import cv2
# Import the time library for timing
import time
# Import the file operation library for directory deletion
import shutil
# Import the enum library for defining frame extraction strategies
from enum import Enum

# Import the Base64 encoding library for converting images to Base64 strings
import base64
# Import the operating system library for file path operations
import os
# Install SDK: python -m pip install --upgrade arkruntime
from arkruntime import Ark
from arkruntime._exceptions import ArkAPIError


# Define the frame extraction strategy enumeration class
class Strategy(Enum):
    # Fixed interval frame extraction strategy, e.g., extract one frame every 1 second
    CONSTANT_INTERVAL = "constant_interval"
    # Even interval frame extraction strategy, extract frames evenly from the entire video based on the set maximum number of frames
    EVEN_INTERVAL = "even_interval"

def preprocess_video(
        video_file_path: str,
        output_dir: str,
        extraction_strategy: Optional[Strategy] = Strategy.EVEN_INTERVAL,
        interval_in_seconds: Optional[float] = 1,
        max_frames: Optional[int] = 10,
        keyframe_naming_template: str = "frame_{:04d}.jpg",
) -> list[str]:
    """Extract frames from video according to the specified strategy
    Args:
        video_file_path (str): Path to the video file
        output_dir (str): Output directory
        extraction_strategy (Optional[Strategy], optional): Frame extraction strategy.
             Constant interval (e.g., extract one frame every 1 second) or
             Even interval (extract frames evenly from the entire video based on the set maximum number of frames)
             Defaults to constant interval (1 frame per second).
        interval_in_seconds (Optional[float], optional): Time interval for constant interval frame extraction. Defaults to 1 second per frame.
        max_frames (Optional[int], optional): Maximum number of frames to extract. Defaults to 10 frames.
        keyframe_naming_template (_type_, optional): Naming template for extracted key frame images
    Returns:
        list[str]: List of paths to the extracted key frame images
    """
    # Check if the output directory exists; create it if it does not
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    # Open the video file using OpenCV
    cap = cv2.VideoCapture(video_file_path)
    # Get the frame rate of the video
    fps = cap.get(cv2.CAP_PROP_FPS)
    # Get the total number of frames in the video
    length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    # Select the frame interval based on the strategy
    if extraction_strategy == Strategy.CONSTANT_INTERVAL:
        # Calculate the frame interval for constant interval extraction
        frame_interval = int(fps * interval_in_seconds)
    elif extraction_strategy == Strategy.EVEN_INTERVAL:
        # Calculate the frame interval for even interval extraction
        frame_interval = int(length / max_frames)
    else:
        # Throw an exception if the strategy is invalid
        raise ValueError("Invalid extraction strategy")
    # Initialize the frame counter
    frame_count = 0
    # Initialize the list of key frames
    keyframes = []
    # Loop to read video frames
    while True:
        # Read one frame
        ret, frame = cap.read()
        # Exit the loop if frame reading fails
        if not ret:
            break
        # Check if the current frame is a key frame
        if frame_count % frame_interval == 0:
            # Generate the filename for the key frame
            image_path = os.path.join(
                output_dir, keyframe_naming_template.format(len(keyframes))
            )
            # Save the key frame as an image
            cv2.imwrite(
                image_path,
                frame,
            )
            # Add the key frame path to the list
            keyframes.append(image_path)
        # Increment the frame counter
        frame_count += 1
        # Exit the loop if the maximum number of key frames is reached
        if len(keyframes) >= max_frames:
            break

    print("[Video Frame Extraction Completed]")
    print("[Number of Extracted Frames]", len(keyframes))
    # Return the list of key frame paths
    return keyframes

def resize(image):
    """
    Resize the image to fit the specified dimensions.
    Args:
        image (numpy.ndarray): Input image in numpy array format.
    Returns:
        numpy.ndarray: Resized image.
    """
    # Get the original height and width of the image
    height, width = image.shape[:2]
    # Determine the target dimensions based on the image's aspect ratio
    if height < width:
        target_height, target_width = 480, 640
    else:
        target_height, target_width = 640, 480
    # Return the original image if its dimensions are already less than or equal to the target dimensions
    if height <= target_height and width <= target_width:
        return image
    # Calculate the new height and width while maintaining the image's aspect ratio
    if height / target_height < width / target_width:
        new_width = target_width
        new_height = int(height * (new_width / width))
    else:
        new_height = target_height
        new_width = int(width * (new_height / height))
    # Resize the image
    return cv2.resize(image, (new_width, new_height))

# Define a method to resize the image at the specified path to an appropriate size and convert it to Base64 encoding
def encode_image(image_path: str) -> str:
    """
    Encode the image at the specified path
    Args:
        image_path (str): Path to the image file
    Returns:
        str: Encoded image string
    """
    # Read the image
    image = cv2.imread(image_path)
    # Resize the image
    image_resized = resize(image)
    # Encode the image in JPEG format
    _, encoded_image = cv2.imencode(".jpg", image_resized)
    # Convert the encoded image to a Base64 string
    return base64.b64encode(encoded_image).decode("utf-8")

def construct_messages(image_paths: list[str], prompt: str) -> list[dict]:
    """
    Construct a list of messages containing text and images.
    Args:
        image_paths (list[str]): List of image file paths.
        prompt (str): Text prompt.
    Returns:
        list[dict]: List of messages containing text and images.
    """
    print("[Assembling Request Parameters]")
    # Initialize the content list with a text message
    content = [
        {
            "type": "text",
            "text": prompt,
        },
    ]
    # Iterate through the list of image paths
    for image_path in image_paths:
        # Construct an image URL message for each image path
        content.append(
            {
                "type": "image_url",
                "image_url": {
                    # Convert the image to a data URL using Base64 encoding
                    "url": f"data:image/jpeg;base64,{encode_image(image_path)}",
                    # Specify the image detail level as low
                    "detail":"low"
                },
            }
        )
    # Return the list of messages containing text and images
    return [
        {
            "role": "user",
            "content": content,
        }
    ]

if __name__ == "__main__":
    # Replace with the path to your video file
    video_path = "<VIDEO_FILE_PATH>"
    # API Key retrieved from environment variables; configure your API Key in advance
    ark_api_key = os.environ.get("ARK_API_KEY")
    # Replace <MODEL> with the Model ID of your model
    model_id = "<MODEL>"
    # Replace with your text prompt; this is for example use only
    prompt = "Describe the video content"
    since = time.time()
    # Delete historical frames
    if os.path.exists("videoFrames"):
        shutil.rmtree("videoFrames")

    selected_images = preprocess_video(
        video_file_path=video_path,
        output_dir="videoFrames",

        # Two frame extraction strategies
        # 1. CONSTANT_INTERVAL: Extract frames at a fixed time interval; adjust the interval as needed
        # 2. EVEN_INTERVAL: Extract a fixed total number of frames evenly; adjust the total number as needed
        extraction_strategy=Strategy.CONSTANT_INTERVAL,
        # extraction_strategy=Strategy.EVEN_INTERVAL,

        # Frame interval for constant interval extraction strategy
        interval_in_seconds=1,

        # Maximum number of frames to extract from the video
        max_frames=20
    )

    print("[Frame Image Compression Completed]")
    preprocess_time_cost = time.time() - since

    client = Ark(
        api_key=ark_api_key,
        base_url="https://ark.cn-beijing.volces.com/api/v3",
    )
    since = time.time()
    try:
        response = client.chat.completions.create(
            model=model_id,
            messages=construct_messages(
                selected_images,
                prompt,
            )
        )

        print("[Video Understanding Result]\n", response.choices[0].message.content)
        print("\n[Total Tokens Consumed]", response.usage.total_tokens)
        print("- Input Tokens:", response.usage.prompt_tokens)
        print("- Output Tokens:", response.usage.completion_tokens)

    except ArkAPIError as e:
        print(e)

    api_time_cost = time.time() - since
    print("\n[End-to-End Total Time Consumption]", round(preprocess_time_cost + api_time_cost, 2))
    print("- Video Preprocessing Time:", round(preprocess_time_cost, 2))
    print("- Result Generation Time:", round(api_time_cost, 2))
```

<span id="7bbc7eed"></span>
## Function Calling 样本要求

对于 Function Calling 样本，数据格式有以下几点特殊要求：
1. **`tools`** **字段 (必填)**：您必须在样本的顶层提供 `tools` 字段，其格式需与推理 API 的定义保持一致。
2. **`parallel_tool_calls`** **字段 (可选)**：这是一个布尔类型字段，默认值为 `True`。

    * 它用于声明该样本是否支持并行函数调用，其含义与推理 API 中的参数一致。

    * 如果您将此字段设为 `false`，但 `assistant` 的回复中又包含了多个 `tool_calls`，将会导致错误。
3. **`assistant`** **消息中的** **`tool_calls`** **字段**：在 `messages` 列表中，如果 `assistant` 的回复触发了函数调用，则该消息中必须包含 `tool_calls` 字段。

    * `tool_calls` 数组中的每个 `function` 对象都必须包含 `name` 和 `arguments` 两个键。

    * `arguments` 的值必须是一个合法的 JSON 格式字符串。
4. **`tool`** **角色的消息**：在 `messages` 列表中，用于表示函数调用返回结果的消息，其 `role` 必须为 `tool`。这类消息的 `loss_weight` 固定为 `0.0`，且不可修改。

以下是一个包含多轮对话和并行函数调用的完整精调样本示例：

```JSON
{
  "messages": [
    {
      "role": "system",
      "content": "你是豆包"
    },
    {
      "role": "user",
      "content": "把北京上海的天气发给Alan"
    },
    {
      "role": "assistant",
      "content": "分别查询北京和上海的天气。",
      "tool_calls": [
        {
          "type": "function",
          "function": {
            "name": "GetCurrentWeather",
            "arguments": "{\"location\": \"北京\"}"
          }
        },
        {
          "type": "function",
          "function": {
            "name": "GetCurrentWeather",
            "arguments": "{\"location\": \"上海\"}"
          }
        }
      ],
      "loss_weight": 1.0
    },
    {
      "role": "tool",
      "content": "北京天气晴，18~25°，微风"
    },
    {
      "role": "tool",
      "content": "上海天气阴，20~30°，大风"
    },
    {
      "role": "assistant",
      "content": "已经查到北京上海天气，需要发送给alan",
      "tool_calls": [
        {
          "type": "function",
          "function": {
            "name": "SendMessage",
            "arguments": "{\"receiver\": \"Alan\", \"content\": \"今天北京天气晴，18~25°，微风；上海天气阴，20~30°，大风\"}"
          }
        }
      ],
      "loss_weight": 1.0
    },
    {
      "role": "tool",
      "content": "发送成功"
    },
    {
      "role": "assistant",
      "content": "已经查到北京上海今日天气，发送给了Alan",
      "loss_weight": 1.0
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "MusicPlayer",
        "description": "歌曲查询Plugin，当用户需要搜索某个歌手或者歌曲时使用此plugin，给定歌手，歌名等特征返回相关音乐",
        "parameters": {
          "properties": {
            "artist": {
              "description": "表示歌手名字",
              "type": "string"
            },
            "description": {
              "description": "表示描述信息",
              "type": "string"
            },
            "song_name": {
              "description": "表示歌曲名字",
              "type": "string"
            }
          },
          "required": [],
          "type": "object"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "GetCurrentWeather",
        "description": "查询当前的天气",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "地理位置，比如北京市"
            },
            "unit": {
              "type": "string",
              "description": "温度单位",
              "enum": [
                "celsius",
                "fahrenheit"
              ]
            }
          },
          "required": [
            "location"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "LinkReaderPlugin",
        "description": "当需要解析网页内容时，调用本插件",
        "parameters": {
          "type": "object",
          "properties": {
            "url": {
              "type": "string",
              "description": "需要解析网页链接,最多3个；"
            }
          },
          "required": [
            "url"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "WebSearchPlugin",
        "description": "当需要搜索互联网内容时，调用本插件",
        "parameters": {
          "type": "object",
          "properties": {
            "keywords": {
              "type": "string",
              "description": "需要搜索的内容"
            }
          },
          "required": [
            "keywords"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "SendMessage",
        "description": "需要发送微信消息时，使用本函数",
        "parameters": {
          "type": "object",
          "properties": {
            "receiver": {
              "type": "string",
              "description": "接受对象"
            },
            "content": {
              "type": "string",
              "description": "需要发送的内容"
            }
          },
          "required": [
            "receiver"
          ]
        }
      }
    }
  ]
}
```

在实际的 `.jsonl` 文件中，上述示例应以单行形式呈现：

```Bash
{"messages":[{"role":"system","content":"你是豆包"},{"role":"user","content":"把北京的天气发给Alan"},{"role":"assistant","content":"","tool_calls":[{"type":"function","function":{"name":"GetCurrentWeather","arguments":"{\"location\": \"北京\"}"}}],"loss_weight":1.0},{"role":"tool","content":"北京天气晴，18~25°，微风"},{"role":"assistant","content":"已经查到北京天气，需要发送给alan","tool_calls":[{"type":"function","function":{"name":"SendMessage","arguments":"{\"receiver\": \"Alan\", \"content\": \"今天北京天气晴，18~25°，微风\"}"}}],"loss_weight":1.0},{"role":"tool","content":"发送成功"},{"role":"assistant","content":"已经查到北京今日天气，发送给了Alan","loss_weight":1.0}],"tools":[{"type":"function","function":{"name":"MusicPlayer","description":"歌曲查询Plugin，当用户需要搜索某个歌手或者歌曲时使用此plugin，给定歌手，歌名等特征返回相关音乐","parameters":{"properties":{"artist":{"description":"表示歌手名字","type":"string"},"description":{"description":"表示描述信息","type":"string"},"song_name":{"description":"表示歌曲名字","type":"string"}},"required":[],"type":"object"}}},{"type":"function","function":{"name":"GetCurrentWeather","description":"查询当前的天气","parameters":{"type":"object","properties":{"location":{"type":"string","description":"地理位置，比如北京市"},"unit":{"type":"string","description":"温度单位","enum":["celsius","fahrenheit"]}},"required":["location"]}}},{"type":"function","function":{"name":"LinkReaderPlugin","description":"当需要解析网页内容时，调用本插件","parameters":{"type":"object","properties":{"url":{"type":"string","description":"需要解析网页链接,最多3个；"}},"required":["url"]}}},{"type":"function","function":{"name":"WebSearchPlugin","description":"当需要搜索互联网内容时，调用本插件","parameters":{"type":"object","properties":{"keywords":{"type":"string","description":"需要搜索的内容"}},"required":["keywords"]}}},{"type":"function","function":{"name":"SendMessage","description":"需要发送微信消息时，使用本函数","parameters":{"type":"object","properties":{"receiver":{"type":"string","description":"接受对象"},"content":{"type":"string","description":"需要发送的内容"}},"required":["receiver"]}}}]}
```

**注意事项**
* `tool_calls` 数组中的函数调用数量，必须与后续 `role` 为 `tool` 的消息数量完全对应。
* 您必须遵循 JSON Schema 规范。在函数参数定义中，`type` 字段的值必须是以下类型之一，否则会导致错误：

    * `string`

    * `number`

    * `boolean`

    * `integer`

    * `object`

    * `array`
* 如果您希望模型在返回函数调用（`fc`）的同时输出思考过程（如 CoT、reasoning），请将这部分文本内容填写在 `content` 字段中。
* 如果您的训练样本不需要包含一个完整的函数调用流程，可以进行截断，但样本必须以一个 `role` 为 `assistant` 的消息结尾。

<span id="c680ed77"></span>
## **深度思考能力支持情况**

> **注意**
>
> Seed 2.0 260415 以上模型，RL 强化学习 rollout 过程的推理默认仅支持 thinking disable，不支持设置此项。

不同模型深度思考能力可配置的枚举值不同，详细信息请参见 [开启/关闭深度思考](/docs/deep-thinking#fa3f44fa)。

|模型版本 |enabled |disabled |auto |custom |
|---|---|---|---|---|
|doubao-seed-1.6｜250615 |✅ |✅（default） |✅ |❌ |
|doubao-seed-1.6-flash｜250615 |✅ |✅（default） |❌ |❌ |
|qwen |❌ |❌ |❌ |✅（default） |
|doubao-1.5-pro-32k｜250115 |❌ |✅（default） |❌ |❌ |
|doubao-1.5-lite-32k｜250115 |❌ |✅（default） |❌ |❌ |

* `enabled` 表示强制模型进行思考，此时模型rollout过程预期会输出reasoning_content
* `disabled` 表示强制模型不进行思考, 此时模型rollout过程预期不会输出reasoning_content。
* `auto` 表示允许模型根据问题自主判断是否需要思考，复杂问题进行思考，简单问题直接回答。
* `custom` 表示训练的数据预处理过程不就对 reasoning_content 内容做任何的校验与处理，在训练过程中，会按模型配套的 chat template 对数据进行处理。以 qwen 为例 ，样本内的 content 和 reasoning_content 会使用 https://huggingface.co/Qwen/Qwen3-32B/blob/main/tokenizer_config.json#L230 所示 chat template 逻辑进行处理。在推理时也需要使用custom type以及和训练相同的reasoning_content。
* 对于上述格式要求，存量数据集可参考 [数据集 Thinking 字段处理工具](/docs/multimodal-fine-tuning-data-format#9656cd75) 进行格式转换。
