开源之夏|李振兴:基于RAG的MindSpore代码助手与智能问答系统实践
开源之夏|李振兴:基于RAG的MindSpore代码助手与智能问答系统实践

01项目介绍
- 项目名称:基于 RAG 的 MindSpore 代码助手与智能问答系统
- 项目描述:面向MindSpore用户与开发者,构建一套基于检索增强生成(RAG)的智能问答系统与代码助手,可自动利用MindSpore官方文档、API参考、实战教程等内容,为用户在安装部署、模型调参、算子使用、性能调优等场景中提供高质量、可执行的解答,显著降低使用门槛,提升开发效率。
- 项目源码链接:
https://github.com/mindspore-courses/competition/tree/master/summer-ospp/MindSporeCodeAssistant
02项目实现思路与核心贡献
1、系统架构与技术选型

整体思路:采用“文档 + RAG + 多前端”三层架构,底层基于vLLM-Ascend部署大语言模型,结合Dify Workflow实现可编排、可观测的RAG流程;上层支持Dify原生前端与OpenWebUI,兼顾对话体验与内网灵活接入。
核心架构分层:
1)数据与知识层:
- 收集 MindSpore 官方文档、API 参考、教程及迁移指南等多源文本。
- 设计统一的文档清洗与切分规则(结合标题层级、代码块、表格和 FAQ 模块),保证检索粒度和语义完整性。
- 通过 Dify / 向量引擎建立“多视角索引”(按模块、版本、任务类型等)。
2)RAG 能力层:
- 使用 vLLM-Ascend 部署 Qwen3-30B-A3B、Qwen3-8B 等模型,分别承担“高质量解答”和“高并发快速响应”的职责。
- 在 Dify 中编排从“问题重写 → 多路检索 → 结果过滤与重排 → 答案生成与格式化”的端到端流程,增强复杂查询下的鲁棒性。
3)前端与集成层:
- 通过 Dify Workflow 提供可视化配置与调用接口,方便维护者调参与排错。
- 编写 OpenWebUI Pipeline 脚本,允许用户在 OpenWebUI 内像调用普通模型一样,直接调用 Dify 中的 MindSpore 助手应用。
关键技术栈:
- 大模型推理:vllm-ascend + Qwen3 系列模型,充分利用 Ascend NPU 的算力优势。
- 应用编排:Dify Workflow 作为统一的应用层编排与观测平台。
- 对话前端:Dify 内置前端 + OpenWebUI + REST API,满足不同场景接入。
- 容器化部署:通过 Docker Compose 管理 vLLM 服务,方便在 ARM64/Ascend 环境下快速启动与扩缩容。
2、实现路径与关键步骤
步骤一:环境搭建与文档分析
- 完成 Ascend 环境准备,确认 NPU 驱动、Ascend Toolkit、容器运行时等组件工作正常。
- 研读 MindSpore 官方文档结构(教学教程、API、安装指南、迁移指南等),梳理出对“新手最友好”和“开发者最刚需”的文档区域。
- 熟悉 Dify 和 OpenWebUI 的插件/Workflow/Pipeline 机制,明确“谁负责检索”和“谁负责生成”的职责划分。
步骤二:知识库构建与索引管线设计
分析 MindSpore 文档的结构特点:
- 单页冗长但内部层次分明,标题层级清晰;
- 大量代码块、参数表格、FAQ 式问答混杂其中;
- 不同版本/后端(Ascend/GPU/CPU)存在参数差异和适配细节。
设计 Offline Indexing Pipeline:
- 文本清洗:去掉无意义导航、页脚、重复菜单等噪声,仅保留正文与关键代码片段。
- 结构化切分:按章节标题、二级小节和代码块边界进行分段;对 FAQ 进行“问-答”级别切分。
- 向量化与元数据标注:对每段内容生成向量,并附带模块名(如 mindspore.nn)、适用场景(训练/推理/部署)、版本号等元数据。
- 索引更新策略:支持增量更新,便于后续在 MindSpore 文档更新时快速重建部分索引。
步骤三:RAG 工作流实现
在 Dify 中实现“检索增强生成”的完整 Workflow:
1)问题理解与改写:
针对用户的口语化问题(例如“为啥训练突然 OOM 了”“动态图能不能用这个算子”),使用系统 LLM 做一次语义标准化与补全,生成适合检索的 Query。
2)多路检索:
- 对不同知识库(官方 API、教程、FAQ、迁移指南)进行并行检索,获取 N 条候选结果。
- 依据相似度、发布时间、版本匹配度等维度进行综合打分与过滤。
3)上下文拼装与提示词工程:
将检索出的段落以“带来源引用”的方式嵌入到 Prompt 中,明确要求模型:
- 优先基于提供上下文回答;
- 输出中保留关键 API 名和代码示例;
- 必须标注对应文档章节,方便用户回溯原文。
4)答案生成与结构化输出:
- 统一答案格式:包括“问题分析 → 解决思路 → 步骤/代码示例 → 可能的坑与注意事项”。
- 支持错误日志场景下,从 Traceback 中自动抽取关键错误类型与堆栈信息。
步骤四: 推理服务部署与调优
1)通过 vllm/docker-compose.yaml 部署两个推理服务:
- Qwen3-30B-A3B:作为高质量、复杂问题的主力模型,采用 4 卡并行,针对长上下文和复杂推理进行优化。
- Qwen3-8B:作为轻量级高并发模型,用于简单问答、编排节点内中间推理,以及在 OpenWebUI 中提供平滑体验。
2)优化 Ascend 环境下的 vLLM 配置:
- 设置 ASCEND_VISIBLE_DEVICES、gpu-memory-utilization 等参数,权衡并发数与单轮响应延迟。
- 打开 ascend_scheduler_config 的分块预填充(chunked prefill),提升长上下文场景下的吞吐能力。
3)为 Dify 和 OpenWebUI 提供统一的推理服务地址和模型别名,简化运维和使用成本。
步骤五:OpenWebUI Pipeline 和 Dify Workflow 集成
1)在 openwebui-pipeline 目录中编写 Pipeline 脚本:
- 通过环境变量 DIFY_API_KEY、DIFY_BASE_URL、DIFY_APP_ID 等完成对 Dify 应用的鉴权与路由。
- 对用户在 OpenWebUI 中输入的问题进行包装,按 Dify API 协议发送请求并返回结果。
- 在 Pipeline 层面处理常见错误(例如 401 未授权、网络超时等),给出明确的错误提示与排查建议。
2)配套编写使用说明(README):
- 指导用户在 OpenWebUI 中导入 Pipeline、配置环境变量以及选择对应的 Dify 应用。
- 说明典型使用场景:如在 OpenWebUI 中一键调用“MindSpore 知识问答”应用,获取带引用的官方解答。
3挑战与突破:遇到的问题及解决方案
问题:MindSpore文档体量大、结构多样,直接分块检索易导致信息缺失或答非所问。
解决方案:
1)引入“结构化切分 + 语义补偿”的混合策略:
- 先按照文档的标题结构做粗粒度切分,再在小节内根据自然段与代码块边界做细粒度切分;
- 检索时允许从中心片段向前/向后扩展若干段,保证语义连续性。
2)针对 FAQ 和错误排查文档,单独按照“问-答”对来构建索引,以提高解决问题类查询的命中率。
3)最终 RAG 的答案质量在多轮自测中有明显提升,特别是在“为什么会报这个错”“这个算子适合什么场景”这类问题上,能够给出带上下文的完整解释。
问题:Dify与vLLM在ARM64架构与Ascend NPU环境中存在镜像兼容、驱动匹配等挑战。
解决方案:
1)对 Dify 侧:
- 按组件拆分镜像来源,优先选择已经提供 ARM64 版本的基础镜像;
- 对部分依赖进行预编译和缓存;
- 在迁移文档中详细记录各服务(Web、Worker、向量数据库)的端口、环境变量和数据挂载策略,便于一键复现。
2)对 vLLM-Ascend 侧:
- 采用官方提供的 quay.nju.edu.cn/ascend/vllm-ascend 镜像,结合 ASCEND_VISIBLE_DEVICES、PYTORCH_NPU_ALLOC_CONF 等环境变量进行调优;
- 在 docker-compose 中显式声明 Ascend 相关设备与驱动库的挂载路径;
- 根据模型大小调整 tensor-parallel-size 和最大并发参数,在保证稳定性的前提下尽可能提高吞吐。
3)最终在目标 ARM64 服务器上稳定跑通 Dify + vLLM-Ascend + OpenWebUI 的一体化方案,并形成可复用的迁移指南文档。
问题:Dify前端与OpenWebUI在调用方式、超时处理等方面存在差异,调试困难。
解决方案:
1)将业务逻辑尽可能统一收敛在 Dify Workflow 中:
- 所有与 MindSpore 相关的检索与推理都在 Workflow 内完成;
- OpenWebUI 通过 Pipeline 仅负责将用户问题转发给 Dify,并展示结果。
2)在 Pipeline 层面增加统一的错误封装与提示:
- 对常见 HTTP 状态码(401/404/500 等)给出人类可读的排查建议;
- 对 Dify 返回的异常信息做适度裁剪,避免泄露敏感配置但保留关键信息。
3)通过这一调整,前端行为高度一致,问题定位也集中到 Dify 工作流和 vLLM-Ascend 服务两处,大大降低了调试和运维复杂度。
04 开发者说:个人成长与开源感悟
- 你选择昇思 MindSpore 的机缘是什么?
李振兴:在选题阶段,我刻意寻找既贴近真实生产场景、又能沉淀通用方案的项目。MindSpore 社区的 RAG 助手项目正好同时满足“工程实战”和“社区价值”两点。在撰写申请书时,我重点强调了自己在文档结构化、RAG 流程设计和容器化部署方面能提供的价值,并给出了一个简化版的技术方案草图。 - 此次开发工作与你以前的项目开发经历有何不可异同?
李振兴:以前我更多做的是“模型侧”的工作,比如复现论文、调参做实验。这次项目更偏“系统与工程”,需要同时考虑部署环境、运维成本、用户体验和文档沉淀。以往评价标准多是准确率、F1 等指标,而这次要面对真实用户的反馈:答得对不对、用得顺不顺、出问题时能不能快速排查。这也让我第一次完整经历了从需求分析、架构设计到实现、部署、文档、交付的全流程,对开源项目的生命周期有了更完整的理解。 - 通过这个项目任务,你对开源有了什么更深刻的理解吗?
李振兴:开源不仅是“把代码放到 GitHub 上”,更重要的是让别人能看懂、能拉起、敢用、愿意贡献。我在本项目里花了大量时间写 README、迁移教程和使用说明,甚至比写代码还久。实践证明,这些文档在降低他人使用门槛、让项目真正“活起来”方面非常关键。同时,我也体会到“可组合”的重要性:项目不是孤立存在的,而是要和 Dify、OpenWebUI、vLLM、Ascend 等多个生态拼起来。只要接口和文档够清晰,后续社区成员就可以在此基础上叠加更多能力。 - 作为学生参与开源项目,你认为最大的挑战是什么?又是如何克服的?
李振兴:最大的挑战是“不确定性”和“沟通成本”——很多问题没有标准答案,需要在和导师、社区以及实际环境的反复沟通中不断调整方案。我的做法是:尽量把每个阶段的目标拆分成可验证的小里程碑;主动输出中间成果,比如设计文档、架构图、测试记录,用文字把自己的思路说清楚;对于不确定的地方,先给出两到三个备选方案,并说明利弊,让讨论更聚焦。 - 作为过来人,有没有什么话****想对过去的自己/学弟学妹/刚加入昇思MindSpore的开发者说呢?
李振兴:不要害怕项目“看起来很大”,把它拆小之后,一步步啃下来,你会发现自己能做的远比想象中多。参与开源不一定非要从“写算子”“写底层框架”开始,像本项目这样围绕文档、工具链和开发者体验做改进,同样非常有价值。多和导师、社区沟通,项目不是一个人的战斗,很多坑前人都踩过,只要愿意问,就能少走很多弯路。最后,早点把你的想法写下来、画出来、开源出来,只有走出第一步,才会有后面一连串意想不到的机会。