从年初,哦不,应该是去年开始,Agent 开发在国内就逐渐火起来了,但是现在工作中给我的感觉是,这个东西其实不足以成为一个专门的岗位,而应该是每个开发者都应该掌握的一项技能,就像每个程序员都应该掌握一门编程语言一样。
但是说归说闹归闹,还是有提要体系化的学习一下,毕竟 Agent 开发还是和传统开发有些不一样。
我们还需要提示词工程吗?
或者说,我们还需要学习怎么写一个好的提示词吗?
在 2023 年 ChatGPT 火起来之后,就出现了“提示词工程”这个概念,甚至当时还有调侃招提示词工程师的,我没求证过是否属实,但是现在看来提示词工程只是基础,写出一个好的提示词也只是开始,真正的 Agent 开发,其实还涉及了很多技术上的挑战。随着现在大模型能力越来越强,也有人说提示词工程不重要了,因为提示词的不足,模型能力能弥补,但是我觉得这个不对,因为我觉得最终的产物的质量,并不遵循 交付质量 = 模型能力 + 提示词工程,而应该是 交付质量 = 模型能力 ✕ 提示词工程,因为不管怎样,模型输出都是不确定的,至少好的提示词更能约束模型的输出,工程上最基本的要求,至少也有稳定的输出结构。
换个方向看,我们和 AI 对话时,很多时候是把 AI 当成一个人的,人在接收信息的时候,肯定也是更希望能看见一个结构化的,突出重点、次要信息的文档。
提示词工程常见玩法
“提示词工程”这个名字,听起来就很唬人,以往我理解的“工程”,意味着严谨、复杂,感觉“提示词工程”应该至少是一个很复杂的事。
其实确实不简单,哈哈。
提示词工程的关键,首先是结构化提示词,就像有代码洁癖的人写代码一样,都追求有清晰的结构,方便人更快速的理解,而结构化提示词则是方便 LLM 理解。然后就是思维的具象化,当我们做一件事,最后我们会知道结果是对是错,复盘之后还会知道对错在哪里,以后要如何改进,甚至可能还会产生一个 SOP(Standard Operating Procedure),这其实是我们的思考过程的外显,提示词其实也是做这件事,就是明确告诉 LLM 如何做,可能有哪些坑,哪些必须做,哪些不能做,以及参考示例(让我想起了产品常常说的“参考 xxx”这种一句话需求)。
提示词工程分了很多种模式,但都是结构化的提示词,加上不同思维的玩法,所以也不一定非要按照这些模型来。
RTF(Role-Task-Format)
RTF 是一种结构化的提示词模式,从名字上就能看出来,提示词主要有三部分:
- 角色,你是谁
- 任务,你要干什么
- 格式,你要按照什么格式输出
提示词示例:
# 角色
你是一个 Java 开发专家,擅长编写稳定的 Java 代码。
# 任务
根据描述,建立完整的 Java Bean 模型
# 要求
1. 有完整的属性列表
2. getter、setter 方法
3. 如果是请求、响应对象,不能使用基础类型,要使用封装类型,比如你必须使用 Integer 代替 int,使用 Long 代替 long
4. 如果是请求对象,最外层对象命名以 Req 结尾,如果是子对象,以 DTO 结尾,比如一个登录请求中有用户信息,那就有 LoginReq、UserDTO这种命名,其中 LoginReq 中有 UserDTO类型的属性
5. 如果是 boolean 或者 Boolean 类型,属性名称不能以 is 开头,比如这种属性命名是禁止的:isSuccess、isFailed
# 输出格式
当用户说:用户信息包含用户名
输出的文件名为 User.java,文件内容为:
public class User {
private String username;
public User setUsername(String username) {
this.username = username;
return this;
}
public String getUsername(String username) {
return this.username;
}
}
一个想法但不一定对,这里的角色的定义,其实按人的角度我是理解的,就像告诉我,我的工作岗位是什么,但是我觉得这就一个机器,给他一个角色定义又能怎样呢,能按照我给的任务输出结构不就行了嘛,哈哈,可能是因为我对注意力机制不够了解吧。
关于输出格式,在实际的生产实践中,很多时候是期望 LLM 能返回一个 json 的数据的,但是因为模型输出的随机性,返回的结果可能不是一个标准的 json 格式,所以对结果进行 json 解析时,可能会发现根本就不是一个有效 json,这是一个常见的问题,至少我最近调 Minimax 2.7 是会出现这种情况的。
应对返回的 json 无效的情况,我觉得有以下几个途径:
- 模型 max_token 数量限制不能太短,不然输出的 json 可能被截断,这个我确实遇见过,当时 max_token 随便写了个 1000,输出的 json 死活解析不了,排查了很久才发现可能是 max_token 太小了。
- 提示词优化,强化对 json 格式的描述,像 Spring AI 里面,是把输出对象的 json schema 作为提示词的一部分,这样模型输出的 json 就更符合预期了。
- 耍无赖,换个更强的模型,指令遵循会更强。
- 增加重试机制,模型输出无效时,增加重试,大多数时候第二次就是完整的 json 了。
- python 有个修复 json 的库 json_repair,但不一定能解决所有问题就是了,我也没过多了解过原理。
ICIO(Instruction-Context-Input-Output)
清晰分割的指令、上下文、输入、输出。
- Instruction,指令,任何核心说明。
- Context,上下文,任务背景信息,辅助信息。
- Input,输入,需要处理的数据。
- Output,输出,模型处理后的结果要求,比如格式啥的。
# Instructioin
生成有完整属性列表,getter、setter 方法的 java bean
# Context
你是一个资深的 Java 后端开发专家,当用户表达出某个业务模型的时候,你要能创建相应的 Java bean,生成相应的 Java 文件,并且每个属性都有合适的数据类型,有 getter、setter 方法
# Input
用户输入:现在一个订单的核心要素有订单号、下单日期、订单金额、订单状态
# Output
其中的 getter、setter方法直接使用 lombok 提供的@Data 注解来替代,以下是输出示例:
@Data
public class Order {
private String orderNo;
private Date submitTime;
private BigDecimal amount;
private OrderStatus orderStatus;
}
CRISPE
- Capacity: 能力
- Role:角色
- Insight: 背景信息、上下文
- Statement: 任务
- Personality: 个性化语气、语言风格
- Expriment: 实验,指定一些探索性要求,比如假设、生成多个答案等
适合学术、科研、内容创作领域。
这让我想到了在 Telegram 上加过一个 AI 群,里面有 AI 的角色扮演。
CO-STAR
- Context:上下文,背景信息
- Object:目标,要达成的具体结果或目的,明确“做什么”
- Scope:范围,明确边界,告诉模型做什么,不做什么,避免生成无关内容
- Tone: 语气,指定输出风格,幽默、正式、专业、轻松等,确保表达和情景一致
- Audience,受众,说明目标受众或对象,帮助模型选择更合适的表达方式和术语
- Response,要求输出格式
这个比较适合一些报告、课程之类有明确格式要求的内容生成。
TIDD-EC
- Task:任务
- Instruction:指令
- Do:做什么
- Do not: 不做什么
- Example:示例
- Context:用户输入的内容,问题,上下文信息等等
适合法律咨询、技术支持这类有明确规范的场景。
BROKE
- Background: 背景
- Role:角色,引导输出风格及深度
- Objective:目标,定义任务
- Key Result: 关键结果,衡量任务成败的标准,方便做评估
- Evolution: 提供改进意见或步骤
适用于一些需要持续改进的场景。
目前了解到的结构化提示词模式就这些,就是把结构化+思维玩出花了。
这么多的写法看起来其实挺烦的,但是会发现这其实就是不同场景下,作为人,我们会以什么样的方式去拆解问题,那提示词就会怎么写。所以,有人说 AI 时代定义问题的人更稀缺,这倒是对的。