别调 BERT 了:我用 Prompt 做了套 NLP 系统,20 分钟搞定

别调 BERT 了:我用 Prompt 做了套 NLP 系统,20 分钟搞定

以前做 NLP = 收集数据 → 标注 → 训练 → 调参 → 部署 = 一周 现在做 NLP = 写 Prompt = 20 分钟 这篇文章告诉你这套方案的核心原理、实战技巧、以及什么时候别用它。


先看效果

我拿这篇产品评论跑了 5 个 NLP 任务:

arduino 复制代码
原始评论:
"我需要一盏漂亮的卧室灯,这款灯具有额外的储物功能,价格也不算太高。
我很快就收到了它。在运输过程中,我们的灯绳断了,但是公司很乐意寄送了一个新的。
几天后就收到了。这款灯很容易组装。我发现少了一个零件,于是联系了他们的客服,
他们很快就给我寄来了缺失的零件!在我看来,Lumina 是一家非常关心顾客和产品的优秀公司!"

5 个 Prompt,5 个结果,全部秒回:

任务 Prompt 结果
情感分析 "用一个单词回答:正面/负面/中性" 正面
愤怒检测 "给出是或否的答案"
信息提取 "格式化为 JSON,key 为 product/brand" {product: "卧室灯", brand: "Lumina"}
多维度提取 "一次返回 4 个维度,布尔值格式" {sentiment: "正面", anger: false, ...}
主题归纳 "5 个主题,1-2 个中文词" 客户服务, 产品质量, 配送问题, 组装体验, 公司形象

20 分钟写完,0 训练,0 标注,0 GPU。


背景:这条路为什么被掀翻了

过去几年,做 NLP 绕不开一条路:

scss 复制代码
收集数据(3天) → 标注数据(3天) → 选模型(1天) → 训练(2天) → 调参(2天) → 部署(1天)

每个任务一个独立模型------情感分析一个,实体提取一个,文本摘要又一个。

但现在,大语言模型把这条路掀翻了。

原因很简单:LLM 在预训练阶段已经"见过"了几乎所有互联网文本。你不需要再教它"什么是情感",你只需要用 Prompt 把它已经会的知识唤醒

这就像------你不需要重新造一个计算器,你只需要知道怎么按按钮。


核心原理:Prompt 为什么有效?

很多人写 Prompt 是凭感觉,但我建议先理解背后的逻辑。

Prompt 的本质是什么?

Prompt 本质上是在激活 LLM 内部的特定知识回路

当你写"判断这段评论的情感"时,LLM 内部会激活:

  1. 语言理解模块 → 读懂中文
  2. 情感识别模块 → 判断正向/负向
  3. 格式生成模块 → 输出指定格式

当你写"提取商品名称和品牌"时,LLM 会激活:

  1. NER(命名实体识别)模块
  2. 属性分类模块
  3. 结构化输出模块

好的 Prompt = 精准定位 + 清晰指令 + 明确格式。

为什么 LLM 能做这么多任务?

因为 LLM 是"通用任务求解器",而不是"专用任务模型"。

BERT 训练时,只学习"做完形填空"这一个任务。 GPT 训练时,学习"预测下一个词"这个任务,然后发现------预测得足够准之后,它自然就学会了翻译、摘要、问答、情感分析......所有任务。

这就是"涌现能力"(Emergent Abilities):当模型大到一定程度,它突然就能做你没专门训练过的事情。


技术栈:简单到不好意思说

整个项目只有两个依赖:

bash 复制代码
npm install openai dotenv
javascript 复制代码
nlp-demo/
├── .env              # API 密钥
├── client.mjs        # LLM 客户端
├── completion.mjs    # 通用调用函数
└── main.mjs          # 入口 + NLP 任务演示

客户端配置:三行搞定

javascript 复制代码
// client.mjs
import { OpenAI } from 'openai';
import dotenv from 'dotenv';

dotenv.config();

const client = new OpenAI({
  apiKey: process.env.LLM_API_KEY,
  baseURL: process.env.LLM_BASE_URL  // 换 API 只需改这里
});

export default client;

关键点 :所有兼容 OpenAI 接口的 LLM(DeepSeek、Claude、千问、GLM......)都适用这套代码。换一个 baseURL,换一套模型,一行代码都不用改。

通用调用函数:一个入口,所有任务复用

javascript 复制代码
// completion.mjs
import client from './client.mjs';

export async function getCompletion(prompt) {
  const response = await client.chat.completions.create({
    model: process.env.LLM_MODEL,
    messages: [{ role: 'user', content: prompt }]
  });
  return response.choices[0].message.content;
}

传入 Prompt,返回 LLM 的文本响应。后面所有 NLP 任务都从这个口子进去。


实战:5 个任务,5 段 Prompt

任务一:情感分析

核心 Prompt 技巧:限定输出格式

javascript 复制代码
const prompt = `
以下用三个反引号分隔的产品评论的情感是什么?
用一个单词回答:正面 或 负面 或 中性
评论文本:\`\`\`${review}\`\`\`
`;

await getCompletion(prompt);  // → 正面

"用一个单词回答"------这六个字是精髓。不加这句,LLM 会给你输出一段三百字的分析报告,你还得写正则去匹配。加上这六个字,直接拿到干净的结果。

任务二:愤怒检测

核心 Prompt 技巧:二分类简化

javascript 复制代码
const prompt = `
以下用三个反引号分隔的产品评论是否表达了愤怒?
给出是或否的答案。
评论文本:\`\`\`${review}\`\`\`
`;

await getCompletion(prompt);  // → 否

Prompt 越简单,LLM 的输出越稳定。 二分类任务不需要复杂描述,问清楚就行。

任务三:信息提取(结构化输出)

这是 Prompt 最强大的用法------从自由文本提取结构化数据:

javascript 复制代码
const prompt = `
从评论文本中识别以下项目:
- 评论者购买的商品
- 制造该物品的公司

评论文本用三个反引号分隔。
将响应格式化为以"product"和"brand"为键的 JSON 对象。
如果信息不存在,请使用"未知"作为值。
评论文本:\`\`\`${review}\`\`\`
`;

await getCompletion(prompt);
// → { "product": "卧室灯(带储物功能)", "brand": "Lumina" }

两个关键操作:

  1. 指定 JSON 的 key 名 → 下游代码直接 JSON.parse() 就能用
  2. 用"未知"兜底缺失信息 → 不会因为 LLM 找不到品牌就输出 null 或报错

任务四:多维度一次性提取

传统方案:三个独立模型 → Prompt 方案:一个调用:

javascript 复制代码
const prompt = `
从评论文本中识别以下项目:
- 情绪(正面或负面)
- 是否表达了愤怒?(是或否)
- 评论者购买的商品
- 制造该物品的公司

评论用三个反引号分隔。
将响应格式化为 JSON 对象,以"sentiment"、"anger"、"product"、"brand"为键。
如果信息不存在,请使用"未知"作为值。
让你的回复尽可能简短。
将 anger 值格式化为布尔值。
评论文本:\`\`\`${review}\`\`\`
`;

await getCompletion(prompt);
// → { "sentiment": "正面", "anger": false, "product": "卧室灯", "brand": "Lumina" }

一次 API 调用,四个维度。 anger 要求布尔值而不是字符串,拿到就能直接写 if 判断。

任务五:主题推断

核心 Prompt 技巧:限制输出数量和格式

javascript 复制代码
const prompt = `
确定以下给定文本中讨论的五个主题。
每个主题用一到两个中文单词概括。
输出时用逗号分隔。
给定文本:${story}
`;

await getCompletion(prompt);
// → 政府调查, 员工满意度, NASA, 社会保障管理局, 工作改善

限定了"五个"和"一到两个中文单词"------没有这些约束,LLM 可能给你输出二十个主题,每个还是一整句话。


批量处理:一条评论是 Demo,一万条才是生产

javascript 复制代码
import { getCompletion } from "./completion.mjs";

const reviews = [
  `这个熊猫公仔是我给女儿的生日礼物,她很喜欢,去哪都带着。
   公仔很软,超级可爱,但是相比于价钱来说,它有点小。`,
  `这款卧室灯有额外的存储空间,价格也不太高。运输过程中灯绳断了,
   但公司很乐意寄送了一个新的。客服态度非常好。`,
  `电动牙刷的电池续航令人印象深刻。但刷头实在太小了。
   如果能以50美元购入,那它就物超所值。`,
  `11月以$49的优惠价买的搅拌机,12月就涨到了$89。
   一年后电机开始发出可疑的声音。整体质量在下滑。`
];

for (let review of reviews) {
  const prompt = `
    你的任务是从电子商务网站上的产品评论中提取相关信息。
    请对三个反引号之间的评论文本进行概括,最多20个字符。
    评论文本:\`\`\`${review}\`\`\`
  `;
  console.log(await getCompletion(prompt));
}

输出:

复制代码
熊猫公仔礼物,可爱但偏小
卧室灯品质好,客服优
电动牙刷续航强,性价比高
搅拌机涨价快,质量下滑

同一个评论,改 Prompt 的聚焦点 ------"聚焦在产品运输上"、"聚焦在价格和质量上"------就能生成完全不同视角的摘要。一个模型,N 种切面。


三个 Prompt 写法的铁律

写了这么多 Prompt,总结出三条最核心的原则:

铁律一:用分隔符隔开指令和数据

javascript 复制代码
// ✅ 反引号分隔,边界清晰
评论文本:\`\`\`${review}\`\`\`

// ❌ 没有分隔符,LLM 可能把指令当内容
评论文本:${review}

不分隔,LLM 有时候会把你的指令当成评论的一部分来分析,输出莫名其妙的结果。

铁律二:明确指定输出格式

javascript 复制代码
// ✅ JSON + 指定 key,下游直接用
格式化为 JSON 对象,以"product"和"brand"为键

// ❌ 不指定格式,输出一大段话
提取商品和品牌信息

你要的是数据,不是散文。格式越明确,输出越可控。

铁律三:限制输出范围

javascript 复制代码
// ✅ 限定字数和数量
最多30个词汇,不超过5个项目

// ❌ 不加限制
提取情感

不加限制的 Prompt 就像不加 deadline 的需求------LLM 会给你交一份洋洋洒洒的毕业论文。


什么时候别用 Prompt 方案?

Prompt 方案不是银弹。这几个场景,乖乖回去调 BERT:

场景一:需要极高精度

LLM 的情感分析精度大概在 85%-95% ,对于大多数场景够用了。 但如果你的业务场景要求 99%+ 的准确率(比如金融风控、医疗诊断),LLM 还是差点意思。

场景二:需要离线部署

LLM API 需要联网,响应延迟在 200-500ms 左右。 如果你的场景要求 毫秒级响应 (比如实时风控)或者需要 完全离线运行(比如嵌入式设备),传统模型更合适。

场景三:数据敏感不能上云

金融、医疗、政务等场景,数据不能发送到第三方 API。 这种情况私有化部署一套 BERT 或者微调一个小模型更稳妥。

场景四:成本考量

一条 LLM API 调用成本约 0.001-0.01 元 ,看起来不多,但如果每天处理 1000 万条评论 ,成本就是 1-10 万元/天 。 对比之下,一个训练好的 BERT 模型,推理成本接近


两种方案对比

scss 复制代码
传统方案(BERT):
标注数据(3天) → 训练模型(2天) → 调参(2天) → 部署(1天) = 8天
精度高,但启动成本大,适合固定场景

Prompt 方案(LLM):
写 Prompt(5分钟) → 测试调优(10分钟) → 上线(5分钟) = 20分钟
精度略低(85-95%),但启动成本极低,适合快速迭代

结论:对于 80% 的通用 NLP 需求------情感分析、实体提取、文本摘要、主题归纳------Prompt 方案的性价比碾压一切。

以前需要算法工程师干一周的活儿,现在一个开发者写几行 Prompt 就能搞定。


写在最后

这个项目只有 4 个文件,核心代码不到 50 行,覆盖了 5 个 NLP 任务

技术栈不重要。DeepSeek、OpenAI、Claude、随便哪个兼容 OpenAI 接口的服务都行。

重要的是思路的转变------从"训练模型解决问题"到"写 Prompt 解决问题"。

如果你也在做 NLP 相关的需求,别急着调 BERT。先写个 Prompt 跑一下。

大概率你会发现,以前花几周做的事情,现在一杯咖啡的功夫就搞定了。


💡 完整源码在这里:nlp-demo 觉得有帮助的话,点个赞 👍 收藏 ⭐,后续持续分享 AI 全栈实战。

相关推荐
半个落月1 小时前
别再死记变量提升了——从 V8 编译过程真正理解 JS 执行机制
前端
装不满的克莱因瓶1 小时前
学习 LLM 的函数回调及格式化输出,让 LLM 拥有更强的能力
人工智能·ai·大模型·llm·agent·智能体
涤生大数据1 小时前
从 ETL 到 Agent:AI数据工程如何搭建企业级“数据工厂“
数据仓库·人工智能·etl
手写码匠2 小时前
手写 DeepSeek 推理引擎优化:从 FP16 到 INT4 的量化加速实战
人工智能·深度学习·算法·aigc
橘子星2 小时前
别再懵圈!JS 执行机制的 “千层套路” 全揭秘
前端·javascript
GuWenyue2 小时前
LeetCode 76 最小覆盖子串|JS 滑动窗口标准解法
前端·算法·面试
YHHLAI2 小时前
前端 HTTP 请求 & LLM 接口开发
前端·网络协议·http
拾年2752 小时前
__proto__ vs prototype:90% 的人分不清的 JavaScript 核心
前端·javascript·面试
国科安芯2 小时前
国科安芯推出商业航天级抗辐照半双工 RS485 收发器 ASC485S2Y
前端·单片机·嵌入式硬件·架构·安全性测试