跳转至

架构概览

1. 适用范围

本页描述当前工程的模块边界和启动流程,重点是 Ali 对话链路与 Omni 联调。项目通过 Product Flavor 在编译时选择语音实现;HEADLESS_MODE 决定本地悬浮窗是否挂载。

Headless 不等于删除 UI 模块

当前源码仍包含本地 UI、卡片和对话状态管理。默认 Headless 模式由 OverlayWindowCoordinator 跳过窗口挂载,状态计算与 gRPC 广播继续工作。维护时需要区分“代码存在”和“当前配置展示”。

2. 模块职责

模块 核心职责 维护时的入口
app Application、前台 Service、Coordinator、状态消费和 gRPC 桥接 VoiceAssistantApplicationVoiceAssistantService
domain 领域实体、Repository 契约、UseCase ChatEvent、对话与语音接口
data Repository 实现、业务路由、会话与事件管理 AliDialogueRepositoryImpl、A2A、业务 Handler
adapter 语音引擎及设备能力适配 ASR / TTS / KWS 接口与 flavor 实现
framework Android 框架、网络和外部能力的装配 Hilt Module、媒体适配
common / core 公共结果类型、工具和 Android 基础能力 公共模型、日志与基础配置
core:grpc-server Omni 服务协议、服务端实现和流会话 OmniAgentProto.protoOmniAgentServiceImpl
core:grpc-lib / core:mock-grpc 通信与 Mock 联调相关基础设施 以各自 Proto 和调用方向为准
sdk:voice-sdk 独立 SDK 接口与集成边界 SDK 的 AIDL 和接口声明
LocalRepo 媒体、多模态、地图、小红书等业务 SDK 各 SDK 模块与依赖配置
AudioRecord 音频采集与原生库集成 录音输入、ECNR / VAD 相关实现

domain 的 Gradle 配置为 Kotlin/JVM,并通过接口描述依赖。运行时由外层实现这些接口,Hilt 在应用层和各 Module 完成装配。

以下图展示主要依赖关系,省略公共工具与部分业务 SDK:

flowchart TD
    App[app] --> Data[data]
    App --> Domain[domain]
    App --> Grpc[core:grpc-server]
    App --> Adapter[adapter]
    App --> Framework[framework]
    Data --> Domain
    Data --> Adapter
    Data --> Framework
    Adapter --> Domain
    Framework --> Domain
    Domain --> Common[common]
    Adapter --> Audio[AudioRecord]
    Data --> Sdk[业务 SDK 与适配模块]

3. 启动流程

sequenceDiagram
    participant App as Application
    participant Grpc as Omni gRPC Server
    participant Service as VoiceAssistantService
    participant Coord as Coordinators
    participant Launcher as Omni Launcher
    App->>Grpc: startAsync()
    App->>Service: startForegroundService()
    App->>App: 初始化导航适配器
    Service->>Coord: 绑定 scope、监听事件、初始化状态
    Service->>Service: 启动 AppCtrlDispatcher 与 GrpcEventBroadcaster
    Launcher->>Grpc: 建立订阅和双向流
    Note over App,Grpc: 异步启动已派发不代表端口已经监听成功

VoiceAssistantApplication.onCreate() 初始化日志与显示基础设施,然后异步启动 gRPC、预热本地存储、启动语音前台 Service,并初始化导航适配器。

VoiceAssistantService 负责生命周期胶合:绑定 Coordinator 的作用域与回调、连接事件总线、注册控制入口。登录检查在唤醒前置分发中执行;用户未登录时会触发登录请求并消费该次唤醒。

启动问题应分别确认进程、前台 Service、gRPC 监听和语音 SDK 状态,不能仅凭 Application 日志判断整条链路可用。

4. 谁处理什么事件

组件 职责 不能据此推断的行为
KWSCoordinator 唤醒监听、命令词处理和事件分发 有唤醒日志不等于对话服务已连接
ASRCoordinator 独立 ASR 接口的启停编排 不代表 Ali 主链路全部走 AliASRAdapter
DialogueCoordinator 对话会话的初始化和启停 SDK 生命周期与 UI 显隐不是同一状态
DialogueStateManager 消费对话事件,维护对话展示状态 Headless 下仍参与状态处理
AppCtrlDispatcher 业务事件转换为 Launcher 控制消息 指令发送成功不等于业务已执行成功
GrpcEventBroadcaster 事件、文本和助手状态推送 前端收到状态不代表收到最终业务结果
OverlayWindowCoordinator 本地窗口生命周期与 Headless 分支 Headless 下无本地窗口是预期行为

5. 对话到业务的边界

flowchart LR
    SDK[Ali 多模态对话] --> Repo[AliDialogueRepositoryImpl]
    Repo --> A2A[A2A 业务路由]
    A2A --> Handler[领域 Handler]
    Handler --> Event[ChatEvent / DialogueEventBus]
    Event --> State[DialogueStateManager]
    Event --> Ctrl[AppCtrlDispatcher]
    Event --> Push[GrpcEventBroadcaster]
    Ctrl --> Omni[Omni Launcher]
    Push --> Omni

维护业务时从 Handler 与事件映射开始,不要将业务逻辑重复放入 Activity、Service 或渲染组件。新增事件需要同时检查业务执行、状态消费和对外推送三条路径。

完整生命周期见语音与对话链路,业务差异见业务能力

6. 接口边界与兼容

  • Omni 服务监听同设备回环地址 127.0.0.1:50056。电脑联调使用 ADB 转发,不能把它当作可直接远程访问的服务。
  • gRPC 的方法存在,不代表已经实现方法名暗示的全部业务;当前状态控制和录音启停的差异见 Omni 接入
  • AppCtrlRequest.parameterstext_input 承载业务输入,AppCtrlResponse.message 是回执说明;领域参数需要同时核对 Handler、Dispatcher 和 Launcher 约定。
  • Product Flavor 切换发生在构建时,不提供通过运行时配置任意切换供应商的承诺。

7. 源码定位

在工程中按下列入口阅读,公开文档仓库本身不包含 Android 源码。

问题 工程入口
模块是否参与构建 settings.gradle.kts
运行变体、Headless、Mock 配置 app/build.gradle.kts
进程启动 app/src/main/java/com/jidouauto/voiceassistant/VoiceAssistantApplication.kt
前台 Service 与窗口 app/src/main/java/com/jidouauto/voiceassistant/service/
Ali 对话与业务执行 data/src/ali/java/com/jidouauto/voiceassistant/data/
Omni 协议和 Session core/grpc-server/src/main/

8. 常见定位顺序

  1. 明确 APK flavor、构建参数和设备版本。
  2. 查看 Application / Service 启动与 gRPC 监听日志。
  3. 确认登录态、录音权限、音频输入和语音连接。
  4. 沿一次请求检查 ASR 文本、A2A 路由、Handler 结果及推送。
  5. 最后核对 Launcher 回执和展示;详细命令见调试与验收