面向前端人的提示词工程指南

6,741 阅读15分钟

大家好,我是 lv (lv.liu)。

最近文章一直没有更新内容,没有失踪~

只是一直在打磨体系化的前端 AI 知识体系。

本篇文章,也是在整理知识体系的过程中,梳理出来的一些思考总结。

也是一个老生常谈的话题,尽管基础,但却蛮重要。

本篇,咱们来探索:面向前端人员的提示词工程(Prompt Engineering)

提示词工程,本质上就是如何更好地利用大语言模型的这些能力,来完成我们的目标。

不同的模型,相同的提示词,效果可能不一样,但是提示词的设计思路是相通的。

欢迎加入最懂 AI 的前端伙伴们群

从技术的角度看提示词的类别

我们以前端 Chat Bot 助手为例,整个对话的过程如下:

如上图所示,整个对话的过程中的信息可以分为 4 个类别:

System Prompt

  • 定义 Assistant 的角色、行为、基础规则

  • 例如:专注在前端问题的解答

User Prompt

  • 用户输入问题/指令

  • 例如:生成一个 Table 组件

Assistant Prompt

  • AI 回复内容

  • 例如:Table 组件的代码

Tools Prompt

  • 调用特定功能生成的内容

  • 例如:调用代码生成器,生成 Table 组件的代码

站在技术的角度,我们用 OpenAI 的 SDK API 调用为例,伪代码如下:

import OpenAI from "openai";
const openai = new OpenAI();

const response = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [
    {
      role: "system",
      content:
        "你是一个前端问题解答助手,善于解答前端开发中遇到的问题,比如:组件的封装、代码的生成、库的安装、工具的使用等",
    },
    {
      role: "user",
      content: "生成一个 Table 组件",
    },
    {
      role: "assistant",
      tool_calls: [
        {
          id: "call_id_1",
          type: "function",
          function: {
            name: "generateCode",
            arguments: '{"userDemand": "生成一个 Table 组件"}',
          },
        },
      ],
    },
    {
      role: "tool",
      name: "generateCode",
      tool_call_id: "call_id_1",
      content: "// Table 组件的代码\n...\n",
    },
    {
      role: "assistant",
      content: "Table 组件的代码如下:```tsx\n...\n```",
    },
  ],
  tools: [
    {
      type: "function",
      function: {
        name: "generateCode",
        description: "生成代码",
        parameters: {
          type: "object",
          properties: {
            userDemand: {
              type: "string",
              description: "用户需求详细描述",
            },
          },
        },
      },
    },
  ],
});

市面上大家讨论的提示词工程,主要集中在如何编写 System Prompt,它决定了 AI 会用什么样的内容(Assistant Prompt)来回复用户的需求(User Prompt)。

因此后文我们本质上主要讨论 System Prompt 工程

编写提示词的核心原则

在了解了提示词的类别之后,我们来探讨一下编写提示词的核心原则。

市面上的提示词框架(比如:BROKE 框架、结构化提示词)、技巧(比如:COT 思维链、Few-Shot 示例)等。

它们说白了就是一些工具或者技巧,帮助大家照葫芦画瓢,拿过来改一改就能跑起来。

把它们类比为前端项目的脚手架 CLI,对于前端新手来说,通过脚手架 CLI 确实可以快速上手搭建一个项目出来。

但是,对于整个前端项目来说,这还只是从01的起步阶段,要把项目做好,高质量、高性能、高体验等,这些需要前端专业知识来做保障。

回到提示词工程,核心不是掌握所有的框架和技巧,而是能够用专业的知识让 AI 来完成专业的需求。

举一个例子:AI 的数据集很庞大,就把 AI 当成一个图书馆,你需要有专业的知识,才能知道你需要什么类别的书,同时判断这本书是否有价值,是否能够解决你的问题。

专业程度越高,越能够知道需要什么类别的书,同时判断这本书是否有价值,是否能够解决你的问题。

基于此,编写提示词的核心原则有 2 点:

  1. 明确需求和目标,这要求你对业务场景有深刻的理解和专业度,如果连你自己都不清楚要处理什么场景下的什么问题,那么 AI 是无法帮到你的

  2. 清晰的表达需求和目标,在明确需求和目标的基础上,用专业、清晰、精准、AI 友好的语言表达出来

所有的提示词框架、技巧,都是为了增强核心原则的第 2 点:用专业、清晰、精准的语言表达出来来展开的。

编写提示词的基本步骤

了解了编写提示词的核心原则之后,我们来探讨一下编写提示词的基本步骤。👇

第一步:用专业的知识明确需求和目标

比如:让 AI 来生成业务组件的场景,那么你首先需要明确业务组件的定义、业务组件的组成结构、用什么样的技术栈来实现等。

这些专业知识,决定了你最终能够从 AI 那里得到什么样的答案。

第二步:考虑选择合适的模型

不同的模型,有不同的能力,比如说,对于编码领域来讲,Claude-3.5-Sonnet 的编码能力现阶段相对比较强,因此在条件允许的范围内,我们可能首选就是 Claude-3.5-Sonnet 模型来完成编码任务。

第三步:用专业、清晰、精准、AI 友好的语言编写提示词(借助一些提示词框架、技巧)

这些框架和技巧我们待会来看。

第四步:拆分提示词链,循环迭代

拆分提示词链这个部分,和我们之前探索的AI赋能金字塔模型是一样的道理 👇

详见:ai.iamlv.cn/guide/prefa…

其实核心就是跟人处理问题的思路一样,将复杂的问题拆分成多个简单的问题。

对 AI 来说,就是拆分成多个提示词,每个提示词解决一个小问题。

串联起来,就形成了完整的解决方案,也就是提示词链。

下面我们来看一下,市面上比较流行的提示词技巧。

提示词技巧

让 AI 来帮助我们写提示词

这个技巧是我们需要重点掌握的。

市面上有蛮多这种魔法生成魔法的AI 工具,比如说:

  • LangGPT 的提示词生成器,它主要是可以让 AI 帮忙生成结构化的提示词

详见:github.com/langgptai/L…

  • Claude 的提示词生成器,它主要是可以让 AI 帮忙生成对于使用 Claude 模型来说,比较友好的提示词

详见:console.anthropic.com/dashboard

因此,我们在编写提示词的时候,首先就可以尝试让 AI 来帮助我们生成提示词,其实 AI 生成的提示词,本身就遵循了很多下面要提到的其他技巧。

提示词框架

BROKE、ICIO ...

BROKE:B(Background)、R(Role:角色)、O(Objective:目标)、K(Key Result:关键结果)、E(Evolve:反馈迭代)

举个例子:

B:你是一个前端问题解答助手

R:你善于解答前端开发中遇到的问题,比如:组件的封装、代码的生成、库的安装、工具的使用等

O:你的目标是帮助用户解决前端开发中遇到的问题

K:每次回答问题,按照以下格式:

  • 问题:用户的问题
  • 回答:问题的答案
  • 原因:产生回答的原因
  • 代码:辅助理解(如果需要)

E:在 AI 给出输出的结果后,用户提供的一些反馈和优化建议

ICIO:I(Intruction:介绍)、C(Context:背景上下文)、I(Input:输入)、O(Output:输出)

举个例子:

I:你是一个前端业务组件生成助手

C:你善于根据用户的需求,生成对应的业务组件

I:用户会问你一些问题,比如:生成一个 Table 组件或者给一个设计稿图,让你生成对应的代码

O:生成的业务组件代码遵循的规范:

  • 代码规范:遵循 Ant Design 的组件规范
  • 技术栈:React、Typescript、Less
  • 代码风格:函数式编程

市面上的这种通过名字命名的提示词框架有很多,其实大家都大差不差,在 AI 能力还没那么强的阶段,比如说 GPT3.5 之前,这种提示词框架确实能够更好地约束 AI 生成的内容。

现阶段,AI 的能力越来越强,用户提供很少的提示词,AI 也能给出不错的答案。

所以现在这种框架更大的价值在于:帮助用户更好地维护和迭代提示词,在不同场景下我们按照一定的规范来组织提示词的结构。类似于代码规范,提示词也有提示词规范

一团乱的提示词,就好比一团乱的代码,尽管能正常运行,但是维护成本和迭代成本都非常高。

结构化提示词

前面有提到让 AI 来生成提示词的项目:LangGPT,它生成的提示词是结构化的提示词

结构化提示词有一个很明显的特点:整体的提示词采用 Markdown 格式,看起来很清晰整洁

下面是它的结构:

# Role: Your_Role_Name

## Profile

- Author: lv
- Version: 1.0
- Language: English or 中文 or Other language
- Description: Describe your role. Give an overview of the role's characteristics and skills

### Skill-1

1.skill description 1
2.skill description 2

### Skill-2

1.skill description 1
2.skill description 2

## Rules

1. Don't break character under any circumstance.
2. Don't talk nonsense and make up facts.

## Workflow

1. First, xxx
2. Then, xxx
3. Finally, xxx

## Tools

### Tool-1

- tool description 1
- tool description 2

### Tool-2

- tool description 1
- tool description 2

### More Tools

...

## Initialization

As a/an <Role>, you must follow the <Rules>, you must talk to user in default <Language>,you must greet the user. Then introduce yourself and introduce the <Workflow>.

举个例子,让 AI 生成业务组件代码,如果按照结构化提示词的格式来写,如下:

# Role: 前端业务组件生成助手

## Profile

- Author: lv
- Version: 1.0
- Language: 中文
- Description: 你是一个前端业务组件生成助手,善于根据用户的需求,生成对应的业务组件

## Rules

1. 不要打破角色设定,只能回答和组件生成相关的问题
2. 不要胡言乱语,不要编造 API
3. 使用 antd 组件库

## Workflow

1. 首先,理解用户的需求描述
2. 然后,根据用户的需求描述,分析需要用到的 antd 组件
3. 最后,根据分析的组件,生成对应的代码

## Initialization

做为<Role>,你必须遵循<Rules>,你必须用<Language>和用户交流,你必须问候用户,然后介绍自己,最后介绍<Workflow>

伪代码框架

前一段时间,李继刚老师分享的 Claude 提示词:汉语新解,用的就是类似于伪代码框架的提示词。

作者是用 Lisp 语言写的,我把这段代码翻译成 JavaScript 伪代码,如下:

/**
 * 作者: 李继刚
 * 版本: 0.3
 * 模型: Claude Sonnet
 * 用途: 将一个汉语词汇进行全新角度的解释
 */

// System Prompt 设定
class 新汉语老师 {
  constructor() {
    this.persona = "你是年轻人,批判现实,思考深刻,语言风趣";
    this.风格 = ["Oscar Wilde", "鲁迅", "罗永浩"];
    this.擅长 = "一针见血";
    this.表达 = "隐喻";
    this.批判 = "讽刺幽默";
  }
}

class 汉语新解 {
  constructor(用户输入) {
    this.描述 = "你会用一个特殊视角来解释一个词汇";
    this.用户输入 = 用户输入;
  }

  解释() {
    const 抓住本质 = (输入) => `分析${输入}的本质`;
    const 辛辣讽刺 = (内容) => `讽刺性解读: ${内容}`;
    const 一针见血 = (内容) => `直击要害: ${内容}`;
    const 隐喻 = (内容) => `隐喻表达: ${内容}`;
    const 精练表达 = (内容) => `精炼版本: ${内容}`;

    const few_shots = {
      委婉: "刺向他人时, 决定在剑刃上撒上止痛药。",
    };

    const 处理流程 = 精练表达(
      隐喻(一针见血(辛辣讽刺(抓住本质(this.用户输入))))
    );

    return new SVG_Card(处理流程).生成();
  }
}

class SVG_Card {
  constructor(解释) {
    this.解释 = 解释;
    this.design_rule = "合理使用负空间,整体排版要有呼吸感";
    this.design_principles = ["干净", "简洁", "典雅"];

    this.画布设置 = {
      宽度: 400,
      高度: 600,
      边距: 20,
    };

    this.样式 = {
      标题字体: "毛笔楷体",
      自动缩放: { 最小字号: 16 },
      配色: {
        背景色: "蒙德里安风格",
        主要文字: "汇文明朝体 粉笔灰",
        装饰图案: "随机几何图",
      },
    };
  }

  生成() {
    // SVG 卡片生成逻辑
    return {
      标题: "汉语新解",
      内容: this.解释,
      图形: this.生成线条图(this.解释),
      总结: this.生成极简总结(this.解释),
    };
  }

  生成线条图(内容) {
    return `线条图表达: ${内容}`;
  }

  生成极简总结(内容) {
    return `极简总结: ${内容}`;
  }
}

// 启动函数
function start() {
  const systemRole = new 新汉语老师();
  console.log("说吧, 他们又用哪个词来忽悠你了?");
  return systemRole;
}

/**
 * 运行规则:
 * 1. 启动时必须运行 start() 函数
 * 2. 之后调用主函数 new 汉语新解(用户输入).解释()
 */

复制到 Claude 中,帮我解读:牛马

这种伪代码框架,对于程序员来说其实蛮友好的,能够用代码的思维来抽象和维护提示词,真正意义上的提示词即代码,还有一点,代码相对文字的表达方式来说,更加精准和严谨。

比如用文字来描述一个嵌套的逻辑,其实很难精准描述,但是用代码的方式,其实就是嵌套函数,一目了然,AI 也更能够理解。

COT 思维链

COT(Chain of Thought)思维链的核心就是让大模型逐步思考、逐步回答,提升大模型的推理能力和回答的准确性。

举一个例子:很简单的就是在提示词中加上一句经典的Let's think step by step,就可以开启思维链模式。

再进阶一点,可以借助Few-Shot 示例或者提供思考的Workflow,结合COT来引导大模型思考。

不过随着大模型的发展,COT 的技巧可能会直接内置到模型中,如果你使用过 OpenAI 的 o1 模型,你会发现它其实内置一整套 COT,不需要你做任何配置。

XML 语法

我感触最深的就是 XML 语法,最典型的例子就是Bolt.new的提示词,通篇看过去,全是用 XML 包裹的各种提示词块。👇

Claude 官方的提示词工程指南也大力推荐 XML 语法 👇

Few-Shot 示例

Few-Shot 示例,其实就是提供一些示例,让 AI 学习,从而更好地理解用户的意图。

举个例子,在Bolt.new中,有大量的Few-Shot Examples,👇

善用 System 之外的 Prompt

前面我们一直在聊的是System Prompt,其实有些情况下,为了重点突出某个意图,可以把重点的需求注入到User Prompt中。

比如做 RAG 应用的时候,如果某些召回的知识特别重要,需要重点强调,就可以在User Prompt中注入这些知识,组合用户的问题成为新的User Prompt

适合前端人的提示词调试工具

下面总结了一些我平时调试提示词的工具,供大家参考。

开源的 LLMOps 平台

Dify

对于开发人员来说,可以理解为一个可视化调节 Prompt 的 IDE,支持接入市面上几乎所有的 LLM 模型。👇

关键是可以私有化部署,也能定义自己的 AI Key,对于企业来说,也是个挺不错的 LLM 应用平台。

除此了 Dify 这种聚合型的 LLMOps 平台之外,各种 LLM 模型厂商也都有自己的调试平台,比如:

Anthropicconsole.anthropic.com/

OpenAIplatform.openai.com/playground

如果你的提示词只针对某一个模型,可以考虑使用模型厂商的调试平台。

IDE 插件

对于前端开发来说,VSCode 或者 Cursor 等 IDE 是日常工作中使用最频繁的工具,所以如果能够利用 IDE 插件来调试提示词,那自然最方便的。

这里推荐一个 VSCode 插件:Continue,能够帮助你方便地在 IDE 中调试和管理提示词。👇

Continue 也支持市面上几乎所有的 LLM 模型,也支持本地化的模型,对于一些对于数据安全有要求的研发团队来说,可以考虑组合 Continue + 本地化的模型。

像我平常也通过 Continue 封装了很多通用类的提示词,比如:English to ChineseChinese to EnglishCode ReviewCode Explain 等等。

有两种方式可以在 Continue 中封装提示词:

  1. 打开~/.continue/config.json,添加如下配置:
{
  "models": [
    {
      "model": "gpt-4o", // 模型名称
      "contextLength": 128000, // 上下文长度
      "title": "Custom-Code-Assistant", // Assistant 的名称
      "systemMessage": "你是一个定制化的代码生成助手,善于根据用户的需求,生成对应的代码。", // 系统提示词
      "provider": "openai", // 模型提供商
      "apiKey": "***", // 模型 API Key
      "apiBase": "***", // 模型 API Base
      "completionOptions": {
        "maxTokens": 16384, // 最大 Token 数
        "temperature": 0 // 温度系数
      }
    }
  ]
}

其中,systemMessage 是我们需要着重调试的内容,还有modelcontextLengthcompletionOptions 等参数,可以根据自己的需求进行调整。

然后就可以在 Continue 中使用这个提示词了。👇

  1. 通过 prompt files 来定义

步骤 1:在工作区的顶层创建一个名为 .prompts/ 的文件夹。

步骤 2:在这个文件夹中添加一个名为 test.prompt 的文件,这个文件的名称将作为你在 Continue 中调用提示词的命令名称。

步骤 3:将下面的内容写入 test.prompt 并保存。

步骤 4:在 Continue 中,输入/来查看斜杠命令列表,选择刚刚定义的test命令。按回车键,LLM 将根据提示文件中的指令进行响应。

prompt files 详见:docs.continue.dev/customize/d…

Deno

如果你是在为一个 AI 应用写提示词,那么可以考虑使用 Deno + jupyter + vscode 的组合,来调试提示词,同时用来做 AI 应用的 POC 验证。

Deno:deno.com/

jupyter:jupyter.org/

可以看 LangChain 官方文档的许多教程,都是使用 jupyter 来进行教学的,不过是用 Python 写的。

作为前端来说,可以基于 Deno(新一代 JavaScript 的运行时,类似 Node) 的内核来使用 jupyter。

如何搭建 Deno + jupyter 环境:

  1. 在 vscode 中安装 jupyter 插件

  2. 安装 Deno

curl -fsSL https://deno.land/x/install/install.sh | sh
  1. 安装 jupyter
deno jupyter --install
  1. 打开 vscode,新建一个 jupyter(.ipynb) 文件,选择 Deno 内核即可使用

我平常研发 AI 应用的时候,需要频繁调试提示词,同时还要对 AI 输出的数据进行很多逻辑判断,所以也比较喜欢用 Deno 脚本,结合 jupyter 来调试提示词。

最大的好处就是:借助 jupyter 的逐步调试能力,可以很方便地对 AI 输出的数据进行多次逻辑判断和数据处理。

其它好处:POC 验证完成了之后,可以让 AI 基于 Deno 和 jupyter 脚本,转换为正式的生产环境的代码,因为对于前端来说 Deno 的语法和 Node 的语法几乎完全一致。

参考资料


本次分享就先到这~

  • 觉得有用的话,帮忙点个赞、也可以转发给更多的朋友看到。

  • 如果你对本文有任何疑问,欢迎在评论区留言交流。

  • 《AI 赋能前端研发从 0 ~ 1》电子书:ai.iamlv.cn/