自定义 RAG Prompt Template


在 RAG 系统中,提示词模板(Prompt Template) 是连接检索结果与生成模型的关键桥梁。它决定了模型如何理解任务、利用上下文以及输出答案。自定义提示词模板可以让你精确控制模型的行为、风格、格式,从而提升回答的准确性、可解释性和领域适配性(如中医)。

下面我将从为什么需要自定义、LlamaIndex 中的实现方法、实战示例到高级技巧,为你全面解析。


一、为什么要自定义提示词模板?

默认的 RAG 提示词可能只是简单拼接:“基于以下上下文回答问题:…”。但在实际应用中,你可能需要:

  1. 注入领域知识:例如在中医场景中,让模型扮演“资深中医专家”,并要求它引用经典条文。
  2. 控制输出格式:要求模型以列表、表格或 JSON 输出,便于下游处理。
  3. 增强可解释性:强制模型标注答案来源(如“根据《伤寒论》第35条……”)。
  4. 减少幻觉:明确指示“如果检索到的资料不足以回答问题,请直接说明不知道”。
  5. 多轮对话:在对话历史中保持角色一致性。

自定义提示词模板能让你灵活地调整模型的行为,以匹配业务需求。


二、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 的响应合成器支持多种模式,如 COMPACTREFINETREE_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 提示词了!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐