Files
ai-agent-dev/06_Prompt模板.ipynb
2026-07-08 10:09:42 +08:00

580 lines
19 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 06 Prompt 模板\n",
"\n",
"## 学习目标\n",
"1. 理解 Prompt 模板的作用:将 Prompt 从硬编码变为可复用、可配置的组件\n",
"2. 掌握两种最常用的模板类型PromptTemplate 和 ChatPromptTemplate\n",
"3. 学会使用变量占位符 {name} 动态填充内容\n",
"4. 理解 Few-Shot Prompt 少样本提示的构建方法\n",
"5. 了解常见的 Prompt Engineering 技巧及其对模型输出的影响"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. 为什么需要 Prompt 模板\n",
"\n",
"直接拼接字符串来构造 Prompt 会带来几个问题:\n",
"\n",
"- **可读性差**Python 字符串拼接难以看清最终给模型的提示长什么样\n",
"- **容易出错**:变量多的时候容易遗漏、顺序错乱\n",
"- **难以复用**:同样的提示结构无法直接复用到不同输入\n",
"- **难以管理**:无法集中管理和版本化 Prompt\n",
"\n",
"**Prompt 模板** 就是解决这些问题的方案。它允许你:\n",
"\n",
"- 把 Prompt 写成一个带占位符的模板\n",
"- 运行时传入变量自动填充\n",
"- 复用同一个结构处理不同输入\n",
"- 把提示逻辑与业务逻辑分离"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. PromptTemplate基础字符串模板\n",
"\n",
"`PromptTemplate` 是最基础的模板类,适用于构造单条文本提示。它只有一个 `template` 字符串和若干 {变量}。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from dotenv import load_dotenv\n",
"\n",
"load_dotenv()\n",
"\n",
"\n",
"# 创建模型\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.7)\n",
"\n",
"# 使用元组列表定义消息模板\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一位{role},擅长用{style}风格回答问题。'),\n",
" ('user', '{question}')\n",
"])\n",
"\n",
"# 查看组装后的 Prompt\n",
"input_vars = {\n",
" 'role': '计算机科学家',\n",
" 'style': '通俗易懂',\n",
" 'question': '什么是递归?'\n",
"}\n",
"print('===== 组装后的 Prompt =====')\n",
"for msg in prompt.format_messages(**input_vars):\n",
" print(f'{msg.type}: {msg.content}')\n",
"\n",
"# 构建链并调用\n",
"chain = prompt | llm\n",
"print('\\n===== 大模型输出 =====')\n",
"result = chain.invoke(input_vars)\n",
"print(result.content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.1 使用 from_template 快速创建\n",
"\n",
"如果你习惯简单写法,可以使用 `from_template` 类方法,自动识别模板中的变量。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.prompts import SystemMessagePromptTemplate, HumanMessagePromptTemplate\n",
"\n",
"# 创建模型\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.7)\n",
"\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" SystemMessagePromptTemplate.from_template('你是一位耐心的老师。'),\n",
" HumanMessagePromptTemplate.from_template('请解释{concept},要求{requirement}。')\n",
"])\n",
"\n",
"# 查看组装后的 Prompt\n",
"input_vars = {\n",
" 'concept': '神经网络',\n",
" 'requirement': '用小学生能听懂的语言'\n",
"}\n",
"print('===== 组装后的 Prompt =====')\n",
"for msg in prompt.format_messages(**input_vars):\n",
" print(f'{msg.type}: {msg.content}')\n",
"\n",
"# 构建链并调用\n",
"chain = prompt | llm\n",
"print('\\n===== 大模型输出 =====')\n",
"result = chain.invoke(input_vars)\n",
"print(result.content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. ChatPromptTemplate聊天消息模板\n",
"\n",
"现代大模型通常采用对话格式每条消息都有角色role。`ChatPromptTemplate` 就是为这种场景设计的。\n",
"\n",
"常见的消息类型:\n",
"\n",
"| 消息类型 | 作用 |\n",
"| --- | --- |\n",
"| system | 设定模型的身份、能力和行为规则 |\n",
"| user / human | 用户的输入问题 |\n",
"| assistant / ai | 模型的回复,可用于 Few-Shot 示例 |\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"\n",
"# 创建模型\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.7)\n",
"\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一位{role}。'),\n",
" ('user', '请{action}{content}')\n",
"])\n",
"\n",
"# 先固定 role 变量,得到一个新的模板\n",
"translator_prompt = prompt.partial(role='专业翻译')\n",
"\n",
"# 查看组装后的 Prompt\n",
"input_vars = {\n",
" 'action': '把以下中文翻译成英文',\n",
" 'content': '今天天气很好'\n",
"}\n",
"print('===== 组装后的 Prompt =====')\n",
"for msg in translator_prompt.format_messages(**input_vars):\n",
" print(f'{msg.type}: {msg.content}')\n",
"\n",
"# 构建链并调用\n",
"chain = translator_prompt | llm\n",
"print('\\n===== 大模型输出 =====')\n",
"result = chain.invoke(input_vars)\n",
"print(result.content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.1 使用消息模板对象构建模板\n",
"\n",
"除了元组,也可以使用 LangChain 提供的**消息模板类**来构建模板。这种方式语义更清晰,而且同样支持变量替换。\n",
"\n",
"**注意区分两类对象**\n",
"- `SystemMessage` / `HumanMessage`:普通消息对象,内容固定,不会解析 `{变量}`\n",
"- `SystemMessagePromptTemplate` / `HumanMessagePromptTemplate`:消息模板对象,内容中的 `{变量}` 会被替换"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"\n",
"# 创建模型\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.1)\n",
"\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一个情绪分析助手,只输出正面或负面。'),\n",
" ('human', '这个产品太差了'),\n",
" ('ai', '负面'),\n",
" ('human', '这次的体验非常愉快'),\n",
" ('ai', '正面'),\n",
" ('human', '{text}')\n",
"])\n",
"\n",
"# 查看组装后的 Prompt\n",
"input_vars = {'text': '物流速度还可以,但包装破损了'}\n",
"print('===== 组装后的 Prompt =====')\n",
"for msg in prompt.format_messages(**input_vars):\n",
" print(f'{msg.type}: {msg.content}')\n",
"\n",
"# 构建链并调用\n",
"chain = prompt | llm\n",
"print('\\n===== 大模型输出 =====')\n",
"result = chain.invoke(input_vars)\n",
"print(result.content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. 模板变量的高级用法\n",
"\n",
"### 4.1 默认值与 partial\n",
"\n",
"你可以先填充部分变量,得到一个新的模板,后续再填充剩余变量。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate\n",
"\n",
"# 创建模型\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.1)\n",
"\n",
"# 准备示例数据\n",
"examples = [\n",
" {'input': '苹果', 'output': 'apple'},\n",
" {'input': '香蕉', 'output': 'banana'},\n",
" {'input': '人工智能', 'output': 'artificial intelligence'},\n",
"]\n",
"\n",
"# 定义每个示例的格式\n",
"example_prompt = ChatPromptTemplate.from_messages([\n",
" ('human', '{input}'),\n",
" ('ai', '{output}')\n",
"])\n",
"\n",
"# 构建 Few-Shot 提示模板\n",
"few_shot_prompt = FewShotChatMessagePromptTemplate(\n",
" example_prompt=example_prompt,\n",
" examples=examples\n",
")\n",
"\n",
"# 组合成完整提示\n",
"final_prompt = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一个中英文翻译助手,请参考示例回答问题。'),\n",
" few_shot_prompt,\n",
" ('human', '{input}')\n",
"])\n",
"\n",
"# 查看组装后的 Prompt\n",
"input_vars = {'input': '机器学习'}\n",
"print('===== 组装后的 Prompt =====')\n",
"for msg in final_prompt.format_messages(**input_vars):\n",
" print(f'{msg.type}: {msg.content}')\n",
"\n",
"# 构建链并调用\n",
"chain = final_prompt | llm\n",
"print('\\n===== 大模型输出 =====')\n",
"result = chain.invoke(input_vars)\n",
"print(result.content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.2 多轮对话模板\n",
"\n",
"模板中可以预设多轮对话历史,常用于构建 Few-Shot 示例或保持上下文:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.prompts import ChatPromptTemplate\n",
"\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一个情绪分析助手,只输出正面或负面。'),\n",
" ('human', '这个产品太差了'),\n",
" ('ai', '负面'),\n",
" ('human', '这次的体验非常愉快'),\n",
" ('ai', '正面'),\n",
" ('human', '{text}')\n",
"])\n",
"\n",
"messages = prompt.format_messages(text='物流速度还可以,但包装破损了')\n",
"for msg in messages:\n",
" print(f'{msg.type}: {msg.content}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Few-Shot Prompt少样本提示\n",
"\n",
"Few-Shot Prompt 是 Prompt Engineering 中最有效的技巧之一。它通过在输入前给出若干「示例-答案」对,让模型学习期望的输出格式和风格。\n",
"\n",
"LangChain 提供了 `FewShotPromptTemplate` 和 `FewShotChatMessagePromptTemplate` 两种主要方式。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate\n",
"\n",
"# 准备示例数据\n",
"examples = [\n",
" {'input': '苹果', 'output': 'apple'},\n",
" {'input': '香蕉', 'output': 'banana'},\n",
" {'input': '人工智能', 'output': 'artificial intelligence'},\n",
"]\n",
"\n",
"# 定义每个示例的格式\n",
"example_prompt = ChatPromptTemplate.from_messages([\n",
" ('human', '{input}'),\n",
" ('ai', '{output}')\n",
"])\n",
"\n",
"# 构建 Few-Shot 提示模板\n",
"few_shot_prompt = FewShotChatMessagePromptTemplate(\n",
" example_prompt=example_prompt,\n",
" examples=examples\n",
")\n",
"\n",
"# 组合成完整提示\n",
"final_prompt = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一个中英文翻译助手,请参考示例回答问题。'),\n",
" few_shot_prompt,\n",
" ('human', '{input}')\n",
"])\n",
"\n",
"messages = final_prompt.format_messages(input='机器学习')\n",
"for msg in messages:\n",
" print(f'{msg.type}: {msg.content}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Prompt Engineering 技巧\n",
"\n",
"Prompt Engineering 是指通过设计和优化提示词,让模型输出更准确、更符合预期。下面介绍几个最常用、最有效的技巧。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6.1 角色扮演Role Prompting\n",
"\n",
"给模型设定一个清晰的角色,可以显著提升回答质量。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.7)\n",
"\n",
"# 无角色设定\n",
"prompt1 = ChatPromptTemplate.from_messages([\n",
" ('user', '解释什么是区块链')\n",
"])\n",
"\n",
"# 有角色设定\n",
"prompt2 = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一位资深技术讲师,擅长用比喻和例子解释复杂概念。'),\n",
" ('user', '解释什么是区块链')\n",
"])\n",
"\n",
"chain1 = prompt1 | llm\n",
"chain2 = prompt2 | llm\n",
"\n",
"print('=== 无角色 ===')\n",
"print(chain1.invoke({}).content[:250])\n",
"print('\\n=== 有角色 ===')\n",
"print(chain2.invoke({}).content[:250])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6.2 明确输出格式Output Formatting\n",
"\n",
"如果你希望模型按特定格式输出,要在 Prompt 中明确说明。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.output_parsers import JsonOutputParser\n",
"\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.7)\n",
"\n",
"# 把 JSON 格式示例放在 system 消息中\n",
"# 注意:{ 和 } 是 LangChain 的变量占位符,如果要显示字面量大括号,必须写成 {{ 和 }}\n",
"system_template = '''你是一个信息提取助手。请只输出 JSON 格式,不要包含任何解释。\n",
"\n",
"输出格式如下:\n",
"{{\n",
" \"names\": [...],\n",
" \"locations\": [...],\n",
" \"time\": \"\"\n",
"}}'''\n",
"\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" ('system', system_template),\n",
" ('user', '文本:{text}')\n",
"])\n",
"\n",
"chain = prompt | llm | JsonOutputParser()\n",
"\n",
"input_vars = {\n",
" 'text': '2024年5月1日李明和王芳一起去了北京故宫参观。'\n",
"}\n",
"\n",
"print('===== 组装后的 Prompt =====')\n",
"for msg in prompt.format_messages(**input_vars):\n",
" print(f'{msg.type}: {msg.content}')\n",
"\n",
"print('\\n===== 大模型输出 =====')\n",
"result = chain.invoke(input_vars)\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6.3 分步骤思考Chain-of-Thought\n",
"\n",
"对于推理类问题,让模型「一步步思考」往往能显著提升准确率。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.1)\n",
"\n",
"# 直接提问\n",
"prompt1 = ChatPromptTemplate.from_messages([\n",
" ('user', '问题一个农场有鸡和兔共35只脚共94只。鸡和兔各几只请直接给出答案。')\n",
"])\n",
"\n",
"# 分步思考\n",
"prompt2 = ChatPromptTemplate.from_messages([\n",
" ('user', '问题一个农场有鸡和兔共35只脚共94只。鸡和兔各几只请一步步思考并给出答案。')\n",
"])\n",
"\n",
"print('=== 直接提问 ===')\n",
"print((prompt1 | llm).invoke({}).content)\n",
"print('\\n=== 分步思考 ===')\n",
"print((prompt2 | llm).invoke({}).content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. 完整示例Prompt 模板与链结合\n",
"\n",
"下面是一个综合示例:使用模板构建一个「学习助手」,根据学生年级和知识点生成适合难度的解释。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.output_parsers import StrOutputParser\n",
"\n",
"llm = ChatOpenAI(model='qwen3.6-35b-A3b', temperature=0.7)\n",
"\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" ('system', '你是一位{grade}水平的优秀教师。'),\n",
" ('user', '请用适合{grade}学生理解的方式解释 {topic},并举一个生活中的例子。')\n",
"])\n",
"\n",
"chain = prompt | llm | StrOutputParser()\n",
"\n",
"result = chain.invoke({\n",
" 'grade': '小学三年级',\n",
" 'topic': '浮力'\n",
"})\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. 本节课练习\n",
"\n",
"1. 使用 `PromptTemplate` 创建一个邮件生成模板,变量包含收件人姓名、主题、正文要点,调用 `format` 输出完整邮件\n",
"2. 使用 `ChatPromptTemplate` 创建一个「代码审查助手」模板system 设定角色user 传入代码片段\n",
"3. 使用 `.partial()` 固定 system 角色为「技术文档写手」,只传入 user 变量运行\n",
"4. 使用 `FewShotChatMessagePromptTemplate` 创建一个三示例的情绪分类器,然后输入新句子测试\n",
"5. 对比实验:分别用「直接提问」和「分步骤思考」两种方式向模型提问同一道数学题,观察输出差异"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}