从基础提示词和每个问题所需的规则组装RAG生成提示

从基础提示词和每个问题所需的规则组装RAG生成提示

从基础提示词和每个问题所需的规则组装RAG生成提示

📰 来源:Towards Data Science | 📅 翻译日期:2026年7月6日
🔗 原文查看原文
🤖 翻译:DeepSeek AI · 仅供参考

生成砖块简介

本文是企业文档智能系列中生成砖块的第二部分,该系列从四个砖块构建企业RAG系统:文档解析、问题解析、检索和生成。第8A篇文章(回答合约)声明了类型化模式家族和ANSWER_REGISTRY,它将每个答案形状映射到其模式。本部分构建了填充合约的调用:输入一个ParsedQuestion;调度器从注册表中选择模式,从固定的BASE加上片段组合系统提示,构建用户提示,调用模型,并保留完整轨迹。调用后对答案的处理是第8C篇文章(验证)。

生成是第四个砖块。初次阅读的读者可以从各自文章中了解前三个砖块:

  • 文档解析:将PDF转换为结构化表格:第5A篇(PDF中读取的内容)和第5B篇(关系数据模型)。
  • 问题解析:将用户字符串转换为类型化的ParsedQuestion:第6A篇(论点)、第6B篇(提取)和第6C篇(调度)。
  • 检索:将段落过滤到应包含答案的范围:第7A篇(检索作为过滤)、第7B篇(锚点检测)和第7C篇(LLM仲裁器)。
本文在系列中的位置:第8篇(生成),提示组装部分,位于第二部分(四个砖块)——图片来源:作者

📓 可运行配套笔记本在GitHub上:doc-intel/notebooks-vol1

公共配套代码仓库doc-intel/notebooks-vol1——图片来源:作者

1. 从简要到提示:调度器

每个问题形状一个提示,在调用时组合。这就是调度器。替代方案是每个RAG代码库容易陷入的巨型提示:一个系统提示同时处理金额、日期、列表、表格和自由文本。每次调用都会增加一个新的条件子句(“如果答案是日期,使用ISO 8601;如果是金额,使用ISO 4217;如果是列表,每个元素一行……”),模型每次都读取所有内容,两个月后没人记得哪个子句是为哪个情况添加的。

我们将构建的调度器取代了这种混乱。合约:输入一个ParsedQuestion;输出三样东西:模式(根据expected_answer_shapeANSWER_REGISTRY中选择)、系统提示(固定的BASE加上简要请求的片段)和用户提示(问题+关键词+标注的段落行)。它调用模型,在轨迹上保留完整的原始响应,返回类型化结果。添加一个新形状就添加一个片段;添加一个新约束就添加一个片段;没有组合爆炸。

一个ParsedQuestion输入,一个类型化调用输出:调度器组合模式、系统提示和用户提示,然后返回答案及其轨迹——图片来源:作者

我们排除了替代方案:一个包含所有子句的巨型提示(浪费token,当表格格式化子句渗入金额答案时难以调试),或者每个形状独立的N个提示(每个形状更清晰,但跨所有模板重复了横切约束(格式、区分、必须消除歧义),并且每次更改都需要重新同步)。

1.1 简要:ParsedQuestion

调度器读取由问题解析砖块产生的ParsedQuestion。完整模式是关系型的(嵌套Pydantic对象,不是扁平简要):keywords(类型化对象,不是字符串)、expected_answer_shapedecompositionscope_filters、执行计划、解析注释,以及为后续砖块(检索:RetrievalQuery和生成:GenerationBrief)做的两个准备。

本文读取该对象的三个部分:expected_answer_shape(选择模式和形状片段)、generation(携带格式约束、近似候选项之间的消歧和要区分的值)和keywords(在用户提示中回显,以便模型标记哪些出现在检索到的段落中)。边界清晰:形状检测位于问题解析中;模板组装位于此处。

我们在下面内联构建ParsedQuestion;包的当前源码src/docintel/question/parse_question.py只提供最小版本。一旦问题解析砖块完成其完整实现,模式和调度器将升级到包中。

class Keyword(BaseModel):
    text: str
    weight: float = 1.0
    source: Literal['direct','llm_expansion','expert_dictionary'] = 'direct'
    is_regex: bool = False

class RetrievalQuery(BaseModel):
    main_query: str
    rewrites: list[str] = []
    anchor_keywords: list[str] = []
    section_hint: str | None = None
    scope: str = 'default'

class GenerationBrief(BaseModel):
    original_question: str
    format_constraint: dict[str, str] = {}
    disambiguation: str | None = None
    must_distinguish: list[Distinction] = []

class ExecutionPlan(BaseModel):
    use_toc_navigation: bool = True
    use_keyword_retrieval: bool = True
    use_embeddings: bool = False
    iterate_on_feedback: bool = True
    max_iterations: int = 3

class ParsedQuestion(BaseModel):
    original_question: str
    keywords: list[Keyword]
    expected_answer_shape: Literal['text','amount','date','boolean','list','table']
    decomposed_subquestions: list[str] = []
    activations: ExecutionPlan = ExecutionPlan()
    parsing_notes: list[str] = []
    suggested_clarification: str | None = None
    retrieval: RetrievalQuery
    generation: GenerationBrief

1.2 来自问题的结构提示

用户的问题措辞限制了检索范围,而无需在管道上添加任何新标志。当问题说“在第1页”、“第5页到第7页”或“在定价表上”时,该指针位于ParsedQuestion.structural_hints上。检索读取它并过滤搜索空间。没有chunk_strategy="passthrough",没有绕过参数,没有特殊的短文档路径。操作员通过在问题中编写来控制范围。

该字段每种格式携带一个列表。本文仅针对PDF,因此pages_hint是此处相关的字段;系列后期涉及的其他格式的兄弟字段暂不讨论:

class Str

📌 *本文由 DeepSeek AI 自动翻译排版,如有不准确之处欢迎指正* 🏠 [返回首页](https://www.suiyuanlu.cn) · 📖 [查看原文](https://towardsdatascience.com/assemble-each-rag-generation-prompt-from-a-base-prompt-plus-the-rules-each-question-needs/)
©版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

评论已关闭