8 节 / 共 12

3.2 提示工程与上下文融合

📌 本节目标

学完本节,你将掌握如何设计高效的提示词(Prompt),让检索到的上下文与用户问题无缝融合。你将学会构建结构化的提示模板,使大语言模型(LLM)能够精准地基于你提供的外部知识回答问题,而不是依赖其自身的“记忆”进行猜测。

1. 核心概念讲解

在RAG架构中,生成器(通常是LLM)就像一个知识渊博但有点“健忘”的专家。你需要把检索到的相关文档(上下文)和用户的问题一起“喂”给它,并告诉它如何使用这些材料。这个过程,就是提示工程上下文融合

让我们来拆解几个核心概念:

1.1 提示词(Prompt)

提示词就是你给LLM的指令,告诉它要做什么。在RAG中,它通常包含两部分:系统指令用户消息

  • 系统指令:设定LLM的角色和回答规则。例如:“你是一个严谨的客服助手,只能根据提供的事实回答。”
  • 用户消息:包含用户的问题,以及我们检索到的上下文。

比如:

系统指令:你是一个文档问答助手。请根据以下提供的上下文,准确、简洁地回答问题。如果上下文中没有答案,请直接说“无法从提供的信息中找到答案”,不要编造。

用户消息:
上下文:爱因斯坦于1879年出生于德国乌尔姆。他于1905年提出了狭义相对论。
问题:爱因斯坦哪一年提出了狭义相对论?

1.2 上下文窗口(Context Window)

LLM一次能处理的文本长度是有限的,这个限制被称为“上下文窗口”。RAG检索到的文档可能很长,我们需要将它们裁剪、拼接,并放入这个窗口内。

比如: 假设你的LLM上下文窗口是4096个token(一种计算文本长度的单位)。你检索到了3份文档,每份有2000个token。你不能直接把3份都塞进去,因为加上用户问题和指令,总长度会超过4096。你需要做的是:只保留最相关的部分,或者对文档进行摘要,确保所有内容都能放进“窗口”里。

1.3 上下文融合(Context Fusion)

这是核心技巧。它不是简单地把上下文和问题堆在一起,而是通过精心设计的提示模板,告诉LLM如何理解它们之间的关系。一个好的融合策略能让LLM清晰地知道:哪些是背景知识,哪些是需要解决的任务。

比如: 一个不好的融合方式:

上下文:...爱因斯坦出生于1879年...问题:爱因斯坦的生平?

一个好的融合方式(使用结构化模板):

【背景知识】
爱因斯坦出生于1879年,地点是德国乌尔姆。他是一位理论物理学家。

【用户问题】
请根据上述背景知识,简述爱因斯坦的出生年份和地点。

通过添加 【背景知识】【用户问题】 这样的标签,LLM能更准确地理解不同部分的角色。

1.4 提示模板(Prompt Template)

为了复用和标准化,我们会把融合了上下文和问题的提示词结构固定下来,形成一个模板。这个模板中有一些变量(比如 {context}{question}),在运行时会被实际内容替换。

代码示例:一个基础的提示模板

# 定义一个提示模板
prompt_template = """
你是一个专业的问答助手。请根据以下提供的上下文内容,回答用户的问题。

重要规则:
1. 如果你的回答基于上下文,请引用原文。
2. 如果上下文中没有足够信息,请回答“信息不足,无法回答”。
3. 不要添加任何上下文之外的信息。

====================
上下文:
{context}
====================

用户问题:{question}

请给出你的回答:
"""

# 假设我们检索到的内容和用户问题
retrieved_context = "杭州西湖位于浙江省杭州市,是国家5A级旅游景区。"
user_question = "西湖在哪个省?"

# 填充模板,生成最终的提示词
final_prompt = prompt_template.format(
    context=retrieved_context,
    question=user_question
)

print(final_prompt)

输出结果:

你是一个专业的问答助手。请根据以下提供的上下文内容,回答用户的问题。

重要规则:
1. 如果你的回答基于上下文,请引用原文。
2. 如果上下文中没有足够信息,请回答“信息不足,无法回答”。
3. 不要添加任何上下文之外的信息。

====================
上下文:
杭州西湖位于浙江省杭州市,是国家5A级旅游景区。
====================

用户问题:西湖在哪个省?

请给出你的回答:

2. 深入理解

2.1 为什么要精心设计提示?

LLM本质上是一个“文字接龙”游戏。它根据你给出的前文(提示词),预测最合理的后文(回答)。如果你给的提示词结构混乱、角色模糊,LLM就可能“跑偏”,甚至忽略你提供的上下文,转而使用它自己训练数据中的“知识”来回答。这在RAG中是致命的,因为我们的目标就是让LLM忠实于检索到的外部知识

2.2 初学者常见的误区

| 误区 | 错误做法 | 正确做法 | | :--- | :--- | :--- | | 上下文过长 | 把检索到的整篇文档不加处理地塞进提示词,导致超出上下文窗口或关键信息被淹没。 | 对文档进行分块、摘要,只提取最相关的1-3个片段。 | | 指令模糊 | 提示词只写“根据以上内容回答”,没有明确规则。 | 明确告诉LLM:“如果找不到答案,就说不知道”,“引用原文”等。 | | 忽视格式 | 上下文和问题混在一起,没有分隔符或标签。 | 使用 【上下文】【问题】 等结构清晰的标签。 | | 角色冲突 | 系统指令说“你是一个数学家”,但上下文是关于历史的。 | 系统指令应与RAG任务匹配,例如“你是一个基于文档的问答助手”。 |

2.3 为什么“说不知道”很重要?

这是RAG提示工程中最关键的一条规则。LLM天生有“幻觉”倾向,即编造事实。如果我们不强制它“不知道就承认”,它可能会自信地给出一个看似合理但完全错误的答案。通过提示词明确要求“如果信息不足,请说不知道”,可以极大地提升回答的可靠性和可信度。

3. 实战演示

让我们从一个简单的客服问答场景开始,一步步构建一个包含检索上下文的提示模板。

场景: 一个关于“公司年假政策”的问答机器人。

步骤1:准备检索到的上下文

假设用户问:“我今年工作满一年了,可以休几天年假?” 我们的检索系统从公司文档中找到了以下相关片段:

上下文片段1:员工连续工作满1年但不足10年的,年休假为5天。
上下文片段2:新入职员工,当年年休假天数按在本单位剩余日历天数折算。
上下文片段3:年休假可以在一个自然年度内分段使用,但最少半天起休。

步骤2:设计提示模板

我们将设计一个包含“角色设定”、“回答规则”、“上下文”和“问题”的模板。

# 提示模板
rag_prompt_template = """
### 角色设定 ###
你是一家科技公司的智能客服助手,名字叫“小科”。
你的任务是回答员工关于公司政策的问题。

### 回答规则 ###
1. 你必须严格根据下面提供的【政策文档】内容来回答。
2. 如果【政策文档】中没有提及,请直接回答:“抱歉,我目前的知识库中没有找到相关信息,请咨询人力资源部。”
3. 回答要简洁、友好,直接给出结论。

### 政策文档 ###
{context}

### 员工提问 ###
{question}

### 你的回答 ###
"""

# 模拟检索到的上下文(通常我们会拼接多个片段)
retrieved_docs = """
1. 年假规定:员工连续工作满1年但不足10年的,年休假为5天。
2. 年假使用:年休假可以在一个自然年度内分段使用,但最少半天起休。
"""

# 用户问题
user_question = "我今年工作满一年了,可以休几天年假?"

# 生成最终提示词
final_prompt = rag_prompt_template.format(
    context=retrieved_docs,
    question=user_question
)

print("=== 生成的最终提示词 ===")
print(final_prompt)

步骤3:将提示词发送给LLM并观察输出

当你把 final_prompt 发送给一个LLM(例如GPT-4或Claude)时,期望的输出应该是:

=== 生成的最终提示词 ===

### 角色设定 ###
你是一家科技公司的智能客服助手,名字叫“小科”。
你的任务是回答员工关于公司政策的问题。

### 回答规则 ###
1. 你必须严格根据下面提供的【政策文档】内容来回答。
2. 如果【政策文档】中没有提及,请直接回答:“抱歉,我目前的知识库中没有找到相关信息,请咨询人力资源部。”
3. 回答要简洁、友好,直接给出结论。

### 政策文档 ###
1. 年假规定:员工连续工作满1年但不足10年的,年休假为5天。
2. 年假使用:年休假可以在一个自然年度内分段使用,但最少半天起休。

### 员工提问 ###
我今年工作满一年了,可以休几天年假?

### 你的回答 ###

LLM的理想回答:

根据公司政策,您连续工作已满1年,属于工作满1年但不足10年的情况,因此您可以享受5天的年休假。

测试“不知道”的情况:

如果用户问:“我今年可以休病假吗?”

由于我们的 context 中没有关于“病假”的信息,LLM应该根据规则2回答:

抱歉,我目前的知识库中没有找到相关信息,请咨询人力资源部。

4. 关键要点

  • 结构化是关键:使用角色、规则、上下文、问题等清晰的标签来分隔提示词的不同部分,帮助LLM理解任务。
  • 明确“不知道”的规则:在提示词中强制要求LLM在信息不足时承认,这是对抗“幻觉”最有效的方法之一。
  • 上下文要精简:不要贪多。只提供最相关、最精炼的上下文片段,避免信息过载。
  • 模板化与可复用:将提示词设计成带变量的模板(如 {context}),方便在RAG系统中动态生成。
  • 测试边界情况:不仅要测试有答案的情况,更要测试“无答案”或“部分答案”的情况,确保提示词规则生效。

✏️ 练习任务

练习方向:编写一个包含检索上下文的提示模板

任务1(基础):

假设你正在为一个“产品说明书问答系统”设计提示词。

  1. 输入:

    • 检索到的上下文: “产品X的电池容量为5000mAh,支持20W快充。充电时请使用原装充电器。”
    • 用户问题: “产品X的电池容量是多少?”
  2. 要求:

    • 请编写一个Python字符串模板,包含角色设定、回答规则、上下文和问题。
    • 回答规则中必须包含“如果上下文中没有答案,请回答‘信息不足’”。
    • 使用 format() 方法将上下文和问题填入模板。
    • 打印出最终的提示词。
  3. 期望输出: 一个结构清晰、符合上述要求的完整提示词字符串。

任务2(进阶挑战):

  1. 输入:

    • 检索到的上下文(多个片段):
      片段A:产品Y的保修期为1年,从购买之日起计算。
      片段B:产品Y的屏幕采用6.1英寸OLED面板。
      片段C:非人为损坏的硬件问题在保修期内免费维修。
      
    • 用户问题: “产品Y的屏幕尺寸是多少?如果坏了,保修政策是怎样的?”
  2. 要求:

    • 你的提示模板需要能够处理多个上下文片段,你需要在模板中设计一种方式将它们合并成一个整体(例如,用列表或段落呈现)。
    • 回答规则中必须要求LLM引用原文片段编号(例如“根据片段B,屏幕尺寸为6.1英寸”)。
    • 编写代码并打印最终的提示词。

💡 下一节我们将学习相关的进阶内容:如何评估RAG系统的生成质量,以及如何通过优化检索和提示来进一步提升准确性。


本节由 StudyAI8 AI 课程团队生成并审核。