面向 AI 助手:本页的 Markdown 版本位于 https://ark.volcengine.com/region:cn-beijing/docs/multimodal-fine-tuning-data-format.md,全部文档索引见 https://ark.volcengine.com/llms.txt。

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

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

本文适用于以文本作为输出的语言及多模态理解模型。训练样本可以只包含文本,也可以混合使用 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 模式详情请参见 深度思考能力支持情况,Function Calling 详情请参见Function Calling(函数调用)。

SFT 精调#

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

格式示例#

样本格式:为 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}]}

格式说明#

将 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 样本要求
content str/list 是 对话内容:
  • 当role为assistant:字符串格式
  • 当role为user/system:数组格式,支持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字段(图片地址)。
参考:图片文件要求
audio_url dict 条件必选
type为audio_url时
音频信息,包含url字段,支持 TOS 地址和 Base64。
参考:音频/视频文件要求
video_url dict 条件必选
type为video_url时
视频信息,支持 TOS 地址和 Base64,包含url字段,支持视频内嵌音频。
参考:音频/视频文件要求
fps float 否
type为video_url时
视频抽帧帧率,表示每秒抽取的帧数。
不填时使用模型默认抽帧策略;建议根据视频时长和任务效果按需配置
loss_weight float 否 仅 assistant 角色支持配置该字段,默认 1.0,取值范围 [0.0,1.0]。system 和 user 角色不支持该字段。
reasoning_content str 否 深度思考内容,仅允许最后一个assistant角色携带。
  • 如有优化多轮对话场景下深度思考能力的精调需求,请参考 多轮 reasoning_content 样本文件拆分。
  • 如多轮对话场景训练时仅最后一轮对话携带reasoning_content,模型将学习到在中间对话轮次不进行thinking,影响模型thinking效果。
extra dict 否 样本顶层的用户自定义扩展字段。extra中的 key 必须为 string 类型,value 类型不限制。
thinking object 否 深度思考能力控制:
  • 部分模型精调支持该字段。
type str 否 枚举值:enabled/disabled/auto/custom(不同模型支持范围不同,详情请参见 深度思考能力支持情况)。

直接偏好学习(DPO)#

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

格式示例#

样本格式:为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"}}

格式说明#

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

Plain
{
  "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字段(图片地址)。
参考:图片文件要求
audio_url dict 是(type=audio_url 时) 音频信息,包含url字段,支持 TOS 地址和 Base64。参考:音频/视频文件要求
video_url dict 是(type=video_url 时) 视频信息,支持 TOS 地址和 Base64,包含url字段,支持视频内嵌音频。参考:音频/视频文件要求
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(不同模型支持范围不同,详情请参见 深度思考能力支持情况)。

强化学习(GRPO/PPO)#

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

格式示例#

样本格式:为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"}}

格式说明#

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 样本要求

最后一个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字段(图片地址)。
参考:图片文件要求
video_url dict 是(type=video_url 时) 视频信息,支持 TOS 地址和 Base64,包含url字段,支持视频内嵌音频。参考:音频/视频文件要求
fps float 否 视频抽帧帧率,表示每秒抽取的帧数。仅在 type=video_url 时生效,不填时使用模型默认抽帧策略。
extra dict 否 样本顶层的用户自定义扩展字段,可用于携带 reward function 与 custom rollout 所需的信息。extra中的 key 必须为 string 类型,value 类型不限制。
thinking object 否 深度思考能力控制。支持该参数的模型选填,不支持的模型禁填。
type str 否 枚举值:enabled/disabled/auto/custom(不同模型支持范围不同,详情请参见 深度思考能力支持情况)。

继续预训练#

继续预训练支持以下几类样本组织方式:

  • 纯文本:适用于标准文本继续预训练。
  • 分段 content[]:适用于需要显式保留内容片段边界的场景。
  • 多模态 content[]:适用于图文、音频、视频等继续预训练样本。

格式示例#

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

Plain
{"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}]}

格式说明#

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

Plain
{
    "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。

图片文件要求#

图片格式要求#

  • 数据集文件大小:单数据集文件大小需控制在 2G 以下。

  • 图片规格:单张图片大小限制在 10M 以内,长宽比要小于 200。单图最大支持 5120 tokens,若超出此数值则会被采样到最大值(图片 token = 长像素 * 宽像素 / 784)。

  • 样本长度:单样本长度若超过模型训练窗口会被截断,图片按单张整体截断。不同模型的窗口大小,参考 选择模型。

  • 支持的图片格式:参见下表。

图片格式 文件扩展名 内容格式 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

图片传入方式#

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

1.(推荐)使用 TOS 存储图片#
  1. 创建存储桶(Bucket)用于存储文件(Object),例如创建如下结构。

创建存储桶详细步骤可见 对象存储控制台快速入门。

Bash
bucketname    #桶名称
├── sample  #桶内文件夹名称
    ├── data.jsonl
└── image   #桶内文件夹名称
    ├── xxx.png
    └── xxxx.png
  1. 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."
    }
  ]
}
2. 图片使用base64编码#
格式示例#

将图片进行 base64 编码后填入 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 以下,大文件可拆分为多个小文件。
附:图片编码方法#

以下是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}"
3. 图片使用相对路径#
格式示例#

以下为 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."}]}
    
格式说明#

为便于展示各个字段关系,将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 文件位于文件夹根路径。

视频抽帧图片序列#

视觉理解模型精调支持用户将视频抽帧为图片后,将时间戳和图片按顺序编排到训练集中。可参考 附3:对视频内容进行抽帧。

格式示例
样本格式:为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/相对路径"
          }
        }
      ]
    }
  ]
}

音频/视频文件要求#

以下要求仅适用于语言及多模态理解模型的音频、视频输入。视频生成模型的输入素材限制,请参见全模态输入。

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

音频文件限制

  • 支持 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),创建存储桶详细步骤可见 对象存储控制台快速入门。例如创建如下结构:

    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文件即可。

数据集 Thinking 字段处理工具#

您可以通过脚本将不含thinking的数据集转换为含thinking的数据集:

  • 对于数据集中不含reasoning_content的样本,将thinking赋值为disabled。
  • 含reasoning_content的样本,则赋值为enabled。

您可下载 此脚本 对数据集进行转换,使您的数据集符合精调模型数据格式规范。

多轮 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()
    

对视频内容进行抽帧处理#

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

代码流程#

  1. 视频文件读取:从本地路径读取视频文件。

  2. 对视频进行抽帧,可以支持 2 种策略:

    1. CONSTANT_INTERVAL:固定时间间隔抽帧,如 1s 一帧,时间间隔可以调整。

    2. EVEN_INTERVAL:固定总帧数均匀抽帧,如不管视频时长,总共抽 20 帧,抽取的总帧数可以调整。

  3. 压缩帧图像:为了降低网络传输时延,以及减少 token 用量,将图像等比例压缩至 640*480 以内。

  4. 请求视觉理解模型:组装请求体,包含提示词(Prompt)及所有帧图像的 Base64,并使用方舟ChatCompletion 接口调用模型服务。

示例代码#

环境配置#

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

创建推理接入点时,请选择支持视觉理解的大模型,具体可参见 视觉理解能力。

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

Bash
pip install opencv-contrib-python
pip install arkruntime

实现脚本以及配置#

配置您的变量,包括:

  • <VIDEO_FILE_PATH>替换您的视频文件的路径。
  • <MODEL>替换为模型的Model ID。
  • prompt = "描述视频内容"配置您的文本提示,这里仅做示例使用。
  • 选择您的抽帧策略。
Python
...
# 1. CONSTANT_INTERVAL:固定时间间隔抽帧,可以调整时间间隔
# 2. EVEN_INTERVAL:固定总帧数均匀抽帧,可以调整总帧数
        extraction_strategy=Strategy.CONSTANT_INTERVAL,
        # extraction_strategy=Strategy.EVEN_INTERVAL,
...

完整的 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))

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 的消息结尾。

深度思考能力支持情况#

不同模型深度思考能力可配置的枚举值不同,详细信息请参见 开启/关闭深度思考。

模型版本 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 字段处理工具 进行格式转换。