Skip to content
MUKAPPPublic

About

Android 上的 AI Agent 聊天客户端,支持 OpenAI 兼容 API、流式响应、工具调用、本地 Shell、多会话历史与 Markdown 渲染。

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Mote

Mote 是一款运行在 Android 设备上的 AI Agent 聊天客户端,面向 OpenAI 兼容的 Chat Completions API。它支持流式响应、工具调用、本地 Shell、思考过程展示、多对话历史、本地文件读取、联网搜索和原生 Markdown 渲染。

功能特性

  • OpenAI 兼容接口:支持自定义 API 地址、API Key、模型、轻量标题模型和上下文压缩模型。
  • 流式聊天:支持 stream=true 响应、增量内容展示、推理内容展示和 token usage 统计;仅输出前的暂时性失败自动重试,输出后失败保留已有内容与独立错误提示。
  • 工具调用:内置文件读取、目录列出、网页抓取、WebView 抓取、联网搜索、Shell 执行、后台进程管理和等待工具。
  • 本地 Shell:打包 BusyBox for Android NDK 1.36.1,支持多 ABI,在 Android 设备上提供更完整的命令行环境。
  • 风险确认:对高风险 Shell 命令进行静态检测,必须经过用户确认后才会执行。
  • 多对话历史:按会话独立 JSON 文件保存,支持标题生成、手动重命名、切换、删除、编辑、重试和停止生成;改名失败会提示且保留旧显示。会话阅读位置在当前进程内按消息锚点恢复,主动发送或回到底部继续跟随输出。
  • 上下文压缩:在上下文过长时自动总结旧消息,降低长对话请求压力。
  • Markdown 渲染:使用原生 View 渲染 Markdown,支持代码高亮、表格、LaTeX 公式和流式增量更新。
  • 附件输入:支持添加图片和文件,文件内容过长时会截断后发送;图片按需读取,可配置附件存储额度,准备失败或超额拒绝保留草稿,不裁剪既有历史。
  • 搜索扩展:可配置 SearXNG、Tavily 或 AnySearch,配置后向模型暴露 web_search 工具;三个服务只能启用一个。

技术栈

类别 技术
语言 Kotlin + Java
Android minSdk 26,targetSdk 36,compileSdk 36.1
Java 语言级别 Java 11
构建 Gradle Kotlin DSL + Version Catalog
UI 传统 View + ViewBinding
架构 MVVM,AndroidViewModel,LiveData,Coroutines
网络 OkHttp 4.12.0
序列化 org.json
Markdown 自研原生视图树 + prism4j + RaTeX

项目结构

app/src/main/java/com/mukapp/mote/
├── MainActivity.kt                 # DrawerLayout 主界面
├── SettingsActivity.kt             # API 设置、权限管理
├── MyApplication.kt                # Application、BusyBox 初始化
├── data/                           # 设置、历史记录、数据模型
├── network/                        # OpenAI 兼容请求和 SSE 解析
├── tools/                          # AI 工具、BusyBox、Shell 风险检测和进程管理
├── ui/                             # 聊天界面、ViewModel、Adapter、侧栏列表
├── ui/markdown/                    # Markdown 解析、渲染、代码高亮、表格和公式
└── util/                           # 通用工具

环境要求

  • Android Studio,建议使用支持当前 Android Gradle Plugin 的较新版本。
  • Android SDK Platform 36,并安装对应构建工具。
  • JDK 使用 Android Studio 自带运行时或与当前 AGP 兼容的版本。
  • Windows PowerShell、macOS Terminal 或 Linux Shell。

构建与运行

克隆项目后,使用 Android Studio 打开仓库根目录,等待 Gradle 同步完成,然后直接运行 app 模块。

也可以在命令行构建:

.\gradlew.bat assembleDebug

生成的 Debug APK 位于:

app/build/outputs/apk/debug/app-debug.apk

Release 构建:

.\gradlew.bat assembleRelease

测试

运行单元测试:

.\gradlew.bat testDebugUnitTest

运行设备测试:

.\gradlew.bat connectedAndroidTest

使用配置

首次启动后进入设置页,至少填写以下内容:

配置项 说明
API 地址 OpenAI 兼容接口地址。地址末尾不是 /chat/completions 时会自动拼接。
API Key 接口密钥。本地模型服务通常可以留空。
模型 主聊天模型名称。
轻量模型 用于生成历史对话标题,留空时使用首条消息作为标题。
压缩模型 用于长上下文摘要,留空时使用主模型。
模型上下文长度 用于估算和限制请求上下文,空串或 0 表示不限制;非法、负数或超出整数范围的输入不会保存。输入预算先扣除实际请求的输出预留。
模型能力 工具调用、图片输入、用量统计分别可配置,旧配置及新模型默认全部支持;关闭后不发送对应的工具或 usage 参数,不会把图片静默改成纯文本。
压缩接管百分比 占有效输入额度(模型上下文长度减输出预留)的百分比,默认 80,填 0 关闭;对话模型未填上下文长度时不自动压缩。后台提前 10 个百分点开始(最低 1%,默认 70%),达到接管百分比后在下一次安全请求边界用摘要替换较早对话,保留近期完整轮次与期间新增消息;摘要未完成可继续对话,仅超过有效输入额度才等待。不删除聊天界面或完整历史,待接管摘要不保存。
SearXNG 地址 配置后启用搜索工具,不可与 Tavily 或 AnySearch 同时配置。
Tavily API Key 配置后启用搜索工具,不可与 SearXNG 或 AnySearch 同时配置。
AnySearch API Key 配置后通过 AnySearch POST /v1/search 启用搜索工具,不可与 SearXNG 或 Tavily 同时配置。
工具权限 Shell 新命令、文件工具、网页抓取、局域网抓取分别可关闭,默认允许;Shell 关闭后仍保留进程查询和停止工具,不自动终止后台进程。
图片附件额度 按全局图片 blob 的 Base64 UTF-8 磁盘字节计算,单位 MiB,0 表示不限额。仅限制新增图片,不删除旧数据或限制文本/工具结果;设置页可刷新历史与附件占用,不完整统计会明确标记。

如果需要让工具读取外部存储文件,需要在设置页授予文件管理权限。该权限由系统设置页手动授予,应用不会自动绕过 Android 的存储限制。

内置工具

Mote 会根据设置和模型能力向 AI 暴露工具:

工具 用途
read_file 读取文本文件内容。读取应用私有数据目录需用户确认。
list_path 列出目录或文件信息。查看应用私有数据目录需用户确认。
get_current_time 获取设备当前本地时间、时区和 UTC 偏移量。
fetch_url 获取 HTTP(S) 网页内容。
fetch_webview 使用隐藏 WebView 渲染动态网页并提取内容。
web_search 通过 SearXNG、Tavily 或 AnySearch 搜索网络内容。
shell 执行本地 Shell 命令,长任务可转为后台进程。
shell_status 查询后台 Shell 进程状态。
shell_stop 停止后台 Shell 进程。
wait 等待指定秒数后继续工具循环。

Shell 工具具备风险检测机制。命中删除、覆盖、权限破坏等高风险命令时,应用会显示确认条,用户确认后才会执行。read_file/list_path 访问应用私有数据目录(如 shared_prefs、聊天历史)时同样需要经确认条确认。

Shell 使用应用权限执行,不是隔离沙箱。局域网开关仅限制网页抓取,不限制模型接口、搜索服务或 Shell 网络访问。仅公网抓取时,fetch_url 在每次真实连接的 DNS 地址集合和重定向目标上拒绝本机/局域网地址,不使用系统代理;fetch_webview 不暴露且直接调用也拒绝。允许局域网时保留动态网页抓取,并关闭 WebView 的文件与内容访问。

自动重试最多四次外层尝试,仅限输出前的 HTTP 408/429/500/502/503/504 或指定暂时性传输失败;遵守 Retry-After 与指数等待,超过 60 秒的服务端等待交给用户稍后重试,停止可取消等待。工具增量也视为输出;缺少 [DONE] 和 finish_reason 的截断流不会交付可执行工具参数。usage 参数兼容降级仅在 HTTP 400/422 明确不支持且尚无任何输出时重发一次。

Shell 的 stdout/stderr 分别按 4096 字符块读取,固定环形缓冲只保留各自最后 65536 个 UTF-16 字符;无换行输出在进程运行时也可查询,原始换行及未终止行不被改写。

数据存储

  • API 设置保存在应用私有存储中,接口密钥经 Android Keystore 加密后落盘。
  • 对话文件保存在 chat_history/conversations/{conversationId}.json(schemaVersion=3)。
  • 当前对话指针保存在 chat_history/index.json;对话列表摘要索引保存在 chat_history/summaries.json(索引 schema v2,每条摘要绑定对话文件的 mtime/length;旧版本、损坏或指纹不匹配时重建)。
  • 图片附件的 base64 数据外置到 chat_history/blobs/{conversationId}/ 目录,对话 JSON 保存 base64Ref;v3 加载保持仅引用,缩略图与压缩后的实际请求在 IO 按需读取。旧版内联格式可直接读取,保存时自动升级;缺失 blob 不隔离整份历史,发送时明确提示重新选择图片。草稿、准备批次与排队保存的活跃引用受进程内 pin 保护,取消只回滚本批新文件,不误删复用附件。
  • 损坏的对话 JSON 会隔离到 corrupted/ 目录。
  • 删除以对话 JSON 文件移除(或确认不存在)为提交点;提交前失败保留当前消息、草稿及用户标题保护,提交后清理失败提示“对话已删除,部分历史数据清理未完成。”,不会恢复已删除记录。
  • 工具结果会完整保存到历史记录中,发送给模型前会按上下文预算截断。工具卡片的参数/结果预览各最多 5000 字符,仅原参数不超过 5000 字符时尝试 JSON 美化;“查看全部”保留原始参数和结果,不美化或截断。详情控件在首次展开时按需创建;跨消息复用同类工具卡片时,重新绑定当前工具身份、内容和展开状态。
  • 请求输入预算包含实际 system prompt、工具定义与每张图片的本地 1024 token 预留(不是提供商精确图像费率)。API usage 锚点同时匹配模型/请求包络、消息前缀及共同工具结果截断额度;不匹配时回退本地估算。输出预留复用请求实际 max_tokens,未设置时在已配置上下文内本地预留最多 1024 token,不改变 API 参数。

Markdown 支持

Mote 使用原生 Android View 渲染 Markdown,不依赖 WebView 展示聊天内容。当前支持常见块级和行内语法、代码块、行内代码、表格、链接、LaTeX 公式、流式未闭合公式回退显示,以及基于 prism4j 的代码高亮。流式 part 结构稳定时按对象引用推导 dirty 提示、复用未变状态;结构、链接定义、展开态或收尾变化仍刷新必要视图与交互。

自由复制页保留单个可选择 TextView:Markdown 解析、样式构建与文本预计算在后台完成后才绑定,表格保持等宽纯文本网格、公式保持原文;纯文本模式逐字符保留输入。排版异常会记录日志并显示完整原文,页面销毁会取消绑定;最终 TextView 布局仍有主线程成本。

权限说明

权限 用途
INTERNET 访问 API、网页抓取和搜索服务。
MANAGE_EXTERNAL_STORAGE 在用户授权后允许工具读取系统允许访问的外部文件路径。

开发约定

  • UI 使用传统 View + ViewBinding,不使用 Compose。
  • 聊天历史直接以 JSON 文件存储,不使用 Room。
  • UI 消息、API 上下文和上下文摘要分离维护。
  • 新增设置字段时,需要同步更新设置存储、设置页和布局。
  • 新增 AI 工具时,需要同步工具定义、执行逻辑和中间步骤展示。
  • 修改 Shell 风险规则时,需要同步更新 ShellRiskDetectorTest。
  • 修改上下文压缩、摘要失效或 token 估算时,需要同步相关测试。

许可证

本项目基于 Apache License 2.0 发布,详见 LICENSE。

内置 BusyBox 二进制来自 Magisk-Modules-Repo/busybox-ndk,上游版本为 1.36.1(二进制版本标识为 BusyBox v1.36.1-osm0sis,module.prop 的 versionCode 为 13614)。本项目中的四个 ABI 文件分别对应上游 busybox-arm64、busybox-arm、busybox-x86 和 busybox-x86_64。

About

Android 上的 AI Agent 聊天客户端,支持 OpenAI 兼容 API、流式响应、工具调用、本地 Shell、多会话历史与 Markdown 渲染。

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages