前言:传统 NLP 任务------情感分类、信息提取、文本总结------往往需要熟练的机器学习工程师花费数天到数周来训练模型。而大语言模型时代的到来彻底改变了这一切:只需一份精心设计的 Prompt,几分钟就能构建出企业级的 NLP 系统。本文从 ES6 模块化架构搭建开始,用 OpenAI SDK 封装调用层,通过四个实战案例带你掌握 Prompt 驱动的 NLP 开发全流程。
目录
- [NLP 的 Prompt 时代](#NLP 的 Prompt 时代 "#%E4%B8%80nlp-%E7%9A%84-prompt-%E6%97%B6%E4%BB%A3")
- [ES6 模块化:三层架构搭建](#ES6 模块化:三层架构搭建 "#%E4%BA%8Ces6-%E6%A8%A1%E5%9D%97%E5%8C%96%E4%B8%89%E5%B1%82%E6%9E%B6%E6%9E%84%E6%90%AD%E5%BB%BA")
- [LLM 客户端的安全封装](#LLM 客户端的安全封装 "#%E4%B8%89llm-%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84%E5%AE%89%E5%85%A8%E5%B0%81%E8%A3%85")
- 实战一:情感分类
- 实战二:结构化信息提取
- 实战三:多聚焦文本总结
- 实战四:主题推断与批量处理
- 总结
一、NLP 的 Prompt 时代
NLP(Natural Language Processing,自然语言处理)曾是机器学习领域最具门槛的方向之一。要搭建一个情感分类系统,过去的标准流程是:标注数据 → 特征工程 → 模型训练 → 调参 → 部署。一个熟练的 ML 工程师可能需要数天到数周。
在大语言模型时代,这一切被简化为一段 Prompt:
你的任务是将以下产品评论的情感分类为正面或负面。
用一个单词回答。
评论文本:这个熊猫公仔很软很可爱,女儿很喜欢。
模型返回:正面。
这不是魔法,而是 Prompt Engineering------用自然语言作为"程序指令",让 LLM 执行分类、提取、总结等 NLP 任务。几分钟替代数周,这是 NLP 的"iPhone 时刻"。
二、ES6 模块化:三层架构搭建
在动手写 Prompt 之前,先把项目架构搭好。ES6(ECMAScript 2015)带来的模块化系统(ESM)让 JavaScript 真正具备了企业级项目的组织能力。
一个清晰的 NLP 项目推荐采用三层架构:
| 层级 | 职责 | 关键语法 |
|---|---|---|
| 客户端模块 | 创建并导出 LLM 连接对象 | export default |
| 任务模块 | 封装可复用的 NLP 函数 | export async function |
| 入口模块 | 调用任务函数,串联业务逻辑 | import |
ES6 模块的核心语法:
javascript
// 默认导出 ------ 一个模块只有一个
export default client;
// 命名导出 ------ 可导出多个
export async function getCompletion(prompt) { ... }
// 导入
import client from './client.mjs'; // 接收默认导出
import { getCompletion } from './completion.mjs'; // 接收命名导出
这种组织方式带来了三个明显的好处:可维护 (每个文件职责单一)、可复用 (任务函数可跨项目使用)、可测试(每个模块独立验证)。
ES6 赋能大型项目的其他利器
除了模块化,ES6 还提供了几个让代码更简洁优雅的特性:
解构赋值 ------ 从对象/数组中"无痛"提取值:
javascript
// 对象解构
let { name, city } = { name: "姚明", city: "上海" };
console.log(name); // "姚明"
// 数组解构 + rest 运算符
let [coach, ...players] = ["范甘迪", "姚明", "麦迪", "穆托姆博", "弗朗西斯"];
console.log(coach); // "范甘迪"
console.log(players); // ["姚明", "麦迪", "穆托姆博", "弗朗西斯"]
rest / spread 运算符 ------ 收拢与展开:
javascript
// rest:收拢剩余项
let [head, ...tail] = [1, 2, 3, 4, 5]; // head=1, tail=[2,3,4,5]
// spread:展开数组
let teamA = ["姚明", "麦迪"];
let teamB = ["科比", "费舍尔"];
let allStars = [...teamA, ...teamB]; // ["姚明","麦迪","科比","费舍尔"]
解构赋值不仅让代码更易读,在性能上也优于逐属性访问------引擎一次性完成属性定位,而非多次查找。
三、LLM 客户端的安全封装
与 LLM 交互的第一步是创建客户端对象。这里有两个关键实践:环境变量管理密钥 ,以及 async/await 处理异步调用。
客户端模块
javascript
import { OpenAI } from 'openai';
import dotenv from 'dotenv';
dotenv.config(); // 将 .env 文件中的变量注入 process.env
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY, // 密钥不硬编码
baseURL: process.env.DEEPSEEK_BASE_URL
});
export default client;
安全红线 :API Key 绝对不能硬编码在源代码中,更不能提交到 Git 仓库。使用
dotenv+.env文件管理,并确保.env已加入.gitignore。一旦 Key 泄露到公开仓库,攻击者可以在几分钟内将其用于加密货币挖矿等恶意行为。
任务封装模块
javascript
import client from './client.mjs';
export async function getCompletion(prompt) {
const response = await client.chat.completions.create({
model: process.env.DEEPSEEK_MODEL,
messages: [
{ role: 'user', content: prompt }
]
});
return response.choices[0].message.content;
}
这里使用了 Completion 接口------LLM 交互的行业标准。chat.completions.create() 接受 messages 数组,每条消息包含 role(身份)和 content(内容)。对于单轮 NLP 任务,只需一个 user 角色即可。
入口模块
javascript
import { getCompletion } from './completion.mjs';
async function main() {
const prompt = `你的 Prompt 指令...`;
const response = await getCompletion(prompt);
console.log(response);
}
main();
入口文件保持极简------只负责导入和调用,具体任务逻辑封装在 Prompt 和任务函数中。
四、实战一:情感分类
情感分类(Sentiment Analysis)是 NLP 最基础也最广泛的应用场景。电商平台用它监控产品口碑,客服系统用它做预警升级,产品团队用它做质检分析。
场景:对一条灯具的产品评论进行情感判断。
javascript
const lamp_review = `
我需要一盏漂亮的卧室灯,这款灯具有额外的储物功能,价格也不算太高。
我很快就收到了它。在运输过程中,我们的灯绳断了,但是公司很乐意寄送了一个新的。
几天后就收到了。这款灯很容易组装。我发现少了一个零件,于是联系了他们的客服,
他们很快就给我寄来了缺失的零件!
在我看来,这是一家非常关心顾客和产品的优秀公司!
`;
Prompt 的递进式设计
Prompt 不是一次写成的,而是逐步精化的。下面展示了同一任务从粗到细的 Prompt 演化:
版本 1 ------ 过于开放:
go
以下用三个反引号分隔的产品评论的情感是什么?
评论文本:``` {评论} ```
模型可能返回一段冗长的解释,不便于程序处理。
版本 2 ------ 约束输出格式:
go
以下用三个反引号分隔的产品评论的情感是什么?
用一个单词回答:正面 或 负面
评论文本:``` {评论} ```
添加"用一个单词回答"后,输出变为可控的 正面 或 负面。
版本 3 ------ 更细粒度的情绪识别:
go
识别以下产品评论中作者表达的情感。
包含不超过 5 个项目。
将答案格式化为以逗号分隔的单词列表。
评论文本:``` {评论} ```
输出可能为:满意, 感谢, 开心, 信任------比简单的正负面更丰富。
版本 4 ------ 特定情绪检测:
go
以下产品评论是否表达了愤怒?给出是或否的答案。
评论文本:``` {评论} ```
这种"是/否"判断在客服预警场景中非常实用------自动标记出愤怒用户,优先处理。
设计要点
| 原则 | 说明 | 示例 |
|---|---|---|
| 使用分隔符 | 用 ``````````` 或 """ 包裹输入文本 |
评论文本:```{text}``` |
| 约束输出格式 | 明确要求"一个单词""是或否""逗号分隔列表" | 用一个单词回答:正面 或 负面 |
| 逐步精化 | 从宽泛到具体,按需增加约束 | 情感 → 正负面 → 多标签 → 愤怒检测 |
五、实战二:结构化信息提取
情感分类的输出是单一标签,但在实际业务中,往往需要从一段文本中同时提取多个字段,并以结构化格式(JSON)返回,方便后续程序处理。
javascript
const prompt = `
从评论文本中识别以下项目:
- 情绪(正面或负面)
- 是否表达了愤怒?(是或否)
- 评论者购买的商品
- 制造该物品的公司
评论用三个反引号分隔。
将你的响应格式化为 JSON 对象,以 "sentiment"、"anger"、"product"、"brand" 为键。
如果信息不存在,请使用 "未知" 作为值。
将 anger 格式化为布尔值。
评论文本:\`\`\` ${lamp_review} \`\`\`
`;
模型返回的 JSON:
json
{
"sentiment": "正面",
"anger": false,
"product": "卧室灯",
"brand": "未知"
}
结构化输出的关键技巧
- 明确键名和类型:"将 anger 格式化为布尔值"------不给模型自由发挥的空间。
- 兜底策略:"如果信息不存在,请使用 '未知'"------防止模型凭空捏造。
- JSON 格式指定:直接告诉模型输出 JSON,大多数现代 LLM 都能准确遵循。
信息提取是 RAG(检索增强生成)和 AI Agent 的基础能力。Agent 需要从用户输入中提取参数(商品名、日期、金额),然后调用相应的工具或 API。这个 Prompt 就是 Agent 工具调用链的雏形。
六、实战三:多聚焦文本总结
文本总结(Summarization)是另一个高频 NLP 任务。一段长评论文本,不同角色关注的信息完全不同:
| 角色 | 关注点 |
|---|---|
| 物流主管 | 运输速度、包装质量、快递体验 |
| 产品经理 | 价格竞争力、产品质量、尺寸感受 |
| 运营编辑 | 整体亮点、可用于营销的正面描述 |
同一个产品评论,三份 Prompt,三种聚焦:
通用总结:
go
你的任务是从电子商务网站上生成一个产品评论的简短摘要。
请对三个反引号之间的评论文本进行概括,最多 30 个词汇。
评论文本:``` {评论} ```
聚焦运输:
go
你的任务是从电子商务网站上生成一个产品评论的简短摘要。
请对三个反引号之间的评论文本进行概括,最多 30 个词汇,
并且聚焦在产品运输上。
评论文本:``` {评论} ```
聚焦价格和质量:
go
你的任务是从电子商务网站上生成一个产品评论的简短摘要。
请对三个反引号之间的评论文本进行概括,最多 30 个词汇,
并且聚焦在产品价格和质量上。
评论文本:``` {评论} ```
同一个 Prompt 模板,只改动一句聚焦指令(聚焦在...),输出截然不同------这正是 Prompt 作为"软代码"的魅力:不需要重新训练模型,改一句话就换了任务视角。
七、实战四:主题推断与批量处理
主题推断(Topic Inference)能从长文本中自动识别讨论的核心话题。这在舆情监控、客服工单分类、社交媒体分析等场景中非常实用。
场景:对一段政府调查报告进行主题提取。
javascript
const story = `
在政府最近进行的一项调查中,要求公共部门的员工对他们所在部门的满意度进行评分。
调查结果显示,NASA 是最受欢迎的部门,满意度为 95%。
一位 NASA 员工 John Smith 表示:
"我对 NASA 排名第一并不感到惊讶。这是一个与了不起的人们共事的好地方。"
调查还显示,社会保障管理局的满意度最低,只有 45%的员工表示满意。
政府承诺解决调查中员工提出的问题,并努力提高所有部门的工作满意度。
`;
const prompt = `
确定以下给定文本中讨论的五个主题。
每个主题用 1-2 个单词概括。
输出时用逗号分隔。
给定文本:${story}
`;
模型输出:员工满意度, NASA, 政府调查, 工作环境, 社会保障
批量处理模式
在真实业务中,往往需要处理大量文本。利用循环 + async/await:
javascript
const reviews = [review_1, review_2, review_3, review_4];
for (let review of reviews) {
const prompt = `
你的任务是从电子商务网站上的产品评论中提取相关信息。
请对三个反引号之间的评论文本进行概括,最多 20 个字符。
评论文本:\`\`\` ${review} \`\`\`
`;
const response = await getCompletion(prompt);
console.log(response, '\n');
}
注意循环中使用
await是串行执行的------适合小批量任务。如果面对数百条以上的文本,可以改用Promise.all()并行调用,大幅提升吞吐量。
八、总结
从"需要 ML 工程师数周"到"写一段 Prompt 几分钟完成",NLP 的门槛已经被 LLM 彻底抹平。回顾本文的核心要点:
架构层面:
- ES6 模块化(
import/export)让项目结构清晰,三层架构(客户端 → 任务 → 入口)职责分明。 dotenv+ 环境变量是 API Key 管理的安全基线,密钥永远不硬编码。
Prompt Engineering 层面: 3. 情感分类 ------ 使用分隔符隔离输入、约束输出格式、逐步精化指令。 4. 信息提取 ------ 指定 JSON 键名和类型、提供兜底策略、结构化输出便于程序消费。 5. 文本总结 ------ 通过"聚焦"指令实现同一文本的多视角摘要。 6. 主题推断 ------ 限制主题数量和输出格式,批量处理时注意串行与并行的选择。
一条核心心法 :把 Prompt 当成代码来迭代。 写代码需要版本管理、单元测试、Code Review------写 Prompt 也应该如此。从一个简单的指令开始,观察输出,逐步加约束,直到结果稳定可靠。
------ NLP 不再是资深人士的专利,而是一个 Prompt 工程师的日常。