
简介YEDDA-py3是一款基于Python 3开发的中文文本细粒度标注工具面向NLP研究人员、算法工程师及数据标注团队可用于命名实体识别、事件抽取等任务的语料构建与质量管控同时兼容多种语言和符号。压缩包为zip格式共13个文件以3个Python脚本为核心辅以2个配置文件、2个pyc缓存以及图片、说明文档、许可证、日志等辅助内容整体约147KB目录与命名清晰便于快速部署查验。目前已有75人学习浏览该资源。通过源码可以查看工具启动流程、颜色方案、默认标注配置和日志记录逻辑README提供了使用说明便于复现与管理标注任务管理员模式相关代码支持标注进度与任务分配管理适合团队协作。资源还适合与既有NLP流水线结合作为中文语料预处理与标注的基础组件为构建高质量数据集提供支撑。 做了几轮命名实体识别NER项目的人基本都有过同款经历模型还没开始调参先被标注环节折腾掉半条命。要么是网页工具一传大文件就卡死要么是标注员之间的快捷键不统一、导出的格式五花八门最后清洗数据的时间比标注还长。我后来一直在用的方案是YEDDA-py3——一个面向文本实体标注的轻量开源工具拿到源码改一改就能跑也方便按项目需求二次开发。这篇文章就把我这几年用YEDDA-py3做中文标注的完整经验过一遍包括安装启动、标注操作、数据导出、源码改造和踩坑记录都是可以直接复用的东西。1. YEDDA-py3 是干什么的一个面向NER的轻量标注方案1.1 标注工具之争YEDDA 的定位自然语言处理项目的上限往往不取决于模型而取决于标注数据质量。模型只是去逼近标注结果里隐含的真实标准如果标准本身混乱再好的模型也白搭。所以标注工具的选择直接决定了一个NLP项目的效率和天花板。市面上的标注工具不少brat适合关系抽取和实体标注但部署起来偏重doccano界面现代化支持多用户协作但大型任务下偶尔卡顿基于Excel标注的团队也有但一致性和规范性很难保证。YEDDA的优势在哪它叫“Yet Another Entity Descriptor and Annotator”来自新加坡科技设计大学团队的工作核心目标就是做轻量级、快捷键驱动的span标注工具——说白了打开就能标、快捷键跑得快、数据格式透明并且源码结构简单到可以直接上手改。在YEDDA里一条文本的标注流程是这样的选中一段文字按一个数字快捷键给它指定实体类型再按回车提交这条实体标注就进入数据库了。整个过程不需要鼠标到处点菜单熟练之后标注速度可以非常快尤其是做中文命名实体标注时配合好的标注规范效率提升是很明显的。1.2 py3 版本修复了什么这才是重点原版YEDDA是基于Python 2开发的当时还没有太多问题但放到现在的环境中就麻烦了系统默认Python 3、pip安装包全是py3版本、数据库驱动和Flask框架的兼容性也会出问题。YEDDA-py3这个版本就是解决这些问题的关键——它把核心代码迁移到了Python 3同时修复了中文字符编码、PyQt版本适配等实际使用中的痛点。中文项目最容易踩的坑就是编码。Python 2时代用str混存中文导出文件经常变成乱码py3版本用Unicode处理全流程至少在编码这块省心很多。而且YEDDA-py3保留了源码级的可读性修改实体类型、增加标注功能、调整导出格式都不需要从头理解复杂的框架适合团队内部做定制。2. 环境搭建与快速启动从拉源码到打开标注界面2.1 依赖安装与源码获取先把项目源码拉下来git clone https://github.com/jiesutd/YEDDA.git cd YEDDA需要说明的是如果你拉到的还是老版本先确认分支或换到支持py3的fork版本。安装Python依赖时注意区分使用场景# Web 模式需要 Flask pip install flask # CLI 命令行模式需要 PyQt5 pip install pyqt5如果你是第一次用建议先只装Flask跑Web模式PyQt的依赖较重远程服务器上也没法用带GUI的CLI模式。国内网络环境下pip安装如果太慢记得配置清华或阿里云镜像源。2.2 启动Web标注界面推荐Web模式下只需要一条命令python server.py启动后浏览器访问 http://localhost:4567 就能看到标注界面这个端口是YEDDA默认的。我在几个项目里都是让标注员直接用浏览器操作无需安装任何本地环境团队协作非常方便。这里有个细节server.py默认绑定的是0.0.0.0还是127.0.0.1取决于版本如果是团队内多人访问确认端口开了防火墙如果只有本机使用绑定localhost就够了没必要暴露到局域网。启动时还有个容易忽略的地方——别把终端关了Flask的开发服务器是前台运行的。我见过有人启动后关掉终端然后页面打不开还以为是端口被占用。2.3 CLI模式与配置准备CLI模式不需要浏览器用PyQt画界面适合在本地桌面环境中使用python YEDDA.py第一次启动前建议先了解项目里的几个关键配置文件。实体类型定义文件通常在entity_type.txt之类的位置决定了快捷键对应的标签名。中文NER项目一般把标签配成PER、ORG、LOC、TIME等属性类型文件则留空或者预置B、I的前缀标签。另外从命名上也能看出YEDDA对数据源的预设它期待的数据文件是每行一个句子句子里的token用空格分隔。这个格式对英文很自然但对中文项目来说需要先分词或者按字符做标注下面第三节细说。3. 标注实操快捷操作、中文文本处理和效率技巧3.1 实体标注选文本、按快捷键、提交YEDDA的核心操作完全可以归纳成三个动作选中文本片段按数字快捷键指定实体类型然后提交保存。当你从文章里选中一个词或一句话时工具会读取当前的用户标签配置。比如给“张三”指定了PER类型那就在选中状态下按Ctrl11号快捷键对应PER界面里“张三”这个span就会挂上PER标记。整套流程中鼠标的角色被削弱到了最低限度标注员只需要在键盘上操作连续标注几十条文本的状态下手不用在键盘和鼠标之间来回切换这比Excel手工标效率高很多。几个常用快捷键我直接列出来Ctrl1~9给选中文本指定对应序号实体类型CtrlD删除当前选中的标注CtrlZ撤销上一步操作CtrlS保存当前进度CtrlB切换Blackout模式提交这个动作容易被忽略。有些版本中必须先把当前句子确认提交才会让标注信息正式进入存储如果直接切到下一句当前句子的标注可能还在编辑态。我的习惯是每完成一个句子就立即保存避免浏览器崩溃或误触刷新导致数据丢失。3.2 属性标注与BIO标签体系YEDDA不只做实体标注它还提供了属性标注的功能。实体标注回答的是“这段文字属于什么类型”属性标注回答的则是“这个token在这个实体中扮演什么位置角色”。最典型的用法就是BIO标签体系B表示实体开始I表示实体内部O表示非实体。在做NER数据准备时实体标注完成后还需要把标注结果转换成BIO序列给模型训练。比如“张三去了人民医院”这句话如果“张三”是PER“人民医院”是ORG那么转换后的标签序列就是“B-PER I-PER O O B-ORG I-ORG I-ORG I-ORG”。YEDDA的实体标注和属性标注结合起来相当于在标注阶段就把BIO标签结构定义清楚了导出后直接喂给模型省去了中间复杂的规则转换。3.3 中文标注的边界处理先分词还是按字符这是中文项目里必须想清楚的问题。YEDDA的底层逻辑是从选中的span生成标注token的边界由数据本身决定。英文天然按空格分词中文没有这个条件。如果你直接丢进去一串“我今天去了人民医院”工具不知道该把“人民医院”切分成几个token。中文NER有两种主流做法第一种是词级标注。先用分词工具如jieba把句子分好词每个词之间用空格分隔然后导入YEDDA。标注员选中“人民医院”这个词指定为ORG导出时就是词级BIO。优点是每个tag对应一个有意义的词可解释性强缺点是分词错误会直接影响标注结果而且不同类型实体对分词颗粒度的要求不一样。第二种是字符级标注。直接把每个汉字当作一个token字与字之间都加空格例如“我 今 天 去 了 人 民 医 院”。标注时选中“人民医院”整个span但转换标签时是四个字各自分配B-ORG、I-ORG、I-ORG、I-ORG。这种做法在医疗、法律等专业领域更常见因为领域术语很难被通用分词器正确处理而字符级标注不受分词误差影响。我的建议是如果做通用领域的NER词级标注体验更好如果是专业领域且术语复杂直接字符级标注模型效果往往更稳。你在实际项目中按这个原则选不会走太多弯路。3.4 Blackout模式质量检查的利器Blackout模式是YEDDA一个很有用的细节功能。开启之后界面会把已经标注出来的实体文本隐藏或者替换成占位符只显示尚未标注的内容。这样做的目的是强迫标注员把注意力集中在没标过的文本上而不是反复看自己已经标过的内容。这个模式适合两类场景一是单条长文本的查漏补缺二是统一的质量抽检。在标注合同文本或者医学病历这种长文本时人工很容易漏掉后半段的实体Blackout模式下没有标注的文本会非常显眼漏标率能明显降低。4. 数据导出与模型训练的无缝衔接4.1 内部存储格式与导出选项标注过程本身不是终点最终要落到模型训练。YEDDA的存储逻辑是分层级的原始文本文件保持不动标注信息以结构化的增量形式存储标注完成后可以通过工具自带的导出功能生成想要的格式。我在实际项目里更常用的方式是直接拉取标注好的数据然后用脚本转换。YEDDA的标注结果可以还原成语料原文加标签的形式只要理解了它的标签对应关系后续转成CoNLL格式、BIOES格式或者Hugging Face的Dataset格式都不难。关键是保证标签映射表只维护一份避免不同文件之间标签叫法不一致。4.2 转换为BIO格式的脚本示例下面是我自己写的一个简单转换脚本适用场景是“文本文件 标注信息文件”的结构化导出。假设内部表示里实体的边界和类型已知核心逻辑就是初始化所有token为O然后根据实体span覆盖到的位置赋予B-或I-标签def convert_to_bio(tokens, entities): tokens: 已经分好词的token列表例如 [我, 今天, 去, 了, 人民医院] entities: [(start, end, label), ...]start/end是token索引 n len(tokens) tags [O] * n for start, end, label in entities: if start 0 or end n or start end: continue tags[start] fB-{label} for i in range(start 1, end): tags[i] fI-{label} return list(zip(tokens, tags)) # 示例用法 tokens [我, 今天, 去, 了, 人民医院] entities [(4, 5, ORG)] result convert_to_bio(tokens, entities) for token, tag in result: print(token, tag)输出结果我 O 今天 O 去 O 了 O 人民医院 B-ORG这个例子里“人民医院”被分词工具识别成了一个词所以只有B-ORG如果是字符级标注token会是“人”“民”“医”“院”转换函数会正常输出B-ORG和三个I-ORG。多标签体系下可能需要根据训练框架的要求额外处理标签的合法组合但基础格式是一致的。4.3 标注一致性检查模型训练最怕的就是标注员之间的标准不一致。同一段“人民医院”A标注员标了ORGB标注员标了LOC模型学到的就是一套混乱的映射。YEDDA提供了一些辅助手段帮助检查一致性但更可靠的方式还是团队内部定期抽检。我的做法是每完成一批标注随机抽取10%~20%的数据让另一位标注员独立重标一遍然后计算标注一致性比如F1或Cohens Kappa。YEDDA的数据导出方便抽检对比做起来很快。这个过程虽然增加了一点时间成本但长期看能避免模型训练阶段发现数据质量问题的巨大返工代价。5. 源码结构分析与二次开发经验5.1 核心模块与数据流YEDDA-py3的源码结构不算复杂熟悉之后改起来很顺手。从功能模块来看大致可以分成四层交互层Web前端HTML/JavaScript和CLI界面PyQt负责接收用户操作服务层server.py基于Flask提供的HTTP接口处理前端请求并调用核心逻辑数据层标注数据的读写、存储、导出配置层实体类型、属性类型、用户配置等理解数据流是关键。用户在网页上选中文本、按下快捷键前端将这个操作封装成请求发送到Flask后端后端更新对应文本的标注状态并写入存储然后前端刷新界面显示新标注。标注数据并不直接改原文件而是采用了叠加式的管理方式这样即使标注有问题也能追溯。如果你需要做二次开发我建议从三个点入手一是看数据格式定义搞清楚标注信息在内部是如何关联到原文的二是看实体类型加载逻辑找到标签配置的入口三是看导出模块确认输出结果的转换规则。5.2 自定义实体类型的正确姿势实际项目中从来没有“只用PER和ORG就够了”这回事。医疗项目要标症状、药物、剂量法律项目要标条款编号、当事人、日期每个领域都得改标签体系。YEDDA定义一个实体类型核心就是在配置文件中增加对应条目并确保快捷键序号唯一。改完之后重启服务前端重新拉取配置新的实体类型就生效了。很多人在这一步容易忽略的是如果项目已经标了一部分数据修改标签定义时要保证旧数据里的标签名称不受影响。最好的做法是只新增不删除废弃的标签可以先留着最后导出时统一过滤。5.3 py3迁移与本地化踩坑记录YEDDA-py3虽然在框架层面解决了Python 2到3的主要问题但使用过程中还是有一些本地化细节需要注意。中文字符串处理是最典型的坑。Python 3默认str就是Unicode正常情况下不会乱码但如果你在Windows环境下用记事本打开UTF-8的语料文件另存为GBK编码后导入YEDDA界面就会出现乱码。我的习惯是所有语料文件统一UTF-8编码处理脚本和Python文件也在文件头声明编码能避免大量无意义的时间浪费。另外一个细节是PyQt5对PyQt4的API差异。CLI模式如果是从老版本升上来的部分信号槽语法和资源文件处理会不一样报错信息通常很隐晦。我的建议是除非确实需要离线GUI操作否则优先用Web模式部署和维护成本低很多问题也少。6. 实操中常见的坑和解决办法速查表以下问题都是我在真实标注项目中碰到过的整理成表方便对照排查现象可能原因解决办法启动server.py后页面打不开端口被占用或Flask还没完成启动检查4567端口占用情况或改启动脚本里的端口配置标注完切换句子后标注丢失忘了保存或还没提交当前句子养成每完成一句就保存的习惯确认当前句子已提交中文显示乱码语料文件不是UTF-8编码统一用UTF-8保存源文件文件头声明编码快捷键没反应页面焦点不在文本框里或快捷键冲突点击文本区域后再操作检查浏览器插件快捷键导出的BIO标签错位分词边界和实体边界不一致先确认分词结果或改用字符级标注多人标注时数据互相覆盖共享了同一个数据文件且没有区分用户每个标注员使用独立的工作目录或用户配置定期合并实体类型修改后旧数据变空白旧标签名在配置中被删除修改配置时只新增不删除保留历史标签这些坑看起来小但在实际项目中每一个都让我返过工。尤其是编码和保存这两个问题等数据标注到一万条时才发现补救成本会非常大。7. 一些流程层面的补充建议工具之外标注规范和管理流程往往更影响最终效果。团队里我会坚持两件事第一标注规范文档必须先行包含实体定义、边界判定标准、歧义处理原则每一条都配正反例第二进度管理不能只依赖工具定期导出数据做统计看看每天每个人的标注量和一致性问题早发现早处理。另外YEDDA这类工具虽然轻量好用但也不要追求一个工具解决所有场景。如果项目规模特别大、需要复杂的多人协作和流程审批可以考虑更完整的标注平台如果是几十个文件、几个标注员的内部项目YEDDA-py3这种轻量方案反而更高效省去平台部署和维护的精力。我的习惯是在标注阶段就用脚本做好数据快照每完成一批就备份一次哪怕后面发现标准需要调整至少还有恢复的余地。这种小习惯关键时刻能省下几天的工作量。本文还有配套的精品资源点击获取