用 Qt 做本地 AI 桌面助手:架构设计、任务编排与聊天界面实现
用 Qt 做本地 AI 桌面助手:架构设计、任务编排与聊天界面实现
过去两年,AI 应用大多集中在网页和云端服务里。但对于很多桌面场景来说,用户真正需要的并不只是一个“聊天框”,而是一个能够长期运行、可接入本地工具、兼顾隐私与效率的桌面助手。如果你已经在用 Qt 做桌面软件,那么把 AI 助手能力整合进现有产品,几乎是一个迟早会遇到的课题。
本文不打算教你“如何调一个大模型接口”,而是从产品和工程的角度,讲清楚:
- 本地 AI 桌面助手应如何拆模块
- 聊天界面该怎么组织
- 任务面板和会话管理如何设计
- 模型调用层如何与 UI 解耦
- 后续如何支持插件和工具调用
一、先想清楚:桌面 AI 助手不是“加个聊天窗口”
很多项目在接入 AI 时,第一反应是:
“做个聊天页,发请求,显示返回内容,不就行了吗?”
这在 Demo 阶段没问题,但一到真实产品就会暴露问题:
- 会话没法持久化
- 模型切换困难
- 回复流式输出卡 UI
- 工具调用逻辑写得到处都是
- 用户输入、任务执行、历史记录、附件处理全耦在一起
所以,桌面 AI 助手更合理的定义应该是:
一个由 UI 层、会话层、任务层、模型层、工具层共同组成的本地应用子系统。
二、推荐的整体架构
一个比较稳妥的架构拆分可以是这样:
┌──────────────────────────────┐
│ Qt UI 表现层 │
│ 聊天窗口 / 侧边栏 / 任务面板 │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 会话与状态管理层 │
│ SessionManager / ViewModel │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 任务编排与调度层 │
│ Prompt组织 / 工具路由 / 队列 │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 模型调用抽象层 │
│ LocalModel / OpenAI / Hybrid │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 工具与存储扩展层 │
│ 文件检索 / 命令执行 / DB / 插件│
└──────────────────────────────┘
这个拆法的好处是:
- UI 不直接耦合具体模型
- 模型切换成本低
- 后续容易接入本地工具或 MCP 类能力
- 聊天助手能逐渐从“问答框”进化成“任务系统”
三、UI 层应该怎么设计?
3.1 聊天区只负责呈现,不负责业务决策
聊天页面建议拆成:
- 消息列表区:展示用户消息、AI 回复、系统提示
- 输入区:支持普通输入、快捷发送、附件拖拽
- 会话侧边栏:切换历史会话
- 任务面板:展示后台任务、执行进度、失败重试
其中,消息列表本身只负责“显示状态”,不要让它直接去管模型请求、数据库写入、工具执行这些业务。
3.2 建议引入 ViewModel / Presenter 层
如果你用 Qt Widgets,可以用 Presenter;如果是 QML,更适合用 QObject + Q_PROPERTY 风格的 ViewModel。
例如:
class ChatViewModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString currentInput READ currentInput WRITE setCurrentInput NOTIFY currentInputChanged)
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
public:
Q_INVOKABLE void sendMessage();
signals:
void currentInputChanged();
void busyChanged();
void messageAppended();
};
这样 UI 层只绑定 ViewModel,不直接碰底层服务。
四、会话管理是桌面助手能不能“长期使用”的关键
一个真正可用的 AI 助手,不可能每次启动都从空白开始。
你至少要考虑:
- 会话标题怎么生成
- 消息历史怎么存储
- 会话切换如何恢复上下文
- 是否支持固定系统提示词
- 是否支持 pin 住重要会话
4.1 建议的数据模型
struct ChatMessage {
QString role; // user / assistant / system / tool
QString content;
QDateTime createdAt;
QString taskId;
};
struct ChatSession {
QString sessionId;
QString title;
QVector<ChatMessage> messages;
QDateTime updatedAt;
};
持久化可以用:
- SQLite
- JSON 文件
- 自定义轻量数据库封装
如果只是桌面应用,SQLite 往往是最稳的选择。
五、模型调用层必须抽象,不要把 API 写死在 UI 里
桌面 AI 助手未来很可能会出现几种模型来源:
- 本地模型(如 Ollama、llama.cpp、vLLM 网关)
- 云端模型(OpenAI、DeepSeek、Kimi 等)
- 混合策略(本地优先,云端兜底)
如果一开始就把请求代码写在 MainWindow::onSendClicked() 里,后面会非常痛苦。
5.1 推荐接口
class IChatProvider {
public:
virtual ~IChatProvider() = default;
virtual void send(const QVector<ChatMessage>& context) = 0;
};
然后分别实现:
OpenAiProviderLocalModelProviderHybridProvider
这样后续切模型、切服务地址、加重试策略都比较自然。
六、任务编排层:让助手从“聊天”走向“做事”
如果你的目标只是问答,聊天层就够了;但如果你要的是“桌面助手”,那它迟早要处理:
- 打开本地文件
- 检索历史资料
- 执行某个批处理任务
- 组合多个子步骤
这就需要一个任务编排层。
6.1 编排层主要做什么?
- 组装 Prompt
- 决定是否调用工具
- 跟踪子任务状态
- 把执行过程同步回 UI
可以理解为:
模型层负责生成,编排层负责决定下一步干什么。
6.2 UI 上要不要显示任务过程?
建议要。
否则用户只会看到:
- “正在思考……”
- “完成了。”
中间发生了什么完全不可见,体验很差。
更好的做法是把执行过程映射到任务面板里:
- 读取文件中
- 正在解析内容
- 正在调用模型
- 正在生成摘要
- 已完成
这样用户对助手的信任度会高很多。
七、流式输出和 UI 响应怎么兼顾?
AI 回复最常见的体验需求是:边生成边显示。
但如果你处理不好,就会出现:
- 文本疯狂 repaint
- QML 富文本区滚动抖动
- 主线程被大量 append 操作拖慢
建议做法
- 后台线程接收 token
- 主线程按小批次刷新 UI
- 不要每个 token 都立即更新界面
例如每 30~50ms 合并一次文本块再刷到消息气泡里,这样视觉上已经足够“实时”,但性能更稳定。
八、插件与工具扩展:一开始就预留接口
就算你现在不做工具调用,也建议先把接口留好。
比如:
class IAssistantTool {
public:
virtual ~IAssistantTool() = default;
virtual QString name() const = 0;
virtual QString description() const = 0;
virtual QString execute(const QVariantMap& args) = 0;
};
未来你可以逐步接入:
- 文件搜索工具
- 本地命令执行工具
- 项目知识库工具
- 文档摘要工具
这样架构演进时不会推倒重来。
九、一个落地顺序建议
如果你准备真正做一个 Qt 本地 AI 桌面助手,建议按下面节奏推进:
第一阶段:最小可用版本
- 聊天窗口
- 基础消息列表
- 单模型调用
- 会话持久化
第二阶段:工程化增强
- 模型抽象层
- 流式输出
- 错误处理与重试
- 会话搜索 / 删除 / 重命名
第三阶段:助手化升级
- 任务面板
- 工具调用
- 文件附件
- 插件体系
第四阶段:产品化细节
- 多窗口协同
- 快捷键唤起
- 系统托盘
- 自动升级 / 配置中心
十、结语
用 Qt 做本地 AI 桌面助手,难点从来都不是“能不能接上模型”,而是:
如何把 AI 能力组织成一个长期可维护、可扩展、可交付的桌面产品模块。
如果你一开始就把聊天、任务、模型、工具、存储拆清楚,后续无论是换模型、加插件还是做产品化,都能顺着现有架构往前走。
反过来,如果一上来就把所有逻辑堆进一个窗口类里,后面几乎一定会重构。
所以这类项目最值钱的,不是“某个模型 API 调通了”,而是:
- 架构有没有边界
- UI 和业务有没有解耦
- 状态和任务有没有被管理好
这决定了你的 AI 助手,最终是一个 Demo,还是一个能长期迭代的产品。
本地 AI 桌面助手真正的竞争力,不只是回答得像不像,而是它能不能稳定、安静、长期地待在用户的桌面上,成为一个真正有用的工具。
更多推荐


所有评论(0)