一、背景知识
1. JSONLine 文件
JSONLine 文件是一种文本文件格式,它以 JSON 格式存储数据,但与标准的 JSON 文件不同,JSONLine 文件的每一行都是一个独立的 JSON 对象。这种格式使得数据易于阅读和解析,并且可以方便地与命令行工具和脚本一起使用。
标准的 JSON 文件通常包含一个数组或对象,其中包含多个数据项,它们被编码为一个单一的 JSON 结构。而 JSONLine 文件则是每行一个 JSON 对象,每个对象之间用换行符分隔。这使得 JSONLine 文件非常适合日志记录和流式数据处理,因为它可以轻松地逐行读取和处理数据。
例如,一个标准的 JSONLine 文件示例如下:
{"name": "Alice", "age": 25}{"name": "Bob", "age": 30}
每个 JSON 对象都是独立的,并且可以单独解析。这种格式在处理大量数据时非常有用,因为它允许逐行读取和处理,而不需要一次性加载整个文件到内存中。
在 LLM 领域,JSONLine 是非常常见的数据集文件格式。
2. JSON 的基本结构
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于 JavaScript 的一个子集,但是它是完全语言无关的,很多编程语言都支持 JSON 格式的数据交换。
对象:用大括号
{}
包围,由一系列的键值对组成,键值对之间用逗号 ,
分隔。例如:{"name": "Alice","age": 25,"isStudent": false}
数组:用方括号
[]
包围,可以包含任意数量的值,这些值可以是字符串、数字、对象、数组等,值之间用逗号 ,
分隔。例如:["apple", "banana", "cherry"]
键值对:键是字符串,值可以是字符串、数字、对象、数组、布尔值或null。键和值之间用冒号
:
分隔。例如:"name": "Alice"
3. YAML 文件
我们使用 YAML 文件格式来定义我们的标注模板,以下介绍下 YAML 文件的语法格式。
YAML(YAML Ain't Markup Language)是一种用于数据序列化的人类可读格式,常用于配置文件、数据交换、以及在不同编程语言之间传递对象。YAML 的设计目标是易于阅读和编写,同时也易于计算机解析和生成。
YAML 文件的基本结构包括以下几个特点:
1. 键值对:YAML 使用冒号加空格(
:
)来分隔键和值。2. 缩进:YAML 使用缩进来表示层级关系,通常使用空格缩进,而不是制表符(Tab)。
3. 列表:YAML 中的列表使用短横线(
-
)开始,每个列表项占一行。4. 字典/映射:YAML 中的字典或映射使用键值对表示,可以嵌套。
5. 注释:YAML 中的注释以井号(
#
)开始,持续到行尾。6. 多文档支持:YAML 可以在一个文件中包含多个文档,每个文档由三个连续的短横线(
---
)分隔。7. 数据类型:YAML 支持多种数据类型,包括字符串、布尔值、整数、浮点数、日期时间等。
8. 复杂结构:YAML 支持复杂的数据结构,如嵌套的列表和字典。
下面是一个简单的 YAML 文件示例:
# 这是一个注释name: John Doeage: 30married: truechildren:- name: Jane Doeage: 10- name: Jim Doeage: 8address:street: 123 Main Stcity: Anytownzip: 12345
在这个示例中,我们定义了一个包含个人信息的YAML文档,其中包括字符串(
name
)、整数(age
)、布尔值(married
)、列表(children
)和嵌套的字典(address
)。二、大模型标注场景
TI 平台数据中心支持 LLM/MLLM 等多模态数据集的导入和标注,并且我们的标注平台具备灵活的自定义数据解析能力,以及对标注页面的开放式编辑能力。
1. LLM 场景
常见的 LLM 场景的标注,一般是对单轮或者多轮的问答对进行标注。原始数据集的每一条样本都是一个 JSON 对象。例如:
单轮问题的样本示例如下:
{"instruction": "请简要回答下面的问题:","input": "您平时用什么投资理财方式?","output": "我一般采用银行储蓄,相对风险较低。"}
多轮问答的样本示例如下:
{"conversations": [{"from": "human","value": "保险是什么,可靠么?"},{"from": "model","value": "保险,是指投保人根据合同约定,向保险人支付保险费,保险人对于合同约定的可能发生的事故因其发生所造成的财产损失承担赔偿保险金责任,或者被保险人死亡、伤残、疾病或者达到合同约定的年龄、期限等条件时承担给付保险金责任的商业保险行为。正规渠道购买的保险都是安全可靠的。"},{"from": "human","value": "我想买一些投资理财类的保险,有哪些险种?"},{"from": "model","value": "年金保险、分红险、投连险等。"}]}
2. MLLM 场景
MLLM 多模态标注场景一般还会涉及到图片等资源的展示和处理。
在样本数据中,我们一般在 JSON 数据中引用图片的相对路径,并且把图片放在对应的目录下。
图片内容标注的示例如下:
{"img": ["images/100230144.jpeg"],"target": [{"question": "请提供一幅生动的图像描述。","answer": "图像中展示了一个玩具娃娃在包装盒内。包装盒主要为白色,有一个透明塑料窗口,可以清楚地看到里面的娃娃。盒子上方印有“Pop! Movies”字样,下方写着“Home Alone”,表明这是一个以电影《小鬼当家》为主题的收藏品。娃娃被标记为“Kevin”,红色字体清晰可见,系列编号为491。这个娃娃造型简洁,是Funko Pop!风格,大大的黑色眼睛,小巧的鼻子,没有嘴巴,留着短发。他穿着一件红色带有毛绒设计的毛衣和绿色裤子。左手持有一把步枪,右手握着一把铁熨斗,这两样道具都保持了简约的设计,细节不多。娃娃直立站立,棕色鞋子透过绿色裤子可见。包装盒的侧面是红色,底部前部是绿色,上面有额外的品牌和警告标签,通常出现在收藏品包装上,还有一项警示,提示可能存在窒息风险。"}]}
三、TIONE 标注平台设计
为了能够在标注工作台上方便的修改这些样本数据,我们需要把每一条样本记录转化成前端多个标注组件的页面组件,并在组件内填充好样本数据。
结合内部算法对数据处理过程的观察和调研,我们设计了数据集 schema 的概念,通过约定的 Schema 语法结构、内置的组件功能,支持用户方便的通过原始数据内容,搭建标注页面,进行数据标注、更新等编辑过程。
标注页面的设计分为两步:
1) 基于原始数据,定义需要的标注组件;
2) 从原始样本数据解析数据,填充到对应的标注组件;
示例如下:


1. 标注组件定义
基于对算法标注场景的梳理,我们定义了如下的内置标注组件:
标注组件 | 说明 | 属性 | 备注 |
TextViewer | 文本展示框 | type | 组件类型:TextViewer |
| | name | 字段名称标识(可使用中文),e.g. question |
| | key | 字段对应标注后输出文件的json key(字母,下划线,数字),e.g. question |
| | help | 标注建议,e.g. “请填写答案” |
| | size | 文本框大小,取值类型为:SingleLine,MultiLine,LongArticle |
| | value | 默认值 |
TextInput | 文本输入框 | type | 组件类型:TextInput |
| | name | 字段名称标识(可使用中文),e.g. question |
| | key | 字段对应标注后输出文件的json key(字母,下划线,数字),e.g. question |
| | help | 标注建议,e.g. “请针对图片,填入问题的建议答案” |
| | size | 文本框大小,取值类型为:SingleLine,MultiLine,LongArticle |
| | value | 输入框的默认值 |
StringSelector | 字符串类型选择按钮(单选/多选) | type | 组件类型:StringSelector |
| | name | 字段名称标识(可使用中文) |
| | key | 字段对应标注后输出文件的json key(字母,下划线,数字) |
| | option | 单选/多选配置:SingleSelector / MultiSelector |
| | help | 标注建议,e.g. “请判断所提供的答案是否正确” |
| | choices | 数组类型,可选选项的枚举,e.g. [正确, 错误, 待定] |
| | value | 数组类型,默认选项,e.g. [正确] |
ImageViewer | 单张图片展示框 | type | 组件类型:ImageViewer |
| | name | 字段名称标识(可使用中文) |
| | key | 字段对应标注后输出文件的json key(字母,下划线,数字) |
| | help | 标注建议,e.g. “请参考以下图片” |
| | value | 图片相对数据集的相对路径 e.g. cat.jpeg |
ImageListViewer | 多张图片展示框 | type | 组件类型:ImageListViewer |
| | name | 字段名称标识(可使用中文) |
| | key | 字段对应标注后输出文件的json key(字母,下划线,数字) |
| | help | 标注建议,e.g. “请参考以下图片” |
| | value | 数组类型,图片相对数据集的相对路径列表:[cat.jpeg, dog.jpeg] |
ImageListInput | 多张图片展示框,同时可增加或删除图片(至少需要有一张图片) | type | 组件类型:ImageListInput |
| | name | 字段名称标识(可使用中文) |
| | key | 字段对应标注后输出文件的json key(字母,下划线,数字) |
| | help | 标注建议,e.g. “请参考以下图片” |
| | value | 数组类型,图片相对数据集的相对路径列表:[cat.jpeg, dog.jpeg] |
List | 组件列表类型。列表每一项可包含多个组件 | type | 组件类型:List |
| | name | 字段名称标识(可使用中文) |
| | key | 字段对应标注后输出文件的json key(字母,下划线,数字) |
| | help | 标注建议,e.g. “请参考以下图文信息” |
| | value | [][]field 双层嵌套列表,其中每一个元素为一个[]field,元素内横向排布,元素之间纵向排布 |
ImageBoxList | 图片上的多个标注框 | type | 组件类型:ImageBoxList |
| | name | 字段名称标识(可使用中文) |
| | key | 字段对应标注后输出文件的 json key(字母,下划线,数字)。 |
| | help | 标注建议,e.g. “请在图上标注内容” |
| | value | [][]field 双层嵌套列表,其中每一个元素为一个[]field,内含一个框上要标注的字段(待标注内容只能为 TextInput/StringSelector/Box)。 |
Box | 标注框的坐标。在标注操作台画框时隐式生成,无需手动填写。 | type | 组件类型:Box |
| | name | 字段名称标识(可使用中文) |
| | key | 输入文件中框的 json key,必须固定为"box"。 |
| | help | 标注建议,e.g. “请在图上框选内容” |
| | value | 框坐标经 json 序列化得到的的一个字符串。 |
以下是每种标注组件的详细 yaml 配置介绍。
TextViewer
只读的文本展示框,不可修改。
# name: 字段名称标识(可使用中文),长度不超过100字节name: 问题# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: question# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: TextViewer# size: 文本框大小。取值类型为:SingleLine,MultiLine,LongArticlesize: MultiLine# value: 该组件可从样本数据的取值语法value: "{{ .Values.question }}"
TextInput
可编辑的文本展示框。
# name: 字段名称标识(可使用中文),长度不超过100字节name: 问题# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: question# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: TextInput# size: 文本框大小。取值类型为:SingleLine,MultiLine,LongArticlesize: MultiLine# value: 该组件从样本数据的取值语法.value: "{{ .Values.xxxx }}"
StringSelector
字符串类型选择按钮(单选/多选) 。
# name: 字段名称标识(可使用中文),长度不超过100字节name: 问题# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: question# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: StringSelector# option: 指明是单选还是多选;SingleSelector-单选;MultiSelector-多选option: SingleSelector# choices: 可选的选项列表choices:- 正确- 错误- 待定# value: 选择的值。单选是长度为1的数组; 多选长度可以大于等于1;value:- 正确
ImageViewer
单张图片展示框, 不可编辑。
# name: 字段名称标识(可使用中文),长度不超过100字节name: 单张图片# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: imgpath# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: ImageViewer# value: 图片的相对路径,从样本数据imgpath取值value: "{{ .Values.imgpath }}"
ImageListViewer
多张图片展示框。
# name: 字段名称标识(可使用中文),长度不超过100字节name: 图片列表# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: imgs# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: ImageListViewer# value: 列表图片的相对路径,从样本数据的imgs取值value:# 使用循环引用图片列表{{- range .Values.imgs }}- {{ . }}{{- end }}
ImageListInput
多张图片展示框,同时可增加或删除图片(至少需要有一张图片)。
# name: 字段名称标识(可使用中文),长度不超过100字节name: 图片列表(可修改)# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: imgs# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: ImageListInput# value: 列表图片的相对路径,从样本数据的imgs取值value:# 使用循环引用图片列表{{- range .Values.imgs }}- {{ . }}{{- end }}
List
组件列表类型,用于复杂数据类型的排版。
组件的值为双层嵌套列表,其中每一个元素为一个组件的列表,元素内横向排布,元素之间纵向排布。
注意:当前不支持 List 内嵌List / ImageListViewer / ImageListinput 组件。
# name: 字段名称标识(可使用中文),长度不超过100字节name: 问答对# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: qa_chunks# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: List# value: 该组件从样本数据的取值语法: [][]field双层嵌套列表,其中每一个元素为一个[]fieldvalue:# 使用循环展开列表内容,列表的每一项是一个组件列表,列表元素间纵向分布,列表项内横向分布{{- range .Values.qa_chunks }} # 表明从单个json样本中的qa_chunks数组循环展示# 列表项内的第一个组件- - name: question # 标注工作台展示的标注组件名称key: question # 导出json标注结果时候该组件对应的json字段keytype: TextViewer # 表明该组件类型是文本展示框,不可编辑size: MultiLine # 表明该字段是多行行文本框,字段取值范围:SingleLine/MultiLine/LongArticlevalue: "{{ .question }}" # 表明从单个json样本中的qa_chunks数组里面单个元素的question字段取值# 列表项内的第二个组件- name: 修改后的response # 标注工作台展示的标注组件名称key: modified_response # 导出json标注结果时候该组件对应的json字段keytype: TextInput # 表明该组件类型是文本输入框size: MultiLine # 表明该字段是多行行文本框,字段取值范围:SingleLine/MultiLine/LongArticlevalue: "{{ .response }}" # 表明文本输入框的默认值为从单个json样本中的qa_chunks数组里面单个元素的response字段取值# 列表项内的第三个组件- name: response # 标注工作台展示的标注组件名称key: response # 导出json标注结果时候该组件对应的json字段keytype: TextViewer # 表明该组件类型是文本展示框,不可编辑size: MultiLine # 表明该字段是多行行文本框,字段取值范围:SingleLine/MultiLine/LongArticlevalue: "{{ .response }}" # 表明从单个json样本中的qa_chunks数组里面单个元素的response字段取值{{- end }}
ImageBoxList
图片上的标注框,可以自定义标注字段。
如果只有图片,没有预标注的数据,需要手动添加一个定义待标注字段的列表:
# name: 字段名称标识(可使用中文),长度不超过100字节name: image_box_list# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: image_box_list# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: ImageBoxList# value: 该组件从样本数据的取值语法: [][]field双层嵌套列表,其中每一个元素为一个[]fieldvalue:- # 定义待标注字段- name: 文本内容 # 标注工作台展示的标注组件名称key: text # 导出json标注结果时候该组件对应的json字段keytype: TextInput # 文本输入框size: LongArticle # 表明该字段是多行行文本框,字段取值范围:SingleLine/MultiLine/LongArticlevalue: "" # 没有预标注的情况下,每个字段可以赋一个空值- name: 文本类型 # 标注工作台展示的标注组件名称key: type # 导出json标注结果时候该组件对应的json字段keytype: StringSelector # 字符串选择器option: SingleSelector # 单选还是多选choices: # 候选项,是一个列表- 正文- 标题1- 表格value: # 选择的值。单选是长度为1的数组; 多选长度可以大于等于1;- "" # 没有预标注的情况下,可以赋一个空值
如果有预标注的数据,除了标注字段,需要配置框坐标box的提取:
# name: 字段名称标识(可使用中文),长度不超过100字节name: image_box_list# key: 字段对应标注后输出文件的json key(仅支持字母,下划线,数字,长度不超过100字节)key: image_box_list# help: 字段详细说明, 用于标注台展示帮助信息help: 请参考以下问题# type: 组件类型type: ImageBoxList# value: 该组件从样本数据的取值语法: [][]field双层嵌套列表,其中每一个元素为一个[]fieldvalue:{{- range .Values.image_box_list}} # 表明从单个json样本中的image_box_list数组提取标注内容- # 定义待标注字段- name: 文本内容 # 标注工作台展示的标注组件名称key: text # 导出json标注结果时候该组件对应的json字段keytype: TextInput # 文本输入框size: LongArticle # 表明该字段是多行行文本框,字段取值范围:SingleLine/MultiLine/LongArticlevalue: "{{ .text }}"- name: 文本类型 # 标注工作台展示的标注组件名称key: type # 导出json标注结果时候该组件对应的json字段keytype: StringSelector # 字符串选择器option: SingleSelector # 单选还是多选choices: # 候选项,是一个列表- 正文- 标题1- 表格value: # 选择的值。单选是长度为1的数组; 多选长度可以大于等于1- 正文- name: 框坐标 # 标注工作台展示的标注组件名称key: text # 导出json标注结果时候该组件对应的json字段keytype: Box # 框坐标value: "{{ .box }}"
Box
标注框的坐标,只能在ImageBoxList中使用。具体使用可以参考ImageBoxList。
2. 解析语法定义
解析语法的本质是需要定义从 JSON 格式的key值中取值,填充到模板定义中。
解析语法我们采用了基于 Go 模板语法的Helm Chart 的 YAML 渲染语法。
模板语法使用双花括号
{{ }}
来包裹模板指令。根节点为.Values,包含用户提供的 JSONLine 样本文件中的每一条记录的值。
data:myvalue: {{ .Values.myvalue }}
基本取值
一行 JSON 样本的对象如下:
{"question": "question","answer": "answer"}
我们可以使用如下的取值语法:
question: {{ .Values.question }}answer: {{ .Values.answer }}
数组元素取值
如果 JSON 是数组,我们需要需要取值数组的第一个元素。
一行 JSON 样本的对象如下:
{"question_list": ["question1","question2","question3"]}
我们可以使用如下的取值语法:
question: {{ index .Values.question_list 0 }} #索引0代表第一个元素
数组转换成模板数组
如果 JSON 是数组,我们需要需要取值数组的所有元素,并转换成 YAML 模板里面的列表。
一行 JSON 样本的对象如下:
{"qa_list": [{"question": "question1","answer": "answer1"},{"question": "question2","answer": "answer2"},{"question": "question3","answer": "answer3"}]}
我们可以使用如下的 range 取值语法:
{{- range .Values.qa_list }}# 注意内部取值是相对于range qa_list的相对路径- question: {{ .question }}answer: {{ .answer }}{{ end }}
模板渲染之后为:
- question: question1answer: answer1- question: question2answer: answer3- question: question3answer: answer3
一般以上语法即可完成基本的 schema 定义需求。如果您有更复杂的业务数据,可以参考 helm chart 语法定义您的 schema。
3. schema 模板定义
将以上组件拼接起来,并且用模板语法定义变量,我们就可以定义我们的 schema 模板。
场景:筛选高质量文本问答对
例如我们的样本的每一行都是 QA 问答对。如下:
{"question": "你平时用什么投资理财方式?","answer": "我一般采用银行储蓄,相对风险较低。但偶尔也想要尝试一些风险可能高一点,收益也更高的理财方式,但我不知道如何选择。"}
我们定义如下的标注 schema:
desc: 筛选高质量的大模型训练数据record_fields:# 标注工作台展示的第一个组件定义- name: question # 标注工作台展示的标注组件名称key: question # 导出json标注结果时候该组件对应的json字段keyhelp: 请参考以下问题 # 组件帮助说明type: TextViewer # 表明该组件类型是文本展示框,不可编辑size: SingleLine # 表明该字段是单行文本框,字段取值范围:SingleLine/MultiLine/LongArticlevalue: "{{ .Values.question }}" # 表明该字段的内容来源是单个json样本中的question字段# 标注工作台展示的第二个组件定义- name: answer # 标注工作台展示的标注组件名称key: answer # 导出json标注结果时候该组件对应的json字段keytype: TextInput # 表明该组件类型是文本输入框help: 请修正问题答案 # 组件帮助说明size: MultiLine # 表明该字段是多行行文本框,字段取值范围:SingleLine/MultiLine/LongArticlevalue: "{{ .Values.answer }}" # 表明该字段的默认内容来源是单个json样本中的answer字段# 标注工作台展示的第三个组件定义- name: 是否正确 # 标注工作台展示的标注组件名称key: correct # 导出json标注结果时候该组件对应的json字段keytype: StringSelector # 表明该组件类型是字符串选择组件help: 请判断答案是否正确 # 组件帮助说明option: SingleSelector # 表明该组件是单选。字段取值范围:SingleSelector/MultiSelectorchoices: # 指定选项的内容- 正确- 舍弃- 存疑value: # 可以指定默认选中的选项,数组类型,单选为1个,多选可设置多个。- 正确# 标注工作台展示的第四个组件定义- name: 舍弃存疑原因 # 标注工作台展示的标注组件名称key: correct_reason # 导出json标注结果时候该组件对应的json字段keytype: StringSelector # 表明该组件类型是字符串选择组件option: MultiSelector # 表明该组件是多选。字段取值范围:SingleSelector/MultiSelectorhelp: 答案不正确的原因 # 组件帮助说明choices: # 指定选项的内容- 无错误- 逻辑错误- 答非所问- 缺失内容value: # 指定默认选中的选项,数组类型,单选为1个,多选可设置多个。- 逻辑错误- 缺失内容
最终可以渲染得到如下的标注台和标注内容:

