能自己托管、能塞进手机浏览器、又能对外提供 API 的免费 AI 聊天引擎,其实比想象中更难得。这次完成的手机端,就是把原本只能在电脑上操作的聊天引擎,重新包了一层适合移动端的 Web 界面:同一套后端,手机和电脑都能访问,多轮对话、历史会话、批量任务都可以在手机上发起。如果你正在找一个“免费 + 手机端可访问 + 可扩展接口”的聊天引擎方案,这篇可以直接收藏。
这个项目的核心能力,可以归纳成四个点:
- 免费开源,不依赖商业平台账号,可以自己部署。
- 手机端不是简单“缩小页面”,而是专门做过触屏、安全区、虚拟键盘和移动端滚动布局适配。
- 支持多轮对话和会话持久化,手机端刷新页面后能恢复历史消息。
- 后端可以当 API 服务用,批量对话任务也能通过接口触发,适合做产品原型或个人工具。
这篇文章会带你完整过一遍手机端 AI 聊天引擎的技术路径,包括核心能力、部署启动方式、手机端适配关键技术、多轮对话与批量任务接口调用、资源占用观察方法,以及常见问题的排查清单。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 免费 AI 聊天引擎 + 手机端 Web 界面 |
| 核心功能 | 多轮对话、会话持久化、移动端访问、API 接入、批量对话任务 |
| 手机端形态 | 移动浏览器直接访问,支持 PWA 方式添加到桌面 |
| 后端能力 | 对话服务、会话管理、批量任务队列、接口服务 |
| 通信方式 | HTTP/HTTPS 接口调用,可通过局域网或公网访问 |
| 硬件门槛 | 纯 API 模式对机器要求很低;若本地加载模型,需按模型尺寸单独评估 |
| 启动方式 | 命令行启动后端服务,手机端通过 IP 地址访问 |
| 是否支持批量任务 | 支持,可以按 prompt 列表排队执行 |
| 是否提供接口 API | 聊天、会话、批量任务都可以通过 HTTP 接口调用 |
| 适合场景 | 自建聊天入口、移动端产品原型、私有知识库助手、自动化测试 |
从上面的表格能看出来,这个项目的定位不是“重模型”,而是“轻入口”。如果你已经有可用的模型 API,手机端就是一个完整的前端壳;如果你想完全本地化,只需要把模型推理服务接到后端,再通过手机端访问。
2. 手机端 AI 聊天引擎适用场景与使用边界
2.1 适合谁用
第一类是想给自己做一个专用聊天工具的开发者。很多 AI 产品在电脑端用起来很顺手,但一到手机上就要开 App、登录账号,数据和会话还被平台管着。自建手机端之后,私有数据、自定义系统提示词、批量测试脚本都可以完全掌控。
第二类是正在做产品原型的人。不需要急着开发原生 App,直接用手机端 Web 界面验证对话流程、交互逻辑和接口稳定性,成本比原生客户端低得多。
第三类是自动化任务使用者。手机端只是入口之一,背后真正有价值的是聊天接口和批量任务队列。比如批量生成文案、批量质检对话、压力测试,都可以通过接口触发。
2.2 不适合什么场景
如果要求零维护、开箱即用,这个方案并不合适。自建服务需要你自己管理依赖、模型或 API Key、端口、证书和备份。
如果要求大规模公网商用,也不能直接裸奔。至少要对接口做身份认证、限流、内容过滤和操作审计,否则很容易被刷接口或产生违规内容。
2.3 使用边界与合规要求
这属于通用开发实践,凡是涉及对话生成、隐私数据、用户输入的内容,都需要注意三条红线:
- 用户对话内容必须加密传输,不能在日志里明文保存敏感信息。
- 如果手机端素材包含人脸、声音、商标、版权文本等内容,使用前必须确认授权。
- 对话结果生成后,发布或商用前要做人工复核,不能直接无审核对外输出。
3. 整体架构与手机端关键技术点
3.1 架构分层
从实现角度看,整个系统可以分成三层:
- 模型接入层:负责对接大模型 API 或本地推理服务,统一输入输出格式。
- 后端服务层:提供对话接口、会话管理、批量任务队列、历史记录存储。
- 手机端展示层:负责移动端聊天界面、会话列表、设置页面、PWA 离线能力。
手机端和后端之间走 HTTP 接口。手机端没有直接调用模型,而是把用户输入发到后端,由后端决定调用哪个模型、是否启用上下文、是否过滤内容。这样做的好处是,以后换模型服务时,手机端代码不用动。
3.2 移动端适配的几个硬指标
这次做手机端,真正花时间的地方不是对话气泡,而是移动端的几个基础问题:
- viewport 必须正确设置,否则手机浏览器会按 980px 宽度渲染页面。
- 输入框不能被手机虚拟键盘遮挡。
- 聊天列表滚动要顺滑,不能出现整页缩放。
- 需要处理刘海屏、挖孔屏的安全区域。
- PWA 添加到桌面后,状态栏颜色和启动画面要协调。
下面是一段基础移动端 HTML 模板,适配了安全区域和禁止双击缩放:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> <meta name="theme-color" content="#1f2937"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <title>AI Chat Mobile</title> <style> html, body { margin: 0; height: 100%; background: #111827; color: #f9fafb; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } #app { height: 100vh; height: 100dvh; padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); display: flex; flex-direction: column; } .message-list { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 16px; overscroll-behavior: contain; } .input-bar { display: flex; gap: 8px; padding: 12px; padding-bottom: calc(12px + env(safe-area-inset-bottom)); border-top: 1px solid rgba(255, 255, 255, 0.1); } .input-bar textarea { flex: 1; resize: none; border: none; outline: none; background: rgba(255, 255, 255, 0.08); color: #fff; border-radius: 12px; padding: 12px; font-size: 16px; min-height: 44px; max-height: 120px; } </style> </head> <body> <div id="app"> <div id="messages" class="message-list"></div> <div class="input-bar"> <textarea id="input" rows="1" placeholder="输入消息"></textarea> <button id="send">发送</button> </div> </div> </body> </html>上面这段代码里,重点不是样式,而是三个细节:
viewport-fit=cover配合env(safe-area-inset-top/bottom),解决刘海屏和底部横条遮挡问题。height: 100dvh适配手机浏览器地址栏收起和展开时的高度变化。-webkit-overflow-scrolling: touch保证 iOS 上长列表滚动位置正确。
如果你在移动端开发时遇到“手机端页面被放大缩小”“状态栏颜色不对”“输入框被键盘顶上去”这类问题,通常就是上面几个属性没处理好。
4. 环境准备与前置条件
手机端只是界面,真正要跑起来的是后端服务。下面是一份通用环境检查清单,具体版本按实际项目调整。
4.1 软件环境
| 依赖项 | 建议要求 | 说明 |
|---|---|---|
| 操作系统 | Windows 10/11、Ubuntu 20.04+、macOS 12+ | 跨平台,但推荐在 Linux 服务器上长期运行 |
| Python | 3.10+ | 多数聊天后端框架的通用要求 |
| Node.js | 18+ | 如果手机端需要单独构建打包 |
| 包管理工具 | pip / npm | 分别管理 Python 依赖和前端依赖 |
| 数据库 | SQLite 起步,生产建议 PostgreSQL | 用于保存会话和消息记录 |
4.2 硬件环境
如果后端只转发第三方模型 API,普通 4 核 8G 内存的机器就够,CPU 占用很低。
如果要在本地加载开源对话模型,就要根据模型体积准备显存或内存。比如轻量对话模型在 6G 显存上可以运行,但具体占用需要按实际模型测试。部署前建议先用小模型跑通,再逐步切换到大模型。
4.3 目录规划建议
建议项目按下面结构组织:
ai-chat-engine/ ├── backend/ │ ├── app.py │ ├── requirements.txt │ └── config.py ├── mobile/ │ ├── index.html │ ├── manifest.json │ └── sw.js ├── data/ │ ├── sessions.db │ └── logs/ ├── scripts/ │ ├── batch_chat.py │ └── export_history.py └── models/ └── README.md把后端、手机端、数据、脚本、模型分开,后续做备份、更新、批量任务时不会互相干扰。
5. 手机端部署与一键启动方式
这个项目不需要太复杂的启动流程,本质上就是“启动后端服务 + 手机访问地址”。
5.1 后端启动示例
先进入后端目录,安装依赖,再启动服务:
cd backend pip install -r requirements.txt # 启动服务,监听局域网地址,让手机端可以访问 python app.py --host 0.0.0.0 --port 7860启动后,服务默认会在http://0.0.0.0:7860上运行。电脑端打开http://127.0.0.1:7860验证服务正常。
5.2 手机端访问方式
手机和电脑连接同一个局域网,在手机浏览器输入电脑的局域网 IP,比如:
http://192.168.1.100:7860手机端会加载聊天界面。如果你用的是 Windows,查看局域网 IP 可以用:
ipconfig如果你用的是 Linux,可以用:
hostname -I这里有一个容易踩的坑:手机访问时不要把地址填成127.0.0.1,因为手机上的 127.0.0.1 指向手机自己,而不是电脑。
5.3 通过 PWA 添加到手机桌面
如果手机端提供了manifest.json和sw.js,就可以用 PWA 方式把聊天页面“安装”到手机桌面。
一个简单的manifest.json示例如下:
{ "name": "AI Chat Engine", "short_name": "AI Chat", "start_url": "/", "display": "standalone", "background_color": "#111827", "theme_color": "#1f2937", "icons": [ { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" } ] }在 HTML 的<head>里引入:
<link rel="manifest" href="/manifest.json">用 Chrome 或 Safari 打开页面后,菜单里会出现“添加到主屏幕”或“安装应用”选项。PWA 的优势是打开后没有浏览器地址栏,全屏体验更像原生 App。
5.4 HTTPS 与远程访问
如果手机不在局域网,想在外面访问,不建议直接把服务端口暴露到公网。稳妥做法是使用反向代理加 HTTPS。
Nginx 反向代理配置示例:
server { listen 443 ssl; server_name chat.example.com; ssl_certificate /etc/nginx/ssl/chat.pem; ssl_certificate_key /etc/nginx/ssl/chat.key; location / { proxy_pass http://127.0.0.1:7860; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; } }这里要注意,配置 HTTPS 之前,先确认手机端对话内容里有敏感信息。没有 HTTPS 的情况下,手机和服务器之间传输的数据是明文,存在被中间人截获的风险。
6. 手机端功能测试与效果验证
部署完成后,重点测试五个维度:多轮对话、手机端界面适配、会话持久化、接口稳定性和批量任务。
6.1 多轮对话测试
测试目标:确认后端能维护上下文,而不是每次请求都当成新对话。
操作步骤:
- 手机端输入第一句:“你好,我叫小明。”
- 等待返回。
- 继续输入:“我叫什么名字?”
- 判断返回是否包含“小明”。
如果第二次回答正确,说明上下文传递正常。如果回答“我不知道你的名字”,要先检查前端有没有传session_id或conversation_id。
后端接口设计参考:
{ "session_id": "abc-123", "messages": [ { "role": "user", "content": "你好,我叫小明。" }, { "role": "assistant", "content": "你好小明,有什么可以帮你?" }, { "role": "user", "content": "我叫什么名字?" } ] }前端每次发送新消息时,把所有历史消息一起提交,由后端拼上下文。这种方式简单,但会越来越长,后续可以改成后端只保存最近 N 条消息。
6.2 手机端界面适配测试
测试目标:确认聊天页面在不同尺寸手机上都不变形、不误触、不遮挡。
建议按下面清单测试:
| 测试项 | 预期结果 |
|---|---|
| 打开页面时是否整页缩小 | 不能出现页面缩成手机宽度一列的情况 |
| 点输入框时虚拟键盘是否遮挡 | 当前输入框应自动滚动到可视区域 |
| iOS 底部横条是否遮挡发送按钮 | 发送按钮要上移 safe-area 距离 |
| 从桌面 PWA 图标打开 | 无浏览器地址栏,状态栏颜色正常 |
| 快速上下滑动长对话 | 列表流畅,不能白屏或跳动 |
| 手机横竖屏切换 | 布局不崩溃,输入框不脱离底部 |
这些测试看起来不涉及 AI,但在实际使用中,一个小问题就会让用户放弃整个工具。
6.3 会话持久化测试
测试目标:聊天记录刷新后不丢。
操作步骤:
- 手机端进入会话,发送几条消息。
- 刷新页面。
- 检查会话列表里是否有历史记录。
- 点击历史会话,确认消息完整。
如果刷新后记录丢失,优先检查后端是否保存了消息,前端是否在初始化时拉取会话列表。不要只在 localStorage 里存聊天记录,那样换设备或清缓存就丢了。
6.4 接口调用测试
手机端页面只是接口的调用者。接口才是真正可以复用的部分。用 Python 或 curl 直接测试聊天接口,能确认问题出在前端还是后端。
import requests url = "http://127.0.0.1:7860/api/chat" payload = { "session_id": "test-session-001", "message": "用一句话介绍你自己" } response = requests.post(url, json=payload, timeout=60) print(response.status_code) print(response.json())正常的返回结构可以设计成:
{ "session_id": "test-session-001", "reply": "我是一个可以私有化部署的 AI 聊天助手。", "created_at": "2025-01-01T12:00:00Z" }这里需要注意,接口返回的字段名要以实际项目为准。如果没有reply字段,可能叫answer、text或content,先看后端接口文档。
6.5 批量任务测试
批量任务的价值在于,不需要在手机端一条条手动输入。只要后端提供任务接口,手机端可以上传一批 prompt,然后定时查询进度。
测试思路:
- 准备 5 条 prompt。
- 批量提交任务。
- 轮询任务状态。
- 任务完成后拉取结果。
如果批量任务卡住,优先检查任务队列是否启动、有没有异常日志、是不是并发数太高导致显存或内存被打满。
7. 批量对话任务与接口 API 实现思路
7.1 批量任务设计
批量任务和普通聊天请求的区别在于“异步”。普通聊天是用户发一条,后端回一条,立即返回。批量任务则是先提交任务列表,后端排队执行,前端或脚本轮询进度。
一个简单的任务状态流程:
待执行 -> 执行中 -> 完成 / 失败任务表可以设计成:
task_id prompt_text status result created_at updated_at批量任务接口可以这样设计:
| 接口 | 作用 |
|---|---|
POST /api/batch/create | 提交批量 prompt 列表 |
GET /api/batch/status | 查询任务进度 |
GET /api/batch/result | 获取单条结果 |
GET /api/batch/export | 导出全部结果 |
7.2 批量任务调用示例
下面是一个 Python 批量提交示例:
import requests import csv import time base_url = "http://127.0.0.1:7860" prompts = [ "给产品写一句广告语", "给这篇文章写一个摘要", "把这句话翻译成英文", "模拟用户反馈问题并生成回复", "生成 5 个短视频标题" ] # 1. 创建批量任务 create_resp = requests.post( f"{base_url}/api/batch/create", json={"prompts": prompts}, timeout=30 ) task_id = create_resp.json().get("task_id") print("task_id:", task_id) # 2. 轮询状态 while True: status_resp = requests.get( f"{base_url}/api/batch/status", params={"task_id": task_id}, timeout=30 ) data = status_resp.json() print("status:", data["status"], "progress:", data["progress"]) if data["status"] in ("completed", "failed"): break time.sleep(2) # 3. 导出结果 if data["status"] == "completed": result_resp = requests.get( f"{base_url}/api/batch/export", params={"task_id": task_id}, timeout=60 ) items = result_resp.json()["items"] with open("batch_result.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["index", "prompt", "result"]) for item in items: writer.writerow([item["index"], item["prompt"], item["result"]]) print("结果已导出到 batch_result.csv")批量任务要注意两点:
- 任务列表不能无限往内存里塞,建议先读 CSV 或 JSONL 文件。
- 任务失败后要记录错误信息,并提供重跑机制,不能卡在“执行中”状态。
7.3 在手机端发起批量任务
手机端不需要长驻后台执行任务,只需要做到“提交任务 - 显示进度 - 查看结果”。所以手机端更适合做控制器,而不是执行器。
手机端界面可以增加一个“批量任务”入口,用户上传 CSV 文件,前端解析出 prompt 列表,调用create接口,然后每隔几秒查询状态并显示进度条。任务结束后,把结果导出为 CSV 下载到手机。
这也回应了手机端开发中常见的“开发 app 时 CLI 与手机端版本不同”问题:手机端只负责任务输入和展示,实际逻辑统一放在后端服务里,可以避免各个端逻辑不一致。
8. 资源占用与性能观察方法
8.1 观察哪些资源
运行手机端聊天引擎时,主要看四个指标:
| 指标 | 观察方法 | 重点 |
|---|---|---|
| CPU 占用 | top/ 任务管理器 | 请求量增大时是否飙升 |
| 内存占用 | free -h/ 任务管理器 | 会话是否被不断缓存 |
| 磁盘占用 | 查看 data 目录 | 日志和数据库是否增长过快 |
| 网络带宽 | iftop/ 路由器管理页 | 手机端是否频繁请求大体积消息 |
8.2 降低资源占用的手段
- 会话历史只保留最近 20 条,不无限拼接。
- 批量任务设置最大并发数,比如同时最多执行 2 个。
- 聊天接口返回结果后立即释放引用,避免占用内存。
- 日志按天切分,避免单个日志文件无限增长。
- PWA 离线缓存只缓存静态资源,不缓存对话数据。
8.3 手机端能耗与流量
手机端本身不做推理,能耗和流量消耗主要在页面渲染和接口请求。如果要降低流量,可以在后端开启流式输出,而不是等整段回答生成完一次性返回。流式输出时,手机端逐字显示,体感也更快。
如果接口返回速度比较慢,手机端最好加 loading 状态和超时提示。常见做法是把请求超时时间设置到 60 秒以上,并在界面显示“正在生成中”。
9. 常见问题与排查方法
手机端聊天引擎踩坑最多的不是模型,而是网络、适配和缓存。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 手机浏览器打不开电脑服务地址 | 未监听 0.0.0.0,或防火墙拦截 | 检查启动日志和防火墙 | 后端绑定0.0.0.0,放行对应端口 |
| 页面打开后整体缩小 | 缺少 viewport 或缩放冲突 | 查看 HTML head 是否正确 | 显式设置width=device-width, initial-scale=1 |
| 发送按钮被虚拟键盘遮挡 | 未适配动态视口高度 | 在浏览器调试台查看元素位置 | 使用100dvh并监听visualViewport变化 |
| 会话刷新后丢失 | 后端未持久化,或前端只存 localStorage | 查看数据库表是否有记录 | 后端保存消息,前端启动时拉取历史 |
| 批量任务一直停在执行中 | 并发数过高或异常未捕获 | 查看后端日志 | 增加任务超时机制和失败重试 |
| PWA 图标打开后白屏 | Service Worker 缓存了旧版本 | 清缓存并强制刷新 | 更新 SW 时使用skipWaiting |
| 端口被占用 | 上一次服务未退出 | 使用lsof -i:7860或netstat -ano | 换端口或结束残留进程 |
| 显存不足 | 本地模型体积超过显存 | 查看 CUDA 报错信息 | 减小模型、降低上下文长度、使用 CPU 模式 |
| 接口请求超时 | 模型响应过慢或网络中断 | 查看后端时间戳和错误日志 | 增加超时时间,使用流式接口 |
| 手机端下载 PDF 或导出 CSV 失败 | 后端未设置正确的下载响应头 | 用 Postman 模拟请求 | 设置Content-Disposition并确认 MIME 类型 |
9.1 启动后页面打不开
优先看后端日志。大多数情况下是端口被占用或监听地址错误。
# 查看端口占用 lsof -i:7860如果端口被占用,就换一个启动端口,例如:
python app.py --host 0.0.0.0 --port 7861同时确认防火墙是否放行端口。Windows 用户在首次运行时会被弹窗询问是否允许访问网络,不要直接点取消。
9.2 手机端页面滑动卡顿
先检查消息列表是不是有大量图片或高精度头像。聊天列表建议用纯文本和简单背景色。列表如果上千条消息,要做虚拟滚动或分页加载,不能一次性渲染全部历史消息。
9.3 状态栏颜色不一致
PWA 模式下,theme_color决定状态栏颜色。如果设置了apple-mobile-web-app-status-bar-style,iOS 上的表现会不同。建议先用真机测试,不要只看模拟器。
10. 最佳实践与合规建议
10.1 先小规模验证,再批量执行
第一次部署时,先用最简单的配置跑通一个“你好”请求,确认接口、页面和存储都正常,再上批量任务。不要把批量任务和真实用户请求混在同一个队列,否则一个卡住的任务会把后面的请求全部堵住。
10.2 保留一套最小可运行配置
项目目录里建议保留一份requirements.txt、一份config.example.yaml和一页说明文档。这样换电脑部署时,不用靠记忆恢复环境。配置示例:
server: host: "0.0.0.0" port: 7860 debug: false chat: session_max_messages: 20 default_timeout: 60 batch: max_concurrency: 2 retry_limit: 3 storage: database: "data/sessions.db" log_dir: "data/logs"10.3 接口服务要做权限控制
手机端页面可以通过局域网直接访问,但接口不能随便让任何人调用。建议在服务前加一层访问令牌:
import requests url = "http://127.0.0.1:7860/api/chat" headers = { "Authorization": "Bearer your-access-token" } payload = { "session_id": "app-test-001", "message": "你好" } response = requests.post(url, json=payload, headers=headers, timeout=60) print(response.json())后端校验Authorization头。没有令牌的请求直接返回 401。这样即使端口被扫到,接口也不会被滥用。
10.4 数据备份与清理
聊天记录属于重要数据,建议每天备份数据库文件。同时设置日志轮转,避免日志文件把磁盘占满。如果清理完日志后发现问题变少,说明之前的问题可能和磁盘空间不足有关。
10.5 合规使用
手机端 AI 聊天引擎在真实场景中使用时,需要明确告知用户对话内容会被记录并用于生成回复。如果产品面向公众,必须在显著位置展示隐私说明。对于生成式内容,建议增加关键词过滤和人工抽检机制。涉及第三方的文字、图片、声音、人脸等素材,使用前必须确认授权,不能在未授权的情况下生成或传播相关内容。
11. 总结与下一步
这个免费 AI 聊天引擎最值得尝试的地方,是把“后端对话能力”和“手机端操作入口”完整串了起来。你不需要等一个现成的 App,只需要启动一个后端服务,手机扫码或输入 IP 就能开始聊天,而且会话记录、批量任务、API 接口都可以在同一个项目里复用。
最先要验证的功能很简单:多轮对话是否连贯,手机端刷新后历史消息还在不在。这两个功能通过之后,整个引擎的骨架就已经稳定了。
最容易踩的坑有三个:手机端想通过127.0.0.1访问电脑服务、页面缺少 viewport 导致整体缩小、批量任务没有超时机制卡在“执行中”。
后面可以继续扩展的方向包括:多用户登录和会话隔离、把普通聊天接口升级为流式输出、把批量任务导出格式改成 JSONL、增加手机端通知推送,以及把静态文件放到 Nginx 或 CDN 上提升访问速度。
如果你正在规划自己的 AI 聊天工具,先把手机端跑通,再用接口接业务,这个路线会比直接开发原生 App 更快验证想法。建议收藏备用,动手部署时直接照着操作即可。