Owl 可穿戴 AI 服务器架构解析:FastAPI、异步任务队列与全局状态管理完整指南
【免费下载链接】OwlA personal wearable AI that runs locally项目地址: https://gitcode.com/gh_mirrors/owl3/Owl
Owl 是一个完全在本地运行的个人可穿戴 AI(A personal wearable AI that runs locally),它通过 Apple Watch、ESP32 等设备持续采集你的语音和位置,再用大模型生成对话转录与摘要。本文带你快速看懂Owl 服务器架构:基于FastAPI的应用工厂、单例AppState 全局状态管理,以及一条自研的异步任务队列如何协同工作,帮助新手在 10 分钟内建立完整心智模型。
一张图看懂数据流:从麦克风到 AI 总结
Owl 的服务器是整套系统的"大脑",所有硬件(如参考设备 Bee 和 XIAO ESP32S3 Sense 开发板)采集到的音频,最终都会汇聚到这里:
完整链路如下:
- 设备端:麦克风采集 16KHz 音频,编码为 AAC 后通过 BLE / LTE / WiFi 发送;
- 服务器入口:FastAPI 应用通过 Socket.IO 流式通道或 HTTP 分块上传接口接收数据;
- 实时处理:流式语音识别实时产出语句,端点检测服务判断"对话结束";
- 后台处理:任务被丢进异步任务队列,由
ConversationService完成精确转录、LLM 摘要; - 推送回端:
NotificationService通过 Socket 把新对话推送给 iOS / Web 客户端。
FastAPI 应用工厂:一条命令搭起整个服务
服务器入口在 owl/core/cli.py 的serve命令中,它只做了两件事:加载config.yaml配置,然后调用应用工厂函数并交给 Uvicorn 运行:
app = server.create_server_app(config=config) uvicorn.run(app, host=host, port=port)真正的魔法在 owl/server/main.py 的create_server_app()工厂函数中,它按依赖顺序组装出全部组件:
| 组装步骤 | 说明 |
|---|---|
① 创建Database | 默认使用 SQLite(sqlite:///./db.sqlite3) |
| ② 创建五大服务 | LLM、异步转录、通知、捕获、对话(ConversationService)服务 |
③ 挂载AppState | 把配置与所有服务塞进app.state._app_state |
| ④ 挂载 Socket.IO | CaptureSocketApp挂载到/socket.io路径 |
| ⑤ 注册路由 | capture与conversations两个 APIRouter |
这种"先建服务、再挂状态、后挂路由"的工厂模式,是 FastAPI 项目中管理复杂依赖的常见且清晰的做法。
全局状态管理:AppState 是唯一"共享内存"
owl/server/app_state.py 定义了核心数据类AppState,它是整个服务器的单一状态容器:
@dataclass class AppState: config: Configuration database: Database capture_service: CaptureService conversation_service: ConversationService llm_service: LLMService notification_service: NotificationService # 每个进行中的捕获会话对应一个处理器 capture_handlers: Dict[str, StreamingCaptureHandler] # 每个分块上传对应的对话检测器 conversation_detection_service_by_id: Dict[str, ConversationDetectionService] task_queue = Queue()它的设计亮点有 3 个:
- 统一取用:
AppState.get(from_obj)静态方法可以从FastAPI或Request对象中取出状态,避免在每个路由里到处传参; - 内置鉴权:
authenticate_request作为 FastAPI 的Depends依赖项,自动校验请求头中的 Bearer Token(即配置文件里的client_token),Socket.IO 连接同样走authenticate_socket校验; - 会话级字典:
capture_handlers和conversation_detection_service_by_id用capture_uuid作为键,为每个进行中的捕获会话维护独立上下文。
异步任务队列:让 AI 处理不阻塞请求
Owl 没有引入 Celery 等重型队列框架,而是用 Python 标准库Queue手写了一个极简异步任务队列,这是本文最值得学习的部分。
任务抽象:owl/server/task.py 中只有一个 5 行的抽象基类:
class Task(ABC): @abstractmethod async def run(self, app_state: AppState): pass任何想进入队列的后台工作,只需继承Task并实现run()。
消费端:owl/server/main.py 中的process_queue()在服务器启动时以协程方式被拉起,无限循环地从队列取任务并await执行:
while True: if not app_state.task_queue.empty(): task = app_state.task_queue.get() await task.run(app_state=app_state) app_state.task_queue.task_done() else: await asyncio.sleep(1)生产者散落在各处,例如:
ProcessConversationTask(owl/server/streaming_capture_handler.py):流式对话结束后入队,调用conversation_service.process_conversation_from_audio()做精确转录 + 摘要;ProcessAudioChunkTask(owl/server/routes/capture.py):分块上传每收到一块音频就入队,增量运行 VAD 对话检测。
这种"HTTP 接口只做快速落盘,重活全部丢队列"的设计,保证音频上传接口毫秒级返回,即使 Whisper 转录要跑几十秒也不会卡住请求。
实时流式通道:Socket.IO 捕获音频
像 XIAO ESP32S3 Sense 这样的 BLE 设备会把音频实时流到 iOS App,再经 Socket.IO 转发到服务器。owl/server/capture_socket.py 中的CaptureSocketApp实现了 3 个事件:
on_connect:先鉴权,Token 不符直接断开;on_audio_data:按capture_uuid查找(或创建)对应的StreamingCaptureHandler,把音频块写入磁盘并转发给流式转录服务;on_finish_audio:客户端停止录制时,触发最后一轮对话处理。
每个StreamingCaptureHandler同时挂着一个端点检测服务(owl/services/endpointing/),基于语音活动检测判断"你说完了",一旦判定对话结束,就自动把任务丢进前面介绍的异步队列——实时流与后台处理就此解耦。
分块上传与 UDP:离线设备怎么同步
不是所有设备都能实时连接:
- 分块上传(
/capture/upload_chunk):Apple Watch 会把音频录成 30 秒一段的 PCM 分块存到本地,等联网后逐块 POST 上来,同capture_uuid的文件按序追加到同一捕获文件; - UDP 通道(owl/server/udp_capture_socket.py):专为 LTE-M 等低带宽设备(如 Sony Spresense)准备,配置中打开
udp.enabled即可在 8001 端口接收分片。
两条路径殊途同归:数据落盘后,对话检测与处理逻辑最终汇入同一个ConversationService。
服务层与通知:结果如何回到你的 App
ConversationService(owl/services/conversation/conversation_service.py)是处理管道的终点:调用异步转录服务(Whisper 或 Deepgram)精确转录整段对话 → 用 LiteLLM 生成摘要 → 关联位置信息 → 全部写入数据库。
处理完成后,NotificationService(owl/services/notification/notification_service.py)通过之前挂载的 Socket.IO 通道把new_conversation事件推送给客户端,iOS App 的列表即刻刷新——无需轮询。
一键启动与配置:config.yaml 和环境变量
所有行为都由一个 YAML 文件驱动,模板见 owl/sample_config.yaml:
- 复制为项目根目录下的
config.yaml,填入你的姓名与client_token; - LLM 可选本地 Ollama 或 OpenAI;转录可选 Deepgram 或本地 Whisper;
- 运行
owl serve --config=config.yaml即可启动。
配置还支持环境变量覆盖,格式为OWL_节名_键名,例如export OWL_ASYNC_WHISPER_HF_TOKEN=xxx,方便 Docker 部署时不落盘密钥。
捕获文件如何落盘:目录结构一览
服务器把音频按"日期 / 设备 / 捕获文件"组织在capture_dir(默认captures/)下,检测到的对话会被切分出来,附带转录与摘要的 JSON 文件,方便人工直接检查:
总结:这套架构值得你抄作业
Owl 服务器架构用极少的组件实现了生产级能力,三个核心设计可以迁移到你自己的项目:
- 应用工厂 + AppState:所有依赖集中构造、统一挂到
app.state,鉴权做成Depends,代码零散但结构清晰; - 轻量异步任务队列:一个抽象基类 + 一个消费协程,实现"请求快返回、重活后台跑",无需引入消息中间件;
- 多通道入口、单一处理核心:Socket.IO、HTTP 流式、分块上传、UDP 四条入口最终汇入同一个服务层,新增设备类型几乎零成本。
想动手验证?克隆仓库后按 docs/macos_and_linux_setup.md 或 docs/docker_setup.md 完成环境搭建,再配合 docs/server_configuration.md 修改配置,10 分钟就能跑起来一台属于自己的可穿戴 AI 服务器 🎉
【免费下载链接】OwlA personal wearable AI that runs locally项目地址: https://gitcode.com/gh_mirrors/owl3/Owl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考