ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

课程资料问答助手:基于RAG的智能体开发案例解析

课程资料问答助手:基于RAG的智能体开发案例解析 1. 课程资料问答助手案例解读这次我们来看厦门大学林子雨老师《AI编程与智能体开发》课程中的第 8 章案例课程资料问答助手。这个案例不是那种只讲概念、不给代码的演示项目。它把一门课程的讲义、文档、教学材料变成可检索的知识库再通过大模型实现自然语言问答。简单说就是用一个基于检索增强生成的智能体来解决“课程资料太多、学生找不到答案、老师重复回答问题”的典型教学问题。核心亮点可以列成四点教学场景落地输入是一堆课程资料输出是带依据的问答结果不是空泛的聊天。通用 RAG 架构文档加载、文本切分、向量化存储、相似度检索、LLM 生成回答这条链路可以迁移到其他知识库场景。工程化训练价值案例覆盖了从数据处理到服务发布的全流程适合作为 AI 编程入门到智能体开发的综合练习。可扩展接口问答服务可以封装成 Web 页面也可以暴露成 API 给第三方系统调用。本文会按智能体开发的完整流程来拆解这个案例先梳理核心能力再讲环境准备然后走一遍知识库构建和问答功能测试最后补充接口调用、性能观察、常见问题和最佳实践。这个案例特别适合三类读者正在学大模型应用开发的学生、想把课程资料或企业内部文档做成问答助手的开发者、以及准备做智能体项目但需要一个完整参考流程的工程师。2. 核心能力速览能力项说明项目类型课程资料问答智能体 / RAG 检索增强生成应用案例来源厦门大学林子雨《AI编程与智能体开发》第 8 章案例主要功能课程资料导入、文本切分、向量化、语义检索、大模型生成问答输入内容课程讲义、PDF、Word、Markdown、TXT 等文本资料输出内容基于知识库的答案可带引用来源推荐开发环境主流 Linux/Windows/macOSPython 编程环境GPU 要求视模型选择而定使用本地小模型需要 GPU使用在线大模型 API 可不依赖 GPU启动方式命令行启动 / Web UI / API 服务是否支持 API支持问答服务可封装为 HTTP 接口是否支持批量任务支持知识库构建、批量文档导入、批量问题测试均可批处理适合场景课程学习答疑、教学辅助、企业内部知识库、文档问答从项目功能来说这个案例最核心的其实不是“问答”本身而是“课程资料怎么变成可被大模型使用的高质量知识库”。很多同学在用大模型 API 写问答应用时发现模型回答得泛泛而谈原因就是没有给模型提供具体的、可检索的上下文。这个案例正好把这一块单独拿出来做了示范。3. 适用场景与使用边界这个智能体最适合做的事情是解决垂直领域的信息查找和答疑问题。以课程场景为例学生问“第一章讲了哪些机器学习的定义”“决策树算法的优缺点是什么”“课程作业的提交截止日期在哪里”这些问题在讲义里都有明确答案。传统做法是学生自己翻 PDF、翻课件费时而且容易漏。问答助手可以把答案直接找出来并标明内容来源。类似的需求也存在于企业内部产品手册问答、规章制度问答、技术文档问答。这套案例的思路基本可以平移过去把文档喂给知识库再通过检索把最相关的段落找出来交给大模型回答。使用边界同样要清楚不适合处理知识库之外的问题。如果资料里没有相关内容模型只能凭训练数据回答可能给出不准确的信息。不适合做实时信息查询。知识库构建完成之后新增资料需要重新入库。不适合处理多模态强依赖的场景。虽然 PDF 可以解析但复杂的图表、公式还原效果取决于解析工具不是所有内容都能无损进入向量库。涉及课程版权、个人隐私、内部资料时必须先确认授权和合规要求。课程讲义如果包含未公开内容只能在教学范围内使用不能随意发布问答服务。这个案例本身是一个教学演示但把它改造成正式服务时要特别注意数据权限和回答质量审核不要直接把未经校验的模型输出发布给外部用户。4. 环境准备与前置条件搭建这个课程资料问答助手环境并不复杂。先给出一份通用检查清单实际版本按自己的系统调整。3.1 操作系统Windows 10/11、Ubuntu 20.04、macOS 12 都可以。建议开发阶段用本地环境线上部署再做容器化。3.2 Python 环境案例涉及文档解析、向量化、模型调用建议使用 Python 3.9 或 3.10 以上的版本。使用虚拟环境隔离依赖避免和系统 Python 环境冲突。python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate pip install --upgrade pip3.3 依赖安装这个案例的依赖通常包括以下几类文档解析pdfplumber、python-docx、pypdf文本处理langchain-text-splitters 或自写分段逻辑向量化与检索向量数据库客户端、Embedding 模型大模型接入OpenAI 兼容接口的 SDK或本地推理框架的客户端这里给一个安装示例实际项目需要按官方文档调整版本pip install pdfplumber python-docx pypdf pip install langchain-text-splitters pip install openai pip install chromadb3.4 模型准备两种典型路线使用在线大模型 API申请 API Key配置模型名称和接口地址。这种方案对本地硬件要求低普通笔记本可跑。使用本地大模型例如通过 Ollama、vLLM、Xinference 等框架部署开源模型。这种方案对 GPU 有要求显存占用需要按实际模型测试。如果本地显存不足可以用 CPU 跑小模型但推理速度会明显变慢。Embedding 模型和回答模型可以不同。通常使用单独的 Embedding 模型做向量化使用更强的对话模型做回答生成。3.5 存储空间课程资料一般不会太大几百 MB 足够。但要注意PDF 转出的中间文本、向量库文件、模型缓存都需要磁盘空间。如果使用本地大模型模型文件可能占用十几 GB 到几十 GB这个要提前规划。3.6 端口规划Web UI 和 API 服务需要固定端口默认常见的有 8000、7860、8501。如果端口被占用可以更换也可以在启动参数中指定。5. 安装部署与启动方式这个案例不是一个大而全的平台而是由几个模块组成的 Python 项目。部署时建议按下面的结构组织目录。4.1 项目目录结构course-qa-assistant/ ├── data/ │ ├── raw/ # 原始课程资料 │ ├── processed/ # 解析后的文本 │ └── vectorstore/ # 向量数据库文件 ├── src/ │ ├── loader.py # 文档加载与解析 │ ├── splitter.py # 文本切分 │ ├── embedder.py # 向量化 │ ├── retriever.py # 检索 │ ├── qa_chain.py # 问答链路 │ └── app.py # Web/API 服务 ├── config.yaml # 配置文件 └── requirements.txt # 依赖清单这样的结构方便后期维护。原始资料和中间产物分开存放向量库单独一个目录重跑构建时不容易混乱。4.2 配置文件示例# config.yaml 示例实际参数需要按项目调整 embedding: model: BAAI/bge-small-zh-v1.5 device: cpu llm: api_type: openai api_base: https://your-api-endpoint model: your-model-name vectorstore: persist_dir: ./data/vectorstore collection_name: course_materials splitter: chunk_size: 500 chunk_overlap: 50 server: host: 127.0.0.1 port: 8000配置文件把模型、向量库、切分参数集中管理。以后换模型、改端口、调整切分粒度都不需要改代码。4.3 一键启动流程整个启动流程可以分成三步构建知识库、启动问答服务、测试问答。第一步构建知识库。这一步读取data/raw下的课程资料解析文本、切分、向量化最终写入向量数据库。python src/loader.py --input data/raw --output data/processed python src/embedder.py --config config.yaml如果项目提供了 build 脚本也可以直接执行。第二步启动问答服务。服务启动后会加载向量数据库和模型配置监听指定端口。python src/app.py --config config.yaml启动日志里如果出现 “Application startup complete” 或者 “Uvicorn running on http://127.0.0.1:8000” 之类的信息说明服务已经起来了。第三步打开浏览器访问。如果启动的是 Web UI访问http://127.0.0.1:8000输入问题就能测试。如果页面打不开优先看两件事控制台日志有没有报错端口有没有被占用。4.4 Docker 部署参考如果要把案例做成可交付的服务可以用 Docker 封装。这里提供一个基础模板需要按项目替换构建命令和依赖。FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD [python, src/app.py, --config, config.yaml]构建和运行命令docker build -t course-qa-assistant . docker run -p 8000:8000 -v $(pwd)/data:/app/data course-qa-assistant注意挂载data目录向量库和原始资料都在这个目录下挂载出来方便更新和备份。6. 功能测试与效果验证部署完成后重点测试五个维度知识库构建、基础问答、引用溯源、多轮对话、知识库更新。5.1 知识库构建测试测试目的确认课程资料能正确加载并向量化。操作步骤在data/raw下放入 3 份不同格式的资料一份 PDF、一份 Markdown、一份 TXT。执行文档加载和向量化脚本。查看日志确认每份文档解析成功统计向量数据库中写入的文本块数量。判断标准日志中不出现文件读取失败或解析异常。向量库中的文本块数量大于 0且和输入文档数量对应。常见失败原因PDF 是扫描件没有文字层解析出来是空内容。编码问题导致 TXT 中文乱码。依赖库版本不兼容导致解析报错。5.2 基础问答测试测试目的验证问答链路是否打通模型能否根据检索结果返回答案。输入示例问题机器学习在数据挖掘中扮演什么角色操作步骤启动问答服务。在 Web 页面或命令行输入问题。观察返回结果。预期结果返回答案中不应出现“我不了解该课程内容”这类完全无信息的回复。答案内容应当与课程讲义中的相关章节匹配。如果系统做了引用展示答案后面应有参考文本块信息。判断标准回答和讲义内容语义一致不是模型随便编的。如果回答不正确优先调整两个地方一是文本切分的chunk_size过大容易引入无关内容过小可能丢失上下文二是检索返回的 top-k 值设置为 3 到 5 比较稳妥。5.3 引用溯源测试测试目的验证问答结果是否可追溯。一个合格的课程问答助手不能只给出答案还要能说明“这个答案来自哪份资料的哪个段落”。这个案例如果实现了溯源功能可以在返回结果中带上来源信息。操作步骤提问一个比较具体的问题例如“第三章讲了哪几种分类算法”。查看返回结果的引用来源。打开对应原始资料人工核对答案和原文是否一致。判断标准引用来源真实存在答案能在对应资料中找到依据。如果溯源信息混乱大概率是文本切分时没有记录原始文档的页码、章节信息需要补充这部分元数据。5.4 多轮对话测试测试目的验证助手能否在连续对话中保持上下文。操作步骤第一轮问“本课程有哪些前置知识”。第二轮追问“那第二章主要讲了什么”。第三轮继续问“和第一章有什么关系”。预期结果助手能理解“那”“继续”这类指代词能结合前文回答问题。如果多轮对话效果差常见原因是没有把对话历史传给模型每次请求都是无状态模式。可以在问答接口中支持传递历史消息数组由前端或调用方管理上下文。5.5 知识库更新测试课程资料经常更新。测试这个场景新增一份资料后重新构建向量库看新内容是否能被检索到。操作步骤把新讲义放入data/raw。重新运行构建脚本。提问一个只有新讲义里才有答案的问题。判断标准新内容能被检索并回答。这里要注意增量更新的问题。如果每次都是全量重建资料多了之后成本会比较高。进阶做法是按文档 ID 做增量写入只处理新增和修改的文件。7. 接口 API 与批量任务这个案例如果实现了服务化通常会提供一个问答接口方便其他系统调用。下面给出一套通用的接口设计模板具体参数以实际项目为准。6.1 问答接口示例import requests url http://127.0.0.1:8000/api/qa payload { question: 什么是数据挖掘, session_id: stu_001, history: [ {role: user, content: 我们课程第一章讲了什么}, {role: assistant, content: 第一章主要介绍了数据挖掘的基本概念和应用场景。} ] } response requests.post(url, jsonpayload, timeout60) print(response.status_code) print(response.json())返回结果可以参考这样的结构{ answer: 数据挖掘是从大量数据中提取有价值信息的过程。, sources: [ { filename: chapter1.pdf, page: 3, text: 数据挖掘定义... } ], cost_time_ms: 850 }answer是最终回答sources是引用来源cost_time_ms可以用于性能监控。6.2 批量问答脚本课程答疑场景经常需要批量处理学生提交的问题。可以写一个脚本循环读取问题文件逐条调用接口把结果写入输出文件。import json import time import requests API_URL http://127.0.0.1:8000/api/qa with open(questions.json, r, encodingutf-8) as f: questions json.load(f) results [] for item in questions: payload { question: item[question], session_id: item.get(session_id, batch_test) } try: resp requests.post(API_URL, jsonpayload, timeout60) data resp.json() results.append({ question: item[question], answer: data.get(answer, ), sources: data.get(sources, []), status: resp.status_code }) except Exception as e: results.append({ question: item[question], answer: , status: error, error_msg: str(e) }) time.sleep(0.5) with open(results.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2)批量任务要考虑两个工程问题限速。如果一次提交大量请求本地服务可能因为排队导致超时。建议加time.sleep或者使用信号量控制并发数。失败重试。单个问题调用失败不应该中断整个任务要把异常捕获记录下来最后统一分析失败原因。6.3 批量知识库构建如果课程资料很多可以把“加载—切分—向量化”做成批处理任务python scripts/build_kb.py \ --input data/raw \ --output data/vectorstore \ --config config.yaml \ --workers 4多进程处理可以明显加快大批量文档的构建速度。需要注意的是Embedding 接口如果走在线 API会有速率限制并发太高可能触发限流。这种情况要降并发或者切到本地 Embedding 模型。8. 资源占用与性能观察这个案例的运行负载主要集中在三个方面向量化阶段、检索阶段、大模型生成阶段。7.1 显存与内存占用如果使用在线大模型 API本地主要开销是 Embedding 模型的加载和向量检索。内存占用通常在几百 MB 到几 GB 之间具体取决于 Embedding 模型大小和向量库数据量。如果使用本地大模型显存占用就变成了关键指标。不同参数量模型的显存占用差异很大需要以实际模型版本和推理参数为准。观察方法很简单服务启动后用系统监控工具查看进程资源占用。Linux 用nvidia-smi和htopWindows 用任务管理器。启动后可以测试几个不同难度的问题观察显存占用是否稳定、问答耗时是否波动。7.2 影响性能的关键因素文本切分参数chunk_size越大每个文本块越长向量化耗时增加检索结果的相关性可能下降。检索返回数量top-k 越大给模型的上下文越长生成耗时增加。上下文拼接长度多轮对话时历史消息越长模型输入越长回答越慢。并发请求数量Web 服务默认并发能力有限大批量请求时需要开启线程池或异步处理。7.3 性能优化建议减少不必要的 Embedding 重复计算。嵌入模型加载后常驻内存不要在每次请求时重新加载。对向量库做持久化。第一次构建后直接加载持久化文件避免每次启动重新建库。控制对话历史长度。多轮对话只保留最近 3-5 轮超出部分截断。检索结果做相关性过滤。相似度低于阈值的文本块不传给模型减少噪音。本地模型推理使用量化版本可以显著降低显存占用但回答质量会有轻微下降。9. 常见问题与排查方法问题现象可能原因排查方式解决方案启动时报依赖安装失败Python 版本不匹配或依赖包冲突查看 pip 报错信息确认 Python 版本更新 Python 版本使用虚拟环境重建依赖服务启动成功但页面无法访问端口被占用或监听地址不对检查启动日志确认监听地址和端口修改配置中的端口为未占用端口或把 host 改为 0.0.0.0构建知识库时提示文件解析失败PDF 为扫描件无文字层或文件编码异常单独打开源文件确认内容可复制扫描件先做 OCRTXT 转成 UTF-8 编码问答回答“不知道”或答案完全错误检索结果不相关或知识库里没有对应内容检查知识库是否包含相关资料测试不同 chunk_size调整切分参数增大 top-k补充知识库内容回答内容与资料原文不一致出现幻觉模型没有拿到足够的上下文或 prompt 指令不够强查看检索到的文本块内容优化 prompt强制要求模型只能基于给定文本回答使用本地大模型时显存不足模型参数量超出显存容量观察 nvidia-smi 显存占用换小模型或使用量化版本降低推理精度批量问答时部分请求超时并发过高服务处理不过来查看服务日志是否有超时和排队记录降低并发增加重试机制必要时部署多个服务实例服务重启后向量库为空向量库未做持久化或路径配置错误检查向量库目录是否存在且有文件正确配置 persist_dir启动时直接加载已有向量库本地 Embedding 模型加载失败模型文件未下载完整或路径不对查看启动日志中的模型加载错误重新下载模型确认路径指向模型所在目录中文乱码文件编码不一致或终端编码问题检查原始文件编码和控制台编码设置统一使用 UTF-8 编码重新解析文件排查问题的通用思路是先看启动日志再看服务状态然后缩小范围到具体模块。如果页面打不开先看端口如果回答不对先看检索到的文本块如果批量任务失败先看异常信息。10. 最佳实践与使用建议9.1 先小后大逐步扩展第一次跑通案例时不建议一口气导入全部课程资料。先放一份 PDF 和一份 Markdown跑通全流程确认问答效果再逐步增加资料。这样排错时范围小更容易定位问题。9.2 保留一份最小可运行配置把能跑通的最简配置单独保存下来例如一份精简版 config 文件和 2 到 3 个测试文档。以后环境变化或项目改崩了可以快速回到可用状态。9.3 数据目录规范化原始资料、解析文本、向量库、测试结果分目录存放。这个案例的课程资料会持续更新目录规范了增量构建和维护会轻松很多。9.4 给 API 服务加访问控制如果问答服务部署在服务器上不要直接暴露公网端口。默认只监听 127.0.0.1需要外部访问时加一层网关和鉴权。接口层面建议增加请求频率限制防止被刷。9.5 输出要做效果复核课程资料问答助手最终面向学生或用户之前要人工抽查一批问答结果确认没有错误信息和幻觉内容。AI 生成内容不能直接作为正式教学依据特别是涉及作业要求、考试范围、成绩政策等敏感信息时一定要以原始资料为准。9.6 合规与版权提醒这个案例的问答内容来自课程资料。如果资料包含未公开的讲义、内部试题、个人隐私信息只能在授权范围内使用。发布问答服务前确认资料版权归属和公开范围涉及学生信息、用户问题时做好隐私脱敏。对外提供问答服务时建议在页面中注明“回答由 AI 生成仅供参考以官方资料为准”。11. 总结与下一步这个课程资料问答助手案例最大的价值不是代码本身而是它把 AI 编程和智能体开发落地到了一个真实教学场景里。你从中可以看到一条完整的 RAG 应用开发链路文档加载、文本切分、向量化、检索、大模型生成、服务化部署、接口封装。这套思路现在迁移到企业知识库问答、个人文档助手、智能客服等领域基本都是同一套打法。建议拿到案例后优先跑通三件事一是知识库构建流程确认课程资料能正确入库二是一个具体问题的完整问答链路确认输出质量三是批量问题测试脚本确认服务稳定性。最容易踩的坑有两个一是 PDF 解析后是空文本这是扫描件导致的需要 OCR 处理二是回答结果和讲义原文不一致这是检索参数或 prompt 设置不合理导致的先调整检索结果再考虑换模型。后续可以继续扩展的方向不少给问答助手加上对话记忆和用户身份区分功能变成多角色课程助手把向量库切换成生产级数据库支持更高并发把接口接入课程平台或微信机器人做成真正的常态化答疑服务也可以增加答案的自动评分和人工反馈机制持续提升回答质量。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进