全部产品
Search
文档中心

向量检索服务 Milvus 版:通过阿里云Milvus知识库搭建教育题库问答应用

更新时间:Aug 27, 2026

阿里云 Milvus 知识库可以把教材、教案、题目与标准答案建成可检索的题库助手:学生用自然语言提问即可拿到讲解与原文依据,也可以上传题目图片,从题库中找出相似题并结合教材讲解。

方案说明

整体链路与通过阿里云Milvus知识库搭建智能客服问答应用完全一致:控制台定义标签 → 按标签批量导入资料 → 发布版本 → SDK 检索(可按标签过滤、可附带图片)→ 大模型生成带来源标注的回答 → Flask 提供问答页面。工程代码(kb_client.py、upload.py、app.py、templates/index.html、start.sh)请直接复用该文,本文只说明教育场景需要改动的部分:学科与知识点标签、图片资料的处理方式、图片查询的能力边界、以及公式展示。

建议第一版只选择一个年级、一个学科的 5~20 篇资料,验证后再扩大范围。整体耗时约 25~40 分钟,其中文档解析耗时取决于资料数量与大小。

前提条件

  • 已创建 Milvus 知识库并记录知识库 ID(形如 kd-803ae9b10cc31)。

  • 创建一个全模态知识库。当前控制台创建知识库时固定使用全模态(ALL_MODAL)类型,页面上没有其他选项,因此无需额外判断;该属性创建后不可修改,可在知识库详情页的基本信息中查看数据类型。需要注意的是,结构化类型的知识库只接受 xlsx、xls、csv、jsonl、faq 五种格式,上传图片会直接返回参数错误,因此题库这类含图资料必须使用全模态知识库。

  • 已使用主账号创建 RAM 用户、勾选使用永久 AccessKey 访问,并授予系统策略 AliyunMilvusFullAccess。

  • 已准备支持 OpenAI chat/completions 协议的大模型地址与 API Key。

  • 本地已安装 Python 3.8 或以上版本,并已按上文教程建好工程目录。

步骤一:定义年级与知识点标签

在知识库详情页的基本信息下方单击标签 > 管理,添加以下四个标签(类型均为 string):

标签名

说明

示例值

grade

年级

八年级

subject

学科

数学、物理

knowledgePoint

知识点

二次函数、勾股定理

questionType

资料类型

教材、练习题、标准答案

标签值支持中文,可直接使用年级、学科与知识点的中文名称。

重要

标签管理对话框是整体保存的。对话框打开后标签列表为异步加载,请等到已有标签全部显示出来,再添加新标签并单击完成;否则可能以"空列表 + 新标签"整体覆盖,导致已有标签定义被清除。

步骤二:准备资料与导入清单

  1. 把资料放进 documents/ 目录,支持 PDF、DOCX、Markdown、TXT 与图片。建议教材、题目、标准答案成套上传:讲解时模型会同时引用教材中的方法、题目原文与答案中的评分要点,回答完整度明显更高。

  2. 创建 documents.jsonl,为每篇资料标注年级、学科、知识点与资料类型。

    {"path": "documents/math-grade8-textbook.pdf", "metadata": {"grade": "八年级", "subject": "数学", "knowledgePoint": "二次函数", "questionType": "教材"}}
    {"path": "documents/math-quadratic-problem.png", "metadata": {"grade": "八年级", "subject": "数学", "knowledgePoint": "二次函数", "questionType": "练习题"}}
    {"path": "documents/math-quadratic-answers.docx", "metadata": {"grade": "八年级", "subject": "数学", "knowledgePoint": "二次函数", "questionType": "标准答案"}}
    {"path": "documents/math-pythagorean-exercise.docx", "metadata": {"grade": "八年级", "subject": "数学", "knowledgePoint": "勾股定理", "questionType": "练习题"}}
  3. 关于图片资料,需要了解其入库方式:图片会先经过文字识别(OCR)转成文本,再按文本切片建立索引。因此:

    • 图中文字能否被识别,决定这张图能否被检索到。纯图形(没有文字的几何图、函数图象)几乎无法被命中,不适合作为独立资料上传,建议与含文字的题干放在同一张图或同一篇文档中。

    • 题目图片应保持清晰、字号足够、尽量使用印刷体。识别结果可能出现偏差(例如把顿号识别成其他符号、把变量 x 识别成乘号 ×),数学符号尤其容易受影响。

    • 上传后建议到数据管理页单击查看切片,确认识别出的文本与图中内容一致,再发布版本。

  4. 题目与解析多为短条目,可在知识库详情页的处理策略中单击创建策略调整切片粒度。最大分段长度的单位是字符(默认 512),建议设置为 580~770 字符(约相当于 384~512 tokens),尽量让"题干 + 解析"保持在同一个切片内。

步骤三:配置检索参数与提示词

在 config.json 中按教育场景调整 retrieval 与 scenario。

{
  "retrieval": {
    "page_size": 8,
    "candidate_count": 64,
    "min_score": 0.2,
    "semantic_weight": 0.75,
    "enable_query_expansion": true,
    "rerank_model_name": "qwen3-rerank",
    "tag_filter": {
      "relation": "and",
      "conditions": [
        {"field": "subject", "op": "=", "value": "数学"}
      ]
    }
  },
  "scenario": {
    "title": "教育题库检索与讲解",
    "system_prompt": "你是教学助理。只依据检索到的教材、题目和标准答案讲解;先给思路,再给步骤,最后给答案,并标注[来源N];公式请使用纯文本书写,不要使用 LaTeX 语法;若检索到的题目与用户描述不一致,必须明确指出差异,不要直接套用题库中的答案;资料不足时不要猜测标准答案。",
    "image_enabled": true,
    "sample_questions": [
      "二次函数顶点式如何求最大值?",
      "找一道使用勾股定理的例题并讲解",
      "这道题考查了哪些知识点?"
    ]
  }
}

参数说明:

  • semantic_weight=0.75 并启用 qwen3-rerank:学生提问多为自然语言题意描述,语义权重更高有利于相似题匹配。

    需注意重排分数与向量分数不是同一量纲:最终分数的算法是 score ≈ (1-semantic_weight) × keywordScore + semantic_weight × semanticScore(另可能叠加 rank feature),未启用重排时 semanticScore 是向量相似度,启用重排后它变成重排模型分数,而 min_score 始终在这个最终分数上过滤。因此实测同一问题在启用重排后返回条数由 5 条降为 4 条,是阈值与新量纲共同作用的结果,并不说明重排让召回变差。

    没有跨语料通用的推荐组合:建议先把 min_score 设为 0 取回一批结果并人工标注相关性,再按召回与误召回的分布选阈值;每次切换重排模型、开关重排或调整 semantic_weight 后都要重新校准。

  • tag_filter 固定 subject:可有效防止跨学科误召回。实测在 subject=数学 过滤下提问物理知识点,返回 0 条,模型会按提示词回答"资料不足"。

  • op 实际只有 =、in、not in 三个运算符生效。写成 eq、==、equal、like 等别名会返回 400 Unsupported tag filter operator,导致每次提问都失败;而 ≠、>、<、≥、≤、empty、not empty、start with、end with 虽然出现在该报错列出的 "Supported operators" 清单中,实测条件会被静默忽略、返回未经过滤的全部数据。

    其中 contains、not contains 只是 in/not in 的别名,并不是字符串包含,按字符串片段传值只会返回 0 条。

    需要按区间筛选时请用 in 枚举取值,需要判断标签为空时请用 = "";配置后务必与不加过滤的结果对比总条数,确认过滤生效。

  • system_prompt 中建议明确"公式使用纯文本":教学类提示词容易让模型输出 LaTeX,而示例页面用 <pre> 纯文本展示,公式不会渲染,会显示为原始的美元符号与反斜杠。若希望保留 LaTeX,请在页面中引入 KaTeX 或 MathJax。

步骤四:图片查询的用法与能力边界

app.py 的 /api/ask 接受可选的 image_url 参数,并透传给 SearchKnowledgeBase 的 image 字段:

curl -sS http://127.0.0.1:7860/api/ask \
  -H 'Content-Type: application/json' \
  -d '{"question":"这道题考查了哪些知识点?","image_url":"https://<可公网访问的图片地址>"}'

图片对指代不明的提问帮助最大。实测同一个问题「这道题考查了哪些知识点?」:不带图片时命中的是勾股定理练习(相关度 0.431,并不是想问的题);带上二次函数题目图片后,命中的是题库中的二次函数题目(0.583),可见图片为检索提供了关键语义。

重要

图片只参与检索,不会被送给大模型。 系统的行为是"根据图片在题库中找出最相似的题目,然后依据检索到的资料讲解",不是"识别并解答图片中的题目"。若上传的是一道题库中不存在的新题,系统会拿最相似的库内题目作答,答案可能与图中题目不同且不易察觉。例如上传 y=-(x-1)²+4(最大值为 4)时,若题库中存在 y=-2(x-3)²+5,回答可能给出最大值 5。 因此建议:在页面上提示"图片用于查找题库中的相似题";在提示词中要求模型指出检索结果与用户描述的差异;因此这项能力应当被称为「图片辅助检索」或「以图搜题」,不能对外表述为「拍照解题」。若确实需要解答图中的新题,必须由应用层把原图另外传给支持多模态输入的大模型,并要求它同时核对检索到的资料,而不是只依赖知识库检索。

图片的识别能力有以下边界,准备题库素材前需要了解:

  • 格式:建议只使用 JPG、JPEG、PNG、GIF。底层文件识别可能还接受 WebP、TIFF 等格式,但没有统一的对外约定,不建议依赖。

  • 大小:接口没有单独的图片字节数或像素硬上限,但实际会受上传网关、图像解码、内存以及图文转换模型服务的共同限制,超大图仍可能失败。

  • 识别准确率:手写体、数学公式、几何图形、坐标系都没有承诺的准确率指标。纯图形可能由图文转换生成一段描述,但不保证能被检索命中。本文实测中,x 被识别成 ×、顿号被识别成「丶」,数学符号尤其需要人工抽查。

  • 没有识别质量阈值:只要图片能被解码且流程未报错,文档状态就是处理完成,即使识别出的文本很少或有错误;只有解码失败或所需模型调用报错才会显示处理失败。因此上传后必须到数据管理页抽查切片文本,不能只看状态。

关于图片地址,image_url 必须是可公网访问的地址,服务端会校验:

传入内容

服务端返回

内网或本机地址(如 127.0.0.1)

400 URL resolves to a non-public or blocked address

非图片资源的链接

400 image_query URL must point to an image.

无法解析的域名

400 Could not resolve hostname

留空

退化为普通文字检索(正常行为)

最后是回显原题图的问题。检索结果里有一个 images 字段,用于返回切片关联的图片(服务端会为已持久化的图片生成短期有效的签名地址)。该字段本身是已实现的能力,并非预留的空字段;如果命中了图片文档但它仍然返回空,说明这批资料在解析切片阶段没有把图片 ID 持久化到对应切片,或者签名关联没有建立,属于需要按具体文档排查的链路问题,没有任何请求参数可以开启它。因此不要把「一直为空」当作产品设计,也不需要为此长期自行维护一份「文件名 → 公网图片地址」的映射表;在它为空期间,页面可以先降级展示识别出的题目文本。

步骤五:上传、发布与验证

  1. 上传资料(MetaFields 对整批生效,脚本会先按标签分组再分批提交)。

    python upload.py --manifest documents.jsonl
  2. 到控制台数据管理页确认资料状态为处理完成,并对图片资料单击查看切片核对识别文本。

  3. 在版本管理页单击发布版本,完成三步向导后确认新版本状态为已发布。

    重要

    同时最多只能存在 3 个已发布版本。达到上限后发布版本按钮会置灰,而页面仍会显示"当前有 N 条待发布变更",需要先在版本记录中删除不再需要的旧版本。版本删除不可恢复。题库通常每学期或每单元都会补充资料,建议只保留"当前版本 + 最近一个历史版本"。

  4. 启动服务并验证。

    python app.py

    按以下四条验收:

    • 页面能正常打开(教育场景会额外显示题目图片 URL 输入框),提交问题后同时返回答案与检索来源。

    • 回答中的 [来源N] 能在下方来源区找到对应的资料切片。

    • 提问题库未覆盖的内容时,回答明确说明资料不足,而不是补写答案。

    • 补充资料并重新发布版本后,页面能检索到新内容。

建议再补一条针对语义召回的验证:用只出现在资料内容里、不出现在文件名中的信息提问(例如题目编号),确认能命中对应资料。这条同样适用于检查图片是否被正确识别入库。

教育场景注意事项

  • 教材、题目、答案成套上传,并用 questionType 区分,便于按需过滤(例如只给学生检索"练习题",给教师检索"标准答案")。

  • 按学科建立独立入口:tag_filter 固定 subject 后,该入口只能回答该学科的问题,示例问题也应保持同一学科,否则学生提问其他学科只会得到"资料不足"。

  • 答案类资料建议单独控制访问:若不希望学生直接拿到标准答案,可在学生入口用 questionType not in ["标准答案"] 之类的条件过滤。

  • 检索结果的 images 字段当前取不到图片地址,页面展示的是识别后的文本。该字段本身是已实现的能力,取不到值属于解析链路未把图片关联到切片,不需要为此长期自行维护「文件名 → 图片地址」的映射表:短期内页面可先降级展示识别文本,需要回显原题图时再按 documentId 关联导入清单临时处理。

  • 关键结论建议保留人工核对,并提示学生以正式教材与教师讲解为准。

常见问题

现象

原因与处理

提问返回 500,日志显示 400 Unsupported tag filter operator

op 使用了 eq、==、like 等别名,改用 =、in、not in。

加了标签过滤但结果条数与不加过滤时完全一样

使用了不生效的运算符(如 >、≥、≠、empty)。只有 =、in、not in 会生效。

图片资料上传后搜不到

依次确认:知识库数据类型是否支持图片;数据状态是否为处理完成;查看切片中识别出的文本是否为空或与图中不符(纯图形、字号过小、手写体都可能导致识别失败)。

上传图片提问,回答的却是另一道题

预期行为。图片只用于检索相似题,模型讲解的是检索到的题目,详见步骤四。

提问返回 400 URL resolves to a non-public or blocked address

image_url 指向内网或本机地址,需改为可公网访问的图片地址。

页面上公式显示成 $y = a(x-h)^2 + k$

模型输出了 LaTeX 而页面按纯文本展示。在提示词中要求使用纯文本公式,或在页面引入公式渲染库。

启用重排后结果反而变少

重排分数与向量分数量纲不同,与 min_score 叠加会过滤更多结果。可先降低 min_score 或关闭重排对比效果。

按标签过滤后总是 0 条

标签名拼写与写入时不一致(接口不会报错,只返回 0 条)。在知识库详情页 → 标签 → 管理中核对。

上传返回 400 No OSS document can be registered.

整批文件都因同名被去重。修改文件名或先在控制台删除旧数据。

检索返回 404 Knowledge base version ... does not exist

尚未发布版本,或指定的版本号不存在。