用 Prompt 做 NLP 任务开发:几分钟构建一个推理系统

仅用几分钟,我们就可以构建多个用于对文本进行推理的系统,而以前这需要熟练的机器学习人员数天到数周的时间。这就是 Prompt 工程带来的效率革命。

一、为什么要模块化?

NLP 项目天然适合模块化:调用 LLM 的逻辑、客户端配置、业务 prompt 都是独立的部分。模块化带来两个核心好处:

  • 维护性和可读性:每个文件只做一件事,职责单一
  • 好复用 :通过 import / export 在任意地方引入

本项目的模块化结构如下:

文件 职责 说明
main.mjs 单点入口 业务逻辑、prompt 编写、结果输出
client.mjs 封装 client 对象 LLM 客户端实例(apiKey、baseURL)
completion.mjs 完成任务的函数 封装 getCompletion(prompt) 统一调用
js 复制代码
// 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;  // 默认导出,一个模块只能有一个
js 复制代码
// completion.mjs ------ 只负责调用 LLM
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;
}
js 复制代码
// main.mjs ------ 只负责业务逻辑
import { getCompletion } from './completion.mjs';
async function main() {
    const prompt = `...你的 prompt...`;
    const response = await getCompletion(prompt);
    console.log(response);
}
main();

关键点main.mjs 里看不到任何 API Key、模型名、HTTP 请求细节,全是业务 prompt。这就是模块化的优势。


二、ESM 模块化语法

ES6(2015 年发布)的目标是让 JS 成为企业级大型项目开发语言。模块化(ESM)是其中最重要的特性之一,让 NLP 项目可以拆成 client / completion / main 三个独立文件。

1. 为什么需要它们

JS 默认每个文件是"封闭"的,文件 A 里写的变量、函数,文件 B 看不到。如果想让文件 B 用文件 A 的东西,必须:

  1. 文件 A 主动暴露 出来 → export
  2. 文件 B 主动引入 进来 → import

就像写笔记:写完要发到掘金 (export),别人才能打开掘金看(import)。

2. 两种导出方式

javascript 复制代码
// ===== 方式一:默认导出(default)------ 一个文件只能有一个 =====
// client.mjs
const client = new OpenAI({ ... });
export default client;

// 引入时:不需要花括号,名字随便起
import client from './client.mjs';       // 叫 client
import whatever from './client.mjs';     // 叫 whatever 也行,拿到的还是同一个东西


// ===== 方式二:命名导出 ------ 可以有多个 =====
// completion.mjs
export async function getCompletion(prompt) { ... }
export async function getImage(prompt) { ... }

// 引入时:必须用花括号,名字必须对得上
import { getCompletion } from './completion.mjs';              // ✅ 只拿一个
import { getCompletion, getImage } from './completion.mjs';    // ✅ 拿多个
import { getCompletion as chat } from './completion.mjs';      // ✅ 重命名为 chat


// ===== 方式三:混合(default + 命名) =====
// client.mjs
export default client;
export const a = 2;
export const b = 3;

// 引入时:default 在外,命名在花括号
import client, { a, b } from './client.mjs';

3. 结合项目理解

项目里三个文件就是通过 import/export 串起来的:

javascript 复制代码
// client.mjs(生产者)------ 提供一个 client 对象
const client = new OpenAI({ apiKey, baseURL });
export default client;  // 默认导出"主打产品"


// completion.mjs(中间消费者 + 生产者)
import client from './client.mjs';  // 拿 client.mjs 的默认导出,命名为 client
// './client.mjs' 中的 ./ 表示同目录

export async function getCompletion(prompt) {  // 命名导出一个函数
    const response = await client.chat.completions.create({ ... });
    return response.choices[0].message.content;
}


// main.mjs(最终消费者)
import { getCompletion } from './completion.mjs';  // 花括号按名字拿
async function main() {
    const response = await getCompletion(prompt);  // 直接用
}
main();

串联关系

  • client.mjs 说:"我提供一个 client 对象(默认)"
  • completion.mjs 说:"我 client,我提供 getCompletion 函数(命名)"
  • main.mjs 说:"我 getCompletion"

每个文件只管自己的事,互不干扰,这就是模块化。

4. 记忆口诀

关键词 作用 谁用
export 暴露给别人 写东西的人(生产者)
import 拿别人的东西 用东西的人(消费者)
export default 暴露"主打产品"(唯一) 生产者
import xxx from 拿主打产品(不用花括号) 消费者
import { xxx } from 拿指定名字的东西(要花括号) 消费者

一句话理解export 是**"我提供什么"import "我要用什么"**。default 是默认提供的那个,花括号 {} 是"按名字挑"。

补充:命名导入 import { getCompletion } 本质就是解构赋值 ,和 const { a, b } = obj 是同一套语法思想。

ES6 的其他语法特性(let/const、rest/spread、解构赋值、模板字符串等)见单独的《ES6 语法特性》笔记。


三、NLP 四大任务

NLP(自然语言处理)在 LLM 出现前是机器学习的"高端局",现在用 Prompt 几行代码就能搞定。

1. 情感分类(Sentiment Analysis / Classification)

场景:电商评论、客服工单、舆情预警、产品质检

任务:判断文本是 正面 / 负面 / 中性

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

进阶:识别多种情绪、限制数量、格式化输出

js 复制代码
const prompt = `
识别以下用三个反引号分隔的产品评论的作者表达的情感。
包含不超过5个项目。
将答案格式化为以逗号分隔的单词列表。
评论文本:\`\`\` ${lamp_review_zh} \`\`\`
`

愤怒检测(一个特殊的二分类):

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

2. 信息提取(Information Extraction)

场景:从非结构化文本中提取结构化字段(商品、品牌、价格等)

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

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

关键技巧:要求输出 JSON 格式,方便后续程序解析处理。

3. 主题推断(Topic Inference)

场景:长文章自动打标签、新闻分类

任务一:推断文本讨论了哪些主题

js 复制代码
const prompt = `
确定以下给定文本中讨论的五个主题。
每个主题用1-2个单词概括。
输出时用逗号分隔。
给定文本:${story_zh}
`

任务二:判断给定主题列表中哪些在文本中出现(零样本分类)

js 复制代码
const prompt = `
判断主题列表中的每一项是否是给定文本中的一个话题,
以列表的形式给出答案,每个主题用0 或 1。
主题列表:${topicList.join(",")}
给定文本:${story_zh}
`

${topicList.join(",")} 中的 , 是 join 的分隔符,把数组 ['NASA','政府'] 转成字符串 "NASA,政府",方便嵌入 prompt。

4. 文本总结(Summarization)

场景:老板看长报告、行政整理会议纪要、小编做内容摘要

基础版

js 复制代码
const prompt = `
您的任务是从电商网站上生成一个商品评论的简要摘要。
请对三个反引号之间的评论文本进行概括,最多30个词汇。
评论文本:\`\`\`${prod_review_zh}\`\`\`
`

聚焦版(用 prompt 引导关注点):

js 复制代码
// 聚焦运输
const prompt = `
...并且聚焦在产品运输上。
评论文本:\`\`\`${prod_review_zh}\`\`\`
`

// 聚焦价格和质量
const prompt = `
...并且聚焦在产品价格和质量上。
评论文本:\`\`\`${prod_review_zh}\`\`\`
`

批量处理 (结合 for...of):

js 复制代码
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');
}

for(let a of b): 这是 ES6 的 for...of 循环 ,用来遍历 可迭代对象 (数组、字符串等),直接拿到值。


四、Prompt 工程的 5 个关键技巧

从上面的案例可以总结出写好 prompt 的通用模式:

1. 用分隔符清晰区分指令和文本

js 复制代码
评论文本:\`\`\` ${review} \`\`\`

常用分隔符:```````````、###---<tag></tag>。避免模型把文本内容误解为指令。

2. 明确约束输出格式

  • "用一个单词回答"
  • "最多30个词汇"
  • "以逗号分隔的单词列表"
  • "格式化为 JSON 对象,以 xxx 为键"

约束越明确,输出越稳定可预测。

3. 限定数量和长度

复制代码
包含不超过5个项目。
最多20个字符。

防止模型啰嗦。

4. 处理未知情况

arduino 复制代码
如果信息不存在,请使用"未知"作为值。

避免模型瞎编(幻觉)。

5. 角色化与聚焦

复制代码
你的任务是从电商网站上生成一个商品评论的简要摘要...并且聚焦在产品运输上。

通过"任务定义 + 聚焦方向"控制输出方向,同一份文本可以多次复用产出不同视角的摘要。


五、完整调用链路

scss 复制代码
.env (DEEPSEEK_API_KEY / BASE_URL / MODEL)
    ↓
client.mjs  →  创建 OpenAI client 实例(默认导出)
    ↓
completion.mjs  →  getCompletion(prompt) 封装调用逻辑(命名导出)
    ↓
main.mjs  →  编写 prompt,调用 getCompletion,console.log 结果

一次完整调用的核心代码

js 复制代码
const response = await client.chat.completions.create({
    model: process.env.DEEPSEEK_MODEL,
    messages: [{ role: "user", content: prompt }]
})
return response.choices[0].message.content;
  • messages:消息数组,每条有 role(system/user/assistant)和 content
  • choices[0].message.content:模型返回的文本内容
  • model:从环境变量读取,便于切换模型

六、总结

维度 传统机器学习 Prompt 工程
开发周期 数天 ~ 数周 几分钟
人员要求 熟练 ML 工程师 会写 prompt 的开发者
数据需求 大量标注数据 零样本 / 少样本即可
部署成本 训练 + 部署模型 调用 API

核心思想:LLM 把 NLP 从"训练模型"变成了"写 prompt"。开发者不需要懂神经网络,只需要会清晰表达任务目标、约束输出格式,就能构建出强大的文本推理系统。

模块化的价值 :业务逻辑(prompt)和工程实现(client、API 调用)分离,换模型只改 .env,换任务只改 main.mjs 里的 prompt,互不影响。这就是 AI 全栈开发的基本范式。

相关推荐
AINative软件工程2 小时前
LLM Streaming 背压工程实践:慢客户端、断流重连与服务端缓冲区的生产设计
node.js·llm
hboot11 小时前
AI工程师第六课 - RAG检索增强生成
后端·langchain·llm
用户4693684832016 小时前
kimi-code 深度掌握系列文章-对话循环TurnFlow(五)
llm·agent
lucas_AI17 小时前
Skill-α:教 Agent 学会自己'改说明书'
llm·agent
DigitalOcean18 小时前
多款模型最高直降 50%:DigitalOcean 无服务器推理大降价
llm·agent
罗高18 小时前
Hermes Agent Token 机制深度解析
llm·agent
众人皆醒我独醉18 小时前
Ray Serve:把 LLM 推理当"分布式 Actor"调度——不是 Kubernetes,是 Python 原生
面试·llm·ai编程
玉鸯18 小时前
界面用完即消失:Agent 生成式 UI 的短暂性哲学与前端工程的未来
前端·llm·agent
组合缺一18 小时前
SolonCode v2026.8.4 发布:界面字体可调、22 种语言、记忆搜索增强
llm·agent·ai编程·solon·claudecode·opencode