基于大模型的视频智能问答桌面应用(Agent)开发(含视频分段+ASR识别+代理配置)
基于大模型的视频智能问答桌面应用(Agent)开发(含视频分段+ASR识别+代理配置)
一个“可本地运行、可工程讲解、可稳定演示”的视频问答桌面应用:导入本地视频后自动完成 ASR 转写、文本分段、向量化入库;提问时通过轻量 Agent 编排输出“答案 + 时间戳”,并支持运行时代理配置(无需重启)。
1. 前言与背景
视频正在成为知识载体的主流形态:课程录播、会议纪要、产品宣讲、技术分享……但“检索体验”仍停留在拖进度条、猜时间点。这个项目的目标,是把“视频可检索”做成一个工程上能落地的最小闭环:
- 导入一个本地视频后,自动完成:语音识别(ASR)→ 文本分段(Chunk)→ 向量化(Embedding)→ 向量库入库(Chroma)
- 用户提问时,系统像一个轻量 Agent:先判断意图(找时间点 / 摘要 / 综合)→ 检索相关片段 →(可选)调用大模型生成摘要 → 返回答案 + 时间戳
- 面向真实网络环境:首次运行往往需要下载 Whisper/Embedding 模型,因此提供“设置页可视化代理配置”,并做到保存后立刻生效(无需重启)
这不是一个“只讲概念”的 Demo,而是一个尽量贴近真实工程约束的桌面应用原型。
2. 整体架构与技术栈
2.1 数据流
2.2 技术栈
- 桌面壳:pywebview(轻量、无 Node/Electron 依赖,工程演示成本低)
- 后端:FastAPI(接口清晰、可单独调试,便于未来拆分为纯 Web 服务)
- ASR:faster-whisper(本地推理,更适合隐私与离线场景)
- Embedding:sentence-transformers(成熟可靠,召回效果稳定)
- 向量库:ChromaDB Persistent(轻量持久化,适合桌面应用/原型)
- LLM:OSCI(OpenAI 兼容标准接口,便于适配国内合规模型服务)
- 配置:YAML(默认配置)+ JSON(本地运行时设置,包含代理、LLM 模型实例等)
默认配置位于 config/config.yaml,示例(节选):
asr:
provider: whisper
model: base
language: zh
embedding:
provider: sentence-transformers
model: all-MiniLM-L6-v2
chunk:
max_length: 500
overlap: 50
2.3 为什么选用 OSCI(OpenAI 兼容)协议接入大模型
在很多文章里,“模型选择”会被等同于“选 ChatGPT 还是 Claude”。但对工程落地来说,更关键的是“用什么接口协议把模型能力接进系统里”。本项目选择 OSCI(OpenAI 兼容)有三个核心原因:工程抽象统一、可替换性强、合规与部署选择更灵活。
先明确一个事实:ChatGPT 与 Claude 是“具体厂商/产品”,而 OSCI 是“接口协议形态”。协议的价值在于把上层业务(摘要、问答)与下层模型服务解耦。
2.3.1 统一协议带来的工程收益
- 一套请求/响应结构即可覆盖多家模型服务:只需要配置
base_url/model/timeout/temperature,不需要在业务代码里写多套 SDK 适配逻辑 - 更易做“运行时切换”:设置页新增/切换模型实例后立即生效,且不影响上层 Agent 编排
- 更易做“失败降级”:当 LLM 不可用或 Key 未配置时,摘要自动降级为抽取式摘要,保证整体链路可演示、可用
2.3.2 与 ChatGPT、Claude 的对比(从工程接入视角)
下面的对比是“接入方式与工程侧影响”的对比,不是模型能力评测:
| 维度 | OSCI(OpenAI 兼容协议) | ChatGPT(OpenAI 生态) | Claude(Anthropic 生态) |
|---|---|---|---|
| 角色 | 协议/接口形态 | 具体服务与模型体系 | 具体服务与模型体系 |
| 接入成本 | 低:统一协议,配置驱动 | 中:依赖 OpenAI API 形态与账号/网络 | 中到高:通常需要单独的协议与 SDK 适配 |
| 可替换性 | 高:切换供应商通常只改 base_url/model | 中:在 OpenAI 体系内替换容易,跨体系需适配 | 中:在 Anthropic 体系内替换容易,跨体系需适配 |
| 国内合规落地 | 友好:可接入国内 OpenAI 兼容端点或自建网关 | 取决于网络、账号体系与合规策略 | 取决于网络、账号体系与合规策略 |
| 代理/网络策略 | 更可控:统一走一个 base_url,便于用代理或网关治理 | 受网络与服务策略影响较大 | 同左 |
2.3.3 为什么不直接绑定某一家 SDK
直接绑定某一家厂商 SDK 的典型问题:
- 一旦切换模型供应商,需要重写调用与错误处理逻辑
- 不同厂商对参数、消息格式、流式返回的细节差异,会侵入业务层(Agent/摘要模块)
- 对桌面应用来说,网络环境多变,统一走协议更便于做代理、网关、审计与降级
因此,本项目的策略是:上层只依赖“OpenAI 兼容的 chat completion 调用形态”,并通过配置选择接入哪家模型服务。这使得“是否用 ChatGPT/Claude/国内模型”变成部署与配置问题,而不是代码重构问题。
3. 核心功能模块实现
这一节按“从导入到问答”的主链路拆解,重点讲清楚:每个模块的职责边界、输入输出与工程化取舍。
3.1 桌面端:pywebview + 本地 HTTP 服务一体化
项目采用“本地 FastAPI 服务 + pywebview 加载本地网页”的模式:
- 后端在后台线程启动(监听
127.0.0.1:8765) - pywebview 打开桌面窗口,加载
http://127.0.0.1:8765/ - 前端用原生 HTML/JS(降低依赖与构建成本,利于文章展示)
关键实现位置:
desktop_main.py:启动 uvicorn + 创建 pywebview 窗口api/server.py:FastAPI 路由 + 挂载ui/为静态站点
工程价值:
- UI/后端职责清晰,易于定位问题
- 未来要升级成纯 Web 或更复杂前端框架,迁移成本低
3.2 视频处理:ASR 转写 + 文本分段(Chunk)
视频处理主入口是后端的 POST /api/videos/process,整体链路:
- 校验视频文件存在
- 注册视频记录(写入
data/videos.json,状态为 processing) VideoProcessor.process():转写 → 分段VectorStore.add_chunks():embedding → 入库 Chroma- 更新视频记录:chunk 数、时长、done/error
3.2.1 ASR:faster-whisper 转写
核心是把 Whisper 的输出统一为工程内部的数据结构 Transcript(文本 + 起止时间):
segments, _info = model.transcribe(video_path, language=self.language)
transcripts = [
Transcript(text=s.text.strip(), start_time=s.start, end_time=s.end, confidence=s.avg_logprob)
for s in segments
]
这样的好处是:后续 Chunk、Embedding、检索、Agent 都基于统一抽象,不被底层 ASR SDK 绑定。
3.2.2 分段(Chunk):滑窗 + overlap 的工程化策略
分段目标不是做 NLP 里的“完美切句”,而是最大化两件事:
- 检索时语义尽量完整(避免句子在 chunk 边界被截断)
- chunk 规模可控(降低 embedding 计算成本,提高检索质量)
当前实现采用“按字符长度切块 + overlap 重叠”的策略:
max_chars:单块最大字符数(默认 500)overlap_chars:块之间重叠字符数(默认 50)
为什么 overlap 重要:
- 用户问题常命中“跨句子/跨段落”的边界
- 无 overlap 时,相关信息被拆散,召回质量会明显下降
3.2.3 当前视频转文字不准确的局限与优化思路
当前项目的 ASR 能力已经足以支撑 Demo 和基础检索,但“视频转文字”并不是一个百分之百准确的过程,尤其在真实视频场景里,误差会直接影响后续检索和问答质量。当前主要局限包括:
-
音频质量不稳定:
- 如果原视频存在背景音乐、环境噪声、回声、收音距离远等情况,ASR 很容易出现漏词、错词
- 对朗诵、戏曲、多人对话、口音较重的内容,识别难度也会明显上升
-
专有名词和领域词识别偏弱:
- 通用 ASR 模型对人名、地名、专业术语、古诗词、品牌名等内容不一定敏感
- 一旦关键词识别错误,后续向量检索就可能命不中真正相关的片段
-
时间戳与语义边界不总是完全对齐:
- Whisper 输出的是转写片段,天然更偏“语音切分”而不是“语义切分”
- 这会导致文本虽然大体正确,但某些句子的起止时间不够精细,影响“精确定位到某一句”的体验
-
错误会沿链路向后传递:
- 转写错了,Chunk 就会错
- Chunk 错了,Embedding 和检索结果也会偏
- 最终用户看到的问答结果,表面像是“大模型回答不准”,实际上根因可能是前面的 ASR 文本就已经有偏差
针对这些问题,后续可以从以下几个方向优化:
-
提升音频预处理质量:
- 在转写前增加降噪、音量归一化、静音切分等预处理步骤
- 对较长视频可先抽离音频并做统一采样率转换,减少模型输入波动
-
升级或切换更适合场景的 ASR 模型:
- 当前使用的是通用本地模型,优点是轻量、易部署
- 如果更关注准确率,可以尝试更大尺寸的 Whisper 模型,或接入阿里云/腾讯云等更适合中文场景的 ASR 服务
-
引入术语热词或后处理纠错:
- 对固定场景(课程、企业宣讲、诗词朗读、医学/法律等)可维护术语表
- 在 ASR 输出后做一轮轻量文本纠错,把高频误识别词映射回正确写法
-
优化分段与检索策略:
- 在当前字符滑窗之外,增加基于标点、停顿或句子边界的切分策略
- 对检索结果做多片段重排,降低单次误识别对最终回答的影响
-
增加“可校正”的产品能力:
- 未来可以支持展示转写文本、允许用户手动修正关键片段
- 一旦关键文本被修正,再重新分段和入库,整体问答质量会明显提升
3.3 向量库:EmbeddingModel + Chroma Persistent
核心思路是“封装与懒加载”:
EmbeddingModel:懒加载SentenceTransformer,只在首次用到时加载模型VectorStore:懒加载chromadb.PersistentClient与 collection,并负责video_id维度的过滤查询
入库的关键点:
ids:video_id_chunkIndex,便于定位与删除metadatas: 存储video_id、start_time、end_time,为“时间戳问答”提供结构化依据
3.4 问答 Agent:Intent → Retrieval → Answer(含大模型摘要与降级)
问答入口为 POST /api/query,核心流程:
- 解析会话(session_id)与当前视频(video_id)
- 轻量会话记忆:对“继续/展开/刚才那段”等追问补全上下文
IntentClassifier:规则关键词分类(find_timestamp / summarize / both)VectorStore.query:检索 top_k 片段(默认 5)- 根据 intent 输出:
find_timestamp:直接返回时间段与片段summarize/both:把检索片段组织成上下文,调用 LLM 摘要
大模型调用具备“工程兜底”:
- 未配置 API Key → 自动降级为抽取式摘要
- 调用异常 → 捕获并降级,保证接口稳定、演示不中断
3.5 代理配置:真实网络环境下的“必需品”(无需重启)
现实问题:Whisper / sentence-transformers 等模型首次运行常需要访问外网(如 huggingface.co),在许多网络环境会超时。
项目提供设置页的“网络代理”能力:
GET /api/settings:读取当前代理与模型状态POST /api/settings:保存代理(host/port),并立刻设置HTTP_PROXY/HTTPS_PROXY环境变量- 代理持久化在
config/local_settings.json的network.proxy中
保存后无需重启即可对后续下载/请求生效,这对桌面 Demo 的可用性提升非常明显。
4. 核心难点与解决方案
4.1 模型下载/网络不通
解决方案:把代理能力做成“产品级设置项”,而不是让用户手动改环境变量或改代码。保存后立即应用代理,最大化首次运行成功率。
4.2 MacOS 环境依赖与 ABI 兼容性
本地推理链路常见“安装能过、运行崩溃/segfault”的问题,尤其与 NumPy/底层推理库 ABI 相关。
当前工程实践中,把 NumPy 版本固定为稳定锚点,并与 SciPy/sklearn 做匹配锁定是非常重要的(桌面应用追求“可运行可演示”,比“追新版本”更关键)。
4.3 资源占用与线程数
本地推理会引入 OpenMP/OpenBLAS/PyTorch 等多线程计算。线程数不受控容易造成 CPU 占满、界面卡顿,甚至触发更难排查的稳定性问题。
解决方案:在后端启动阶段限制 native threads,并尽量把推理变成可控、可复现的运行方式。
4.4 密钥治理:不落盘明文
LLM 摘要是可选能力,但一旦涉及 API Key,就必须把“密钥不进配置文件”当作硬约束。
解决方案:模型实例信息可落盘(base_url/model/timeout 等),但密钥优先存系统 Keychain/凭据库,不可用时回退本地加密存储;前端只显示掩码与“已配置/未配置”状态。
5. 功能演示与效果展示
5.1 配置模型实例
- 选择新增模型模版

-
配置对应的模型的key

-
保存后效果

-
temperature的作用:- 用来控制模型输出的“发散程度”或“随机性”
- 值越低,回答越稳定、越保守,更适合本项目这种“基于视频片段做问答/摘要”的场景
- 值越高,回答会更灵活,但也更容易出现措辞漂移、总结过度发挥的问题
- 对视频问答来说,通常建议从
0.2 ~ 0.7开始;如果更强调“忠于检索结果”,可以把值调低一些
-
timeout_s的作用:- 表示单次大模型请求的超时时间(单位:秒)
- 如果模型响应较慢、网络较差,超时时间过短会导致请求提前失败
- 如果超时时间过长,用户会感觉界面一直在等待,交互反馈变差
- 本项目里它的本质是“稳定性与等待时长”的平衡参数,通常可以先使用默认值
60s
-
为什么这一项要做成“模型实例配置”:
- 不同模型供应商、不同网络环境,响应速度和输出风格差异很大
- 把
base_url、model、temperature、timeout_s做成可配置项后,切换模型时不需要改代码,只需要在设置页调整即可
5.2 网络代理配置

-
代理的作用:
- 让应用访问外部模型资源或接口时,先经过本地代理转发
- 本项目里最典型的场景是首次下载 Whisper / sentence-transformers 相关模型,或访问外部兼容接口时网络不稳定
- 配置后,后端会把代理同步到
HTTP_PROXY/HTTPS_PROXY环境变量,对后续请求立即生效,无需重启
-
huggingface.co等资源到底是什么:huggingface.co可以理解为开源 AI 模型社区和模型文件分发平台,很多常见的模型权重、配置文件、tokenizer 文件都会从这里下载- 对本项目来说,
sentence-transformers在首次加载 embedding 模型时,通常会去 Hugging Face 拉取对应模型文件 - 某些 Whisper 相关依赖、模型配套文件,或其他第三方 AI 组件,也可能在初始化时访问类似的外部模型仓库
- 所以这里说的“访问 huggingface.co 等资源”,本质上不是在访问某个普通网页,而是在拉取模型运行所需的文件和依赖元数据
-
为什么这些资源很关键:
- 如果本地还没有缓存模型,应用第一次运行时必须先把模型文件下载到本机,后续才能完成 embedding 或语音识别
- 一旦这些文件下载失败,常见表现就是:视频处理启动了,但在模型初始化阶段超时、报错,或者一直卡在加载中
- 这也是为什么很多用户会觉得“代码没问题,但项目就是跑不起来”,根因往往不是业务逻辑,而是模型资源没有成功拉取
-
为什么要配置代理:
- 有些网络环境下无法稳定访问
huggingface.co等外部资源,模型下载会超时 - 即使接口本身可访问,模型首次拉取、依赖初始化时也常常因为网络抖动而失败
- 对桌面应用来说,用户更希望“在设置页填一个 IP 和端口就能解决问题”,而不是手动修改终端环境变量
- 有些网络环境下无法稳定访问
-
什么情况下建议优先配置:
- 第一次启动后模型一直下载失败
- 日志里出现连接超时、读取超时、无法连接外部模型仓库等错误
- 需要通过代理访问的外部兼容模型服务
-
这一能力的工程意义:
- 把“网络问题”从代码层转成配置层处理
- 降低首次运行失败率
- 让模型下载、外部推理接口访问和后续调试都更可控
5.3 导入视频,选择文件 → 开始处理 → 处理成功(片段数、状态)
视频素材为一段将进酒的的京剧朗读视频,时常为1分46秒,处理后得到分片数,该页面支持反复上传解析。

5.4 视频库:列表展示 → 选为当前视频 → 删除视频记录
解析完成之后的视频库列表记录中可以直接选定某个视频开始对话。选择操作栏中的“选为当前视频”。

5.5 问答:
- 时间定位类:“视频里什么时候讲到 XXX?”

-
摘要类:“总结一下视频讲了什么?”

-
多轮追问:“展开说说刚才那段”

- 为什么要预设问答选项:
- 因为这个项目并不是一个完全开放式的大模型聊天产品,而是一个“围绕视频内容检索与摘要”的垂直问答系统
- 预设几类典型问题,可以更稳定地覆盖项目的核心能力:时间定位、内容总结、多轮追问
- 对演示和博客读者来说,预设问题能更直观地看到系统不同分支的行为差异,而不是把结果混在一起
- 从产品角度看,预设问法也是一种“引导用户提问”的方式,能降低首次使用门槛,提高命中有效检索的概率
- 当前项目的决策循环依据是什么:
- 第一步是看“用户问题属于哪一类”,这里不是让大模型自由发挥判断,而是先经过
IntentClassifier做规则分类 - 当前分类依据主要来自关键词规则,例如“什么时候、时间点、定位”更偏向时间定位;“总结、概括、讲了什么”更偏向摘要
- 第二步是根据分类结果去执行不同路径:
- 如果是
find_timestamp,优先返回相关片段及其时间段 - 如果是
summarize或both,先检索相关片段,再调用 LLM 生成摘要
- 如果是
- 第三步会结合当前视频上下文和最近一轮会话记忆,决定是否补全“追问语义”,比如“继续说”“刚才那段”
- 所以这个项目的“决策循环”本质上不是复杂的自主规划,而是一个可解释的确定性流程:
问题分类 → 向量检索 → 按意图分支输出 → 会话记忆补全
- 第一步是看“用户问题属于哪一类”,这里不是让大模型自由发挥判断,而是先经过
- 为什么这里采用“规则 + 检索 + 摘要”的决策方式:
- 对视频问答场景来说,用户真正关心的大多是“在哪一段讲过”和“这段内容在讲什么”
- 先做规则分类,再做检索和摘要,能够保证流程稳定、输出可解释,也更适合工程化落地
- 相比完全交给大模型自由决策,这种方式更容易控制成本、排查问题,并减少无关幻觉输出
6. 源码说明
6.1 关键目录与文件
video-agent/
├── desktop_main.py # 桌面应用入口:启动服务 + pywebview 窗口
├── api/server.py # FastAPI 路由、设置、静态 UI 挂载
├── src/
│ ├── video_processor.py # ASR 转写 + 分段
│ ├── embeddings.py # sentence-transformers 懒加载封装
│ ├── vector_store.py # Chroma 向量库封装 + videos.json 记录表
│ ├── agent.py # Agent 编排(intent → 检索 → 摘要/时间戳)
│ ├── summarizer.py # LLM 摘要(失败自动降级抽取式)
│ ├── session_memory.py # 轻量会话记忆(多轮追问补全)
│ └── llm_registry.py # 模型实例与密钥治理(Keychain/加密回退)
├── ui/ # 原生前端:index.html / app.js / style.css
├── config/config.yaml # 默认配置(ASR/Embedding/Chunk/检索等)
└── config/local_settings.json # 运行时生成:代理、模型实例等(不建议提交)
6.2 推荐安装环境版本
为了保证在桌面端稳定运行(尤其是 macOS 本地推理链路),建议优先使用以下环境组合:
- Python:3.12(推荐),可选 3.9–3.12;不建议使用 3.13(部分依赖在某些平台缺少可用 wheel,容易触发安装/解析失败)
- NumPy:1.26.4(稳定锚点,避免与部分本地推理依赖的 ABI 兼容问题)
- SciPy:1.13.1(与 NumPy 1.26.x 组合更稳)
- scikit-learn:1.5.2(与 NumPy 1.26.x 组合更稳)
- typing-extensions:>= 4.16.0(保证 FastAPI/Pydantic 相关依赖兼容)
建议使用 venv 或 conda 创建隔离环境后再安装 requirements.txt,避免污染系统 Python。
6.3 安装与运行命令(conda,macOS / Linux)
conda create -n video-agent python=3.12 -y
conda activate video-agent
python -m pip install --upgrade pip
pip install -r requirements.txt
python desktop_main.py
6.4 安装与运行命令(conda,Windows)
在 Windows 上建议使用 Anaconda Prompt / PowerShell 执行:
conda create -n video-agent python=3.12 -y
conda activate video-agent
python -m pip install --upgrade pip
pip install -r requirements.txt
python desktop_main.py
6.5 安装与运行命令(venv / python,macOS / Linux)
macOS 如果系统里没有合适版本的 Python,可以先安装 Python 3.12:
brew install python@3.12
然后在项目目录创建 venv 并安装依赖:
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
python desktop_main.py
6.6 安装与运行命令(venv / python,Windows)
在 Windows 上建议优先用 conda;若使用 venv,可在 PowerShell 执行:
py -3.12 -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
pip install -r requirements.txt
python desktop_main.py
6.7 运行方式
python desktop_main.py
后台服务监听 127.0.0.1:8765,桌面窗口加载同地址。首次运行可能需要下载 Whisper/Embedding 模型;若网络受限,建议先在“设置 → 网络代理”中配置代理后再进行视频处理。
结语
这套实现的核心价值不在“堆叠更多大模型能力”,而在于把视频问答拆成可控、可解释、可演示的工程闭环:ASR 给出结构化时间戳,Chunk/Embedding/向量库保证检索确定性,Agent 编排把“找时间点”和“生成摘要”做成稳定流程,代理与密钥治理则确保能在真实环境中跑起来。
更多推荐



所有评论(0)