资讯详情

资讯详情

用LLM做NER和IE:从提示词设计到生产部署的完整指南

简介基于大语言模型LLM的命名实体识别NER与实体关系抽取IE项目面向计算机、人工智能相关专业的学生、教师与开发者可作为课程设计、毕业设计或项目初期演示使用。代码均经测试通过聚焦ChatGLM、GPT、LLaMA等预训练模型的调用与效果对比帮助读者理解实体识别与关系抽取的基本流程。资源共13个文件以12个Python脚本和1个README说明文档为主压缩包仅约50KB脚本按模型和任务拆分便于对照不同LLM的写法差异data、uer、models三个目录则清晰展示数据、预训练模型与保存结果的模块化组织方式。对于希望快速上手大模型信息抽取的初学者这是一套轻量可跑的参考实现对于需要完成相关课题或作业的开发者也可作为扩展起点。这份资源文件较小便于下载后快速阅读源码已有124人学习浏览适合作为自然语言处理方向的入门练手资源。1. 为什么先用LLM做NER和IE从“训练任务”变成“提示词任务”实体识别NER和关系抽取IE曾经是两件“重装备”工程要标注数据、要训练模型、要调CRF或BIO标签上线后换个领域还得重新来一轮。LLM把这个逻辑彻底改写了——你把一句话、一封邮件或一段病历丢给它它直接回复JSON实体和关系同时出来不再需要单独的标注管道和训练流程。这意味着过去一周到一个月的工作量现在一个晚上能跑通最小闭环。但这不等于“白嫖”LLM在NER和IE上的关键变化是召回率和准确率的权衡方式变了错误模式也变了你需要重新学的是怎么设计提示词、怎么设置输出格式、怎么兜底而不是去调损失函数。适合谁做过传统NER/IE想快速验证LLM方案的工程师以及正在搭RAG或Agent、需要从非结构化文本里抽结构化信息的从业者。本文围绕LLM做NER和IE的完整路径展开从选型、实现到评测优化每步都有可复现的命令和代码。2. LLM做NER和IE的三条技术路线与选型2.1 确定目标从文本到结构化输出的映射LLM做NER和IE的本质是把它当成一个“文本到JSON”的转换器。你需要输入一段文本和一段指令它输出包含实体和关系的结构化数据。这条路能不能走通取决于三件事模型是否理解你的领域语言、输出是否可控、失败后怎么降级。与传统的bert-BiLSTM-CRF路线相比LLM方案的直接收益是少写代码、快速换领域、天然支持复杂关系代价是推理成本升高、延迟变大、输出偶发不合规。我的判断标准是样本量少、领域杂、关系种类多的话用LLM划算如果超高并发、要求低延迟、且标注数据已积累到10万条级别传统模型仍然有优势。实际项目中二者并非互斥而是可以混合部署。2.2 三种路线零样本、少样本、微调在动手之前先把路线看清不然很容易在“调了个寂寞”上浪费两周。路线适用场景成本预期F1区间参考主要风险零样本提示词快速验证、领域标准最低只花API费用0.55-0.75格式不稳、召回偏低少样本示例需要稳定输出格式、特定实体类型低提示词变长0.70-0.85示例要精心选、token消耗上升指令微调开源模型数据敏感、高精度要求、离线部署高算力数据集构建0.80-0.93需要标注数据质量兜底零样本的核心代码只有几十行后面第三章详细写少样本则是在提示词里加few-shot示例。微调这条路最重但数据准备有诀窍不要直接用原始文本做训练样本而是生成“带标注说明的对话模板”即把NER和RE任务拆成“指令输入输出JSON”三元组。我一般用Qwen、GLM或Llama系做微调底座LoRA就能覆盖大部分行业场景。需要特别注意微调数据里的实体边界必须统一比如“北京市朝阳区”是整体还是“北京市/朝阳区”分开这直接决定模型输出的一致性和评测分数。2.3 选型对照API调用还是本地部署选型时不要只看模型榜单要看你自己的部署边界。纯API方案如GPT、通义、文心等上手快、模型能力强适合业务验证和中小流量本地部署开源模型如Qwen2.5-7B-Instruct、Llama-3.1-8B适合金融、医疗等数据不出域的强约束场景但要自己解决显存、并发队列和推理优化。另一个常被忽略的维度是框架。LangChain提供完整链式封装适合多步骤任务LlamaIndex的重点在文档检索和向量化适合把LLM-NER接在RAG管道里Dify则偏向低代码工作台适合内部工具快速搭建。我个人在LLM做NER和IE时倾向于“少用框架多做裸调用”因为解析逻辑本来就简单两层工具函数足以封装加框架反而增加排错成本。3. 实现一个LLM解析流水线从裸调用到JSON输出3.1 最小实现用API做零样本NER和IE先跑通最小闭环。无论你用哪家模型核心逻辑都是通用的构造指令、抓取输出、解析JSON。下面以Python和OpenAI兼容协议为例这套代码同样适用于本地部署的Qwen、Llama等自建服务。import json from openai import OpenAI # 初始化客户端指向官方API或本地推理服务 client OpenAI( api_keysk-xxx, base_urlhttps://your-endpoint/v1 # 本地部署时替换为目标地址 ) def extract_entities_relations(text: str, entity_types: list[str]) - dict: 从一段文本中抽取实体和实体间关系 prompt f 你是一个信息抽取引擎。请从用户文本中识别实体并抽取出实体之间的关系。 实体类型{entity_types} 输出要求必须是严格JSON不要输出任何额外文字或Markdown。 输出格式 {{ entities: [{{name: 实体名, type: 实体类型, mention_span: 原文上下文}}], relations: [{{source: 头实体, target: 尾实体, relation_type: 关系类别}}] }} 用户文本{text} resp client.chat.completions.create( modelgpt-4o-mini, # 替换为你可用的模型名 messages[{role: user, content: prompt}], temperature0.0, # 信息抽取任务必须低随机性 response_format{type: json_object} # 要求模型输出JSON ) content resp.choices[0].message.content return json.loads(content) # 演示调用 text 特斯拉收购了SolarCity马斯克担任CEO而大股东是摩根大通。 result extract_entities_relations(text, [公司, 人物, 事件]) print(json.dumps(result, ensure_asciiFalse, indent2))这段代码里有两个关键参数必须解释。第一个是temperature0.0信息抽取是确定型任务不需要创造性温度越高越容易出现实体幻觉和关系乱连第二个是response_format{type: json_object}这个参数强制模型输出合法JSON否则你的json.loads会在没有任何预处理的情况下直接抛异常。实际工作中即使加了json_object约束我仍然会套一层try-except做兜底因为模型偶尔还会输出空字段。mention_span这个字段的价值在于后续做数据校验和人工复核时你能快速定位实体在原文中的位置而不是面对一个孤立的名字。3.2 少样本增强把示例写明白F1能涨8个点零样本能跑但不稳定。同一句话换几个说法模型可能漏掉一个实体类型。少样本few-shot是性价比最高的提升手段。方法很简单在提示词里附上2-3个“输入-输出JSON”的完整示例让模型模仿你的输出风格和边界标注粒度。FEW_SHOT_EXAMPLES [ { text: 苹果公司今天宣布库克在发布会上介绍了新款iPhone。, expected: { entities: [{name: 苹果公司, type: 公司}, {name: 库克, type: 人物}, {name: 新款iPhone, type: 产品}], relations: [{source: 苹果公司, target: 库克, relation_type: 雇佣}, {source: 苹果公司, target: 新款iPhone, relation_type: 发布}] } }, { text: A轮融资由红杉中国领投跟投方包括高瓴创投。, expected: { entities: [{name: 红杉中国, type: 投资机构}, {name: 高瓴创投, type: 投资机构}], relations: [{source: 红杉中国, target: A轮融资, relation_type: 领投}] } } ] def build_few_shot_prompt(text: str, entity_types: list[str]) - str: prompt f你是一个信息抽取引擎。实体类型{entity_types}\n\n prompt 以下是示例\n for idx, exo in enumerate(FEW_SHOT_EXAMPLES): prompt f示例{idx1}\n输入{exo[text]}\n输出{json.dumps(exo[expected], ensure_asciiFalse)}\n\n prompt f请抽取以下文本的实体和关系只输出JSON\n{text} return prompt示例数量的平衡点在3-5个超过5个提示词长度增加导致token消耗明显上涨而效果基本不再提升少于2个模型的“模仿锚点”太少输出格式容易跑偏。选示例时有一条实操原则覆盖你任务里最难的边界情况比如嵌套实体、同义词实体“苹果公司”和“苹果”应视为同一实体还是两个、还有容易混淆的关系类型。示例的质量比数量重要得多一行“错误的关系标注”会被模型学成坏习惯这就是为什么很多人加了几条示例反而掉分。3.3 本地开源模型启动llama.cpp或vLLM跑通NER敏感数据无法出域的企业需要本地部署开源模型。推理框架选vLLM的居多但在显存小于16G的机器上llama.cpp配合GGUF量化模型更实用。下面是vLLM部署一套Qwen2.5-7B-Instruct做NER的常见命令vllm serve Qwen/Qwen2.5-7B-Instruct \ --served-model-name qwen7b \ --port 8000 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192 \ --enforce-eager参数含义说明--served-model-name是客户端调用时填的模型名--gpu-memory-utilization 0.9允许模型占用90%显存剩下留给KV Cache--enforce-eager关闭CUDA Graph加速解决某些显卡兼容问题如果显存足够且追求吞吐可以去掉。启动后用OpenAI兼容端点调用base_url换成http://localhost:8000/v1上一节的客户端代码不用改任何业务逻辑。但有一个大坑本地小模型的JSON能力不够稳定经常输出“连带解释的JSON”或把关系数量丢三落四。应对手段是加一层“解析规整函数”用正则把模型输出中第一个“{”到最后一个“}”之间的内容截出来再做json.loads这样能抢救大约80%的不合规输出。3.4 失败兜底不合法JSON的清洗与重试策略生产线不能因为一次解析失败就断掉。我的兜底顺序是截取JSON片段、尝试解析、失败则重构请求并降低输出长度上限、再失败则返回空结构和告警。用结构化重试代替盲目重发可以在不增加太多成本的情况下显著提升可用率。def safe_parse_json(text: str) - dict | None: 从模型输出中提取JSON并解析失败返回None import re try: return json.loads(text) except json.JSONDecodeError: pass # 截取第一个{到最后一个}之间的内容 pattern r\{.*\} match re.search(pattern, text, re.DOTALL) if not match: return None try: return json.loads(match.group()) except json.JSONDecodeError: return None这个函数的逻辑是“先整段尝试、再截取重试”之所以要分两步是因为整段解析适用于模型完全合规的情况而截取是处理“多解释了一句”的常用降级。注意re.DOTALL没有它跨行的JSON永远匹配不上。重试策略我用的是指数退避第一次失败等0.5秒重发第二次等1秒最多重试2次超过就跳过并记日志。在高吞吐场景重试带来的排队效应会显著拉高P99延迟与其无脑重试不如在提示词里直接追加“不要输出任何解释”的硬约束。4. LLM在NER和IE上的评测与调优4.1 构造评测集从20条到200条的分层方法跑通之后第一件事是评测。很多人的误区是拿零散的几个人名去测然后主观判断“还行”。这么做没有任何信息量。评测集要有层次否则你不知道模型到底是哪里弱。我一般把评测集按类别分层简单句单实体单关系、中等句多实体、困难句嵌套实体、共指消解、隐式关系。每一层至少20条总共60-200条即可。用这个评测集跑出的F1才有对比意义。分层构造的方法很简单从你的真实语料里按句子复杂度抽样然后人工标注不要把全部样本标完再测而是先标20条试跑模型暴露出格式缺陷后再决定要不要继续扩大标注。4.2 三个必看的指标实体F1、关系宏平均F1、完整匹配率LLM做NER和IE的评测指标和传统模型不完全一样。传统NLP评测只看严格F1但LLM输出的实体边界经常“差不多对”一刀切会低估真实水平。我同时看三个指标指标计算方式反映的问题实体严格F1精确匹配实体名和类型模型对实体边界的敏感度实体宽松F1类型正确、实体名包含即可模型“差不多对”但边界差一点的比例关系完整匹配率三元组source, relation, target全部正确关系级联误差的累积情况关系宏平均F1每个关系类的F1取平均低频关系类的表现是否被淹没严格F1和宽松F1的差值代表模型的边界误差如果差值超过10个点说明提示词里实体定义写得太模糊需要在自定义实体类型时补充同义词或边界规则。关系宏平均F1比实体F1更重要因为关系错了抽出的结构化数据直接不可用。一个常见现象是实体F1在0.82关系只有0.65原因是关系错误是级联的——实体漏一个至少两三个关系跟着错。所以调优顺序是先调实体、后调关系。4.3 调优清单提示词、模型、后处理的三层递进调优时按这个顺序走每个层级验证后再进入下一层不要一开始就换模型换提示词来回试。第一层提示词调优。检查点实体类型是否写全、是否有歧义示例、输出格式是否强制JSON、temperature是否归零。我在实体类型定义里的惯用做法是“类型边界说明”例如写“作品(包括电影、小说、歌曲不含品牌周边)”模型对内容边界的理解立刻清晰。第二层模型选型。如果提示词调优后实体F1仍低于0.75优先考虑增大模型或多加示例而不是继续调措辞。从7B换到72B通常能带来5-10个F1点提升但推理成本上升5倍以上这是工程取舍不是越大越好。第三层后处理兜底。这是最常被忽略的杠杆。例如重名实体的消歧规则、关系类型映射模型输出“任职于”和“雇佣”指同一个关系时用字典映射归类、时间表达式归一化等。后处理能拉回2-3个F1点而且不增加任何推理开销。4.4 错误分析最常见幻觉从哪里来跑完评测后看错误case多数问题集中在三类第一类是实体边界扩散模型把修饰词吃进实体里比如“红杉中国”被抽成“知名投资机构红杉中国”第二类是关系方向颠倒把“A收购B”抽成“B收购A”第三类是幻觉关系句子根本没说模型根据常识脑补了“任职”关系。看完错误再回头调整提示词方向会很明确边界问题补示例、方向问题在关系定义里写清主客体语义、幻觉问题加一条“不要推断原文未明确表述的关系”的硬性指令。评测跑完一轮后把这套case沉淀成回归集每次改提示词或换模型后都重跑一遍防止“修了张三、坏了李四”。5. 把LLM-NER/IE接进生产RAG、Agent与垂域部署的三个实战技巧当评测分稳定在业务可接受范围接下来要解决的是“怎么用起来”。最常见的使用场景有三类文档解析建库、Agent工具调用、垂域流水线。下面每个技巧都是生产环境的实战配置。5.1 RAG场景先抽取再切片而不是先切片再抽取把LLM-NER接进RAG时顺序有讲究。常见做法是文档先切片再向量化、用户提问后再检索。但如果你要做实体级问答例如“去年Q3哪些公司投了制药项目”直接向量检索的效果不佳因为问题里的实体和文档里的实体可能措辞不同。正确的做法是在文档预处理阶段先用LLM抽取实体和关系把结构化信息存成索引字段检索时先做实体匹配、再做相似度检索两个结果集做融合排序。这类实体索引的成本是一次性推理但后续查询的速度和准确率都上了一个台阶。数据量大的时候可以只对新入库文档做抽取历史文档做离线批量任务。5.2 Agent场景把抽取结果定义成工具的参数SchemaLLM Agent如果要用NER/IE的结果不要让它直接处理原始文本而是把抽取函数封装成一个工具tool在函数描述里写清输入输出。agent_tool { type: function, function: { name: extract_entities_and_relations, description: 从文本中抽取出实体和实体间关系返回结构化JSON, parameters: { type: object, properties: { text: {type: string, description: 待抽取的原始文本}, entity_types: {type: array, items: {type: string}, description: 期望识别的实体类型列表} }, required: [text, entity_types] } } }这里的关键是description要写得具体因为Agent是靠函数描述决定“什么时候调用这个工具”的。我见过很多人只写“抽取实体”导致Agent在不需要抽取的场景也调用。写清“仅当用户询问实体关系或需要结构化信息时”能明显减少无效调用。另外一个细节返回给Agent的JSON不要原样塞回而是压缩成一行摘要例如“已抽取出3个实体、2条关系”需要细节时Agent再追问避免上下文被长JSON污染。5.3 垂域部署基于标题热词“垂域llm 数据准备”的流程垂域金融、医疗、法律是LLM做NER和IE价值最大的地方也是坑最多的地方。如果只靠通用模型专业实体如“三期临床”“股权质押”的识别率会很惨。垂域部署的标准流程是先准备500-2000条“领域种子数据”用零样本模型跑一遍人工修正输出得到第一批标注数据再拿这批数据做指令微调或者构造少样本库。数据准备时有个容易被忽略的点不要只标实体要把领域特有的关系也标进去。比如金融领域“股权质押”关系中出质人、质权人、质押比例谁是主体谁是客体通用模型很难分清必须在数据里反复强化。微调时建议用“基础NER任务领域任务”混合训练保留通用能力的同时增强领域准确率。模型规模上7B-14B是垂域部署的甜点区间超过这个规模推理成本会吃掉收益。5.4 prompt版本管理与回归测试LLM-NER/IE进入生产后最怕的不是模型降级而是你忘了“哪个提示词版本在线上跑”。我强烈建议把提示词当代码管每个版本标注日期、模型名、评测分数、变更内容保存到Git或配置中心。每次改动提示词跑一遍回归集确认所有指标不低于上一个版本才允许切流。切流时用灰度20%流量先走新版本观测一天实体F1无波动再全量。这套机制配合上面的评测集能让LLM-NER/IE的线上稳定性达到传统模型的水平。最后记住一个原则提示词越写越短是目标不是手段删除一句废话之前先跑评测。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →