核心问题:能不能让 decoder-only 因果 LLM 像 BERT 那样做逐 token 分类式的 NER?BERT 类编码器有双向注意力,天然适合打标签,但参数小(<1B)、世界知识少;LLM 知识丰富,可因果掩码让每个 token 看不到后文,无法消歧,于是所有 LLM-NER 方案都退回到「让模型生成实体列表」——慢、贵、还会幻觉出原文没有的实体。
JPT 的做法:把输入抄两遍拼成一条序列(x₁…xₙ [SEP] x₁…xₙ)。因果掩码不变,但第二遍的每个 token 都排在第一遍全部 token 之后,于是能「回看」完整句子——白拿双向上下文,模型结构一行不改。分类时只取第二遍 token 的 hidden state。
第二个部件:用自然语言「定义」而不是标签名来表示实体类型,并且定义同时注入 prompt 文本和 embedding 向量两条通道。这让用户能直接用一句话规定边界情况(比如 PRICE 要不要包含「budget-friendly」)。
效果:CrossNER + MIT 上平均 74.1 F1,比之前最好的 SaM 高 7.9 分;同时比生成式方法快 20 倍以上——因为翻倍的输入全在并行的 prefill 阶段吃掉,而生成式的开销在串行的 decode 阶段。
先约定几个说法,全文保持一致:
NER 最经典的做法是逐 token 打标签:给句子里每个 token 分配一个类型,然后把连续同类的 token 合并成实体 span。BERT / RoBERTa / DeBERTa 这类双向编码器天生适合这件事——每个 token 都能同时看到左右上下文。GLiNER、NuNER 等一批 NER 系统都建立在这个范式上。
但编码器有个硬天花板:通常不到 1B 参数,上下文窗口小,世界知识远不如大模型。碰到 CrossNER 里的 AI、文学、音乐这类需要领域常识的场景,编码器就吃力了。
LLM 知识够了,但它是因果注意力:处理第 i 个 token 时只能看到 x₁…xᵢ。论文用一个例子说明这为什么致命——
句子 “Paris released a new album” 中,把 Paris 判成人名而非城市的唯一依据是后半句「发了一张新专辑」。因果掩码恰好把这条线索挡在了外面——这正是 decoder-only LLM 做不了标准 token 分类的根本原因。
于是几乎所有 LLM-NER 工作都绕开了 token 分类,改用生成式抽取:把实体类型写进 prompt,让模型吐出实体列表。这条路避开了架构问题,却引入三个新的:
所以这篇论文真正要回答的是:能不能把编码器时代成熟的 token 分类范式,原封不动搬到因果 LLM 上?
在看 JPT 之前,先理清三类相关工作各自的位置:生成式 LLM 方案提供了知识但牺牲了效率,编码器判别式方案效率高但容量受限,已有的双向化技巧要么需要特殊预训练,要么和 JPT 的目标不同。下面每张卡片折叠时已给出它在本文论证中的角色和留下的缺口,展开可看方法细节。
让 decoder 拿到双向上下文并不是新问题,论文列了三条已有路子,并说明为什么它们都不能拿来即用:
一个需要如实说明的例外:Mistral 系列是个特例——对它去掩码几乎不掉分,NER 上甚至略有提升,逐层表示相似度也保持很高。两篇论文给出了同一个猜测:Mistral 的预训练里可能混入了某种双向或 prefix-LM 成分。所以准确的说法不是「去掩码一定失败」,而是它不可靠、且依赖你恰好挑中哪个模型——而一个只在特定 backbone 上成立的做法,很难称之为方法。
JPT 的做法绕过了以上全部前提:掩码是标准的下三角,权重是现成的,什么都不用重新预训练。它只是让同一句话在序列里出现两次,于是第二次出现时,模型在完全常规的因果计算下就自然拥有了完整上下文。这也是为什么论文反复强调「requires no architectural modifications」——这不是修辞,而是它相对上述三条路子的核心区别。
值得一提的是,FIM 在机制上其实是三者里离 JPT 最近的:它同样只靠重排 token 序列、不碰掩码。区别在于 FIM 的重排只有被它训练过的模型才看得懂(<PRE>/<SUF>/<MID> 这些标记不在普通模型的词表里),而「把话说两遍」对任何因果 LLM 都是合法的——第二遍不过是一段前面碰巧有相同内容的普通文本。
把这些放在一起,缺口就很清楚了:要么有双向上下文但模型太小(编码器),要么模型够大但只能生成(LLM),要么需要改预训练(Prefix-LM / FIM)。JPT 想同时拿到「大模型的知识」和「双向的上下文」,而且不改架构、不重新预训练——剩下唯一能动的地方,就是输入本身。
JPT 由两个正交的部件拼成:输入复制解决「看不到后文」,定义制导实体类型解决「怎么零样本泛化到没见过的类型」。最后用一个双线性分类器把 token 和类型在共享空间里对齐。
图 2(论文原图):上半部分是实体类型编码通路(可离线预计算并缓存),下半部分是token 通路。雪花 = 冻结,火焰 = 可训练。
展开说明 ▸给定输入 x = (x₁, …, xₙ),JPT 构造这样一条序列:
这就是全文的核心 trick,而且它没有修改任何注意力机制——掩码还是标准的下三角,模型还是那个模型。变的只是「同一句话在序列里出现了两次」,于是第二次出现时,它的每个 token 天然排在完整句子之后。
下面这个演示可以直接感受这件事。点击任意 token,看它在因果掩码下能看到哪些位置:
点击一个 token 作为「查询」,高亮的是它在因果掩码下可以 attend 到的全部位置。
切到 JPT 模式点第二遍的 Paris 就能看到:它前面站着一整句完整的话。「未来上下文」被搬到了它的过去。
论文里还有一个容易忽略但很实在的实现细节:所谓的 [SEP] 在真实 prompt 里不是特殊 token,而是一句大白话。整条输入长这样:
<|im_start|>system You are an information-extraction assistant. Task: Perform Named Entity Recognition (NER) on the user-supplied text. The user will give you the supported entity types and their definitions. The user will give you the text twice in the format "The first time: 'actual text' The second time: 'actual text'". Rules: (1) Keep multi-word entities together; (2) Only use provided types; (3) Output once; (4) No bare-noun labelling; (5) Output types exactly as listed; (6) Only label if clearly matches definition. <|im_end|> <|im_start|>user Supported entity types (3): ["PERSON", "ORGANIZATION", "LOCATION"] Entity type definitions: - "PERSON": "A named individual, including fictional characters" - "ORGANIZATION": "A company, institution, or group with a formal name" - "LOCATION": "A geographical place such as a city, country, or landmark" <|im_end|> <|im_start|>assistant I have read the definitions. Please provide the text in the format 'The first time: ... The second time: ...' <|im_end|> <|im_start|>user The first time: '<Input_Sequence>' The second time: '<Input_Sequence>' <|im_end|>
几点值得注意:(1) 分隔符就是 ' The second time: ' 这句自然语言,不需要新增词表;(2) 中间那轮 assistant 回复是硬编码的,作用是让对话格式合法、并把定义和文本分成两个 user 轮;(3) system prompt 里写满了「输出格式」规则,但模型其实什么都不生成——这些规则只是为了让分布贴近 backbone 熟悉的指令模式;真正的输出来自分类头。
第二个设计针对零样本泛化。常规做法是把类型名(PERSON)编码成向量,这依赖标签名本身的表层语义;JPT 改成编码一整段定义:
好处是解耦了模型和固定标签词表——新类型在推理时用一句话描述即可,无需重训。更进一步,定义给了用户对边界情况的直接控制权。论文举的例子:
LOCATION: “Any word indicating WHERE: explicit place names (Boston, downtown), relative indicators (nearby, around), directional words (east, south side).”
写不写「relative indicators」,直接决定了 nearby 会被标成地点还是当普通形容词忽略。这把 JPT 从「一个固定的 NER 模型」变成了可控的信息抽取器。
定义走两条通道同时注入,这是论文强调的「dual-channel」:
定义被文本编码器编码成 pj,供分类器与 token 向量做匹配。作用在分类阶段。
因为定义推理时不变,这条通路可离线算好缓存,不增加任何运行时延迟。
定义列表原样写进 LLM 的输入 prompt。作用在编码阶段——LLM 的注意力在处理每个 token 时可以直接看这些定义。
消融显示两条通道互补:单用任一条只有有限提升,合起来比不用定义高 +12.6 F1。
token 向量 ti 和类型向量 pj 都在 256 维共享空间里,打分方式是一个双线性形式:
注意 O 类不是「其他」兜底桶,而是一个有定义的正常类别(“A token that is not part of any named entity”),同样走 embedding 通路。
论文正文为简洁只写了单个双线性打分器,实际实现用了两个共享同一套 t 和 p 的头,最终预测取两者概率的平均:
这个 ensemble 比单 softmax 头提升 1–2 F1。论文明确说明核心方法(输入复制 + 定义制导)与这个选择无关。有意思的是,sigmoid 头的独立按类概率也是论文提到的未来支持嵌套实体的路径:让重叠 span 同时输出多个概率 > 0.5 的类型。
backbone 全程冻结,可训练的只有三样:注意力投影上的 LoRA 适配器、两个投影 MLP、以及双线性分类器。合计 JPT-4B 是 38.8M(0.95%),JPT-8B 是 142.8M(1.71%)。4×H100 上训 5 个 epoch 只要约 1.5 小时。
损失只在第二遍的 token 上计算——第一遍的隐状态从头到尾只是给第二遍当上下文用的,不参与监督。
训练数据的构造方式本身挺值得一看,而且直接支撑了「定义制导」的动机:
为什么类型数这么夸张地多?因为类型分布是长尾的——中位数每个类型只有 4 次提及,71% 的类型出现不超过 10 次。这种分布下模型根本没法靠记忆频繁模式取胜,只能被迫去读定义的语义。长尾在这里是特意设计的训练信号,不是数据缺陷。
训练集里出现的类型包括 EARTHQUAKE、TIMEZONE、RACECATEGORY 这类相当细的类别。作者强调这份数据与任何评测 benchmark 都无重叠——即使 PERSON、LOCATION 这类常见类型出现过,用的也是不同的定义,所以评测确实是零样本的。
这是最容易被直觉误导的一点:JPT 把序列长度从 N 变成了 2N,听起来应该更慢。但对熟悉推理栈的人来说,答案一句话就够——它把开销从 decode 阶段挪到了 prefill 阶段。
延迟随输出长度增长。每生成一个 token 都要把整个模型权重从 HBM 读一遍,只为做一步计算——串行、memory-bound、算力大量闲置。
UniNER 更极端:它一次只查一个实体类型,17 个类型的 CrossNER-AI 就是 17 轮完整解码。
2N 个 token 一次性并行算完,compute-bound、GPU 利用率高。之后没有任何自回归步骤,分类头一次出全部标签。
相当于拿便宜的并行输入 token换掉了昂贵的串行输出 token——这也正是 API 定价里输出比输入贵 3–5 倍的同一个原因。
实测(CrossNER-Politics,同一张 A100,batch size = 1):
| 方法 | 类别 | 成本 ($) ↓ | 耗时 (秒) ↓ | F1 ↑ |
|---|---|---|---|---|
| UniNER-7B | 生成式 | 2.77 | 1970.2 | 61.8 |
| GNER | 生成式 | 8.21 | 5831.5 | 75.8 |
| GPT-5 | 生成式 API | 0.49 | 579.6 | 67.1 |
| GLiNER-L | 判别式编码器 | 0.05 | 33.3 | 60.9 |
| JPT-4B | 判别式 LLM | 0.13 | 89.7 | 76.4 |
| JPT-8B | 判别式 LLM | 0.21 | 146.2 | 77.0 |
最有说服力的对比是 GNER:它是生成式里精度最高的(75.8 F1),但要跑 5831 秒、花 8.21 美元。JPT-8B 精度略高(77.0),耗时是它的 1/40,成本是 1/39。而 GLiNER-L 虽然最便宜最快,精度落后 16 分——JPT 拿到的是「编码器量级的成本 + 超过最强生成式的精度」。
注:论文 Table 3 的 F1 列口径不完全一致——表注写的是 CrossNER-Politics,而 UniNER-7B(61.8)与 GLiNER-L(60.9)对应的是 Table 1 里 CrossNER+MIT 的平均值。跨方法比较请以下一节 Table 1 的完整结果为准;这张表真正无歧义的是成本与耗时两列。
论文最漂亮的一张证据图。输入 “The Eiffel Tower is in Paris, France.”,纵轴是第二遍的 token,横轴是第一遍的 token,格子颜色是跨层平均的注意力权重。
图 3(论文原图):亮点不在对角线,而在第 5 列——「The / E / iff / el」这几个 token 全都强烈地看向后面才出现的「Tower」。
展开说明 ▸论文附录里有一张容易被略过但信息量极大的表:同一个模型,只改实体类型的定义文本,F1 能差出几十分。
| 类型 | 笼统的定义 | 精确的定义 | ΔF1 |
|---|---|---|---|
| LOCATION | “A geographical place” | “Any word indicating WHERE: explicit places (NYC, downtown), relative indicators (nearby, around, close by), directional phrases (east, south side). Tag the location word itself.” | +32.6 |
| PRICE | “A monetary value” | “Explicit monetary amounts ($50, 100 dollars) AND qualitative price indicators (cheap, expensive, budget-friendly, overpriced, pricey).” | +34.9 |
| AMENITY | “An available service” | “A feature, facility, or service offered by a restaurant. Includes: physical features (bar, parking), services (delivery, reservations, takeout), atmosphere descriptors (romantic, casual, family-friendly).” | +14.3 |
MIT-Restaurant 上把 LOCATION 的定义从「一个地理位置」改成明确包含 “nearby” 这类相对指示词,单类型 F1 涨了 32.6 分。这说明所谓的「模型识别不出来」,很多时候其实是标注口径没说清——benchmark 的 gold label 有自己的隐含约定,而定义正好是把这些约定显式写出来的接口。
论文因此给了三条定义撰写守则:说清包含什么和排除什么、给具体例子、直接点名边界情况(“nearby” 算不算地点?)。
| 配置 | 平均 micro-F1 | 说明 |
|---|---|---|
| 单次输入(去掉复制) | 55.7 | 专门用单输入重新训练的变体,不是推理时才关掉复制 |
| 不用定义(只用类型名) | 58.3 | 退回传统的标签名编码 |
| 定义只进 prompt | 63.3 | 单通道 |
| 定义只进 embedding | 65.2 | 单通道 |
| 双通道定义 + 输入复制(完整 JPT-4B) | 70.9 | 输入复制 +15.2,双通道定义 +12.6 |
值得注意的是单输入变体是重新训练的,而不是训练时用双份、推理时砍成单份。作者特意说明这一点,是为了排除「训练/推理不匹配」这个混淆因素——所以 −15.2 F1 确实来自缺少双向上下文本身。
论文分析了单输入变体的失败模式,规律非常一致:实体出现在句首、而决定性线索在句尾时必错。
| 句子(实体在句首) | 正确类型 | 单输入预测 | 为什么必须看后文 |
|---|---|---|---|
| “Autoencoders are trained to minimise…” | algorithm | product | 要看到 “trained to minimise” 才知道说的是算法 |
| “François Bayrou (…) is a French centrist politician…” | politician | person | 要看到后面的 “politician” 才能定到细粒度类型 |
| “The Color Purple is a 1982 epistolary novel…” | book | (漏标) | 要看到 “novel” 才能认出这是书名 |
| “Young’s work on squid giant axons…” | scientist | (漏标) | 要看到后面的科研语境才能判为科学家 |
两类错误各占一半:类型混淆(标出了 span 但类型错)和完全漏标(压根没识别出实体)。第二类更能说明问题——缺了后文,模型连「这里有个实体」都不敢确认。
一个干净的对照实验:拿同一个 Qwen3-4B,一边按 JPT 框架用,一边纯生成式地 prompt 它做 NER。CrossNER 五个域平均,生成式 57.4 vs JPT-4B 74.4,+17.0 F1。同一套权重、同样的世界知识,差距全部来自输入复制 + 定义制导 + 判别式分类这三件事。
主结果在 CrossNER(AI / 文学 / 音乐 / 政治 / 科学五个专业域,每域 9–17 个领域特定类型)和 MIT Movie / Restaurant(对话式查询的槽位填充)上。这些数据集全部是零样本——训练语料与它们无重叠。
| 方法 | AI | 文学 | 音乐 | 政治 | 科学 | Movie | Rest. | 平均 |
|---|---|---|---|---|---|---|---|---|
| UniNER-7B 生成 | 62.9 | 64.9 | 70.6 | 66.9 | 70.8 | 61.2 | 35.2 | 61.8 |
| GoLLIE 生成 | 59.1 | 62.7 | 67.8 | 57.2 | 55.5 | 63.0 | 43.4 | 58.4 |
| InstructUIE 生成 | 49.0 | 47.2 | 53.2 | 48.2 | 49.3 | 63.0 | 21.0 | 47.8 |
| SaM (MoE) 生成 | 60.9 | 66.9 | 73.5 | 74.4 | 62.6 | 72.1 | 52.9 | 66.2 |
| GLiNER-L 判别 | 57.2 | 64.4 | 69.6 | 72.6 | 62.6 | 64.4 | 42.9 | 60.9 |
| JPT-4B | 68.3 | 73.7 | 84.1 | 76.4 | 69.5 | 60.7 | 63.4 | 70.9 |
| JPT-8B | 71.9 | 72.2 | 85.3 | 77.0 | 71.3 | 76.5 | 64.4 | 74.1 |
JPT-8B 平均 74.1,比最强基线 SaM 高 7.9 分。提升最大的三个域是音乐(+11.8)、Restaurant(+11.5)、AI(+11.0)——都是术语高度专业化的场景,正好是 LLM 世界知识发挥作用的地方。连 JPT-4B 都超过了所有基线(+4.7)。
扩展到 20 个数据集(涵盖生物医学、社交媒体、多语言)后,JPT-4B 平均 55.5,对比 GLiNER-L 47.8 和 UniNER-7B 45.7,20 个里赢了 19 个。唯一输的是 GENIA(生物医学嵌套实体,50.8 vs GLiNER 55.5)——这与下文的「不支持嵌套实体」局限直接对应。
论文挑了 CrossNER-Politics 上的几组对照,能看出定义制导在解决什么:
共同点是语义相邻类型的区分:POLITICIAN vs PERSON、POLITICAL_PARTY vs ORGANIZATION、COUNTRY vs ORGANIZATION。这些区分靠标签名本身很难做,但靠一句定义可以说清。另外注意 UniNER 的过度预测是它「一次查一个类型」的结构性后果——每个类型独立判断,自然没人保证互斥。
作者做了完整的错误分析,主要有三类:
1. 边界检测错误(最常见):类型判对了、核心 mention 也对,但 span 多切或少切一截,通常是被修饰语或同位语带偏:
| 数据集 | Gold span | 预测 span |
|---|---|---|
| CrossNER-Science | Virgo interferometer | Virgo interferometer collaboration |
| CrossNER-Politics | Social Credit Party of Canada | national Social Credit Party of |
| MIT-Movie | the reflecting skin | reflecting skin movie |
| MIT-Restaurant | within a mile | a mile of here |
2. 类型混淆:集中在语义相邻的类别之间。例如 “NIST” 被判成 CONFERENCE 而非 METRICS(缩写歧义)、“Augustus” 判成 POLITICIAN 而非 PERSON(角色 vs 实体)、“London Calling” 判成 LOCATION 而非 ALBUM(专辑名恰好是地名)。
3. 过度预测:领域术语长得像实体但 gold 里没标,比如把 “frame language” 标成编程语言。
混淆矩阵(论文 Figure 8)印证了这一点:错误几乎全部落在语义相邻的类型对上——PER↔ORG、LOC↔COUNTRY、POL_PARTY↔POLITICIAN——而不是随机的标签乱翻。作者的结论是这些错误源于表层歧义和定义重叠,而非缺乏上下文理解;对应的解法也很直接:把定义写得更细,或补充针对性训练样本。
论文自己的收尾很克制,但落点很准:因果注意力的约束,并不意味着 LLM 只能走生成式路线。绕过它不一定需要改架构或改预训练,有时候改一下输入就够了。而且作者点出这个思路不限于 NER——任何 token 级任务(POS、chunking、span 抽取)都可以照搬。