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

开源之夏|李振兴:基于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的开发者说呢?
    李振兴:不要害怕项目“看起来很大”,把它拆小之后,一步步啃下来,你会发现自己能做的远比想象中多。参与开源不一定非要从“写算子”“写底层框架”开始,像本项目这样围绕文档、工具链和开发者体验做改进,同样非常有价值。多和导师、社区沟通,项目不是一个人的战斗,很多坑前人都踩过,只要愿意问,就能少走很多弯路。最后,早点把你的想法写下来、画出来、开源出来,只有走出第一步,才会有后面一连串意想不到的机会。