AI原生应用中的实体识别:从贴标签到定身份,生成式抽取实战指南 这次想聊个老技术但聊法不太一样AI原生应用里的实体识别。如果你近一年在折腾智能客服、企业知识库问答、AI搜索这类产品大概率感受过这么一种场面——模型对话能力很强但问它“咱们上次讨论的那个预算方案”时它要么答非所问要么瞎猜一个。表面上看是上下文理解问题可拆到底层往往撞上的第一堵墙就是实体识别。用户把一个模糊的指代、一个口语化的名称、一个跨角色出现的名字丢给系统系统得先从这段文字里把“预算方案”这个实体的边界找出来再映射到业务里真正的“方案编号”。我讲这些是因为实体识别早就不是NLP教材里那个只需要圈出“人名、地名、时间”的入门任务。在AI原生应用里它更像一个“信息入口”决定了后面的检索、决策、执行到底能不能站稳。这篇文章我会从技术视角聊清楚新一代实体识别的突破点也会把我自己落地过程中的经验、踩过的坑一并整理出来适合正在做AI应用的技术同学也适合想理解“为什么AI经常抓不到重点”的产品同学。1. 看懂实体识别在AI原生应用里的真实角色从“贴标签”到“定身份”很多做应用的人对实体识别的理解还停留在“给文档断开词标出每段话提到的人名、地名、时间”。这套思路用在学术评测上没问题但放到业务系统里它更像“贴标签”看到一个词判断它属于哪个预定义类型。真正的问题是AI原生应用需要的不是“贴标签”而是“定身份”。什么叫定身份比如用户说“把上周我在财务群里说的那个文件发给我”这句话里真正起作用的实体不是“财务群”这三个字而是那三个字背后指向的那个微信群ID“上周”也不是一个简单的时间类型要落到具体时间区间“那个文件”更是需要通过对话状态反查才能确定的一个业务对象。这几个层次的解析传统实体识别都会非常吃力。AI原生应用之所以叫“原生”是因为整个交互路径都以模型理解和生成为中心。它的实体识别不仅要“认出词”还要“关联到业务对象”“跟着上下文变化”甚至“容忍用户说错”。这一章我把这个问题拆成三个层面来看。1.1 传统实体识别的看家本领和天花板传统方案里最有代表性的就是词典、规则和序列标注模型。词典和规则最大的优势是可控你写一条“匹配‘发货日期’后面跟着的‘日期’”的规则它就能在一个格式固定的表单里稳定跑很久成本还极低。序列标注模型则更进一步把分词、词性、实体类型串在一起做联合预测例如经典的BIO标注法能在大量标注数据上学习出上下文模式。这不是说老方法没用。我今天仍然建议凡是格式高度固定的场景比如解析证件号、订单号、日期时间就先用规则别为了AI而AI。规则能把那些高频、确定性强的实体抽得又快又准连成本都用不着算。但老方法有个天花板它对“多变的表达”无能为力。同一个实体换一种说法、加一个错别字、插一段冗长的修饰规则就断了模型在训练集外也容易识别不动。我见过一个团队做售后服务工单系统最开始用了正则去抽“产品型号”准确率95%看起来很好。但一接入对话场景用户说话变成了“充电仓坏了”“上回那个白色的耳机仓不亮了”规则直接失效。这就是传统方案的边界它们擅长处理“确定性文本”不擅长处理“人的表达”。1.2 AI原生应用里的三座新大山AI原生应用里的实体识别跟传统NLP任务相比多了三个非常棘手的约束。第一是动态体系。业务方今天要用户“姓名”明天要“手机号”后天要“选购原因”。每加一个新需求传统方案就得重新定义标签、准备样本、重新训练。这个成本在小步快跑的AI应用周期里基本不可接受。第二是口语化和重复冗余。真实用户不会按标准文本说话代词、省略、指代非常频繁。比如“帮我把这个和那个一起下单”如果不结合上下文“这个”和“那个”根本无法用静态模型识别。更麻烦的是用户还会用错别字、方言词、中英文混用这些噪声对基于规范文本训练的传统模型影响非常大。第三是上下文联动。在单轮文本里实体识别的对象主要是句子中的显式名词可多轮对话里用户经常用“它”“这个”“刚才说的那款”来指代前文实体。这意味着实体识别必须跟对话状态管理集成起来把跨轮的指代消解一并考虑。这三点合起来指向一个结论AI原生应用里实体识别本质上是在“动态业务体系口语表达多轮上下文”的三重压力下运行的。它不是被简化了而是被复杂度全面抬高了。1.3 最容易被忽略的关键实体归一化很多人只看重“实体抽得准不准”却忽略了抽取之后那一环实体归一化。这一环决定了你是不是真的把“字面表达”和“业务对象”接进了一条链路。举个例子。用户说“我要买爱疯15”模型很容易把“爱疯15”抽成实体。但业务系统里的商品表可能叫“iPhone 15”也许还有个属性叫“苹果手机15代”。如果系统只把“爱疯15”抽出来却不对齐到商品编码后面的检索、比价、下单全部无从谈起。实体归一化要做的事情就是同义词识别、近义表达归并、实体消歧、关联到标准ID。我自己做过一个企业内部的采购助手用户问“上次那个蓝牙耳机多少钱”系统必须明白“上次”指的是哪个订单“蓝牙耳机”在订单里的标准SKU是什么。如果只是抽取出了“蓝牙耳机”这个字符串但没有跟用户的订单历史、商品库关联这个问题的回答质量会非常差。所以你看实体识别在AI原生应用里的真正角色不是NLP上游一个可有可无的模块而是整个产品能否建立“语义-业务”映射的底座。如果这一层做不扎实后面所有组件都会在同一个地方翻车接到了字面表达却没接住真实意图。2. 真正的技术突破口用生成式抽取重构整个流程传统实体识别一直沿着“序列标注”的路线往前走模型为一个文本序列逐个打标签哪个字符属于什么实体类别全部在同一时间一次性指定。这个路线成熟、稳定可对AI原生应用来说灵活性已经严重不足。最近几年真正发生突破的地方是把实体识别重新定义成“生成式抽取”让模型直接输出结构化信息而不是去预测每个token的类型。2.1 为什么序列标注模式不够用了序列标注的经典操作是把任务建模成一个分类问题给定一个词和它的上下文模型判断它属于哪种实体。这样做的优点是有成熟的理论体系和训练框架缺点也明显实体的类型往往是提前定义好的训练多少类就只能识别多少类。到了AI原生应用里这个“先定类再训练”的过程太笨了。业务体系一个月变好几次模型被频繁重新发布标注数据也永远追不上需求。此外序列标注很难处理嵌套实体和重叠实体。“上海市浦东新区”既是一个“区划”实体也是“上海市”的修饰用平铺的标签体系基本表达不清楚。而生成式抽取把实体识别看作“根据一段文本生成一段结构化结果”的过程天然支持动态schema也天然适合处理嵌套关系。这里补一句理解生成式抽取的类比序列标注像是戴着固定颜色的眼镜看世界看到什么颜色就必须归到那一类生成式抽取则更像一名帮人整理名单的助手你早上告诉它“今天按部门整理”下午告诉它“改成按项目整理”它不需要换脑子只要改一下理解规则就行。2.2 三种主流的可落地方案对比实操落地时我见过的主流方案大概有三类各有各的适用土壤不一定谁替代谁。第一类是“大模型API零样本抽取”。把目标实体类型和示例写进提示词让大模型直接返回JSON好处是开箱即用、业务体系改动零成本特别适合快速验证和低频调用场景。坏处是API单次调用成本高且对于某些很冷僻的专有词存在幻觉风险。第二类是“开源小模型微调”。拿一个7B级别的开源基座模型把标注好的指令数据整理成“文本-抽取结果”的生成格式最常用的格式是“文本JSON schema输出JSON列表”做有监督微调。训练完成后可以本地部署单次推理成本极低、延迟可控效果也能逼近大模型。缺点是需要标注数据且模型能力受底座影响复杂推理容易露怯。第三类是“规则小模型兜底”。用规则、词典、外部知识库保证高频和确定性高的实体抽取再用小模型处理动态、开放类的实体。这类方案看起来不够酷但往往是最耐打的因为它在成本、准确率和迭代速度之间找到了一个非常健康的平衡点。我把这三种方案的核心差异整理成一张表方便你根据自己的场景对号入座方案配置成本动态体系适应度推理成本推荐场景大模型API零样本抽取低高单次高原型验证、低频任务开源小模型微调中中高低高频生产服务、私有化部署规则小模型兜底中中低复杂业务、强合规场景我自己在多数项目里的选择是先用大模型API跑通流程积累一批真实问题样本再把这些样本整理成微调数据换成开源小模型。原因很朴实成本降到原来的几十分之一效果却往往不会明显变差。很多团队一上来就排斥API其实大可不必也可以用它做“数据引擎”帮自己批量造训练集这不丢人。2.3 生成式抽取的通用模式长什么样我自己的经验里一个稳妥的生成式抽取系统通常由三个组件拼接而成体系描述、抽取指令、结构化输出格式。体系描述就是把业务相关的实体类型定义写得足够具体避免措辞模糊。比如不能只写“时间”要写“订单的创建时间、发货时间、退款时间”。抽取指令负责说明规则比如“只抽取明确出现的实体不推测”。结构化输出格式则直接告诉模型“返回JSON数组每个元素包含name和type两个字段”。一个最简单的模板长这样你是一个结构化信息抽取助手。请从用户文本中抽取以下实体类型 - 姓名 - 商品名 - 品牌 要求 1. 只抽取文本中明确出现的实体不要推测或联想。 2. 如果同一实体出现多次只返回一次。 3. 如果文本中存在介于多种类型之间的情况选择含义最具体的一种。 返回格式为JSON数组例如 [{name: 实体文本, type: 实体类型}]给模型加这样的体系定义本质上是把实体识别从“凭感觉猜类型”变成“按说明书做事”。我踩过最痛的一个坑是早期提示词写得太随意模型会把“价格”也抽成“品牌”后来把所有类型都补上解释和反例才把误抽率压下来。还有一个关键点如果要模型输出JSON务必在系统测几次完整示例最好让模型先输出一个空的列表再开始正式抽取。这个方法看起来奇怪但实测下来能明显降低空输出和格式错乱的概率。原因在于它把一个生成任务的起点锚定在了“已经有合法输出结构”的位置上模型更容易顺着结构完善内容。3. 把方案落进真实项目一次完整的实现记录理论讲再多最后都得回到能不能上线。这一章我按自己在某知识库问答项目里的实际推进过程来写把从定义实体、写提示词、做后处理到搭评测集的完整链路展开。如果有可直接照抄的动作我会尽量写清楚。3.1 第一步先把实体边界说清楚否则后面全是坑很多项目失败不是因为模型不行而是因为实体边界根本没说清楚。比如产品提出要识别“产品名称”那“苹果”算不算“苹果手机”算不算“红色苹果手机”里的“红色”要不要单独作为一个实体类型这些如果不达成共识模型输出后才发现字段没对齐返工成本极高。我建议用一个下午专门做“实体头脑风暴”把目标用户最常问的100条真实问题拿出来逐个标出里面包含的可执行信息。每条问题里至少包含一到两个能被后续系统消费的信息点这些信息点就是真正的实体。标完之后再跟业务方逐条确认尤其要问清楚两个问题这个信息点在业务系统里有没有对应字段如果没有抽取出来之后要做什么用把这两个问题搞清楚能砍掉一半看似必要实则无用的实体类型。我印象很深的一次是在做内容审核辅助系统时产品提了20多个实体类型结果追问下来真正被下游规则和召回模块使用的只有5个。多余的实体类型不仅增加标注和训练负担还会引入噪音让模型在推理时更犹豫。有了实体边界第二步是把它们写成“可执行的体系定义”。我给每条实体类型配上三要素定义、正例、反例。比如“品牌”这个类型定义写“商品详情页中展示的品牌名”正例写“苹果”“华为”反例写“旗舰店”“官方旗舰店”。这些带反例的描述会直接决定后续提示词的效果。3.2 第二步用Schema化的提示词提高稳定性确定了实体边界下一步是把它结构化地传递给模型。我不建议把实体类型堆在一个自然语言段落里因为模型对长段描述的理解容易漂移不同类型之间的关系也不清晰。更推荐使用类似JSON Schema的写法把字段类型、约束条件都明明白白铺出来。举个例子一个电商客服助手里的实体提示词我会写成这样{ 实体类型: [ { name: 商品名称, type: string, description: 用户在问题中提到的具体商品如手机、耳机、充电器, examples: [iPhone 15, 蓝牙耳机, 白色充电宝], negative_examples: [苹果, 数码] }, { name: 数量, type: integer, description: 用户购买或咨询的商品数量, examples: [3, 两台], negative_examples: [很多, 大概] } ] }把这段JSON插入到提示词里再配合一句“请严格按以上Schema抽取并输出JSON数组”模型输出的结构化程度会明显提升。我实测过比起自由文本描述Schema化之后字段命名错误和类型混乱的情况能少一半以上。这种方法的核心原理在于给模型一个明确的目标结构比让模型自由发挥更符合它训练时见过的“指令遵循”数据分布。大模型非常擅长在给定的输出围栏里完成生成一旦围栏消失它的想象空间就会膨胀。Schema本质上就是那个围栏。有个容易被忽略的小细节负例negative_examples很重要。“品牌”类型里不写“苹果直营店”模型就很可能会把“苹果直营店”整个抽成“品牌”。加负例之后同样的提示词下误抽率普遍能下降两三个百分点。多花十分钟收集负例是投入产出比非常高的工程动作。3.3 第三步把模型输出变成干净可用的结构化结果模型输出的结果哪怕格式严格是JSON也不能直接用。第一个原因是生成式模型偶尔会输出非法JSON尤其当文本里出现关系引号、中文冒号混排时解析很容易失败。第二个原因是抽取结果往往包含冗余字段、重复项比如“张三”“张三先生”被抽成两个实体。我自己习惯在模型输出后接一个后处理管线按顺序做四件事格式清洗先尝试用标准JSON解析失败就用容错解析再补一轮字符串清理。去重合并基于实体文本和类型做融合同词不同写法统一用归一化规则处理。实体映射把“爱疯15”“iPhone15”“iPhone 15”这类表达映射到标准ID规则表能在这一步帮上大忙。置信度过滤这部分要跟模型能力结合可以靠提示词让模型给出confidence字段再用阈值卡掉低质量结果。我第一次做后处理时只做了格式解析结果下游检索模块把“iPhone 15”和“苹果15”当成两个不同商品去搜召回结果质量明显下降。后来把实体映射这一步补上问题立刻缓解。如果你发现用户query里大量使用简称或昵称实体映射表的建设优先级就要调高甚至比抽取模型本身的调优更值得投入。这里多说一句实体映射不能只靠字典。业务里一个品牌可能有几十种写法还包括“官方旗舰店”这类带修饰的名称。建议在规则映射之外再加一层向量召回把候选标准名称和抽取出的实体文本都先做嵌入相近的候选自动匹配。两者一起用效果要比单独用任何一个稳定得多。3.4 第四步用一套小评测集把效果“钉”住很多团队会把“效果调优”寄托在模型选择上换一个模型、调一次提示词却说不清到底好了还是坏了。我强烈建议从第一天就建一套固定评测集规模不用大100到200条真实用户问题就够。评测集里的每条样本要包含用户原句、标准实体列表、标准JSON输出。有了这个基础每次改动模型或提示词都可以跑一遍评测集记录精确率、召回率、F1值。这样你会非常清楚地知道某次调整到底是“好了”还是“只是感觉好了”。精确率和召回率的计算方法也不复杂按实体级别去算就行精确率 模型抽出的实体中与标准实体匹配的数量 / 模型抽出的实体总数召回率 模型抽出的实体中与标准实体匹配的数量 / 标准实体总数F1 2 * 精确率 * 召回率 / (精确率 召回率)匹配标准可以先从宽松匹配开始即实体文本包含关系即可走到稳定阶段再升级为完全匹配。我在多个项目里用这套流程效果都立得住。最典型的例子是有次我把提示词里“只抽明确出现的实体”这句话删掉了全量评测集的精确率立刻从88%掉到81%这个数字比任何直觉都更有说服力。4. 真实环境中反复出现的坑排查实录与原因速查说实话AI原生应用里的实体识别真正难的不是第一次跑通Demo而是上线后面对五花八门的真实输入还能稳得住。这一章我把几个翻过车、修过补丁的问题串在一起你可以当成一份排查速查表来用。4.1 “幻觉实体”模型编造文本里没有的东西生成式模型一个最让人头疼的问题就是它会在抽取任务里把“顺理成章”的内容也补出来。用户问“这个防水手机多少钱”模型可能给你输出“品牌某品牌”“型号某型号”即使这句话里根本没出现品牌和型号。这就是幻觉实体对整个业务链路来说是被直接带歪的起点。我用的最有效的一套组合拳是三层压制。第一层在提示词里写死“只能抽取用户文本中出现的短语不得补充任何上下文信息”。第二层在输出Schema里加上“confidence”字段并且明确说明“无法确定时confidence给低值”。第三层在后处理里对所有输出做短语命中校验只要实体文本不是用户原话的子串直接丢弃。三层同时上幻觉率能压到非常低。这里有个容易被忽视的原理模型在抽取任务里产生幻觉其实跟你把问题问得太开放有关。“从文本中抽取所有实体”是个开放题模型很容易按照自己的知识猜测。改成“从文本中抽取出现在下列句子里的实体短语并以原样输出”相当于把问题从开放题变成翻译题模型的幻觉空间瞬间被压缩。4.2 实体重叠与嵌套一次抽取拿不干净真实文本中的实体边界经常交叉。比如“北京市朝阳区”是一个完整地名但“朝阳区”本身也是一个实体“北京市”也是一个实体。再比如“张三的公司”张三和公司之间的关系要不要抽也常常成为纠结点。传统的序列标注对这类嵌套几乎无解但生成式模型天然能输出多层嵌套结构。我的做法是在Schema里增加“parent”字段允许一个实体指定它的上级实体。模型先抽粗粒度实体再抽细粒度实体通过id和parent字段把它们串起来。例如[ {id: 1, name: 北京市朝阳区, type: 行政区, parent: null}, {id: 2, name: 朝阳区, type: 区, parent: 1} ]这个做法不仅保留嵌套关系还方便下游系统按层级去消费。有一点要提醒加了嵌套结构后评测方式也要跟着改不能再按“实体全集是否一致”来算得改成按“实体列表是否完整且依赖关系正确”来评估。4.3 成本和性能的平衡是我踩过的最大的坑我见过不少团队在原型阶段用大模型API跑得很开心结果一上线就傻眼。某个客服系统每天要处理几十万条用户问题每条问题都要抽实体单日API调用成本极高延迟也不稳定。后来把高频实体用规则兜住低频动态实体才走模型成本直接降了一个数量级延迟也稳定在可接受范围内。性能这一侧我建议用“分层抽取”来替代“一股脑全量抽取”。先把用户问题过一遍轻量级分类器判断这条query更可能涉及哪类实体再只调用对应领域的抽取模块。比如售前问题和售后问题涉及的实体差别很大分开抽比一次全抽要快得多准确率也更好控制。还有一个小技巧值得写下来对于超高并发场景不要每个请求都发一次模型推理。把相似结构的用户问题聚在一起做批量提示词填充一次推理同时处理多条输入。这样能显著提升吞吐但要注意批次不能太大否则模型在长文本里更容易分心。4.4 常见问题速查表我把项目里出现过的高频问题整理成一张速查表你自己排查时可以直接对照问题表现最可能的根因优先排查方向实体抽出来但类型错乱类型字段和实体明显对不上实体类型定义模糊缺负例检查Schema中的定义和负例实体漏抽标准实体没出现在输出里召回能力不足或目标体系过大减少单次抽取任务量拆分领域输出不是合法JSON解析直接报错模型输出里混入了说明文字强化输出格式约束加容错清洗同一实体重复输出列表里出现多条相似值归一化层缺失增加实体映射、去重、合并逻辑网络词和错别字导致误抽把包含字符的词误认为实体模型对噪声缺乏鲁棒性增加规则白名单构建纠错映射表这张表也许不会覆盖所有项目但它已经能解决我这边80%的线上问题。排查实体识别问题最忌讳在模型层面反复横跳先回看数据、定义、后处理通常比换模型更有效。我自己在多个项目里一直保持一个习惯每次排查线上问题第一件事不是改提示词而是在评测集里复现一遍看是“新样本没覆盖”还是“老样本回归”。这个习惯帮我省下了无数改来改去却看不出效果的时间。最后再分享一个小技巧给你的实体识别模块加一个“可解释出口”也就是让模型在输出实体时附带它在原文中定位到的关键词。这样每个实体都有据可查线上排查时有用得多。也正因为这些经验我现在重新评价实体识别的时候已经不仅仅把它当成一个NLP任务而是一个关乎产品稳定性的系统工程。希望这篇文章能让你在构建AI原生应用时少踩几个我踩过的坑。