prompt engineering 总览- part2
在 part1里面,我们已经讲解了,初版prompt生成,给出清楚、直接、详细的描述,少样本技术,CoT。下面介绍剩余的优化prompt的方式。即使用标签结构话prompt,角色扮演,预填充回复,链接复杂prompt,长上下文处理方式。
1.使用标签结构化prompt
当你的prompt涉及到多个部分的时候,如上下文,指令和示例,使用XML标签可以更准确的给llm提示,从而产生更加高质量的输出。
tips:使用、、等xml标签,防止llm混淆。
为什么要使用XML标签?
清晰性:清晰地分隔提示中的不同部分,并确保提示结构良好。
准确性:减少llm误解提示部分导致的错误。
灵活性:轻松查找、添加、删除或修改提示的部分,而无需重写所有内容。
可解析性:让llm在其输出中使用XML标签,使得通过后处理提取其响应的特定部分变得更加容易。
使用标签的一些建议
----保持一致:在整个提示中使用相同的标签名称,并在讨论内容时引用这些标签名称(例如,使用标签中的合同…)。
----嵌套标签:对于层次化内容,你应该嵌套标签。
tips:还记得我们在part1中提到的CoT嘛?将标签和part1提到的技巧结合起来使用,会效果更好。
例子如下:
没有使用标签:
prompt: 分析这份软件许可协议中的潜在风险和责任:{{CONTRACT}}。重点关注赔偿、责任限制和知识产权所有权条款。同时,注意任何不寻常或有问题的条款。以下是我们的标准合同供参考:{{STANDARD_CONTRACT}}。为我们的法律团队提供一份发现和建议的总结。
answer:提供的软件许可协议存在几个令人担忧的方面。赔偿条款过于宽泛,可能会使我们面临重大责任。责任限制部分将损害赔偿上限定为仅500美元,这对于我们的企业级使用来说是不够的。关于知识产权,协议授予供应商对我们创建的任何修改或集成的共同所有权。
总之,这份协议不符合我们的最佳利益。它使我们面临不当风险,限制了我们在失败情况下的补救措施,并损害了我们的知识产权权利。我建议重新谈判这些条款或寻找其他供应商。
使用标签:
分析这份软件许可协议中的法律风险和责任。
我们是一家跨国企业,正在考虑将此协议用于我们的核心数据基础设施。
<agreement>{{CONTRACT}}</agreement>
这是我们的标准合同供参考:
<standard_contract>{{STANDARD_CONTRACT}}</standard_contract>
<instructions>
1. 分析以下条款:
- 赔偿
- 责任限制
- 知识产权所有权
2. 注意不寻常或有问题的条款。
3. 与我们的标准合同进行比较。
4. 在<findings>标签中总结发现。
5. 在<recommendations>标签中列出可操作的建议。</instructions>
answer:
<findings>
1. 赔偿(第8条):
- 问题:过于宽泛。我们赔偿供应商因我们使用而产生的“任何和所有索赔”。
- 风险:即使供应商的疏忽或产品缺陷,也可能使我们承担责任。
- 偏差:我们的标准将赔偿限制在我们违反协议所产生的索赔。
2. 责任限制(第9条):
- 问题:所有损害赔偿上限为500美元,包括直接损害。
- 风险:对于企业使用来说严重不足。一次重大故障可能耗资数百万。
- 偏差:我们的标准允许直接损害赔偿高达12个月的费用。
3. 知识产权所有权(第12条):
- 问题:授予供应商对我们修改/集成的共同所有权。
- 风险:供应商可以使用或出售我们的专有算法或数据洞察。
- 偏差:我们的标准保留我们工作的全部所有权。
4. 不寻常条款:
- 第5.3条:供应商可以将我们的使用数据用于“任何目的”。
- 第7.2条:供应商可以仅提前7天通知终止“出于方便”。
- 第11条:没有任何形式的保证,甚至不包括基本的适销性。
</findings>
<recommendations>
1. 拒绝此协议。对于企业来说,风险远大于收益。
2. 反提议:
- 赔偿:限制在我们违反协议所产生的索赔。
- 责任:直接损害赔偿上限为12个月的费用;协商间接损害。
- 知识产权:我们修改/集成的全部所有权。
- 数据使用:仅限于服务改进。
- 终止:至少提前90天通知;仅因故终止。
- 保证:要求基本的适销性和适用性。
3. 如果供应商拒绝,探索其他供应商或内部解决方案。
4. 鉴于高风险,请法律顾问参与合同谈判。
</recommendations>
可以看出,根据给定的标签提示,llm给出的数据更加清晰。
2.角色提示
在使用llm时,通过使用系统参数为其赋予角色,可以显著提高其性能。这种技术称为角色提示。正确的角色可以将llm从通用助手转变为您的虚拟领域专家!
系统提示技巧:使用system参数设置角色。将其他所有内容,如特定任务的指令,放在user部分中。
为什么要使用角色提示?
----提高准确性:在法律分析、财务建模等专业领域场景中,角色提示可以显著提升性能。
----定制语调:无论您需要首席财务官的简洁还是文案撰稿人的文采,角色提示都可以调整llm的沟通风格。
----增强专注度:通过设置角色上下文,更能保持在任务特定要求范围内。
使用方法: langchain+deepseek的方式如下
from langchain.chat_models import ChatOpenAI
# 创建对话检索链
llm = ChatOpenAI(
model_name="deepseek-chat",
openai_api_key="XXXXXXXXXXXXXXXXXX", #填写你的api key
openai_api_base="https://api.deepseek.com",
request_timeout=30,
temperature=0.7,
max_tokens=150
)#type:ignore
messages = [
(
"system",
"你是一名专业的财经翻译人员.请你以财经专家的口气将下文翻译成中文",
),
("human", "Stock market fluctuations reflect investors' confidence in economic prospects.Inflation rate is a key indicator of changes in purchasing power.Financial planning helps individuals and families achieve long-term financial goals."),
]
llm.invoke(messages)
3.预填充llm的输出
在使用llm时,可以通过预填充assistant消息来引导其响应。这种技术可引导llm的行为,跳过开场白,强制执行特定的格式(如JSON或XML),甚至在角色扮演场景中帮助llm保持角色一致性。
如何预填充
例子:
没有预填充
角色 | 内容 |
---|---|
user(与“夏洛克·福尔摩斯”llm进行了50轮对话) | 你能推断出这双鞋的主人是什么样的人吗?<image>muddy_shoe.jpg |
assistant | 作为AI助手,我很乐意分析你提供的这双沾满泥巴的鞋的图片。以下是我的推断… |
有预填充
继续表格形式:
角色 | 内容 |
---|---|
用户(与“夏洛克·福尔摩斯”llm进行了50轮对话) | 你能推断出这双鞋的主人是什么样的人吗?<image>muddy_shoe.jpg |
assistant(预填充) | [夏洛克·福尔摩斯] |
助手(llm的响应) | 啊,我们这里有什么?一个非常有趣的样本,华生!让我们用敏锐的眼光来检查这双鞋。你看,这泥巴不是普通的伦敦泥土,而是只有在汉普斯特德荒野附近才能找到的富含铁的红色土壤。然而,鞋底的磨损表明,这种步态更适合白教堂的鹅卵石路,而不是荒野的缓坡。 现在,观察鞋带!它们打了一个特定的结,这是医学界人士喜欢的——毫无疑问,这是多年系手术服的习惯。但是,鞋头盒上的划痕讲述了一个不同的故事:它们与一个人在武术中可能使用的踢腿动作一致,特别是巴里茨。 因此,我们可以得出结论,我们这位失踪的鞋主人是一位医生,可能是一位外科医生,他住在白教堂,但经常去汉普斯特德荒野——也许是为了秘密练习巴里茨,远离窥探的眼睛。一个非常有趣的案件,华生!我们必须抓紧时间;游戏开始了! |
可以看出,llm直接以预填充的身份给出结果。
4.链式prompt
在处理复杂任务的时候,当我们试图在一个提示里面给出所有的任务要求,有时候llm会出错。虽然可以使用CoT,但是,当任务有多个需要深入思考的不同步骤时候,链式prompt就有了用武之地。他将复杂任务分解为更小、更易管理的子任务。
为什么要链式prompt?
----准确性:每个子任务都能得到llm的全部关注,减少错误。
----清晰度:更简单的子任务意味着更清晰的指令和输出。
----可追溯性:轻松定位和修复提示链中的问题。
何时使用链式prompt?
将提示链用于多步骤任务,如研究综合、文档分析或迭代内容创建。当任务涉及多个转换、引用或指令时,链式提示可以防止llm遗漏或错误处理步骤。
如何进行链式prompt?
----识别子任务:将任务分解为不同的、顺序的步骤。
----使用XML结构化以实现清晰的交接:使用XML标签在提示之间传递输出。
----设定单一任务目标:每个子任务应有一个单一、明确的目标。
----迭代:根据llm的输出优化子任务。
链式prompt workflow例子:
----多步骤分析:参见下面的法律和商业示例。
----内容创建pipeline:研究 → 大纲 → 草稿 → 编辑 → 格式化。
----数据处理:提取 → 转换 → 分析 → 可视化。
----决策制定:收集信息 → 列出选项 → 分析每个选项 → 推荐。
----验证循环:生成内容 → 审查 → 优化 → 重新审查。
tips: 对于独立子任务例如分别分析各个文档,可以考虑创建独立的prompt,而且并行处理以提升速度。
链式prompt例子之一:自我修正
通过链式提示让llm审查自己的输出。
角色 | 提示 |
---|---|
user | prompt1:总结如下的论文<paper>{{PAPER}} <\paper>重点关注方法论、发现和意义 |
user | prompt2:你的任务是根据提供的论文和对论文的总结给出反馈。以下是总结:{{SUMMARY}} 以下是论文{{PAPER}} |
user | prompt3:你的任务是根据反馈修改论文的总结。以下是总结:{{SUMMARY}} 以下是论文:{{PAPER}} 以下是反馈:{{FEEDBACK}} |
5.长上下问提示技巧
目前,各家llm都在扩充自己的上下文窗口,以处理复杂的、数据量丰富的任务。这里给出一些使用长下文提示的技巧。
----将长篇数据放在顶部:长文档和输入(~20K+个token)放在提示的顶部,位于查询、指令和示例之上。
----使用XML标签结构化文档内容和元数据:当使用多个文档时,将每个文档包装在标签中,并使用<document_content>和(以及其他元数据)子标签以提高清晰度。
多文档例子:
<documents>
<document index="1">
<source>annual_report_2023.pdf</source>
<document_content>
{{ANNUAL_REPORT}}
</document_content>
</document>
<document index="2">
<source>competitor_analysis_q2.xlsx</source>
<document_content>
{{COMPETITOR_ANALYSIS}}
</document_content>
</document>
</documents>
Analyze the annual report and competitor analysis. Identify strategic advantages and recommend Q3 focus areas.
----在引号中接地响应:对于长文档任务,要求llm首先引用文档的相关部分,然后再执行其任务。这有助于llm过滤掉文档其余内容的“噪音”。
如:
您是一名AI医师助理。您的任务是帮助医生诊断可能的患者疾病。
<documents>
<document index="1">
<source>patient_symptoms.txt</source>
<document_content>
{{PATIENT_SYMPTOMS}}
</document_content>
</document>
<document index="2">
<source>patient_records.txt</source>
<document_content>
{{PATIENT_RECORDS}}
</document_content>
</document>
<document index="3">
<source>patient01_appt_history.txt</source>
<document_content>
{{PATIENT01_APPOINTMENT_HISTORY}}
</document_content>
</document>
</documents>
从患者记录和预约历史中找到与诊断患者报告症状相关的引文。将这些放在<quotes>中。然后,根据这些quotes,列出所有有助于医生诊断患者症状的信息。将您的诊断信息放在<info>中。
最后:各家的llm对于同一个prompt的反馈是不同的,以上技巧只是泛泛而谈,针对具体任务,认真阅读llm反馈,利用提到的技巧,反复更新prompt。