差别
这里会显示出您选择的修订版和当前版本之间的差别。
| 两侧同时换到之前的修订记录 前一修订版 | |||
| 智能体二次开发:langchain:核心组件详解_prompts [2026/05/20 19:01] – 移除 - 外部编辑 (未知日期) 127.0.0.1 | 智能体二次开发:langchain:核心组件详解_prompts [2026/05/20 19:01] (当前版本) – ↷ 页面langchain二次开发:核心组件详解_prompts被移动至智能体二次开发:langchain:核心组件详解_prompts 张叶安 | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| + | ====== 第三章:核心组件详解 - Prompts ====== | ||
| + | |||
| + | 在 LangChain 框架中,Prompt(提示词)是与大语言模型(LLM)交互的核心桥梁。精心设计的提示词可以显著提升模型的输出质量和准确性。本章将深入探讨 LangChain 中的提示词工程、PromptTemplate 的使用、Few-shot Prompting 技术以及动态提示词的管理方法。 | ||
| + | |||
| + | ===== 3.1 提示词工程基础 ===== | ||
| + | |||
| + | ==== 3.1.1 什么是提示词工程 ==== | ||
| + | |||
| + | 提示词工程(Prompt Engineering)是指通过设计和优化输入提示词,引导大语言模型生成高质量、符合预期的输出内容的技术。它是与大语言模型交互的艺术和科学。 | ||
| + | |||
| + | **提示词工程的重要性:** | ||
| + | |||
| + | * **输出质量**:好的提示词能让模型产生更准确、更有用的回答 | ||
| + | * **一致性**:通过结构化提示词,可以确保模型输出的格式一致 | ||
| + | * **可控性**:提示词工程让我们能更好地控制模型的行为和输出风格 | ||
| + | * **效率**:优化后的提示词可以减少不必要的迭代和修正 | ||
| + | |||
| + | ==== 3.1.2 提示词的基本结构 ==== | ||
| + | |||
| + | 一个完整的提示词通常包含以下几个部分: | ||
| + | |||
| + | **1. 指令(Instruction)** | ||
| + | 告诉模型需要执行什么任务。这是最核心的部分。 | ||
| + | |||
| + | <code python> | ||
| + | instruction = " | ||
| + | </ | ||
| + | |||
| + | **2. 上下文(Context)** | ||
| + | 提供完成任务所需的背景信息。 | ||
| + | |||
| + | <code python> | ||
| + | context = """ | ||
| + | 这篇文章发布于2024年,作者是人工智能领域的专家。 | ||
| + | 目标读者是技术初学者,因此需要使用通俗易懂的语言。 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **3. 输入数据(Input Data)** | ||
| + | 模型需要处理的具体内容。 | ||
| + | |||
| + | <code python> | ||
| + | input_data = """ | ||
| + | 人工智能(AI)正在改变我们的生活方式... | ||
| + | [文章内容] | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **4. 输出指示(Output Indicator)** | ||
| + | 明确说明期望的输出格式。 | ||
| + | |||
| + | <code python> | ||
| + | output_indicator = """ | ||
| + | 请输出: | ||
| + | 1. 核心观点(50字以内) | ||
| + | 2. 三个关键要点 | ||
| + | 3. 结论 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **完整的提示词示例:** | ||
| + | |||
| + | <code python> | ||
| + | full_prompt = f""" | ||
| + | {instruction} | ||
| + | |||
| + | {context} | ||
| + | |||
| + | 文章: | ||
| + | {input_data} | ||
| + | |||
| + | {output_indicator} | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | ==== 3.1.3 提示词设计原则 ==== | ||
| + | |||
| + | **原则一:清晰明确** | ||
| + | |||
| + | 提示词应该清楚地表达你想要什么。模糊的要求会导致模糊的答案。 | ||
| + | |||
| + | <code python> | ||
| + | # ❌ 不好的示例 | ||
| + | bad_prompt = " | ||
| + | |||
| + | # ✅ 好的示例 | ||
| + | good_prompt = """ | ||
| + | 请写一篇200字的产品描述,介绍 iPhone 15 的主要特点: | ||
| + | - 钛金属设计 | ||
| + | - A17 Pro 芯片 | ||
| + | - 专业级摄像系统 | ||
| + | |||
| + | 语气要求:专业、吸引人、面向科技爱好者 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **原则二:提供上下文** | ||
| + | |||
| + | 模型不知道你知道什么。提供足够的背景信息可以帮助模型更好地理解任务。 | ||
| + | |||
| + | <code python> | ||
| + | # ❌ 缺乏上下文 | ||
| + | no_context = " | ||
| + | |||
| + | # ✅ 提供上下文 | ||
| + | with_context = """ | ||
| + | 背景:你是一位数据分析专家,正在为一家电商公司工作。 | ||
| + | |||
| + | 数据:2024年第一季度销售数据 | ||
| + | - 总销售额:1000万元 | ||
| + | - 订单数量:5000单 | ||
| + | - 退货率:5% | ||
| + | |||
| + | 请分析这些数据,并给出改进建议。 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **原则三:指定输出格式** | ||
| + | |||
| + | 如果你想要特定格式的输出,一定要在提示词中明确说明。 | ||
| + | |||
| + | <code python> | ||
| + | format_prompt = """ | ||
| + | 请根据以下客户反馈,生成一份报告。 | ||
| + | |||
| + | 反馈内容: | ||
| + | " | ||
| + | |||
| + | 输出格式(JSON): | ||
| + | {{ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }} | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **原则四:使用分隔符** | ||
| + | |||
| + | 使用清晰的分隔符(如### | ||
| + | |||
| + | <code python> | ||
| + | structured_prompt = """ | ||
| + | ### 指令 | ||
| + | 总结以下文章的主要观点。 | ||
| + | |||
| + | ### 文章 | ||
| + | """ | ||
| + | {article_content} | ||
| + | """ | ||
| + | |||
| + | ### 要求 | ||
| + | - 不超过100字 | ||
| + | - 使用 bullet points | ||
| + | - 突出关键数据 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **原则五:给出示例(Few-shot)** | ||
| + | |||
| + | 当任务比较复杂或格式要求严格时,提供示例是最好的方式。 | ||
| + | |||
| + | <code python> | ||
| + | few_shot_prompt = """ | ||
| + | 将以下描述转换为结构化数据。 | ||
| + | |||
| + | 示例1: | ||
| + | 输入:张三,25岁,软件工程师,北京 | ||
| + | 输出:{{" | ||
| + | |||
| + | 示例2: | ||
| + | 输入:李四,30岁,产品经理,上海 | ||
| + | 输出:{{" | ||
| + | |||
| + | 现在请处理: | ||
| + | 输入:王五,28岁,数据分析师,深圳 | ||
| + | 输出: | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | ==== 3.1.4 常见的提示词模式 ==== | ||
| + | |||
| + | **模式一:角色扮演(Role Prompting)** | ||
| + | |||
| + | 让模型扮演特定角色,以获得更专业的回答。 | ||
| + | |||
| + | <code python> | ||
| + | role_prompt = """ | ||
| + | 你是一位经验丰富的心理咨询师,拥有15年的临床经验。 | ||
| + | |||
| + | 一位来访者说:" | ||
| + | |||
| + | 请给出专业的建议,注意: | ||
| + | 1. 语气温和、同理心强 | ||
| + | 2. 提供具体可行的建议 | ||
| + | 3. 如果情况严重,建议寻求专业帮助 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **模式二:思维链(Chain-of-Thought)** | ||
| + | |||
| + | 引导模型逐步思考,而不是直接给出答案。 | ||
| + | |||
| + | <code python> | ||
| + | cot_prompt = """ | ||
| + | 问题:一个农场有鸡和兔子,一共有35个头,94只脚。鸡和兔子各有多少只? | ||
| + | |||
| + | 请按以下步骤思考并回答: | ||
| + | 1. 设鸡的数量为x,兔子的数量为y | ||
| + | 2. 根据头的数量列出方程 | ||
| + | 3. 根据脚的数量列出方程 | ||
| + | 4. 解方程组 | ||
| + | 5. 验证答案 | ||
| + | |||
| + | 详细展示你的思考过程。 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **模式三:零样本思维链(Zero-shot CoT)** | ||
| + | |||
| + | 即使没有示例,也可以通过简单的指令引导模型逐步思考。 | ||
| + | |||
| + | <code python> | ||
| + | zero_shot_cot = """ | ||
| + | 问题:如果5台机器5分钟生产5个零件,那么100台机器生产100个零件需要多少分钟? | ||
| + | |||
| + | 让我们一步一步思考: | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | **模式四:自洽性检查(Self-Consistency)** | ||
| + | |||
| + | 让模型从多个角度思考问题,然后选择最一致的答案。 | ||
| + | |||
| + | <code python> | ||
| + | self_consistency_prompt = """ | ||
| + | 问题:解释为什么天空是蓝色的。 | ||
| + | |||
| + | 请从以下三个角度分别解释,然后综合得出最准确的答案: | ||
| + | 1. 物理学角度(光的散射) | ||
| + | 2. 生物学角度(人眼感知) | ||
| + | 3. 大气科学角度(大气成分) | ||
| + | |||
| + | 最后,整合以上观点,给出简洁准确的解释。 | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | ===== 3.2 PromptTemplate 详解 ===== | ||
| + | |||
| + | ==== 3.2.1 PromptTemplate 概述 ==== | ||
| + | |||
| + | PromptTemplate 是 LangChain 中用于创建和管理提示词的核心组件。它允许你定义带有变量的模板,并在运行时动态填充这些变量。 | ||
| + | |||
| + | **为什么使用 PromptTemplate?** | ||
| + | |||
| + | * **可复用性**:定义一次模板,多次使用 | ||
| + | * **类型安全**:变量可以被验证和处理 | ||
| + | * **灵活性**:轻松切换不同的模型和配置 | ||
| + | * **维护性**:集中管理提示词,易于修改 | ||
| + | |||
| + | ==== 3.2.2 基础使用 ==== | ||
| + | |||
| + | **安装和导入:** | ||
| + | |||
| + | <code python> | ||
| + | # 安装依赖 | ||
| + | # pip install langchain | ||
| + | |||
| + | from langchain.prompts import PromptTemplate | ||
| + | </ | ||
| + | |||
| + | **创建基础模板:** | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import PromptTemplate | ||
| + | |||
| + | # 定义一个简单的模板 | ||
| + | template = " | ||
| + | |||
| + | # 创建 PromptTemplate 对象 | ||
| + | prompt_template = PromptTemplate( | ||
| + | input_variables=[" | ||
| + | template=template | ||
| + | ) | ||
| + | |||
| + | # 查看模板结构 | ||
| + | print(prompt_template.input_variables) | ||
| + | </ | ||
| + | |||
| + | **格式化模板:** | ||
| + | |||
| + | <code python> | ||
| + | # 方式1:使用 format 方法 | ||
| + | prompt = prompt_template.format( | ||
| + | style=" | ||
| + | topic=" | ||
| + | length=100 | ||
| + | ) | ||
| + | print(prompt) | ||
| + | # 输出:请用幽默的风格,写一段关于人工智能的描述,大约100字。 | ||
| + | |||
| + | # 方式2:使用 format_prompt 方法(返回 PromptValue 对象) | ||
| + | prompt_value = prompt_template.format_prompt( | ||
| + | style=" | ||
| + | topic=" | ||
| + | length=200 | ||
| + | ) | ||
| + | print(prompt_value.to_string()) | ||
| + | </ | ||
| + | |||
| + | ==== 3.2.3 高级模板功能 ==== | ||
| + | |||
| + | **部分变量(Partial Variables)** | ||
| + | |||
| + | 有时你希望预先填充部分变量,创建一个" | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import PromptTemplate | ||
| + | |||
| + | # 定义完整模板 | ||
| + | full_template = PromptTemplate( | ||
| + | template=" | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 部分填充:预先设定角色 | ||
| + | partial_template = full_template.partial(role=" | ||
| + | |||
| + | # 使用时只需提供剩余变量 | ||
| + | prompt1 = partial_template.format( | ||
| + | language=" | ||
| + | question=" | ||
| + | ) | ||
| + | print(prompt1) | ||
| + | # 输出:你是一位Python专家,请用中文回答:什么是装饰器? | ||
| + | |||
| + | # 可以再次部分填充 | ||
| + | chinese_template = partial_template.partial(language=" | ||
| + | prompt2 = chinese_template.format(question=" | ||
| + | print(prompt2) | ||
| + | </ | ||
| + | |||
| + | **使用函数作为部分变量:** | ||
| + | |||
| + | <code python> | ||
| + | from datetime import datetime | ||
| + | |||
| + | def get_current_date(): | ||
| + | return datetime.now().strftime(" | ||
| + | |||
| + | template_with_date = PromptTemplate( | ||
| + | template=" | ||
| + | input_variables=[" | ||
| + | partial_variables={" | ||
| + | ) | ||
| + | |||
| + | prompt = template_with_date.format(content=" | ||
| + | print(prompt) | ||
| + | # 输出:今天是2024年01月15日,请根据以下信息生成报告:销售数据... | ||
| + | </ | ||
| + | |||
| + | ==== 3.2.4 模板验证 ==== | ||
| + | |||
| + | PromptTemplate 会自动验证输入变量,确保所有必需变量都已提供。 | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import PromptTemplate | ||
| + | |||
| + | # 定义模板 | ||
| + | template = PromptTemplate( | ||
| + | template=" | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # ✅ 正确:提供所有变量 | ||
| + | try: | ||
| + | prompt = template.format(name=" | ||
| + | print(" | ||
| + | except Exception as e: | ||
| + | print(" | ||
| + | |||
| + | # ❌ 错误:缺少变量 | ||
| + | try: | ||
| + | prompt = template.format(name=" | ||
| + | except KeyError as e: | ||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | ==== 3.2.5 自定义输入解析器 ==== | ||
| + | |||
| + | 有时输入变量需要特殊的处理,你可以自定义输入变量的解析方式。 | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import PromptTemplate | ||
| + | from langchain.prompts.base import StringPromptValue | ||
| + | |||
| + | class MyPromptTemplate(PromptTemplate): | ||
| + | def format(self, | ||
| + | # 自定义格式化逻辑 | ||
| + | if " | ||
| + | kwargs[" | ||
| + | return super().format(**kwargs) | ||
| + | |||
| + | template = MyPromptTemplate( | ||
| + | template=" | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | prompt = template.format(name=" | ||
| + | print(prompt) | ||
| + | </ | ||
| + | |||
| + | ===== 3.3 Few-shot Prompting ===== | ||
| + | |||
| + | ==== 3.3.1 什么是 Few-shot Prompting ==== | ||
| + | |||
| + | Few-shot Prompting(少样本提示)是一种通过提供少量示例来指导模型完成任务的技术。它特别适用于: | ||
| + | |||
| + | * 需要特定输出格式的任务 | ||
| + | * 复杂的推理任务 | ||
| + | * 风格转换或语气调整 | ||
| + | * 特定的命名实体识别 | ||
| + | |||
| + | ==== 3.3.2 基础示例 ==== | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import FewShotPromptTemplate, | ||
| + | |||
| + | # 定义示例 | ||
| + | examples = [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | |||
| + | # 定义示例的格式 | ||
| + | example_template = """ | ||
| + | 文本:{input} | ||
| + | 情感:{output} | ||
| + | """ | ||
| + | |||
| + | example_prompt = PromptTemplate( | ||
| + | template=example_template, | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 创建 FewShotPromptTemplate | ||
| + | few_shot_prompt = FewShotPromptTemplate( | ||
| + | examples=examples, | ||
| + | example_prompt=example_prompt, | ||
| + | prefix=" | ||
| + | suffix=" | ||
| + | input_variables=[" | ||
| + | example_separator=" | ||
| + | ) | ||
| + | |||
| + | # 生成提示词 | ||
| + | prompt = few_shot_prompt.format(input=" | ||
| + | print(prompt) | ||
| + | </ | ||
| + | |||
| + | **输出示例:** | ||
| + | < | ||
| + | 请判断以下文本的情感倾向(积极/ | ||
| + | |||
| + | 文本:今天天气真好,我想去公园散步。 | ||
| + | 情感:积极 | ||
| + | |||
| + | --- | ||
| + | |||
| + | 文本:这部电影太糟糕了,完全浪费时间。 | ||
| + | 情感:消极 | ||
| + | |||
| + | --- | ||
| + | |||
| + | 文本:会议定在下午三点。 | ||
| + | 情感:中性 | ||
| + | |||
| + | --- | ||
| + | |||
| + | 文本:这家餐厅的饭菜真好吃! | ||
| + | 情感: | ||
| + | </ | ||
| + | |||
| + | ==== 3.3.3 示例选择器(Example Selectors) ==== | ||
| + | |||
| + | 当示例很多时,你可能只想选择最相关的几个示例。LangChain 提供了多种示例选择器。 | ||
| + | |||
| + | **长度限制选择器:** | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import FewShotPromptTemplate | ||
| + | from langchain.prompts.example_selector import LengthBasedExampleSelector | ||
| + | |||
| + | examples = [ | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | ] | ||
| + | |||
| + | example_prompt = PromptTemplate( | ||
| + | template=" | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 根据长度选择示例 | ||
| + | example_selector = LengthBasedExampleSelector( | ||
| + | examples=examples, | ||
| + | example_prompt=example_prompt, | ||
| + | max_length=100 | ||
| + | ) | ||
| + | |||
| + | dynamic_prompt = FewShotPromptTemplate( | ||
| + | example_selector=example_selector, | ||
| + | example_prompt=example_prompt, | ||
| + | prefix=" | ||
| + | suffix=" | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 输入越长,选择的示例越少 | ||
| + | short_prompt = dynamic_prompt.format(input=" | ||
| + | print(" | ||
| + | |||
| + | long_prompt = dynamic_prompt.format(input=" | ||
| + | print(" | ||
| + | </ | ||
| + | |||
| + | **语义相似度选择器:** | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import FewShotPromptTemplate | ||
| + | from langchain.prompts.example_selector import SemanticSimilarityExampleSelector | ||
| + | from langchain.embeddings import OpenAIEmbeddings | ||
| + | from langchain.vectorstores import Chroma | ||
| + | |||
| + | examples = [ | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | ] | ||
| + | |||
| + | example_prompt = PromptTemplate( | ||
| + | template=" | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 使用语义相似度选择器 | ||
| + | example_selector = SemanticSimilarityExampleSelector.from_examples( | ||
| + | examples, | ||
| + | OpenAIEmbeddings(), | ||
| + | Chroma, | ||
| + | k=2 # 选择最相似的2个示例 | ||
| + | ) | ||
| + | |||
| + | similar_prompt = FewShotPromptTemplate( | ||
| + | example_selector=example_selector, | ||
| + | example_prompt=example_prompt, | ||
| + | prefix=" | ||
| + | suffix=" | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 输入与示例相关的问题 | ||
| + | prompt = similar_prompt.format(input=" | ||
| + | print(prompt) | ||
| + | # 可能会选择《哈利·波特》和《呼啸山庄》相关的示例 | ||
| + | </ | ||
| + | |||
| + | ==== 3.3.4 Few-shot 最佳实践 ==== | ||
| + | |||
| + | **选择合适的示例数量:** | ||
| + | |||
| + | <code python> | ||
| + | # 通常 3-5 个示例效果最好 | ||
| + | # 太多示例可能导致: | ||
| + | # 1. Token 消耗增加 | ||
| + | # 2. 上下文窗口限制 | ||
| + | # 3. 模型注意力分散 | ||
| + | |||
| + | # 平衡策略 | ||
| + | examples = [ | ||
| + | # 示例1:展示基本格式 | ||
| + | {...}, | ||
| + | # 示例2:展示边界情况 | ||
| + | {...}, | ||
| + | # 示例3:展示复杂场景 | ||
| + | {...}, | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | **示例的质量要求:** | ||
| + | |||
| + | <code python> | ||
| + | # ✅ 好的示例特点: | ||
| + | # 1. 清晰明确 | ||
| + | # 2. 覆盖不同场景 | ||
| + | # 3. 格式一致 | ||
| + | # 4. 输入输出相关 | ||
| + | |||
| + | good_examples = [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | |||
| + | # ❌ 避免: | ||
| + | # 1. 示例之间矛盾 | ||
| + | # 2. 格式不一致 | ||
| + | # 3. 示例与任务不相关 | ||
| + | </ | ||
| + | |||
| + | ===== 3.4 Prompt 组合与管理 ===== | ||
| + | |||
| + | ==== 3.4.1 组合多个 Prompt ==== | ||
| + | |||
| + | 在实际应用中,你可能需要组合多个提示词模板来构建复杂的工作流。 | ||
| + | |||
| + | **使用 PipelinePromptTemplate:** | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import PipelinePromptTemplate, | ||
| + | |||
| + | # 定义各个阶段的模板 | ||
| + | introduction_template = """ | ||
| + | 你的任务是:{task} | ||
| + | """ | ||
| + | introduction_prompt = PromptTemplate( | ||
| + | template=introduction_template, | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | example_template = """ | ||
| + | {examples} | ||
| + | """ | ||
| + | example_prompt = PromptTemplate( | ||
| + | template=example_template, | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | question_template = """ | ||
| + | {question} | ||
| + | """ | ||
| + | question_prompt = PromptTemplate( | ||
| + | template=question_template, | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 组合成完整的 pipeline | ||
| + | full_template = """ | ||
| + | |||
| + | {example} | ||
| + | |||
| + | {question}""" | ||
| + | full_prompt = PromptTemplate( | ||
| + | template=full_template, | ||
| + | input_variables=[" | ||
| + | ) | ||
| + | |||
| + | # 创建 pipeline | ||
| + | pipeline_prompt = PipelinePromptTemplate( | ||
| + | final_prompt=full_prompt, | ||
| + | pipeline_prompts=[ | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | ] | ||
| + | ) | ||
| + | |||
| + | # 使用 pipeline | ||
| + | result = pipeline_prompt.format( | ||
| + | role=" | ||
| + | task=" | ||
| + | examples=" | ||
| + | question=" | ||
| + | ) | ||
| + | print(result) | ||
| + | </ | ||
| + | |||
| + | ==== 3.4.2 使用 ChatPromptTemplate ==== | ||
| + | |||
| + | 对于聊天模型,LangChain 提供了专门的 ChatPromptTemplate,可以定义不同角色的消息。 | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import ChatPromptTemplate, | ||
| + | |||
| + | # 系统消息模板 | ||
| + | system_template = """ | ||
| + | 你的专长领域是:{expertise} | ||
| + | 回答时请遵循以下规则: | ||
| + | {rules} | ||
| + | """ | ||
| + | system_message_prompt = SystemMessagePromptTemplate.from_template(system_template) | ||
| + | |||
| + | # 人类消息模板 | ||
| + | human_template = " | ||
| + | human_message_prompt = HumanMessagePromptTemplate.from_template(human_template) | ||
| + | |||
| + | # 组合成聊天提示词 | ||
| + | chat_prompt = ChatPromptTemplate.from_messages([ | ||
| + | system_message_prompt, | ||
| + | human_message_prompt | ||
| + | ]) | ||
| + | |||
| + | # 格式化 | ||
| + | messages = chat_prompt.format_prompt( | ||
| + | role=" | ||
| + | expertise=" | ||
| + | rules=" | ||
| + | user_input=" | ||
| + | ).to_messages() | ||
| + | |||
| + | for message in messages: | ||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | **输出:** | ||
| + | < | ||
| + | system: 你是一个编程助手。 | ||
| + | 你的专长领域是:Python 和数据分析 | ||
| + | 回答时请遵循以下规则: | ||
| + | 1. 代码必须可运行 | ||
| + | 2. 添加详细注释 | ||
| + | |||
| + | human: 写一个计算斐波那契数列的函数 | ||
| + | </ | ||
| + | |||
| + | ==== 3.4.3 多轮对话模板 ==== | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import ChatPromptTemplate, | ||
| + | from langchain.schema import HumanMessage, | ||
| + | |||
| + | # 创建包含对话历史的模板 | ||
| + | chat_prompt = ChatPromptTemplate.from_messages([ | ||
| + | (" | ||
| + | MessagesPlaceholder(variable_name=" | ||
| + | (" | ||
| + | ]) | ||
| + | |||
| + | # 模拟对话历史 | ||
| + | history = [ | ||
| + | HumanMessage(content=" | ||
| + | AIMessage(content=" | ||
| + | HumanMessage(content=" | ||
| + | AIMessage(content=" | ||
| + | ] | ||
| + | |||
| + | # 格式化 | ||
| + | messages = chat_prompt.format_prompt( | ||
| + | history=history, | ||
| + | input=" | ||
| + | ).to_messages() | ||
| + | |||
| + | for msg in messages: | ||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | ==== 3.4.4 Prompt 管理最佳实践 ==== | ||
| + | |||
| + | **使用配置文件管理提示词:** | ||
| + | |||
| + | <code python> | ||
| + | # prompts.yaml | ||
| + | # prompts_config.yaml | ||
| + | greeting: | ||
| + | template: " | ||
| + | input_variables: | ||
| + | |||
| + | summarization: | ||
| + | template: | | ||
| + | 请总结以下内容: | ||
| + | {content} | ||
| + | | ||
| + | 要求: | ||
| + | - {style} | ||
| + | - 大约{length}字 | ||
| + | input_variables: | ||
| + | </ | ||
| + | |||
| + | <code python> | ||
| + | import yaml | ||
| + | from langchain.prompts import load_prompt | ||
| + | |||
| + | # 加载 YAML 配置 | ||
| + | with open(" | ||
| + | config = yaml.safe_load(f) | ||
| + | |||
| + | # 动态创建模板 | ||
| + | templates = {} | ||
| + | for name, cfg in config.items(): | ||
| + | templates[name] = PromptTemplate( | ||
| + | template=cfg[" | ||
| + | input_variables=cfg[" | ||
| + | ) | ||
| + | |||
| + | # 使用 | ||
| + | greeting_prompt = templates[" | ||
| + | print(greeting_prompt.format(name=" | ||
| + | </ | ||
| + | |||
| + | **版本控制提示词:** | ||
| + | |||
| + | <code python> | ||
| + | from dataclasses import dataclass | ||
| + | from datetime import datetime | ||
| + | import json | ||
| + | |||
| + | @dataclass | ||
| + | class PromptVersion: | ||
| + | version: str | ||
| + | template: str | ||
| + | variables: list | ||
| + | description: | ||
| + | created_at: str | ||
| + | performance_score: | ||
| + | |||
| + | class PromptRegistry: | ||
| + | def __init__(self): | ||
| + | self.prompts = {} | ||
| + | | ||
| + | def register(self, | ||
| + | if name not in self.prompts: | ||
| + | self.prompts[name] = [] | ||
| + | self.prompts[name].append(version) | ||
| + | | ||
| + | def get_latest(self, | ||
| + | if name in self.prompts and self.prompts[name]: | ||
| + | return sorted(self.prompts[name], | ||
| + | | ||
| + | return None | ||
| + | | ||
| + | def save(self, filepath: str): | ||
| + | data = {} | ||
| + | for name, versions in self.prompts.items(): | ||
| + | data[name] = [ | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | for v in versions | ||
| + | ] | ||
| + | with open(filepath, | ||
| + | json.dump(data, | ||
| + | |||
| + | # 使用示例 | ||
| + | registry = PromptRegistry() | ||
| + | |||
| + | v1 = PromptVersion( | ||
| + | version=" | ||
| + | template=" | ||
| + | variables=[" | ||
| + | description=" | ||
| + | created_at=datetime.now().isoformat(), | ||
| + | performance_score=0.85 | ||
| + | ) | ||
| + | |||
| + | registry.register(" | ||
| + | registry.save(" | ||
| + | </ | ||
| + | |||
| + | ===== 3.5 动态提示词 ===== | ||
| + | |||
| + | ==== 3.5.1 条件提示词 ==== | ||
| + | |||
| + | 根据输入动态调整提示词内容。 | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import PromptTemplate | ||
| + | from typing import Optional | ||
| + | |||
| + | def create_conditional_prompt( | ||
| + | content: str, | ||
| + | audience: str = " | ||
| + | include_examples: | ||
| + | ) -> str: | ||
| + | """ | ||
| + | | ||
| + | # 基础模板 | ||
| + | base = " | ||
| + | | ||
| + | # 根据受众调整 | ||
| + | audience_instructions = { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | | ||
| + | instruction = audience_instructions.get(audience, | ||
| + | | ||
| + | # 条件添加示例 | ||
| + | example_section = "" | ||
| + | if include_examples: | ||
| + | example_section = """ | ||
| + | |||
| + | 请提供具体的例子帮助理解。 | ||
| + | 示例格式: | ||
| + | - 场景描述 | ||
| + | - 具体应用 | ||
| + | - 预期结果""" | ||
| + | | ||
| + | template = f""" | ||
| + | |||
| + | 受众:{audience} | ||
| + | 要求:{instruction}{example_section} | ||
| + | """ | ||
| + | | ||
| + | return template.format(content=content) | ||
| + | |||
| + | # 使用示例 | ||
| + | prompt_general = create_conditional_prompt( | ||
| + | content=" | ||
| + | audience=" | ||
| + | include_examples=True | ||
| + | ) | ||
| + | print(" | ||
| + | print(prompt_general) | ||
| + | |||
| + | prompt_technical = create_conditional_prompt( | ||
| + | content=" | ||
| + | audience=" | ||
| + | include_examples=False | ||
| + | ) | ||
| + | print(" | ||
| + | print(prompt_technical) | ||
| + | </ | ||
| + | |||
| + | ==== 3.5.2 模板继承与组合 ==== | ||
| + | |||
| + | <code python> | ||
| + | class PromptBuilder: | ||
| + | """ | ||
| + | | ||
| + | def __init__(self): | ||
| + | self.sections = [] | ||
| + | self.variables = set() | ||
| + | | ||
| + | def add_instruction(self, | ||
| + | """ | ||
| + | self.sections.append((" | ||
| + | return self | ||
| + | | ||
| + | def add_context(self, | ||
| + | """ | ||
| + | self.sections.append((" | ||
| + | self.variables.update(vars.keys()) | ||
| + | return self | ||
| + | | ||
| + | def add_constraints(self, | ||
| + | """ | ||
| + | constraint_text = " | ||
| + | self.sections.append((" | ||
| + | return self | ||
| + | | ||
| + | def add_output_format(self, | ||
| + | """ | ||
| + | self.sections.append((" | ||
| + | return self | ||
| + | | ||
| + | def build(self) -> str: | ||
| + | """ | ||
| + | parts = [] | ||
| + | for section_type, | ||
| + | parts.append(f"### | ||
| + | return " | ||
| + | |||
| + | # 使用示例 | ||
| + | builder = PromptBuilder() | ||
| + | prompt = (builder | ||
| + | .add_instruction(" | ||
| + | .add_context( | ||
| + | " | ||
| + | feedback="", | ||
| + | product_type="" | ||
| + | ) | ||
| + | .add_constraints([ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ]) | ||
| + | .add_output_format(""" | ||
| + | JSON格式: | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | """ | ||
| + | .build()) | ||
| + | |||
| + | print(prompt) | ||
| + | </ | ||
| + | |||
| + | ==== 3.5.3 动态 Few-shot 示例 ==== | ||
| + | |||
| + | 根据查询动态选择最相关的示例。 | ||
| + | |||
| + | <code python> | ||
| + | from typing import List, Dict | ||
| + | import numpy as np | ||
| + | |||
| + | class DynamicExampleSelector: | ||
| + | """ | ||
| + | | ||
| + | def __init__(self, | ||
| + | self.examples = examples | ||
| + | self.embeddings = embeddings_model | ||
| + | self.example_embeddings = None | ||
| + | | ||
| + | if embeddings_model: | ||
| + | # 预计算示例的嵌入向量 | ||
| + | texts = [ex[" | ||
| + | self.example_embeddings = embeddings_model.embed_documents(texts) | ||
| + | | ||
| + | def select_by_similarity(self, | ||
| + | """ | ||
| + | if not self.embeddings or not self.example_embeddings: | ||
| + | # 如果没有嵌入模型,随机选择 | ||
| + | import random | ||
| + | return random.sample(self.examples, | ||
| + | | ||
| + | # 计算查询的嵌入向量 | ||
| + | query_embedding = self.embeddings.embed_query(query) | ||
| + | | ||
| + | # 计算相似度 | ||
| + | similarities = [ | ||
| + | np.dot(query_embedding, | ||
| + | (np.linalg.norm(query_embedding) * np.linalg.norm(ex_emb)) | ||
| + | for ex_emb in self.example_embeddings | ||
| + | ] | ||
| + | | ||
| + | # 选择最相似的 k 个 | ||
| + | top_k_indices = np.argsort(similarities)[-k: | ||
| + | return [self.examples[i] for i in top_k_indices] | ||
| + | | ||
| + | def select_by_category(self, | ||
| + | """ | ||
| + | return [ex for ex in self.examples if ex.get(" | ||
| + | | ||
| + | def create_few_shot_prompt( | ||
| + | self, | ||
| + | query: str, | ||
| + | k: int = 3, | ||
| + | template: str = " | ||
| + | ) -> str: | ||
| + | """ | ||
| + | selected = self.select_by_similarity(query, | ||
| + | | ||
| + | example_texts = [] | ||
| + | for ex in selected: | ||
| + | example_texts.append(template.format(**ex)) | ||
| + | | ||
| + | return " | ||
| + | |||
| + | # 使用示例 | ||
| + | examples = [ | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | {" | ||
| + | ] | ||
| + | |||
| + | selector = DynamicExampleSelector(examples) | ||
| + | prompt = selector.create_few_shot_prompt(" | ||
| + | print(prompt) | ||
| + | </ | ||
| + | |||
| + | ==== 3.5.4 自适应提示词长度 ==== | ||
| + | |||
| + | 根据上下文窗口自动调整提示词长度。 | ||
| + | |||
| + | <code python> | ||
| + | from langchain.prompts import PromptTemplate | ||
| + | |||
| + | class AdaptivePromptTemplate: | ||
| + | """ | ||
| + | | ||
| + | def __init__( | ||
| + | self, | ||
| + | base_template: | ||
| + | max_tokens: int = 2000, | ||
| + | tokenizer=None | ||
| + | ): | ||
| + | self.base_template = base_template | ||
| + | self.max_tokens = max_tokens | ||
| + | self.tokenizer = tokenizer | ||
| + | | ||
| + | def estimate_tokens(self, | ||
| + | """ | ||
| + | if self.tokenizer: | ||
| + | return len(self.tokenizer.encode(text)) | ||
| + | # 简单估计:中文字符约1个token,英文单词约1.3个token | ||
| + | return len(text) // 2 | ||
| + | | ||
| + | def format_adaptive( | ||
| + | self, | ||
| + | **kwargs | ||
| + | ) -> str: | ||
| + | """ | ||
| + | # 尝试完整格式化 | ||
| + | prompt = self.base_template.format(**kwargs) | ||
| + | tokens = self.estimate_tokens(prompt) | ||
| + | | ||
| + | if tokens <= self.max_tokens: | ||
| + | return prompt | ||
| + | | ||
| + | # 需要压缩内容 | ||
| + | compression_ratio = self.max_tokens / tokens * 0.9 # 留一些余量 | ||
| + | | ||
| + | compressed_kwargs = {} | ||
| + | for key, value in kwargs.items(): | ||
| + | if isinstance(value, | ||
| + | # 截断长文本 | ||
| + | keep_length = int(len(value) * compression_ratio) | ||
| + | compressed_kwargs[key] = value[: | ||
| + | else: | ||
| + | compressed_kwargs[key] = value | ||
| + | | ||
| + | return self.base_template.format(**compressed_kwargs) | ||
| + | |||
| + | # 使用示例 | ||
| + | template = """ | ||
| + | |||
| + | 文档内容: | ||
| + | {document} | ||
| + | |||
| + | 分析要求: | ||
| + | {requirements} | ||
| + | |||
| + | 输出格式: | ||
| + | {format} | ||
| + | """ | ||
| + | |||
| + | adaptive = AdaptivePromptTemplate(template, | ||
| + | |||
| + | long_document = " | ||
| + | |||
| + | result = adaptive.format_adaptive( | ||
| + | document=long_document, | ||
| + | requirements=" | ||
| + | format=" | ||
| + | ) | ||
| + | |||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | ==== 3.5.5 实时提示词优化 ==== | ||
| + | |||
| + | 根据模型反馈实时调整提示词。 | ||
| + | |||
| + | <code python> | ||
| + | class PromptOptimizer: | ||
| + | """ | ||
| + | | ||
| + | def __init__(self, | ||
| + | self.llm = llm | ||
| + | self.history = [] | ||
| + | | ||
| + | def optimize_prompt( | ||
| + | self, | ||
| + | original_prompt: | ||
| + | target_output: | ||
| + | feedback: str = None | ||
| + | ) -> str: | ||
| + | """ | ||
| + | | ||
| + | optimization_instruction = f""" | ||
| + | 你是一位提示词工程专家。请优化以下提示词,使其产生更好的结果。 | ||
| + | |||
| + | 原始提示词: | ||
| + | {original_prompt} | ||
| + | |||
| + | """ | ||
| + | if target_output: | ||
| + | optimization_instruction += f""" | ||
| + | 目标输出示例: | ||
| + | {target_output} | ||
| + | |||
| + | """ | ||
| + | | ||
| + | if feedback: | ||
| + | optimization_instruction += f""" | ||
| + | 当前问题反馈: | ||
| + | {feedback} | ||
| + | |||
| + | """ | ||
| + | | ||
| + | optimization_instruction += """ | ||
| + | 请提供优化后的提示词,并说明: | ||
| + | 1. 改进了哪些方面 | ||
| + | 2. 为什么这些改进会产生更好的结果 | ||
| + | 3. 优化后的完整提示词 | ||
| + | |||
| + | 优化后的提示词: | ||
| + | """ | ||
| + | | ||
| + | optimized = self.llm.predict(optimization_instruction) | ||
| + | return optimized | ||
| + | | ||
| + | def iterative_improvement( | ||
| + | self, | ||
| + | base_prompt: | ||
| + | test_cases: list, | ||
| + | iterations: int = 3 | ||
| + | ) -> str: | ||
| + | """ | ||
| + | current_prompt = base_prompt | ||
| + | | ||
| + | for i in range(iterations): | ||
| + | print(f" | ||
| + | | ||
| + | # 在当前提示词上测试 | ||
| + | results = [] | ||
| + | for test in test_cases: | ||
| + | result = self.llm.predict(current_prompt.format(**test[" | ||
| + | results.append({ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }) | ||
| + | | ||
| + | # 分析结果 | ||
| + | feedback = self._analyze_results(results) | ||
| + | print(f" | ||
| + | | ||
| + | # 优化提示词 | ||
| + | if i < iterations - 1: # 最后一次不需要优化 | ||
| + | current_prompt = self.optimize_prompt( | ||
| + | current_prompt, | ||
| + | feedback=feedback | ||
| + | ) | ||
| + | print(f" | ||
| + | | ||
| + | return current_prompt | ||
| + | | ||
| + | def _analyze_results(self, | ||
| + | """ | ||
| + | correct = sum(1 for r in results if r[" | ||
| + | total = len(results) | ||
| + | | ||
| + | feedback = f" | ||
| + | | ||
| + | for i, result in enumerate(results): | ||
| + | if result[" | ||
| + | feedback += f" | ||
| + | feedback += f" | ||
| + | feedback += f" | ||
| + | feedback += f" | ||
| + | | ||
| + | return feedback | ||
| + | |||
| + | # 使用示例(伪代码) | ||
| + | """ | ||
| + | from langchain.llms import OpenAI | ||
| + | |||
| + | llm = OpenAI() | ||
| + | optimizer = PromptOptimizer(llm) | ||
| + | |||
| + | test_cases = [ | ||
| + | {" | ||
| + | {" | ||
| + | ] | ||
| + | |||
| + | final_prompt = optimizer.iterative_improvement( | ||
| + | base_prompt=" | ||
| + | test_cases=test_cases, | ||
| + | iterations=3 | ||
| + | ) | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | ===== 3.6 本章小结 ===== | ||
| + | |||
| + | 本章深入探讨了 LangChain 中的提示词工程,涵盖了以下核心内容: | ||
| + | |||
| + | **提示词工程基础:** | ||
| + | * 提示词的基本结构:指令、上下文、输入数据、输出指示 | ||
| + | * 设计原则:清晰明确、提供上下文、指定输出格式、使用分隔符、给出示例 | ||
| + | * 常见模式:角色扮演、思维链、自洽性检查 | ||
| + | |||
| + | **PromptTemplate 详解:** | ||
| + | * 基础使用方法 | ||
| + | * 部分变量(Partial Variables)技巧 | ||
| + | * 模板验证机制 | ||
| + | * 自定义输入解析器 | ||
| + | |||
| + | **Few-shot Prompting:** | ||
| + | * 基础示例和实现 | ||
| + | * 示例选择器(长度限制、语义相似度) | ||
| + | * 最佳实践和注意事项 | ||
| + | |||
| + | **Prompt 组合与管理:** | ||
| + | * PipelinePromptTemplate 的使用 | ||
| + | * ChatPromptTemplate 处理多轮对话 | ||
| + | * 使用配置文件管理提示词 | ||
| + | * 提示词版本控制 | ||
| + | |||
| + | **动态提示词:** | ||
| + | * 条件提示词 | ||
| + | * 模板继承与组合 | ||
| + | * 动态 Few-shot 示例选择 | ||
| + | * 自适应提示词长度 | ||
| + | * 实时提示词优化 | ||
| + | |||
| + | 掌握这些提示词技术,将帮助你构建更高质量、更可控的 LLM 应用。在实际项目中,建议: | ||
| + | |||
| + | * 建立统一的提示词管理规范 | ||
| + | * 使用版本控制跟踪提示词变化 | ||
| + | * 收集用户反馈持续优化提示词 | ||
| + | * 根据具体场景选择合适的提示词策略 | ||
| + | |||
| + | 在下一章中,我们将学习 LangChain 的 Chains 组件,了解如何将多个操作串联起来构建复杂的工作流。 | ||
| + | |||
| + | ===== 练习 ===== | ||
| + | |||
| + | 1. **基础练习**:创建一个 PromptTemplate,用于生成产品描述。模板应包含产品名称、特点列表、目标受众等变量。 | ||
| + | |||
| + | 2. **进阶练习**:实现一个 Few-shot 情感分析提示词,包含5个示例,并使用长度限制选择器。 | ||
| + | |||
| + | 3. **综合项目**:设计一个动态提示词系统,能够根据用户输入的复杂度自动选择不同数量和类型的示例。 | ||
| + | |||
| + | ===== 参考资源 ===== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | |||