AI 辅导老师要真正走进课堂,“答对题”只是第一步。学生在几何题里说“这个角为什么等于六十度”,AI 需要知道“这个角”指的是图像里哪一个角;学生在生物图里问“这个细胞器叫什么”,AI 必须把回答和图像中的具体位置对应起来。这种把自然语言查询与图像区域精确对齐的能力,就是 Visual Grounding,也就是视觉基础/视觉定位。
本文将围绕这一主题,从概念、原理到实战,完整拆解如何构建一个具备视觉定位能力的 AI 辅导系统。无论你是教育产品开发者、AI 初学者,还是对多模态模型感兴趣的工程师,都能从中找到可以直接落地的思路和代码。
1. 背景与核心概念
1.1 什么是 AI 辅导系统
传统在线教育中,“AI 辅导”通常只停留在自动答题和题库推荐层面。系统通过关键词匹配,把学生的问题映射到预置答案,本质上还是一个检索系统。近年来,随着大语言模型(LLM)和多模态模型的发展,AI 辅导开始向真正的“智能老师”方向演进。
一个完整的 AI 辅导系统至少需要具备以下能力:
- 理解学生提出的问题,包括文字、图片、语音等多种形式。
- 定位问题在教材、习题、图像中的具体位置。
- 基于定位结果进行推理、讲解,并给出可验证的答案。
- 支持多轮对话,能够根据学生的追问持续输出。
其中,“定位问题在图像中的具体位置”往往被忽略,却恰恰是 AI 辅导从“看起来智能”到“真正好用”的关键分水岭。如果系统不知道学生问的是哪一块内容,后面所有的讲解都可能答非所问。
1.2 Visual Grounding 是什么
Visual Grounding,中文常称为“视觉基础”或“视觉定位”,任务定义是:给定一张图像和一个自然语言描述,模型需要输出图像中与该描述对应的目标区域,通常用包围框(bounding box)表示。
举个例子,给定一张包含红色三角形和蓝色圆形的几何图片,查询文本是“红色的三角形”,Visual Grounding 模型会返回图片中红色三角形所在位置的坐标框。
这个任务与常见图像理解任务的区别在于:
| 任务 | 输入 | 输出 | 核心特点 |
|---|---|---|---|
| 图像分类 | 图像 | 类别标签 | 描述整张图 |
| 目标检测 | 图像 + 预定义类别 | 多个框 | 只能检测固定类别 |
| 图像分割 | 图像 | 像素级掩码 | 精细到像素 |
| Visual Grounding | 图像 + 任意文本 | 目标框 | 文本任意、范围开放 |
传统的目标检测模型只能检测训练集中出现过的类别,比如“人”“车”“猫”。而 Visual Grounding 的查询文本可以是描述性的自然语言,例如“图中箭头所指的角”“被虚线围住的区域”“题目中给出的已知条件”。这意味着模型具备更强的开放语义理解能力,非常适用于教育场景中千变万化的问题描述。
1.3 为什么 AI 辅导需要视觉定位
AI 辅导引入视觉定位,解决的并不是“模型能不能看到图”的问题,而是“模型能不能看懂学生在问什么”的问题。
第一个价值是精确指代。学生在对话中经常使用“这个”“那个”“左边的角”“上面的圆”等指代表达。没有视觉定位,系统就只能靠猜。有了定位能力,系统能把指代表达映射到具体图像区域,再基于该区域进行讲解。
第二个价值是减少幻觉。大语言模型在纯文本环境下很容易一本正经地编造答案。如果让模型先定位到图像中的关键区域,再把裁剪后的区域图像输入多模态模型,模型回答时就有据可依,幻觉问题会明显缓解。
第三个价值是可视化教学反馈。真正的辅导不能只给一行文字答案,最好能在原图上高亮关键区域,告诉学生“注意看这一块”。这种可解释性对教学效果至关重要。
第四个价值是支撑多轮互动。AI 老师可以追问学生:“你指的角是图中左下角的那个锐角吗?”这个过程依赖视觉定位来实现指代消解。
1.4 典型应用场景
- 数学几何题讲解:定位题目中的三角形、圆、已知边角,再结合定理讲解。
- 生物/物理图像标注:在复杂结构图中定位细胞、器官、受力物体。
- 文档和屏幕教学:定位 PDF 截图中的公式、段落、箭头标注。
- 幼儿认知教育:孩子指着图片问“这是什么”,系统定位并回答。
- 在线一对一辅学:结合学生手写圈选,实时理解学生想关注的内容。
2. 环境准备与项目结构
2.1 运行环境与版本说明
本文示例代码使用 Python 编写,核心依赖是 Hugging Face Transformers。环境版本建议如下,但需要根据你的实际项目情况调整:
- 操作系统:Windows / Linux / macOS 均可,建议 Linux 服务器或本地 IDE。
- Python:3.9 或 3.10。
- PyTorch:2.0 或更高版本,CPU 版也可运行,但 GPU 推理速度更快。
- Transformers:4.30 以上版本,新版本 API 基本兼容。
如果你使用的是云服务器或自主搭建的机器学习环境,建议使用 conda 或 venv 创建独立虚拟环境,避免依赖冲突。
2.2 创建虚拟环境并安装依赖
下面使用 venv 创建虚拟环境,并安装必要依赖。
python -m venv venv source venv/bin/activate # Windows 系统使用:venv\Scripts\activate安装 PyTorch 时,根据自己的 CUDA 环境选择对应命令。如果没有 NVIDIA GPU,安装 CPU 版本即可:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu然后安装其他依赖:
pip install transformers accelerate pillow matplotlib opencv-python为了后续方便迁移依赖,可以把依赖写入 requirements.txt:
torch>=2.0.0 torchvision>=0.15.0 transformers>=4.30.0 accelerate>=0.20.0 pillow>=9.0.0 matplotlib>=3.5.0 opencv-python>=4.5.02.3 项目目录设计
我们用一个干净的目录结构组织代码:
ai_tutor_grounding/ ├── data/ │ └── geometry_sample.jpg ├── src/ │ ├── __init__.py │ ├── visual_grounding.py │ ├── question_parser.py │ ├── tutor_agent.py │ └── utils.py ├── main.py └── requirements.txtdata/:存放测试图像。src/visual_grounding.py:实现视觉定位模块。src/question_parser.py:实现问题文本解析模块。src/tutor_agent.py:实现辅导回答生成模块。main.py:主流程入口,串联整个系统。
3. 核心原理拆解
3.1 从图文匹配到区域定位
要理解 Visual Grounding,不妨从图文匹配说起。早期的 CLIP 模型把图像和文本分别编码到同一个向量空间,计算相似度。这种方法能判断“这张图是否与这段文本相关”,但无法回答“这段文本对应图中的哪个区域”。
为了做到区域级定位,研究者提出了一系列跨模态融合方案。以文本驱动的目标检测模型 OWL-ViT 为例,流程大致如下:
- 图像被切分为多个 patch,经过视觉编码器提取特征。
- 查询文本经过文本编码器得到语义向量。
- 视觉特征和文本特征在模型内部进行跨模态交互。
- 模型输出候选目标框以及每个框与查询文本匹配的置信度。
最终,模型输出一组带置信度的坐标框。置信度越高,表示该区域越符合文本描述。这一过程本质上是把“开放词典”的文本查询融入到目标检测框架中。
3.2 基于文本查询的目标检测
在 Transformers 库中,OWL-ViT 的调用方式非常接近普通目标检测模型。你只需要准备一张图像和一组查询文本,就可以获得目标框。
核心调用代码如下:
import torch from PIL import Image from transformers import OwlViTProcessor, OwlViTForObjectDetection processor = OwlViTProcessor.from_pretrained("google/owlvit-base-patch32") model = OwlViTForObjectDetection.from_pretrained("google/owlvit-base-patch32") image = Image.open("data/geometry_sample.jpg").convert("RGB") texts = [["a triangle", "a circle", "an angle"]] inputs = processor(text=texts, images=image, return_tensors="pt") with torch.no_grad(): outputs = model(**inputs) target_sizes = torch.tensor([image.size[::-1]]) results = processor.post_process_object_detection( outputs=outputs, threshold=0.1, target_sizes=target_sizes )这里最关键的是post_process_object_detection,它会把模型输出的归一化坐标还原成原始图像尺寸。results[0]中包含:
boxes:目标框坐标,格式为[x1, y1, x2, y2]。scores:每个框的置信度。labels:命中的查询文本索引。
这个简单接口,就是我们构建 AI 辅导系统的地基。
3.3 定位结果如何用于辅导对话
有了目标框之后,下一步是把“坐标”变成“教学内容”。整体流程如下:
学生提问 → 解析出可定位的查询短语 → 视觉定位模型返回候选区域和置信度 → 裁剪目标区域图像 → 多模态大模型结合裁剪区域生成讲解 → 输出文字 + 可视化高亮我们可以把视觉定位模块看作 AI 辅导老师的“眼睛”,把大语言模型看作“大脑”。眼睛负责锁定学生提问的位置,大脑负责把当前位置的知识讲解清楚。如果没有眼睛,大脑就只能凭空发挥。
4. 完整实战:构建一个可以“指认图像”的 AI 辅导助手
接下来,我们实现一个简化但足够完整的 AI 辅导系统。它能根据学生的问题,在一张几何习题图片中定位“三角形”“圆”“角”等目标,并生成对应的辅导讲解。
4.1 准备测试图像
你可以从网络上找一张包含几何图形的教学图片,也可以自己用绘图工具生成一张。为了演示效果,图像中最好包含明显的三角形、圆形和角。
我建议准备一张类似这样的几何图:
- 一个直角三角形,直角位置清晰。
- 一个内切圆或外接圆。
- 一个标注了角度的角。
图片放到data/geometry_sample.jpg。如果没有合适图片,先用任意教学插图代替,后续只要调整查询文本即可。
4.2 实现视觉定位模块
文件路径:src/visual_grounding.py
import torch from typing import List, Dict from PIL import Image from transformers import OwlViTProcessor, OwlViTForObjectDetection class VisualGroundingModule: """基于 OWL-ViT 的视觉定位模块。""" def __init__( self, model_name: str = "google/owlvit-base-patch32", device: str = None ): self.device = device or ("cuda" if torch.cuda.is_available() else "cpu") self.processor = OwlViTProcessor.from_pretrained(model_name) self.model = OwlViTForObjectDetection.from_pretrained(model_name) self.model.to(self.device) self.model.eval() def ground( self, image_path: str, queries: List[str], threshold: float = 0.15 ) -> Dict: """ 在图像中定位查询文本对应的区域。 Args: image_path: 图像路径 queries: 查询文本列表,例如 ["a triangle", "a circle"] threshold: 置信度阈值,低于该值的预测会被过滤 Returns: {"image": PIL.Image, "boxes": [...], "scores": [...], "labels": [...]} """ image = Image.open(image_path).convert("RGB") # OWL-ViT 的文本输入需要嵌套一层列表 texts = [queries] inputs = self.processor( text=texts, images=image, return_tensors="pt" ).to(self.device) with torch.no_grad(): outputs = self.model(**inputs) target_sizes = torch.tensor([image.size[::-1]]) results = self.processor.post_process_object_detection( outputs=outputs, threshold=threshold, target_sizes=target_sizes ) boxes = results[0]["boxes"].cpu().tolist() scores = results[0]["scores"].cpu().tolist() labels = results[0]["labels"].cpu().tolist() return { "image": image, "boxes": boxes, "scores": scores, "labels": labels, "queries": queries, }模块封装好之后,调用方只需要传入图片路径和查询文本,就能拿到一组带置信度的坐标框。
4.3 实现问题解析模块
文件路径:src/question_parser.py
学生在真实提问时,很少会直接说“请定位三角形”。他们通常会问“图中这个三角形面积怎么求”。我们需要从自然语言中提取出可用于定位的查询短语。
import re from typing import List class QuestionParser: """从学生问题中提取用于视觉定位的候选短语。""" # 关键词映射表:中文关键词 → 查询短语 # 实际项目可以替换为意图识别模型或 LLM 抽取 KEYWORD_MAP = { "三角形": ["a triangle", "triangle"], "圆": ["a circle", "circle"], "角": ["an angle", "angle"], "直角三角形": ["a right triangle", "right triangle"], "直线": ["a straight line", "line"], "矩形": ["a rectangle", "rectangle"], "正方形": ["a square", "square"], } def extract_grounding_queries(self, question: str) -> List[str]: """ 从问题文本中抽取视觉定位查询短语。 示例: "这个三角形的面积怎么求?" → ["a triangle", "triangle"] """ queries = [] for keyword, phrase_list in self.KEYWORD_MAP.items(): if keyword in question: queries.extend(phrase_list) return list(set(queries))这个模块使用了最简单的关键词规则。在生产环境中,你可以用更大规模的大语言模型做信息抽取,但核心思路不变:从问题中提取出与图像区域强相关的描述短语。
4.4 实现辅导回复生成模块
文件路径:src/tutor_agent.py
拿到定位结果后,需要生成辅导回答。为了演示,这里提供两种方式:
- 方式一:本地规则生成,适合离线演示。
- 方式二:接入多模态大模型 API,适合生产环境。
from typing import Dict class TutorAgent: """根据定位结果生成辅导讲解。""" def generate_answer( self, question: str, grounding_result: Dict ) -> str: """ 基于视觉定位结果生成辅导回答。 生产环境中,这部分可以替换为: 将裁剪后的目标区域图像 + 问题文本发送给多模态大模型, 获得更自然、更有教学逻辑的讲解。 """ boxes = grounding_result["boxes"] scores = grounding_result["scores"] labels = grounding_result["labels"] queries = grounding_result["queries"] if not boxes: return "我暂时没有在图中定位到关键区域,建议把问题描述得更具体一些,例如“左边的三角形”或“红色的圆”。" answer = f"我先帮你定位到题目中的 {len(boxes)} 个关键区域,我们逐一分析:\n" for i, box in enumerate(boxes): x1, y1, x2, y2 = box score = scores[i] label_index = labels[i] label = queries[label_index] if label_index < len(queries) else "目标" answer += ( f"\n第 {i + 1} 个目标:{label},置信度 {score:.2f}。\n" f"对应区域在坐标 ({x1:.0f}, {y1:.0f}) 到 ({x2:.0f}, {y2:.0f})。\n" ) answer += ( "\n建议:几何题目先标注已知条件,再尝试寻找等角、相似三角形或特殊角。" "如果你能告诉我具体卡在哪一步,我可以进一步讲解。" ) return answer这里生成的内容偏规则化,但已经具备基本的教学交互逻辑。生产系统中,更推荐的方式是让大模型根据裁剪图像内容生成自然语言讲解,例如把指定区域裁剪出来,连同问题一起发给视觉语言模型(VLM)。
4.5 实现可视化标注模块
文件路径:src/utils.py
from PIL import Image, ImageDraw from typing import Dict def draw_grounding_result( grounding_result: Dict, output_path: str = "output_with_boxes.jpg" ) -> None: """ 在原图上绘制定位框,并保存结果。 """ image = grounding_result["image"].copy() draw = ImageDraw.Draw(image) boxes = grounding_result["boxes"] scores = grounding_result["scores"] labels = grounding_result["labels"] queries = grounding_result["queries"] for i, box in enumerate(boxes): x1, y1, x2, y2 = box label_index = labels[i] label = queries[label_index] if label_index < len(queries) else "target" draw.rectangle([x1, y1, x2, y2], outline="red", width=4) draw.text((x1, y1 - 10), f"{label}:{scores[i]:.2f}", fill="red") image.save(output_path) print(f"标注结果已保存到 {output_path}")使用 PIL 的ImageDraw可以在原图上直接绘制矩形框和文本说明。这个可视化模块的用途是让教师或学生直观看到模型锚定的区域。
4.6 集成主流程
文件路径:main.py
from src.visual_grounding import VisualGroundingModule from src.question_parser import QuestionParser from src.tutor_agent import TutorAgent from src.utils import draw_grounding_result def main(): image_path = "data/geometry_sample.jpg" question = "这个三角形的高怎么求?" # 1. 初始化各模块 grounding_module = VisualGroundingModule() question_parser = QuestionParser() tutor_agent = TutorAgent() # 2. 从问题中提取查询短语 queries = question_parser.extract_grounding_queries(question) print(f"提取到的查询短语:{queries}") if not queries: print("未从问题中提取到可定位的关键词,请尝试换一种描述方式。") return # 3. 视觉定位 grounding_result = grounding_module.ground( image_path=image_path, queries=queries, threshold=0.15 ) # 4. 生成辅导回答 answer = tutor_agent.generate_answer(question, grounding_result) print("\n===== 辅导回答 =====") print(answer) # 5. 保存可视化结果 draw_grounding_result(grounding_result) if __name__ == "__main__": main()4.7 运行与预期输出
在项目根目录下运行:
python main.py预期输出类似如下:
提取到的查询短语:['a triangle', 'triangle'] ===== 辅导回答 ===== 我先帮你定位到题目中的 2 个关键区域,我们逐一分析: 第 1 个目标:a triangle,置信度 0.32。 对应区域在坐标 (120, 80) 到 (320, 260)。 第 2 个目标:triangle,置信度 0.21。 对应区域在坐标 (118, 78) 到 (322, 262)。 建议:几何题目先标注已知条件,再尝试寻找等角、相似三角形或特殊角。同时,当前目录会生成output_with_boxes.jpg,图片中会用红色框标出模型识别出的三角形区域。虽然规则生成的回答还不够智能,但整个“问题解析 → 区域定位 → 回答生成 → 可视化反馈”的链路已经跑通。
4.8 替换为多模态大模型接口
如果希望回答更自然,可以把TutorAgent中的生成逻辑替换为多模态大模型调用。以 OpenAI 风格 API 为例,思路如下,接口细节以你实际使用的模型为准:
# 核心思路:把定位到的区域裁剪成小图,发送给多模态模型 def generate_answer_with_vlm(question, image_path, box): cropped_image = crop_box(image_path, box) # 将裁剪图片与问题一起构造为多模态模型的输入 # 返回模型的文本回答 ...这种方案的优势是模型不仅知道“这里有一个三角形”,还能真正看到三角形的边长、角度和标注信息,从而给出完整的解题步骤。
5. 常见问题与排查思路
在实现 AI 辅导视觉定位的过程中,比较容易遇到下面这些问题。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型无法加载 | Transformers 版本过低或网络原因导致权重下载失败 | 升级 transformers,提前下载模型并放入本地缓存 |
| 定位结果为空 | 置信度阈值设置过高 | 调低 threshold,例如从 0.15 调整到 0.05 |
| 中文查询效果差 | OWL-ViT 训练数据以英文为主 | 使用英文查询短语,或者用规则把中文关键词映射到英文 |
| 推理速度慢 | 模型较大且运行在 CPU | 换 GPU 推理,或使用量化版本、蒸馏模型 |
| 目标框定位不准 | 查询文本过于抽象 | 使用更具体的描述,如“红色三角形”“大的圆” |
| CUDA 显存不足 | 输入图像分辨率过大 | 限制输入图像尺寸,或使用torch.cuda.empty_cache() |
| 多轮对话中指代漂移 | 没有维护对话历史中的指代关系 | 增加指代消解模块,把“这个”“它”还原为具体名词 |
如果你遇到定位结果不稳定的情况,优先检查两点:第一,查询短语是否具体;第二,阈值设置是否合理。很多时候不是模型能力不够,而是输入的表达方式不够明确。
此外,模型权重下载也需要提前准备。建议在正式环境部署前,把模型权重下载到本地或私有集群,避免运行时频繁访问外网导致延迟。
6. 最佳实践与工程建议
6.1 查询短语构造策略
查询短语的质量直接决定定位效果。实际项目中有以下几种构造策略。
第一种是规则映射,适合领域固定、知识点有限的场景。例如数学教育中,常见关键词就几十个,可以用字典维护映射。
第二种是 LLM 抽取,适合开放领域。把学生问题交给大语言模型,让它输出若干个候选查询短语。优点是泛化能力强,缺点是增加一次模型调用延迟。
第三种是混合策略。先用规则快速判断是否能提取出查询短语,如果失败再调用大模型兜底。这种方式兼顾了速度和效果。
6.2 多轮对话中的指代消解
学生很少会在第二句话里重复完整名词,更多是说“它”“这个部分”“刚才那个角”。因此,必须把对话历史中的空间指代关系保存下来。
一种轻量做法是:每次定位成功后,把“代词 → 具体目标框”的映射记录在会话状态中。当下一轮出现“它”时,优先匹配上一轮的目标框。
另一种做法是维护一个“候选实体列表”,把学生提到过的所有对象及其坐标保存起来,新的问题先用视觉定位全局搜索,再与候选实体做语义匹配。这样即使学生换了表述方式,也能找到意图指向的位置。
6.3 结合更多多模态能力
视觉定位不是终点。实际教育场景中,经常还需要 OCR 识别文本、公式识别、手写轨迹识别、图表理解等能力。建议把视觉定位作为多模态理解链路中的一环,而不是孤立模型。
例如,在处理一张物理试卷截图时,可以先 OCR 识别题目文字,再用视觉定位定位配图中的受力对象,最后把文字和图像区域同时发给大模型,综合生成解答。整个过程本质上就是一个小型 AI Agent 工作流。
6.4 模型部署与性能优化
视觉定位模型如果直接部署在高并发服务中,成本会很高。工程上建议从三个方向优化。
一是模型量化。使用 FP16 甚至 INT8 量化,推理速度通常有显著提升。
二是级联推理。先用一个轻量级目标检测模型快速排除无关区域,再对候选区域使用更重的视觉定位模型精排。这样可以降低单次请求的计算量。
三是缓存复用。如果学生多次点击同一张图片,相同图像和查询文本的定位结果可以缓存,避免重复计算。
6.5 安全与隐私边界
教育产品往往会涉及未成年人的数据,必须格外重视隐私安全。
- 不要上传包含学生人脸、家庭环境等敏感信息的图像。
- 图片数据建议在端侧脱敏后再上传到服务端。
- 对话记录、图像数据需要明确存储期限和访问权限。
- 模型生成的回答必须经过内容安全过滤,避免出现不当引导。
同时,要建立失败回退机制。当模型置信度过低或系统判断无法回答时,主动提示“暂时无法确定,建议人工老师介入”,而不是硬生生生成一个错误答案。对教育场景来说,错误讲解比不讲解危害更大。
6.6 评测与持续优化
视觉定位模块的效果可以用 mAP(平均精度均值)和 IoU(交并比)评估。建议人工标注一批“学生问题 → 目标区域”的测试集,定期回归。
辅导回答的质量评估则更复杂,可以结合以下指标:
- 答案是否正确。
- 是否引用了图像中的具体位置。
- 学生追问后能否正确修正。
- 讲解步骤是否清晰、可理解。
建议把每次辅导过程的定位结果、学生反馈记录下来,形成数据闭环,持续用真实数据微调模型或优化 Prompt。
7. 总结与下一步
本文从一个真实的教育产品痛点切入:AI 老师必须知道学生“问的是哪里”,才能真正教得明白。围绕这个目标,我拆解了 Visual Grounding 的基本概念、技术原理,以及它与通用目标检测的区别,并给出了一套完整可运行的 AI 辅导系统示例。
示例中最核心的思考路径是:问题解析 → 视觉定位 → 区域裁剪 → 辅导回答 → 可视化反馈。哪怕你现在只实现了前两步,也已经比大部分“纯文本 AI 老师”前进了一大步。
下一步可以继续学习的内容包括:
- 开放词汇检测模型的最新进展,例如 Grounding DINO、OWLv2。
- 多模态大模型(VLM)的输入输出格式与 Prompt 设计。
- RAG(检索增强生成)与视觉定位结合,实现更精准的知识召回。
- 模型轻量化部署,把视觉定位模型落地到移动端或 Web 端。
如果你正在构建 AI 教育产品,建议先从一个小场景做起,例如“几何题目定位 + 讲解”或“生物图像定位 + 问答”,把链路跑通后再逐步扩展。
如果这篇文章对你有帮助,可以收藏备用,也欢迎在评论区聊聊你在 AI 辅导、多模态模型落地过程中遇到的实际问题。