在日常教学中,我们经常会碰到如下场景:正在用PPT讲课,然后需要演示一下AI对当前问题的回答,启发学生思维,因此我们不得不退出PPT——打开浏览器——登录豆包或deepseek——提问等待回答——回答完毕切换到PPT播放上,如果需要对屏幕上的内容提问,还得先截图保存、再手动上传。整个流程琐碎且割裂,如果再遇到电脑卡顿,常常会打乱整个讲课节奏。而且通用AI经常无法将回答限制在课堂内容上,导致回答偏离课堂主线。
为解决这一问题,我开发了AIAsker软件, 这是一款面向 Windows 平台的桌面 AI 助手,它将这些步骤压缩到「点击—提问—获得回答」三个动作以内,将 AI 交互融入操作系统层面,大幅减少使用步骤的同时,提供简单易用的上下文设置功能,让AI真正赋能课堂而不是扰乱课堂。
📥 软件获取
AIAsker_Setup_v1.0.exe 安装包 | |
AIAsker_portable.zip,解压即用,无需安装 | |
git clone |
# 项目主页:https://gitee.com/devount/aiasker# 夸克网盘:https://pan.quark.cn/s/e38799feb0b6?pwd=8Gk5
⚠️ 目前仅提供 Windows 64 位版本,支持 Windows 7 / 10 / 11。
📦 Part 1 —— 普通用户使用指南
⚡ 安装(两种方式任选)
方式一:一键安装(推荐)
1. 下载 AIAsker_Setup_v1.0.exe2. 双击运行,如弹出 UAC 提示点击「是」3. 等待安装完成,安装程序会询问是否立即启动,按 Y 启动安装程序会自动完成以下操作:
📁 将程序文件拷贝至 C:\Program Files\AIAsker\📌 在开始菜单创建「AIAsker」程序组(含启动快捷方式和卸载入口) 🖥️ 在桌面创建快捷方式
方式二:便携模式
如果不想安装,直接运行压缩包内的 AIAsker.exe 即可,注意运行路径不要有中文。不写注册表、不留系统痕迹,适合放在 U 盘里随身携带。
🔵 初次见面:一个悬浮在桌面上的球
安装完成后,屏幕右下角会出现一个带有径向渐变效果的蓝色悬浮球,中央显示「AI」标识,并伴有呼吸灯动画。该控件始终置顶于所有窗口之上,可自由拖拽至任意位置,不干预正常办公。

🔑 首次配置
初次使用需要填入大模型 API Key:
右键悬浮球 →「设置...」
在「基础设置」页签中选择模型预设(如"阿里千问 3.7"),API 地址和模型名称会自动填充
填入你的 API Key

(可选)切换到「知识配置」页签,设置系统提示词或粘贴知识库文本

点击「保存」
阿里云百炼 API Key 可在阿里云百炼注册账号并免费申请。其他服务商(DeepSeek、智谱、豆包)同理,填入对应 Key 即可。
#阿里云百炼地址:https://bailian.console.aliyun.com/cn-beijing#/home
💬 聊天窗口:极简但不简陋
点击悬浮球后,会弹出一个圆角白色面板的聊天窗口。设计上遵循「最小干扰」原则:无标题栏按钮(仅保留一个关闭图标)、无多余装饰。输入区域位于底部,支持多行文本,Ctrl + Enter 发送。

📸 截图提问 —— 核心功能
这是 AIAsker 最具实用价值的能力。操作流程如下:
点击输入框左侧的 相机图标 
窗口自动隐藏,200ms 延迟后全屏截图(给你时间将目标内容展示在屏幕上) 截图以缩略图形式呈现在输入区域上方 
点击缩略图可进入 ✂️ 裁剪编辑器:用鼠标拖拽创建裁剪框,支持 8 锚点自由调整(四角 + 四边中点),精确选取需要 AI 关注的区域 
在输入框中键入问题,点击「发送」
发送后,截图(自动压缩为 JPEG、分辨率 ≤ 1920px)与文字问题一同传递给大模型,视觉模型可理解图片内容并基于上下文作答。
对话支持多轮上下文记忆,可连续追问,AI 会关联历史消息作答。
🎤 语音输入 —— 边说边出字
点击输入框左侧的 🎙️ 麦克风图标

开始录音,再次点击结束。
底层基于 阿里云 Qwen3-ASR-Flash-Realtime 实时语音识别引擎,通过 WebSocket 流式传输音频数据。支持以下特性:
- 实时中间结果
边说边在输入框中显示识别进度 - VAD 断句
语音活动检测自动分段,长段语音会被切分为多个句子逐段追加 - 追加模式
多次录音结果以空格拼接,不会覆盖已有文本 - 最长 15 秒单次录音
超时自动停止
实测在普通办公和教学环境下,标准普通话识别准确率非常高。
✨ AI 回复的渲染效果
AI 回复气泡具备完整的富文本渲染能力:
📝 Markdown 完整支持:标题、列表、粗体、斜体、链接等 💻 代码语法高亮:基于 Pygments 的 friendly 浅色主题,适配白色聊天背景 📊 表格渲染:自适应列宽,横向溢出时可滚动 🧮 LaTeX 数学公式:基于 MathJax 3 引擎,行内公式 $...$和块级公式$$...$$均以矢量 SVG 呈现,支持 ams 宏包🔄 流式输出:逐 token 渲染,呈现「打字机」效果,避免长时间空白等待
⚙️ 设置详解
右键悬浮球 →「设置...」,打开两页配置对话框。
📋 标签页一:基础设置
/chat/completions 后缀 | |
qwen3.7-plus、deepseek-chat 等 | |
内置模型预设清单:
选择预设后,API 地址和模型名称自动填充。填入 API Key 即可使用。注意:非视觉模型不能识别图片,如deepseek-v4-pro等,请选择可以识别视觉图片的模型,如qwen3.7-plus
📚 标签页二:知识配置
- 🧠 系统提示词
定义 AI 的身份与行为边界。例如:「你是一位有多年教学经验的语文教师,擅长知人论世、诗词赏析。」 - 📖 知识库
粘贴参考文本,如本节课的文章内容等,AI在回答时将优先基于这些内容。支持从 .txt/.md文件导入,内容会追加到已有知识库之后。
两项均为可选。留空则使用模型的默认行为。
🩺 诊断功能
设置对话框中设有「🔍 诊断」按钮,点击后启动一套 10 步全链路自动检查:
| 图片理解实测 | |
| 语音识别实测 |
每一步都有 [PASS] / [FAIL] / [WARN] 标记,出现问题时可快速定位故障环节。
🗑️ 卸载
打开开始菜单 → AIAsker → Uninstall AIAsker 或手动删除 C:\Program Files\AIAsker目录
便携版直接删除解压文件夹即可,不在系统中留任何痕迹。
🔧 Part 2 —— 开发者继续开发指南
以下内容面向具备 Python 基础的开发者,介绍项目架构、关键技术细节与二次开发切入点。
📥 源码获取
git clonegit clone https://gitee.com/devount/aiasker.gitcd AIAsker💻 开发环境搭建
# 1. 创建虚拟环境(Python 3.8+)python -m venv venvvenv\Scripts\activate # Windows# source venv/bin/activate # macOS/Linux# 2. 安装依赖pip install -r requirements.txt# 3. 创建配置文件(参考 core/config.py 中的 DEFAULT_CONFIG)echo {} > config.json# 4. 直接运行python main.py# 5. 打包为 exepip install pyinstallerpyinstaller AIAsker.spec注意事项:
⚠️ PyAudio 在 Windows 上可能需要从 .whl文件安装,可访问 Python Extension Packages 获取对应 Python 版本的预编译包⚠️ 语音功能依赖物理麦克风,纯文本对话开发可跳过 ⚠️ 打包时如果新增了动态 import 的模块,需在 AIAsker.spec的hiddenimports列表中添加⚠️ QtWebEngine 模块体积较大(约 100MB),打包后的 exe 包含完整的 Chromium 内核
📐 技术栈总览
🗂️ 项目文件结构
AIAsker/├── main.py # 🚀 应用入口,App 主控类├── core/│ ├── ai_client.py # AI 客户端(OpenAI 兼容流式调用)│ ├── config.py # 配置读写(config.json,默认值定义)│ ├── screenshot.py # 截图管理(抓取/缩略图/Base64/裁剪替换)│ ├── voice_input.py # 语音识别(Qwen-ASR WebSocket 实时流)│ ├── markdown.py # Markdown → HTML(代码高亮、表格样式注入)│ ├── latex.py # LaTeX 公式 → MathJax 标记处理│ ├── math_page.py # 生成嵌入 MathJax 的完整 HTML 模板│ ├── diagnostics.py # 🔍 诊断引擎(10 步全链路检查)│ └── scale.py # DPI 缩放适配工具├── ui/│ ├── floating_ball.py # 🔵 悬浮球控件(置顶/拖拽/呼吸灯/右键菜单)│ ├── chat_dialog.py # 💬 聊天窗口(消息气泡/流式渲染/语音/截图)│ ├── image_editor.py # ✂️ 截图裁剪覆盖层(8 锚点自由调整)│ ├── image_editor_dialog.py # 截图编辑对话框容器│ ├── settings_dialog.py # ⚙️ 设置对话框(模型预设/知识配置)│ ├── config_test_dialog.py # 🩺 诊断结果显示对话框│ ├── icons.py # 🎨 图标绘制(SVG 手绘按钮图标)│ └── styles.py # 🎨 全局 QSS 样式表├── assets/ # 静态资源(logo、SVG 图标)├── config.json # 用户配置文件├── requirements.txt # Python 依赖清单├── AIAsker.spec # PyInstaller 打包配置├── Install_AIAsker.bat # 一键安装批处理├── AIAsker_Install.ps1 # PowerShell 安装脚本└── AIAsker_Setup.iss # Inno Setup 安装包脚本🧩 核心架构解析
应用主控(main.py)
App 类是全局调度中心,持有 FloatingBall(悬浮球)和 ChatDialog(聊天窗口)两个核心实例。关键交互逻辑:
悬浮球左键单击 → App._toggle_dialog() → 在悬浮球左上方定位并显示/隐藏聊天窗口悬浮球右键设置 → App._show_settings() → 打开模态设置对话框悬浮球的「点击」判断采用位移阈值法:在 mouseReleaseEvent 中,只有当拖拽位移 ≤ 3px 时才视为点击,否则视为拖拽移动。这有效避免了拖拽操作误触发对话框。
AI 流式对话(core/ai_client.py + ui/chat_dialog.py)
对话流程采用 QThread 后台线程 + Qt 信号回调 的经典模式:
用户发送消息 → _AIThread(QThread) 启动 → AIClient.chat_stream_sync() 同步阻塞流式调用 → 每收到 token → token.emit(token) 信号跨线程发射到主线程 → 主线程 _on_ai_token(): → markdown_to_html() 转换为 HTML → render_math_in_html() 处理 LaTeX 标记 → QWebEngineView.set_content_html() 更新气泡内容 → JS: document.getElementById("bubble").innerHTML = ... → JS: MathJax.typesetPromise() 重新渲染公式系统提示词与知识库在 _AIThread.run() 中注入:如果用户配置了 system_prompt 或 knowledge_base,会在消息列表头部插入一条 role: "system" 消息。
AI 回复气泡:QWebEngineView + MathJax
选择 QWebEngineView 而非 QLabel 或 QTextBrowser 的核心原因是 MathJax 需要完整的 JavaScript 运行环境来将 LaTeX 公式渲染为 SVG。
气泡组件 _AIBubble 封装了以下关键机制:
- 首次加载
注入完整的 MathJax HTML 页面模板( make_math_page()) - 后续更新
通过 page().runJavaScript()热替换#bubble元素内容,触发 MathJax 增量重排 - 滚轮转发
WebView 中注入 JS 拦截 wheel事件,将deltaY写入document.title,Qt 端通过titleChanged信号解析"scroll:xxx"前缀,再驱动外层QScrollArea滚动——解决了 WebView 吞掉滚轮事件的问题 - 高度自适应
每次内容更新后 JS 将 document.body.scrollHeight通过document.title传回 Qt,动态调整 WebView 高度
语音识别(core/voice_input.py)
基于阿里云 dashscope SDK 的 OmniRealtimeConversation:
_VoiceThread(QThread) → VoiceInput.recognize() → OmniRealtimeConversation.connect() 建立 WebSocket → 等待 session.created 事件(超时 10 秒) → update_session() 配置中文识别参数(16kHz PCM) → PyAudio 麦克风循环读取 → base64 编码 → append_audio() → VAD 断句回调: - input_audio_transcription.text → interim 信号(中间结果) - input_audio_transcription.completed → result 信号(最终段落) → end_session() + close()识别结果采用追加模式:on_result 回调将每段确认文本追加到 voice_accumulated,on_interim 回调将中间结果拼接在已确认文本之后显示。这样多次说话之间不会互相覆盖。
截图编辑器(ui/image_editor.py)
_CropOverlay 是一个自定义 QLabel,实现了完整的截图裁剪交互:
在图片区域内拖拽绘制裁剪框 已有裁剪框时,8 个锚点(四角 + 四边中点)可独立拖拽调整 裁剪框内部可拖拽平移 所有操作约束在图片显示区域内,最小尺寸 20px 通过 get_crop_rect_pil()方法将控件坐标逆映射回 PIL Image 坐标
🛠️ 二次开发切入点
1. 接入新的 AI 服务商
只要目标 API 兼容 OpenAI Chat Completions 格式,只需在 ui/settings_dialog.py 的 _MODEL_PRESETS 字典中添加一行:
"你的服务商名称": ("https://your-api.example.com/v1/chat/completions","your-model-name",),如果需要非标准的请求头或 payload 结构,修改 core/ai_client.py 中的 chat_stream_sync() 方法。
2. 添加新的聊天功能按钮
在 ui/chat_dialog.py 的 _init_ui 方法中,参考相机按钮的模式:
btn_new = IconButton(IconType.XXX, tooltip="功能描述")btn_new.setFixedSize(dp(_BTN_ICON), dp(_BTN_ICON))btn_new.clicked.connect(self._your_handler)il.addWidget(btn_new)图标类型枚举定义在 ui/icons.py 中,如有需要可扩展 IconType 并实现对应的 draw_xxx_icon() 函数。
3. 修改悬浮球外观
ui/floating_ball.py 的 paintEvent() 方法控制悬浮球的完整绘制:阴影椭圆 → 径向渐变主体 → AI 图标文字。修改形状、颜色、呼吸灯速度(_breath_dir)、透明度等均在此处。
4. 本地化 MathJax
当前 MathJax 通过 jsdelivr CDN 加载。内网环境可下载 tex-svg.js 及相关资源放置于项目中,修改 core/math_page.py 中 <script src> 为本地路径。
📌 结语
AIAsker 是一个为优化课堂教学中AI使用流程的工具型桌面软件:只做「最快把屏幕上的东西丢给 AI 并获得回答」这一件事。悬浮球 + 截图 + 流式回答的组合,让 AI 以最便捷的方式融入了课堂之中。
从开发者角度看,它是一个麻雀虽小五脏俱全的 PyQt5 参考案例——多线程通信、WebView 双向通信(JS ↔ Qt)、WebSocket 音频流处理、Markdown/LaTeX 渲染管道、跨线程信号安全——每一块都写得清晰克制,适合作为桌面 AI 应用开发的起步模板。
项目代码量适中(核心约 2500 行),结构干净,注释充分。欢迎 clone、fork、提 PR。
👇 关注公众号,获取更多效率工具分享
Edtshare
教育技术分享平台

分享|合作|进步|提高
夜雨聆风