一、 核心认知:Prompt 驱动的 NLP 任务开发
在 AI 全栈开发中,利用大语言模型(LLM)构建自然语言处理(NLP)系统,正在彻底改变传统的开发范式。以往需要熟练的机器学习工程师耗费数天到数周才能构建的推理系统,现在仅需几分钟编写 Prompt 即可实现。
1. 常见 NLP 任务场景
- 情感分类(Sentiment Analysis/Classification) :判断文本的情感倾向(正面/负面/中性)。在电商、客户服务、舆情预警等后台系统中至关重要。
- 信息提取(Information Extraction) :从非结构化文本中精准提取特定字段(如商品名、品牌、情绪、布尔值等),并格式化为 JSON 对象。
- 主题推断(Topic Inference) :判断给定文本是否包含特定话题,或让 AI 自动总结文本中讨论的多个主题。
- 文本总结(Summarization) :针对长文本进行概括,提取核心信息。适用于老板、行政岗、内容小编等角色,大幅减少人工阅读工作量。
2. Prompt 工程的核心原则
- 使用分隔符隔离数据:使用三个反引号(```)或 XML 标签将"指令"与"待处理数据"明确隔离,防止 AI 将文本内容误认为指令(防止越狱),提升系统健壮性。
- 兜底策略(Fallback) :在 Prompt 中明确规定"如果信息不存在,请使用'未知'作为值",防止 AI 产生幻觉或输出
null导致代码崩溃。 - 规范输出格式 :要求 AI 仅输出纯 JSON 字符串或纯文本,禁止包含"好的,这是为您提取的..."等废话,确保后端代码能直接通过
JSON.parse()解析。
二、 ES6 核心语法特性
ES6(ECMAScript 2015)是 JavaScript 发展史上的里程碑,其目标是让 JS 成为支持企业级大型项目开发的语言。
1. 变量声明:let 与 const
彻底修复了 var 带来的变量提升(Hoisting)和作用域混乱问题。
-
块级作用域 :变量仅在当前的
{}块内有效,避免循环或条件语句中的变量污染。 -
禁止重复声明:同一作用域内不能重复定义同名变量。
-
const赋值规则:- 基本数据类型(数字、字符串):一旦赋值,不可重新赋值。
- 引用数据类型(对象、数组):变量指向的内存地址不可变,但内部属性或数组元素可以修改。
2. 解构赋值(Destructuring)
将"取值"行为升维为声明式模式匹配,代码简洁且底层原生实现,取值性能优于连续使用 . 操作符。
-
对象解构 :按属性名匹配取值。变量名必须与对象的 Key 完全一致,找不到则为
undefined。javascript
编辑
ini1let obj = {"name":"姚明","age":30}; 2// 传统写法:let name = obj.name; let age = obj.age; 3// ES6解构写法: 4let {name, age} = obj; 5console.log({name, age}); // { name: '姚明', age: 30 } -
数组解构:按下标顺序一一对应取值。
javascript
编辑
css1let [coach, ...players] = ['范甘迪','姚明','麦迪']; 2console.log({coach, players}); // { coach: '范甘迪', players: ['姚明', '麦迪'] }
3. 扩展运算符与剩余参数(...)
-
Rest(剩余运算符) :用于解构,必须放在参数或数组末尾,收集剩余的所有数据。
-
Spread(展开运算符) :拆解数组或对象,用于快速拼接、合并数据或传递函数参数。
javascript
编辑
css1let [hurenCoach, ...hurenPlayers] = ['杰克逊','科比','费舍尔']; 2// 合并两个球员数组 3let allPlayers = [...players, ...hurenPlayers]; 4console.log({allPlayers}); // { allPlayers: ['姚明', '麦迪', '科比', '费舍尔'] }
4. 模块化规范(ESM)
终结了全局污染与依赖隐式加载的历史,是现代前端工程化(Webpack/Vite)和 Node.js 的基石。
-
export default(默认导出) :一个模块只能有一个默认导出,外部导入时无需花括号,常用于导出全局唯一的实例(如大模型 Client)。 -
export(命名导出) :一个模块可以有多个命名导出,外部导入时必须加花括号,常用于导出具体的业务处理函数。javascript
编辑
javascript1// 混合导出示例 2export const a = 2; 3export const b = 3; 4export default client; // 默认导出 5 6// 导入示例 7import client, { a, b } from './client.mjs';
三、 NLP 项目的模块化工程搭建
随着接口、提示词、模型配置增多,将代码堆砌在单个文件中会导致代码臃肿、无法复用、维护成本暴涨。依托 ES6 模块化语法,企业级 NLP 项目通常采用标准的三层架构拆分:
1. 基础设施与配置(.env)
将敏感信息(API 密钥、接口地址、模型版本)抽离至 .env 文件,使用 dotenv 库在运行时注入到 process.env 中,实现配置与代码的彻底解耦。
2. 底层客户端模块(client.mjs)
-
职责:专注于大模型客户端的初始化。
-
实现 :读取环境变量,实例化 SDK(如 OpenAI/DeepSeek),并通过
export default暴露全局唯一的 Client 对象。javascript
编辑
arduino1import { OpenAI } from 'openai'; 2import dotenv from 'dotenv'; 3dotenv.config(); 4const client = new OpenAI({ 5 apiKey: process.env.DEEPSEEK_API_KEY, 6 baseURL: process.env.DEEPSEEK_API_BASE_URL, 7}); 8export default client;
3. 业务逻辑封装模块(completions.mjs)
-
职责:封装与大模型交互的具体业务函数。
-
实现:通过默认导入获取底层 Client 实例,对外提供命名导出的异步函数。
javascript
编辑
javascript1import client from './client.mjs'; 2export async function getCompletions(prompt) { 3 const response = await client.chat.completions.create({ 4 model: process.env.DEEPSEEK_API_MODEL, 5 messages: [{ role: "user", content: prompt }], 6 }); 7 return response.choices[0].message.content; 8} 9export async function genImage(prompt) { /* 待扩展 */ }
4. 单点入口文件(main.mjs / main2.mjs)
- 职责:项目的唯一逻辑起点,统筹业务逻辑。
- 实现:通过命名导入获取 NLP 任务函数,组装 Prompt,调用异步函数并处理输出。
四、 实战案例全解析(Prompt 驱动 NLP)
案例 1:情感分类(Sentiment Analysis)
-
Few-Shot(少样本)提示:用一个单词回答,强制约束输出。
javascript
编辑
go1const prompt = ` 2 以下用三个反引号分隔的产品评论的情感是什么? 3 用一个单词回答:正面或负面 4 评论文本:``` $ {lamp_review_zh}``` 5`; -
多维度情绪提取:要求输出逗号分隔的列表。
javascript
编辑
python1const prompt = ` 2 识别以下评论的作者表达的情感。包含不超过5个项目。 3 将答案格式化为以逗号分隔的单词列表。 4 评论文本:'''${lamp_review_zh}''' 5`; -
布尔值逻辑判断:判断是否表达了愤怒。
javascript
编辑
go1const prompt = ` 2 以下用三个反引号分隔的产品评论是否表达了愤怒? 3 给出是或否的答案。 4 评论文本:``` $ {lamp_review_zh}``` 5`;
案例 2:信息提取(Information Extraction)
-
基础提取:提取商品与品牌,使用兜底策略。
javascript
编辑
go1const prompt = ` 2 从评论文本中识别以下项目: 3 -评论者购买的商品 4 -制造该物品的公司 5 评论文本用三个反引号分隔。将你的响应格式以"物品(product)"和"品牌(brand)"为键的JSON对象。 6 如果信息不存在,请使用**未知**作为值。 7 评论文本:``` $ {lamp_review_zh}``` 8`; -
高级结构化提取:提取情绪、愤怒布尔值、商品与品牌。
javascript
编辑
arduino1const prompt = ` 2 从评论文本中识别以下项目: 3 -情绪(正面或负面) 4 -是否表达了愤怒?(是或否) 5 -评论者购买的商品 6 -制造物品的公司 7 评论文本用三个反引号分隔。将你的响应化为JSON对象,以"sentiment"和"anger"和"product"和"brand"为键。 8 如果信息不存在,请使用**未知**作为值。 9 将anger值格式化为布尔值。 10 评论文本:``` $ {lamp_review_zh}``` 11`;
案例 3:主题推断(Topic Inference)
-
判断给定话题列表:
javascript
编辑
ini1const topicLst = ["美国国家航空航天局", "地方政府", "工程", "员工满意度", "联邦政府"]; 2const prompt = ` 3 判断主题列表中的每一项是否是给定文本中的一个话题, 4 以列表的形式给出判断,每个主题用0或1。 5 主题列表:${topicLst.join(', ')} 6 文本:${story_zh} 7`; -
自动推断主题:
javascript
编辑
ini1const prompt = ` 2 确定以下给定文本中讨论的五个主题。 3 每个主题用1到2个单词回答。 4 输出时用逗号分隔主题。 5 文本:${story_zh} 6`;
案例 4:文本总结(Summarization)
-
基础概括:
javascript
编辑
go1const prompt = ` 2 您的任务是从电子商务网站上生成一个产品评论的简短摘要。 3 请对三个反引号之间的评论文本进行概括,最多30个词汇。 4 评论文本:``` $ {prod_review_zh}``` 5`; -
聚焦特定维度(人物) :
javascript
编辑
go1const prompt = ` 2 您的任务是从电子商务网站上生成一个产品评论的简短摘要。 3 请对三个反引号之间的评论文本进行概括,最多30个词汇,并且聚焦在人物上。 4 评论文本:``` $ {prod_review_zh}``` 5`; -
聚焦特定维度(价格和质量) :
javascript
编辑
go1const prompt = ` 2 您的任务是从电子商务网站上生成一个产品评论的简短摘要。 3 请对三个反引号之间的评论文本进行概括,最多30个词汇,并且聚焦在产品的价格和质量上。 4 评论文本:``` $ {prod_review_zh}``` 5`;
案例 5:批量处理与并发优化
-
串行处理(低效) :
javascript
编辑
ini1for(let review of reviews){ 2 const prompt = `...`; 3 const response = await getCompletions(prompt); 4 console.log(response); 5} -
并发处理(高效) :使用
Promise.all同时处理多个请求。javascript
编辑
ini1const tasks = reviews.map(async (review) => { 2 const prompt = `...`; 3 return await getCompletions(prompt); 4}); 5const results = await Promise.all(tasks); 6console.log(results);
五、 企业级代码最佳实践与避坑指南
1. 异步编程的规范处理
await的作用域限制 :await关键字必须且只能在async函数内部使用。如果在文件顶层直接使用,会导致 Node.js 抛出语法错误。- 并发请求优化 :处理多个文本任务时,避免使用
for...of进行串行等待。应使用Promise.all()结合map进行并发请求,将等待时间从 N 倍缩短为 1 倍。
2. 异常与错误处理
- 防止静默失败 :在调用 LLM API 时,务必使用
try...catch包裹。如果 API 调用失败或网络超时,必须在catch块中打印错误信息(console.error),避免程序静默崩溃且无任何输出。
3. 语法与结构自查
- 括号闭合 :
SyntaxError: Unexpected end of input通常是因为文件末尾缺少了}、)或。在编写嵌套的模板字符串和异步函数时,需特别注意大括号的层级闭合。 - 函数调用规范 :确保函数的定义名称与调用名称完全一致(如定义了
main就必须调用main()),避免ReferenceError。