别调 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 内部会激活:
- 语言理解模块 → 读懂中文
- 情感识别模块 → 判断正向/负向
- 格式生成模块 → 输出指定格式
当你写"提取商品名称和品牌"时,LLM 会激活:
- NER(命名实体识别)模块
- 属性分类模块
- 结构化输出模块
好的 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" }
两个关键操作:
- 指定 JSON 的 key 名 → 下游代码直接
JSON.parse()就能用 - 用"未知"兜底缺失信息 → 不会因为 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 全栈实战。