自定义 RAG Prompt Template
目录
自定义 RAG Prompt Template
在 RAG 系统中,提示词模板(Prompt Template) 是连接检索结果与生成模型的关键桥梁。它决定了模型如何理解任务、利用上下文以及输出答案。自定义提示词模板可以让你精确控制模型的行为、风格、格式,从而提升回答的准确性、可解释性和领域适配性(如中医)。
下面我将从为什么需要自定义、LlamaIndex 中的实现方法、实战示例到高级技巧,为你全面解析。
一、为什么要自定义提示词模板?
默认的 RAG 提示词可能只是简单拼接:“基于以下上下文回答问题:…”。但在实际应用中,你可能需要:
- 注入领域知识:例如在中医场景中,让模型扮演“资深中医专家”,并要求它引用经典条文。
- 控制输出格式:要求模型以列表、表格或 JSON 输出,便于下游处理。
- 增强可解释性:强制模型标注答案来源(如“根据《伤寒论》第35条……”)。
- 减少幻觉:明确指示“如果检索到的资料不足以回答问题,请直接说明不知道”。
- 多轮对话:在对话历史中保持角色一致性。
自定义提示词模板能让你灵活地调整模型的行为,以匹配业务需求。
二、LlamaIndex 中的提示词管理
LlamaIndex 将提示词封装为 PromptTemplate 对象,并针对不同任务(如问答、摘要、合并)预定义了多个模板。你可以轻松地获取、修改或替换它们。
核心概念
PromptTemplate:包含模板字符串和模板变量(如{context_str}、{query_str})。- 提示词集(
PromptSet):LlamaIndex 预定义的一系列提示词,如DEFAULT_TEXT_QA_PROMPT。 update_prompts方法:通过查询引擎或索引更新特定任务的提示词。
三、自定义提示词的步骤
1. 获取当前默认提示词(可选)
首先,你可以查看当前使用的默认提示词,以便在此基础上修改。
from llama_index.core import PromptTemplate
from llama_index.core.query_engine import CustomQueryEngine
# 查看默认的 QA 提示词模板
default_qa_prompt = PromptTemplate.get_template(DEFAULT_TEXT_QA_PROMPT)
print(default_qa_prompt.template)
2. 定义自定义提示词
创建一个新的 PromptTemplate 对象,包含你想要的指令和变量。
from llama_index.core import PromptTemplate
custom_qa_prompt = PromptTemplate(
"你是一位资深中医专家,请根据以下参考资料回答问题。\n"
"如果参考资料不足以支持答案,请明确说明‘参考资料中未找到相关信息’,不要自行编造。\n"
"在回答末尾,请列出所引用的具体文献名称(如《伤寒论》第X条)。\n\n"
"参考资料:\n{context_str}\n\n"
"问题:{query_str}\n\n"
"回答:"
)
变量说明:
{context_str}:检索到的文本块拼接后的内容。{query_str}:用户的问题。
3. 将自定义提示词应用到查询引擎
LlamaIndex 的查询引擎允许你通过 update_prompts 方法替换特定任务的提示词。任务的键名通常是 "response_synthesizer:text_qa_template"(用于问答)。
query_engine = index.as_query_engine()
# 更新提示词
query_engine.update_prompts(
{"response_synthesizer:text_qa_template": custom_qa_prompt}
)
# 现在查询将使用自定义提示词
response = query_engine.query("麻黄汤的组成")
4. 验证提示词是否生效
你可以通过回调或直接打印内部使用的提示词来确认。
# 获取当前使用的提示词
current_prompt = query_engine.get_prompts()[
"response_synthesizer:text_qa_template"
]
print(current_prompt.template)
四、针对不同响应模式的自定义
LlamaIndex 的响应合成器支持多种模式,如 COMPACT、REFINE、TREE_SUMMARIZE 等。不同模式使用不同的提示词模板,你可能需要分别自定义。
text_qa_template:用于直接问答(COMPACT模式)。refine_template:用于逐块优化(REFINE模式),逐步合并多个检索块。summary_template:用于摘要任务。
示例:自定义 REFINE 模式的提示词
from llama_index.core import PromptTemplate
custom_refine_prompt = PromptTemplate(
"你是一位中医专家,正在逐步完善一个答案。\n"
"已有的部分答案:{existing_answer}\n"
"新的参考资料:{context_msg}\n"
"问题:{query_str}\n"
"请根据新的参考资料改进或补充已有答案。如果新资料无帮助,则返回原答案。\n"
"改进后的答案:"
)
query_engine.update_prompts(
{
"response_synthesizer:text_qa_template": custom_qa_prompt,
"response_synthesizer:refine_template": custom_refine_prompt,
}
)
五、实战示例:中医问答并引用出处
假设我们构建了一个中医古籍索引,现在希望模型回答时引用具体条文。
完整代码
import os
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.core import Settings
from llama_index.core import PromptTemplate
# 设置 embedding 模型
Settings.embed_model = HuggingFaceEmbedding(
model_name="BAAI/bge-large-zh-v1.5"
)
# 加载文档(假设包含《伤寒论》条文)
documents = SimpleDirectoryReader("./tcm_data").load_data()
index = VectorStoreIndex.from_documents(documents)
# 定义自定义提示词
custom_qa_prompt = PromptTemplate(
"你是一位精通中医古籍的专家。请根据以下参考资料回答问题。\n"
"要求:\n"
"1. 答案应基于参考资料,如果资料不足,请说‘参考资料中未提及’。\n"
"2. 在答案末尾,列出所引用的具体文献名称和条文号(如《伤寒论》第35条)。\n"
"3. 若涉及方剂,请注明其组成和功用。\n\n"
"参考资料:\n{context_str}\n\n"
"问题:{query_str}\n\n"
"回答:"
)
# 创建查询引擎并应用自定义提示词
query_engine = index.as_query_engine(similarity_top_k=3)
query_engine.update_prompts(
{"response_synthesizer:text_qa_template": custom_qa_prompt}
)
# 查询
response = query_engine.query("麻黄汤主治什么?")
print(response)
# 同时打印检索到的片段,验证引用
print("\n检索片段:")
for node in response.source_nodes:
print(f"来源: {node.metadata.get('source', '未知')}, 条文: {node.text[:50]}...")
预期输出效果
回答:麻黄汤主治太阳病伤寒表实证,症见恶寒发热、头身疼痛、无汗而喘、脉浮紧。其组成为麻黄、桂枝、杏仁、甘草。
引用:《伤寒论》第35条。
检索片段:
来源: 伤寒论, 条文: 太阳病,头痛发热,身疼腰痛,骨节疼痛...
...
六、在自定义查询引擎中使用提示词
如果你需要更精细的控制,可以继承 CustomQueryEngine 并完全自定义检索和合成逻辑。
from llama_index.core.query_engine import CustomQueryEngine
from llama_index.core.retrievers import BaseRetriever
from llama_index.core.response_synthesizers import BaseSynthesizer
class MyCustomEngine(CustomQueryEngine):
"""自定义查询引擎,使用自己的提示词合成回答。"""
retriever: BaseRetriever
synthesizer: BaseSynthesizer
def custom_query(self, query_str: str):
nodes = self.retriever.retrieve(query_str)
response = self.synthesizer.synthesize(query_str, nodes)
return response
# 使用自定义提示词的合成器
from llama_index.core.response_synthesizers import CompactAndRefine
synthesizer = CompactAndRefine(
text_qa_template=custom_qa_prompt,
refine_template=custom_refine_prompt,
)
custom_engine = MyCustomEngine(
retriever=index.as_retriever(),
synthesizer=synthesizer
)
response = custom_engine.query("麻黄汤组成")
七、高级技巧
1. 动态选择提示词
可以根据问题类型选择不同的提示词。例如,如果问题涉及方剂,使用方剂专用提示词;如果涉及医案,使用医案提示词。可以通过问题分类器(如另一个 LLM 或规则)实现。
def get_prompt_by_query(query):
if "方剂" in query or "组成" in query:
return formula_prompt
else:
return general_prompt
query_engine.update_prompts(
{"response_synthesizer:text_qa_template": get_prompt_by_query(query)}
)
2. 多语言提示词
如果你的知识库是中文,但用户可能用英文提问,可以在提示词中指定输出语言,或动态切换。
3. 集成对话历史
在多轮对话中,你可能需要在提示词中包含历史对话。可以使用 ChatEngine,它内部会管理历史并自动构建带历史的提示词。
chat_engine = index.as_chat_engine(
chat_mode="condense_question", # 自动压缩历史
system_prompt="你是一位中医专家,请用中文回答。"
)
response = chat_engine.chat("麻黄汤的组成")
4. 评估提示词效果
通过 A/B 测试不同提示词对回答质量的影响。可以使用 LlamaIndex 的评估模块(如 FaithfulnessEvaluator)或人工评价。
八、常见问题与调试
Q: 提示词修改后没有生效?
A: 确认 update_prompts 的键名是否正确。可以通过 query_engine.get_prompts().keys() 查看所有可用的键。
Q: 如何恢复默认提示词?
A: 重新创建查询引擎,或从 PromptSet 重新加载默认模板。
from llama_index.core import PromptHelper
default_prompt = PromptHelper.get_default_text_qa_prompt()
query_engine.update_prompts({"response_synthesizer:text_qa_template": default_prompt})
Q: 提示词太长导致超限?
A: 确保提示词长度加上检索内容不超过模型的上下文窗口。可以减小 similarity_top_k 或使用更短的提示词。
九、总结
自定义 RAG 提示词模板是提升系统智能和可控性的重要手段。通过 LlamaIndex,你可以:
- 轻松替换默认提示词,实现领域定制。
- 针对不同响应模式分别自定义。
- 结合动态选择、对话历史等实现高级功能。
在中医等专业领域,一个好的提示词能让模型更准确地引用经典、避免幻觉,显著提升回答的权威性和可用性。现在你可以根据具体需求,动手定制你自己的 RAG 提示词了!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)