第 2 课 拍题讲解:拍下一道题,AI 先思考再一步步讲 | 大模型多模态专题

返回专题

做完你会得到什么

一个「拍题讲解」App:拍下一道作业题,AI 先想十几秒,再用 1. 2. 3. 一步步讲;打开开关能看到它是怎么想的;没听懂就点「这步没看懂」,想练习就点「出道类似题」。

拍题讲解界面预览

图为执行最终 .aia 里的真实积木生成的布局预览,不是真机截图;AI 的回答与照片、生成的图片都是示意。

难度 用时 前置 用到的模型
★★ 40 分钟 第 1 课 拍照识物 DeepSeek(deepseek-flash + 思考模式)

下载本课 .aia(HomeworkTutor.aia)

和第 1 课比,这一课新在哪

新东西 做什么用
ThinkingEnabled 思考模式 模型先推理再作答。数学、物理这类要算的题,开了明显更准
GotReasoning 事件 思考过程单独从这里送来,和回答(GotStream)完全分开
开关 「只讲思路」切换两套提示词;「显示思考过程」只控制看不看得见
固定话术的追问按钮 把常用追问做成按钮,学生不用自己组织语言

API Key 卡片、拍照选图、压缩、防重复点击、出错提示的做法与第 1 课一样,这里不再重复,下载的 .aia 里都有。

界面组件

在第 1 课的基础上:

组件 命名 关键属性 / 作用
开关 开关_只讲思路 文字:只讲思路,不直接给答案;已打开 默认为真
开关 开关_显示思考 文字:显示 AI 的思考过程
垂直布局 垂直布局_思考 浅灰底,默认不可见,里面放 标签_思考
标签 标签_思考、标签_讲解 思考用 12 号灰字,讲解用 15 号正文
按钮 按钮_没看懂、按钮_出类似题、按钮_追问  

分步搭

第 1 步:打开思考模式

两行就够。ReasoningEffort 有 high(默认,普通题目)和 max(竞赛题、长推理)两档,max 更慢、更费 token。

when Screen1.Initialize() {
  组件美化1.SetAsCard(垂直布局_密钥)
  组件美化1.SetAsCard(垂直布局_拍题)
  组件美化1.SetAsCard(垂直布局_讲解)
  组件美化1.SetAsCard(垂直布局_追问)
  // 数学题开思考模式:先推理再作答,准确率明显更高
  DeepSeek1.ThinkingEnabled = true
  DeepSeek1.ReasoningEffort = "high"
  密码输入框_密钥.Text = 微数据库1.GetValue("deepseekKey", "")
  使用密钥(密码输入框_密钥.Text)
}

只有 DeepSeek 组件有 ThinkingEnabled。千问、Kimi、豆包的组件不暴露这个开关,拓展也不会给它们发思考参数。

第 2 步:两套提示词,按开关二选一

提示词写得越具体,讲解越像老师。两条经验:

  • 规定格式:「每步一行,用 1. 2. 3. 编号」,手机上才好读。
  • 不要 Markdown 和 LaTeX:模型默认爱用 **加粗** 和 \frac{1}{2},标签不会渲染,满屏符号。让它把公式写成 x^2、√、× 这样的普通字符。
global 正在回答 = false
global 有题 = false

function 讲题提示词(只讲思路) {
  return choose(只讲思路, "你是耐心的家教。看图里的题目:先用一句话说出题型和考的知识点;再分步骤讲解题思路,每步一行,用 1. 2. 3. 编号;不要给出最终答案,最后用一句话提示学生自己算出结果。只用纯文字,不要用 Markdown 和 LaTeX,公式写成 x^2、√、× 这样的普通字符。", "你是耐心的家教。看图里的题目:先用一句话说出题型和考的知识点;再分步骤写出完整解题过程,每步一行,用 1. 2. 3. 编号;最后单独一行写「答案:」和结果。只用纯文字,不要用 Markdown 和 LaTeX,公式写成 x^2、√、× 这样的普通字符。")
}

procedure 讲题(图片) {
  if 正在回答 {
    底部提示条1.Show("上一题还没讲完,稍等一下")
  } else if DeepSeek1.APIKey == "" {
    底部提示条1.Show("先在上面填好 API Key 并点保存")
  } else {
    // 题目照片压到最长边 1600:字要看得清,比识物多留一些细节
    var 小图 = 图片处理1.Compress(图片, 1600, 85)
    if 小图 == "" {
      底部提示条1.Show("这张图片处理不了,换一张试试")
    } else {
      图像_题目.Picture = 小图
      有题 = true
      DeepSeek1.StartNewChat()
      开始回答("正在思考……")
      DeepSeek1.ChatWithImage(讲题提示词(开关_只讲思路.On), 小图)
    }
  }
}

题目照片压到 1600(第 1 课是 1024):识物看轮廓就够,读题要看清每个数字和符号。

照相机的「拍摄完成」和图像选择器的「选择完成」都调用 讲题,写法与第 1 课相同。

第 3 步:思考与讲解分开显示

思考模式下,一次回答分两段送来:

  1. 先是一串 GotReasoning(part, 假)——模型在「想」;
  2. 想完了来一次 GotReasoning("", 真);
  3. 然后才是 GotStream(part, 假)……最后 GotStream("", 真)。

所以把两条通道接到两个标签上就行,互不干扰。想隐藏思考过程,不用改任何属性:不连接 GotReasoning 就不显示;这里为了能随时打开,内容照收,只用开关控制布局可不可见。

when 开关_显示思考.Changed() {
  垂直布局_思考.Visible = 开关_显示思考.On
}

when DeepSeek1.GotReasoning(part, finished) {
  标签_思考.Text = join(标签_思考.Text, part)
  if finished {
    标签_状态.Text = "想好了,正在讲解……"
  }
}

when DeepSeek1.GotStream(part, finished) {
  标签_讲解.Text = join(标签_讲解.Text, part)
  if finished {
    结束回答()
    标签_状态.Text = "讲完了。哪步没懂就接着问。"
  }
}

中途验证:拍一道一元一次方程。状态行先是「正在思考……」,十来秒后变成「想好了,正在讲解……」,讲解一行行出来;打开「显示思考过程」,灰色区域里是它的草稿。

第 4 步:常用追问做成按钮

when 按钮_没看懂.Click() {
  追问("上面讲的我没看懂,请换一种更简单的说法,最好举个生活里的例子,再讲一遍。")
}

when 按钮_出类似题.Click() {
  追问("按同样的知识点出一道类似的题考考我,难度差不多。先只给题目,不要给答案和提示。")
}

when 按钮_追问.Click() {
  var 问题 = trim(文本输入框_追问.Text)
  if 问题 == "" {
    底部提示条1.Show("先写下想问的话")
  } else {
    文本输入框_追问.Text = ""
    追问(问题)
  }
}

procedure 追问(问题) {
  if not 有题 {
    底部提示条1.Show("先拍一道题")
  } else if 正在回答 {
    底部提示条1.Show("还在讲,稍等一下")
  } else {
    开始回答("正在思考……")
    DeepSeek1.Chat(问题)
  }
}

中途验证:讲完后点「出道类似题」,得到一道新题且没有答案;把自己的答案写进追问框点「问」,它会批改。

第 5 步:开始与结束(按钮状态集中管理)

按钮多了以后,把「变灰」和「恢复」各写成一个过程,所有入口都调用它们,就不会漏掉哪一个。

procedure 开始回答(状态) {
  正在回答 = true
  标签_思考.Text = ""
  标签_讲解.Text = ""
  标签_状态.Text = 状态
  按钮_拍照.Enabled = false
  图像选择器_相册.Enabled = false
  按钮_没看懂.Enabled = false
  按钮_出类似题.Enabled = false
  按钮_追问.Enabled = false
}

procedure 结束回答() {
  正在回答 = false
  按钮_拍照.Enabled = true
  图像选择器_相册.Enabled = true
  按钮_没看懂.Enabled = true
  按钮_出类似题.Enabled = true
  按钮_追问.Enabled = true
}

这一课的要点

  • 思考模式只在 DeepSeek 上有,开了以后多一条 GotReasoning 通道;回答照样从 GotStream(流式)或 GotText(非流式)出来。
  • 显示与否只看你接不接 GotReasoning,旧版的 HideReason 属性已经去掉了。
  • 多轮对话会一直累积:第 4 次追问时,请求里是前 3 问 3 答再加这一问,图也一直在里面。所以换题必须 StartNewChat。
  • 提示词里规定格式和不要什么,比只说「讲一下这道题」有用得多。

常见问题

现象 原因与处理
状态行一直停在「正在思考……」二三十秒 思考模式本来就慢,难题更久。只想快点出结果就把 ThinkingEnabled 设为假
讲解里满是 **、\frac、$ 提示词里没说「不要 Markdown 和 LaTeX」。也可以搭配 Markdown 拓展 把回答渲染出来
打开「显示思考过程」后灰色区域是空的 当前回答没有思考内容:ThinkingEnabled 为假,或接的是不支持思考的第三方服务
题目里的数字认错了 照片太小或拍歪了:压缩边长用 1600 以上,拍的时候让题目占满画面、光线均匀
「只讲思路」开着,它还是把答案说出来了 模型不是百分百听话。提示词里的「不要给出最终答案」放在最后一句再强调一次会更稳
讲完一题再拍下一题,回答还在说上一题 换题时没调用 StartNewChat

平台说明

  • 安卓、鸿蒙都支持思考模式;鸿蒙版的 DeepSeek 组件同样有 GotReasoning 事件。
  • 业务检查见验证记录:思考片段只进思考标签、讲解标签不混入、开关只控制可见性、追问时请求里带着题目图片等,都逐条执行过。

下一课

第 3 课 拍餐估热量:前两课的回答都是给人看的文字;下一课让模型回 JSON,App 自己解析、计算、记账——这是把大模型接进「真正的功能」的关键一步。

文档反馈