借助大语言模型与Prompt工程,通过Node.js模块化架构和ES6语法,高效完成了情感分类、信息提取、主题推断及文本总结等传统NLP任务。代码分层清晰、易于复用,LLM调用与Prompt设计灵活可控,显著缩短了开发周期。
传统自然语言处理(NLP)开发,哪怕只是一个简单的二分类任务,也得走完数据清洗、特征工程、模型选型、训练调优、部署上线这一整套流程。一个经验丰富的算法团队,交付一个可用的情感分析接口,通常需要数天甚至数周的时间。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
但现在,借助大语言模型(LLM)和 Prompt Engineering,同样功能的 NLP 系统,几分钟就能搭起来。下面以一个真实的 Node.js 项目为例,完整展示如何通过模块化的代码结构、ES6 现代语法和精心设计的 Prompt,高效完成一系列任务:
所有代码和注释都来自这个项目,接下来逐段分析其设计思想与实现细节。
一个优秀的 AI 应用,首先应该是一个结构清晰、易于维护和复用的 Node.js 模块。项目分为三个核心文件:
| 文件 | 职责 | 导出内容 |
|---|---|---|
client.mjs | 封装 LLM 客户端(OpenAI 兼容接口) | 默认导出 client 对象 |
completions.mjs | 定义具体的 LLM 调用函数 | 命名导出 getCompletion、getImage |
main.mjs / main2.mjs | 程序入口,编排 Prompt 并执行 | 不导出,直接运行 |
这种分层设计带来了三个直接好处:
client.mjs,新增 Prompt 任务只改 main 文件。getCompletion 可以在任何地方被引入,无需重复编写 chat.completions.create 逻辑。client.mjs) 解析import { OpenAI } from 'openai';
import dotenv from 'dotenv';
dotenv.config();
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: process.env.DEEPSEEK_API_BASE_URL,
});
export default client;
几个关键设计点:
dotenv 从 .env 文件读取 API 密钥和 Base URL,避免硬编码。OpenAI 实例时,baseURL 指向了 DeepSeek 或其他兼容服务——说明这套代码不局限于 OpenAI 官方,可以替换任意提供相同接口的 LLM。client 作为整个模块的核心资源暴露出去。completions.mjs) 解析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;
}
export async function getImage(prompt) {
// 预留:图像生成接口
}
设计亮点:
getCompletion 是一个通用的 LLM 调用入口,接收任意 Prompt 字符串,返回模型的文本回复。DEEPSEEK_MODEL 控制,方便切换不同模型(如从 DeepSeek-V3 换到 GPT-4)。getImage 函数,体现了可扩展性——未来可以轻松加入图像生成能力。export async function),允许多个任务函数共存。在 main2.mjs 的开头,有一段被注释掉的代码,正是对 ES6 核心特性的精彩演示。我们来深入分析一下。
let { name, age } = { "name": "詹姆斯", "age": 20 };
console.log(name, age); // 詹姆斯 20
let obj = { "name": "姚明", "city": "上海" };
let { name, city } = obj;
传统写法需要 obj.name、obj.city 逐个访问,解构赋值让代码更简洁,同时性能更好(因为引擎可以直接绑定属性到变量)。在大型项目中,这种写法极大地提升了代码的可读性。
let [coach, ...players] = ['范甘迪', '姚明', '麦迪', '穆托姆博', '弗朗西斯'];
console.log(coach); // '范甘迪'
console.log(players); // ['姚明', '麦迪', '穆托姆博', '弗朗西斯']
let [hrCoach, ...hrPlayers] = ['杰克逊', '科比', '费舍尔', '加索尔'];
let allPlayers = [...players, ...hrPlayers];
console.log(allPlayers); // ['姚明', '麦迪', '穆托姆博', '弗朗西斯', '科比', '费舍尔', '加索尔']
... 在赋值左边时是 Rest 运算符,用于收集剩余元素到一个数组。... 在表达式右边时是 Spread 运算符,用于展开数组或对象。// 同时导入默认导出和命名导出
import client, { a, b } from "./client.mjs";
// 默认导出
export default client;
// 命名导出
export const a = 2;
export const b = 3;
这些注释清晰地解释了默认导出只能有一个,而命名导出可以有多个。在大型项目中,这种区分可以让模块的公共接口更加明确。
main.mjs 和 main2.mjs 中包含了大量被注释掉但非常有价值的 Prompt 示例。下面按任务类型重新组织,每个示例都配有完整代码和输出说明。
const lamp_review_zh = `我需要一盏漂亮的卧室灯,这款灯具有额外的储物功能,价格也不算太高。我很快就收到了它。在运输过程中,我们的灯绳断了,但是公司很乐意寄送了一个新的。几天后就收到了。这款灯很容易组装。我发现少了一个零件,于是联系了他们的客服,他们很快就给我寄来了缺失的零件!在我看来,Lumina 是一家非常关心顾客和产品的优秀公司!`;
const prompt = `以下用三个反引号分隔的产品评论的情感是什么?用一个单词回答:正面或负面
评论文本:
\`\`\`${lamp_review_zh}\`\`\``;
const response = await getCompletion(prompt);
console.log(response);
// 正面
分析:
const prompt = `以下用三个反引号分割的产品评论是否表达了愤怒?给出是或否的回答。
评论文本:
\`\`\`${lamp_review_zh}\`\`\``;
// 输出:否
这是一个更细粒度的情感分析。传统方法需要额外标注“愤怒”类别并重新训练模型。而这里只需修改一句指令,同一个 LLM 就能完成新任务。
const prompt = `识别以下用三个反引号分隔的产品评论的作者表达的情感。包含不超过5个项目。将答案格式化为逗号分隔的单词列表。
评论文本:
\`\`\`${lamp_review_zh}\`\`\``;
// 可能输出:满意, 感激, 高兴, 放心, 惊喜
不限制情感类型(正面/负面),而是让 LLM 自由提取评论中蕴含的情感词。这对于客户反馈的深度分析非常有用。“不超过5个项目” 可以防止输出过长,也迫使 LLM 聚焦于最显著的情感。“逗号分隔的单词列表”是一种简单的结构化输出,便于后续用 split(',') 解析。
虽然文件中没有完整写出,但根据注释提示,典型写法如下:
const prompt = `将评论的情感分类为:正面、负面、中性。
示例:
评论:"非常好用" -> 正面
评论:"垃圾产品" -> 负面
评论:"一般般" -> 中性
现在请分类:
评论:"${someReview}"`;
Few-Shot 是指给 LLM 提供少量示例(通常是 1~5 个),让它通过模仿来完成任务。当任务边界模糊或输出格式复杂时,Few-Shot 可以显著提高准确率。示例覆盖了正面、负面、中性三类,LLM 会学习这种映射关系,然后对未知评论进行分类。
const prompt = `从评论文本中识别以下项目:
- 评论者购买的商品
- 制造该商品的公司
将你的响应格式以"物品(product)"和"品牌(brand)"为键的JSON对象。如果信息不存在,请使用**未知**作为值。
评论文本:
\`\`\`${lamp_review_zh}\`\`\``;
// 输出:{"product": "卧室灯", "brand": "Lumina"}
强制要求输出 JSON 对象,这是让 LLM 输出的结果可以被程序直接 JSON.parse() 的关键。增加“如果信息不存在,请使用未知”可以避免 LLM 胡乱编造(幻觉问题)。例如,如果评论中没有提到品牌,LLM 不会瞎猜一个,而是输出 "brand": "未知"。这种技术可以用于自动抽取电商评论中的产品属性、价格、物流信息、售后评价等,实现非结构化数据到结构化数据的转换。
const story_zh = `在政府最近进行的一项调查中,要求公共部门的员工对他们所在部门的满意度进行评分。调查结果显示,NASA 是最受欢迎的部门,满意度为 95%。一位 NASA 员工 John Smith 对这一发现发表了评论,他表示:"我对 NASA 排名第一并不感到惊讶。这是一个与了不起的人们和令人难以置信的机会共事的好地方。我为成为这样一个创新组织的一员感到自豪。"NASA 的管理团队也对这一结果表示欢迎,主管 Tom Johnson 表示:"我们很高兴听到我们的员工对 NASA 的工作感到满意。我们拥有一支才华横溢、忠诚敬业的团队,他们为实现我们的目标不懈努力,看到他们的辛勤工作得到回报是太棒了。"调查还显示,社会保障管理局的满意度最低,只有 45%的员工表示他们对工作满意。政府承诺解决调查中员工提出的问题,并努力提高所有部门的工作满意度。`;
const prompt = `确定以下给定文本中讨论的五个主题。每个主题用一到两个单词概括。输出时用逗号分隔。
给定文本:${story_zh}`;
// 输出:NASA, 员工满意度, 政府调查, 管理团队, 社会保障局
主题推断是传统无监督学习(如 LDA)的典型任务,需要调参(主题数量、超参数)且输出是一堆概率分布词,可读性差。而这里直接用 Prompt 完成,输出可读性极高,并且可以指定主题数量和词长限制。注意:LLM 在这里不仅做了聚类,还做了命名实体识别(NASA、社会保障局)和抽象概念归纳(员工满意度、管理团队)。
const prod_review_zh = `这个熊猫公仔是我给女儿的生日礼物,她很喜欢,去哪都带着。公仔很软,超级可爱,面部表情也很和善。但是相比于价钱来说,它有点小,我感觉在别的地方用同样的价钱能买到更大的。快递比预期提前了一天到货,所以在送给女儿之前,我自己玩了会。`;
const prompt = `您的任务是从电子商务网站上生成一个产品评论的简短摘要。请对三个反引号之间的评论文本进行概括,最多30个词汇。
评论文本:
\`\`\`${prod_review_zh}\`\`\``;
“最多30个词汇”是常见的长度控制技巧。LLM 会严格遵守,因为这是明确的数值约束。相比之下,如果说“简短一点”,LLM 的“简短”可能因人而异。这种摘要可以直接用于商品页面的短评展示、客服工单的自动摘要等。
const prompt = `您的任务是从电子商务网站上生成一个产品评论的简短摘要。请对三个反引号之间的评论文本进行概括,最多30个词汇。并且聚焦在产品运输上。
评论文本:
\`\`\`${prod_review_zh}\`\`\``;
// 可能的输出:快递提前一天到货,买家在送给女儿前自己先玩了。
通过添加“并且聚焦在产品运输上”,我们要求 LLM 忽略其他信息(如价格、质量),只关注物流体验。这是可控文本生成的典型应用。在电商客服分析中,可以批量抽取“物流差评”的共同原因,而不被其他内容干扰。
const prompt = `您的任务是从电子商务网站上生成一个产品评论的简短摘要。请对三个反引号之间的评论文本进行概括,最多30个词汇。并且聚焦在产品运输上,以及产品的价格和质量上。
评论文本:
\`\`\`${prod_review_zh}\`\`\``;
// 输出:快递提前一天到货,价格偏高且公仔偏小,但柔软可爱。
可以同时聚焦多个方面,用“以及”或逗号连接即可。LLM 能够综合这些指令,输出一个融合了运输、价格、质量的摘要。这种多维度控制非常灵活,可用于生成不同视角的摘要,供不同部门使用(物流部看运输摘要,产品部看质量摘要)。
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');
}
四篇评论分别是:熊猫公仔(软但价格偏高)、台灯(灯绳断裂但客服好)、电动牙刷(电池续航好但刷头太小)、搅拌机(价格波动大、质量下降)。每篇评论都独立调用 getCompletion,输出极短的摘要(最多20个字符)。这个循环展示了如何将 Prompt 工程应用到批量数据处理场景,例如分析过去一周的所有用户评论。
传统 NLP 任务需要“熟练的机器学习人员数天到数周的时间”,而 Prompt 方法只需要几分钟。这种差距的本质是什么?
| 传统 ML 流程 | Prompt 流程 |
|---|---|
| 标注大规模数据集 | 无需标注 |
| 设计特征工程 | 无需特征 |
| 选择模型架构(CNN/RNN/Transformer) | 无需选型 |
| 训练、调参、验证 | 无需训练 |
| 部署模型服务 | 调用 LLM API |
| 处理 OOV(未登录词)问题 | LLM 泛化能力强 |
传统方法中,模型的知识完全来自训练数据,一旦遇到训练集外的表达方式就会失效。而 LLM 在海量语料上预训练后,已经具备了语言理解与推理的通用能力。我们只需要通过 Prompt 将这种能力引导到特定任务上。
LLM 并不是真正“理解”了任务,而是通过注意力机制从 Prompt 中提取模式。例如,当我们给出“评论:xxx -> 正面”的示例时,模型会在内部表示空间中调整权重分配,从而对下一个输入产生类似输出。这种能力称为 In-Context Learning。
Prompt 方法并非万能:
temperature=0 提高确定性。通过分析这个项目,可以梳理出几个关键收获:
client.mjs 封装 LLM 连接,用 completions.mjs 定义通用调用函数,用 main.mjs 编排业务逻辑。现在,可以回到编辑器中,尝试修改 main.mjs 里的 review 数组,加入自己的产品评论,看看 LLM 会给出怎样的摘要和情感分析。通往 AI 原生应用开发的路,已经铺好了。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述