Agent & RAG 测试工程 02:RAG 从最小闭环到可信

前言

当前这个项目的目标:
做一个能基于课程资料,稳定回答课程相关问题的 RAG Copilot。

在上一篇中,已经把 RAG 的最小闭环跑通了:

  • 能读取 PDF

  • 能返回模型结果

但在继续往下推进时,意识到一个问题:

这个输出,我其实不太敢信。

一、遇到的问题:不是"不准",而是"不稳"

真正卡住我的,并不是模型能力本身,而是输出形态的问题

  • 同一份 PDF,多次运行输出结构不一致

  • 有时候像课程大纲,有时候又像项目说明

  • 内容看起来都"说得通",但无法稳定复现

从项目工程视角,就会变成一个核心风险:
结果不可预测,就无法被真正使用。

二、想解决的问题是什么

这一阶段,并不是想让模型"生成得更聪明",

而是想解决一个更基础、也更工程的问题:

模型能不能按照"规定的结果形态"来生成内容。

具体来说就是:

  • 只回答课程相关内容

  • 回答必须基于已有文档

  • 输出结构本身是可预期的

这不再是简单的 prompt 调整,而是一个输出契约(Output Contract)的问题。

三、做了什么

围绕"输出是否可控"这个问题,做了这些调整:

  • 将「课程大纲」和「项目说明」拆成两种独立的输出模式

  • 同一份 PDF,通过不同 prompt 明确约束输出形态

  • 对「项目说明」模式,强制固定为三页结构,用于说明背景、方案与测试视角

没有引入新的模型能力,也没有提前做复杂优化,只是先把"结果长什么样"这件事控住。

prompt_course_outline.py 文件要点记录:

复制代码
SYSTEM_PROMPT = (
    "你是一个 helpful assistant,会根据需要调用工具来获取信息。"
    "当需要获取 PDF 内容时,你必须调用 read_local_pdf 工具读取文件内容。"
    "后续输出必须基于工具返回内容,不得虚构。"
)

FIRST_PROMPT_TEMPLATE = (
    "请读取以下 PDF 文件内容,然后基于内容生成一个详细的课程大纲(使用 Markdown)。\n"
    "要求:每条大纲要点末尾请注明来源,格式为:(来源:文件名 摘录:...)。\n\n"
    "PDF 文件路径:{pdf_path}"
)

SECOND_PROMPT = (
    "请仅基于上面 tool 返回的【文件名 + p1/p2/p3 摘录】生成课程大纲(Markdown)。\n"
    "要求:3~8章,每章3~7要点;每条要点末尾必须带(来源:文件名 pX 摘录:...)。\n"
    "不要再次要求读取PDF,也不要再次调用任何工具。"
)

这个文件的定位:"课程大纲版"输出契约

它解决的问题

  • 把 PDF 内容重组为"课程结构"

  • 强制章节数/要点数

  • 每条都要带来源(可追溯)

具体就是:

  • 输出必须是 课程大纲

  • 必须 3~8 章 ,每章 3~7 要点

  • 每条要点末尾必须携带 (来源:文件名 pX 摘录:...)

  • 第二轮不再调用工具(只基于 tool 返回的 p1/p2/p3)

适用场景:

  • 需要"讲解式"材料:培训、对外讲解、内容二次加工

  • PDF 内容本身像教材/方案文档,适合课程化拆解

怎么验证:

  • 同一 PDF 多次跑:章节结构稳定(不会变成三页说明)

  • 每条要点都有来源,且 pX 正确

prompt_project_brief.py 要点记录:

复制代码
# -*- coding: utf-8 -*-
SYSTEM_PROMPT = (
    "你是一个工程型 AI 助手。"
    "当需要获取 PDF 内容时,你必须调用 read_local_pdf 工具读取文件内容。"
    "后续输出必须严格基于工具返回内容,不得虚构或扩写。"
    "输出结构必须遵循用户明确��求的格式。"
)

FIRST_PROMPT_TEMPLATE = (
    "请读取以下 PDF 文件内容。\n"
    "注意:这是【项目说明文档(说明版)】,不是课程教材。\n"
    "本轮只需要读取 PDF 并返回工具调用,不要做总结。\n\n"
    "PDF 文件路径:{pdf_path}"
)

SECOND_PROMPT = (
    "请仅基于上面 tool 返回的【文件名 + p1/p2/p3 摘录】生成《3页项目说明(说明版)》Markdown。\n"
    "严格要求:\n"
    "1) 必须按 p1 / p2 / p3 三页结构输出,标题格式为:\n"
    "   # 第1页:...\n"
    "   # 第2页:...\n"
    "   # 第3页:...\n"
    "2) 每页输出 4~6 条要点(不要超过 6 条)。优先保留:目标/边界/流程/验收/测试。\n"
    "3) 不要生成课程大纲或第X章目录式结构。\n"
    "4) 不得新增 PDF 中不存在的观点。\n"
    "5) 不要再次调用任何工具。\n"
    "6) 允许轻度整理语句,但不要改变原意。\n"
    "7) 每条要点末尾必须带来源:(来源:文件名 pX 摘录:...)。\n"
    "8) 【重要】每条来源摘录控制在 20~40 个汉字,必要时用...省略,但保留关键词。\n"
)

文件定位:"项目说明版(说明版)"输出契约(更工程、可复述)

它解决的问题:

  • 解决你说的核心痛点:"能跑但不可信"

  • 让输出形态稳定(固定三页)

  • 把"日志式输出"变成"可交付说明"

具体说明:

  • 输出必须按 三页结构

    • # 第1页:...

    • # 第2页:...

    • # 第3页:...

  • 每页 4~6 条要点(不超过 6)

  • 不允许输出"课程大纲/第X章/目录式结构"

  • 不允许新增 PDF 中不存在的观点

  • 每条要点必须带来源,且 摘录长度受控(20~40 字,可省略号)

  • 第一轮只触发读 PDF(不总结),第二轮才输出

适用场景:

  • 写 README、对外解释项目

怎么验证它(最小回归点):

  • 输出一定是三段标题(第1/2/3页)

  • 每页条数 ≤ 6

  • 引用摘录明显变短(不再一大坨)

  • 不会漂移成"课程大纲"

四、这一步对后续 RAG 有什么意义

这一步是 RAG 从"能跑"走向"可信" 的分水岭。

原因:

  • 只有当输出是稳定、可控、可复现的

  • 后面的检索效果评估、回归测试、质量对比才有意义

否则,即使检索做得再好,也很难判断问题到底出在检索、生成,还是输出组织本身。

五、这一篇暂不展开的内容

本文只记录这一阶段的判断与实践结果,暂不展开以下内容:

  • RAG 检索策略

  • chunk / embedding 设计

  • 离线评测与回归验证

这些内容后面看情况再补充。


附:代码记录(GitHub)

本阶段的代码放在 GitHub,

主要用于记录这一阶段「输出形态控制」的实现与验证,方便后续回看与迭代。

GitHub(私有仓库,用于阶段性存档):
https://github.com/test202005/project2_mvp

相关推荐
无风听海2 小时前
C# 中的 LinkedList
开发语言·c#
tudficdew2 小时前
C++中的策略模式实战
开发语言·c++·算法
查无此人byebye2 小时前
手写Multi-Head Attention多头注意力机制,Pytorch实现与原理详解
人工智能·pytorch·python·深度学习·transformer
Gavin在路上2 小时前
SpringAIAlibaba之深度剖析序列化过程中LinkedHashMap类型转换异常(十)
人工智能
naruto_lnq2 小时前
实时语音处理库
开发语言·c++·算法
wfeqhfxz25887822 小时前
击剑运动员姿态识别与关键部位检测_YOLOv26模型应用与优化
人工智能·yolo·目标跟踪
OpenCSG2 小时前
OpenCSG(开放传神)开源数据贡献解析:3大标杆数据集,筑牢中文AI基建
人工智能·开源
_xaboy2 小时前
开源Vue组件-动态表单组件设计,告别重复CRUD,JSON一键生成表单
前端·vue.js·低代码·开源·json
程序员良辰2 小时前
JDK 环境变量的核心作用 ? 如果使用 IDEA 运行程序,是否可以不配置环境变量 ?
java·开发语言·intellij-idea