← 返回官网 Agent Runtime SDK · 集成指南 v0.1.1
For Developers / Docs

把端侧 Agent 运行时,
接进你自己的 App

Agent Runtime SDK 将「手机内嵌桌面级 Agent 运行时」封装为 UI 无关的模块化组件:App 只见到 Kotlin API 与一个 localhost 基址,proot 容器、serve 端口与令牌全部内聚为 SDK 私产。龙宫 App 是它的第一个宿主与集成样例。

group com.jvscopilot.agentruntime version 0.1.1 minSdk 28 compileSdk 36 Kotlin 2.1.21 AGP 8.11.0+

01概览与模块

SDK 按「客户端 / 运行时 / 界面 / 能力 / 物料」五类切分,按需组合:最小集成只需 sdk-runtime,要现成设置页加 sdk-ui,要屏幕、浏览器、语音等能力再按需引入对应 capability 模块。

Module形态 / 职责
sdk-clientKMP(commonMain 零 Android 类型,iOS 预留)。qwen serve 协议类型化客户端:会话 / prompt / SSE→Flow / MCP / 技能 / 设置 / 预热 / transcript 恢复。
sdk-runtimeAndroid AAR。物料铺设、init 编排、proot 启动、serve 生命周期与后台保活;Service 运行于 :runtime 独立进程,与 UI 崩溃隔离。
sdk-uiCompose 设置页(模型·密钥·语音·MCP·技能开关),可选挂入宿主导航。
sdk-capability-screen可选屏幕感知/操控:无障碍服务 + A11yHttpServer + device-screen MCP。
sdk-capability-browser可选可见浏览器:专用 WebView + CDP 中继 + 覆盖层 + 跨站重建链。
sdk-capability-voice可选语音输入 ASR 三协议桥。
sdk-capability-fileopen可选系统应用打开文件(FileProvider;JNI keep 规则随 AAR 分发)。
sdk-assetsOSS 物料包(不入 git,仅 SHA256SUMS 指针):bootstrap rootfs / debs / python / npm 引擎 / skills / mcp / init.sh。

02环境要求

  • minSdk 28(Android 9.0)、compileSdk 36、targetSdk 建议 36。
  • Kotlin 2.1.21+AGP 8.11.0+JDK 17
  • 使用 sdk-ui 时需 Compose,推荐 BOM 2025.08.00
  • 设备架构 arm64(物料按 aarch64 分发);无需 root。

03接入步骤

3.1 依赖

// build.gradle.kts
implementation("com.jvscopilot.agentruntime:sdk-runtime:0.1.1")
implementation("com.jvscopilot.agentruntime:sdk-ui:0.1.1")          // 可选:现成设置页
implementation("com.jvscopilot.agentruntime:sdk-capability-screen:0.1.1")  // 可选,按需

开发期推荐 composite build:把坐标替换为本地工程,SDK 改动即时生效、免 publish。

// settings.gradle.kts(开发期)
includeBuild("../agent-runtime-sdk") {
    dependencySubstitution {
        substitute(module("com.jvscopilot.agentruntime:sdk-runtime")).using(project(":sdk-runtime"))
        substitute(module("com.jvscopilot.agentruntime:sdk-ui")).using(project(":sdk-ui"))
    }
}

3.2 入口与初始化门闸

AgentRuntime.get(context) 是唯一入口;initialize() 返回状态流,覆盖「物料铺设 → init 幂等编排 → proot 启动 → serve 就绪」全过程。进入主界面前必须消费该流。

val runtime = AgentRuntime.get(context)

lifecycleScope.launch {
    runtime.initialize().collect { state ->
        when (state) {
            is RuntimeState.Initializing ->
                showProgress(state.stepIndex, state.stepTotal, state.firstInstall)
            RuntimeState.Running -> enterHome()
            is RuntimeState.Failed ->
                showDiag(runtime.readRuntimeErrorReport())  // runtime-error.json 五字段
            else -> Unit  // NotStarted
        }
    }
}
文案纪律:Initializing.step 是 SDK 内部步骤名,不要直接展示给用户;面向用户的进度请用 stepIndex / stepTotal(「第几步 / 共几步」)。firstInstall = false 表示设备已完成过初始化(升级重铺物料),避免误用「首次安装」类文案。

3.3 会话与流式 prompt

val client = runtime.client   // serve 就绪后可用

val session = client.createSession(title = "新会话")

// 事件流:SSE→Flow,先订阅再发 prompt
launch { client.events(session.id).collect { event -> render(event) } }

client.prompt(session.id, text)          // 退避重试内建;404→resume 链
// 中止:client.abortSession(session.id)
内建机制,无需自实现:建会话强制 thread scope(防预热会话混线);events() 懒建流,仅活跃会话自动恢复;prompt 连接退避 5 次(1/2/4/8/8s)。

3.4 提问应答与附件(可选)

  • Agent 发起 ask_user_question 时,用 answerQuestion(sessionId, requestId, answers) 提交(键为题目 0-based 序号字符串,值为选中 label);取消走 cancelQuestion
  • 附件必须先经 runtime.attachments.importAttachment() 落盘,拿到 PromptAttachment 后再 prompt(sessionId, text, attachments);未落盘即发,模型读到空。

3.5 现成设置页(可选)

// Compose 导航中挂入
AgentSettingsScreen(
    runtime = runtime,
    developerExtras = myPanels,        // 宿主自定义面板
    featureToggles  = myToggles,       // 宿主功能开关
    hiddenMcpServers = setOf("edu-classroom"),
)

覆盖模型与密钥、语音、MCP 开关、技能清单;宿主面板与开关以参数注入,不必 fork SDK。

3.6 能力模块(可选)

能力集成方需要做什么
screen引导用户开启无障碍服务(读屏);点击/输入/滑动默认关闭,由宿主显式打开。
browser无额外权限;浏览器 UI 由 SDK 提供,宿主仅触发打开。
voice运行时请求麦克风权限;ASR 目标经 resolveVoiceTarget() 解析,无可用目标时语音按钮不渲染。
fileopen零配置;路径翻译必须取自 runtime.workspace,不要自行拼接 guest 路径。

04进程与运行时模型

  • 双进程:UI 进程持有 Compose 与业务;:runtime 独立进程由 RuntimeEngineService 承载 proot、serve 与全部 Node 子进程。UI 崩溃不拖垮运行时,运行时崩溃不拖垮 UI。
  • 杀 UI 进程后 serve 存活:watchdog 与收养幂等内建,重进 App 自动接回。
  • 边界:proot、serve 端口、serve-token 均为 SDK 私产;runtime.client 的 baseUrl 由本地代理注入,令牌不外泄。宿主代码中不应出现端口号或 guest 路径字面量。
  • 停止:runtime.shutdown() 按 serve → proot 子树 → 前台服务顺序回收。

05保活与权限

sdk-runtime 清单已声明并合并以下权限;前台服务类型为 mediaPlayback(国产 ROM 后台存活实证最优),通知文案与图标由宿主注入。

INTERNET / FOREGROUND_SERVICE / FOREGROUND_SERVICE_MEDIA_PLAYBACK
WAKE_LOCK / ACCESS_NETWORK_STATE / POST_NOTIFICATIONS
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS   // 电池优化白名单引导
  • 四层保活防线的状态检查与引导 Intent 经 runtime.keepAlive.requirements() 暴露;引导页面由宿主渲染(如电池优化白名单、自启动管理)。
  • 本地代理与 serve 均为 127.0.0.1 明文 HTTP;宿主若自设 networkSecurityConfig,以宿主为准(library 清单低优先级,静默覆盖)。

06物料与更新

  • 物料经 OSS 分发,SHA256 MANIFEST 逐项校验后释放;init 编排幂等,中断可断点续做。
  • 升级时自动重铺物料并自愈对齐;Initializing.firstInstall = false 即该场景。
  • SDK 版本(根 build 单源,宿主关于页经 BuildConfig 自动跟随)与物料版本两轨独立递增,互不绑架。
  • 诊断:readRuntimeErrorReport() 读 runtime-error.json 五字段;readInitProgress() 读 init 进度原文。

07API 一览

AgentClient 为纯 Kotlin 协程接口(suspend / Flow),KMP commonMain,零 Android 类型。

生命周期
  • awaitReady()等待 serve 就绪,discovery 空窗内建重试
  • serveReady(): Flow<Unit>「不可达→可达」跃变广播,供自愈重拉
  • runtimeState(): Flow<RuntimeState>初始化进度 / 运行中 / 异常
会话
  • createSession(title?)thread scope 强制内建,防混线
  • listSessions()封套 / 裸数组双兼容;懒建流
  • deleteSession(id)归档语义:转录移 archive,列表不再返回
  • renameSession(id, name)进程内存语义,跨重启持久化归 App 层
事件流 & prompt
  • events(sessionId): Flow<AgentEvent>SSE→Flow;仅活跃会话自动恢复
  • prompt(sessionId, text, attachments)退避重试内建;404→resume 链
  • abortSession(id)中止进行中 turn
  • answerQuestion / cancelQuestionask_user_question 应答与取消
MCP
  • mcpStates(): Flow<List<McpServerState>>connected / connecting / disabled
  • setMcpEnabled(server, enabled)官方路由优先,回落写 settings
  • addMcpServer / updateMcpServer / removeMcpServer落盘先、REST 条件性后
  • importMcpServers / previewImportMcpServers / exportMcpServer批量导入预览与导出
  • warmupMcpConnections(previousId?)隐藏 thread 预热,id 由 App 持久化与过滤
设置 & 模型目录
  • getSettings() / setModel(provider, model, overrides?)settings.json 类型化投影
  • setSessionModel / sessionModelOverride / writeSessionModelOverride会话级模型覆写
  • refreshModelCatalog() / readModelCatalog()动态目录并集合并 / 纯文件投影
  • listEduProviders / setApiKey / addCustomProvider / removeCustomProvider提供商与密钥(加密存储)
  • setVoiceInputService / resolveVoiceTarget()语音 ASR 选择与目标解析
技能 · 工作区 · 诊断
  • listSkills()serve 只读投影;写路径走 runtime.skills
  • runtime.workspace / runtime.attachments文件列举、路径翻译、附件落盘
  • restoreTranscript(sessionId)磁盘 jsonl 重建,含 tool part
  • serveLogs(lines) / execDebugCommand(cmd)运行状态面板数据源(白名单强制)
  • close()释放 SSE 与协程域,实例不可再用

08构建与混淆

  • R8:无需额外规则;capability-fileopen 的 JNI 反射面 keep 规则随 AAR 的 consumer rules 分发,随包免疫。
  • 明文:仅 127.0.0.1 本地通信使用 cleartext;对外网络全部走宿主自己的 HTTPS 栈。
  • KMP:sdk-client 位于 commonMain,零 Android 类型,iOS 目标预留;宿主无需关心平台分支。
  • 清单合并:sdk-runtime 的 service / 权限声明随 AAR 合并;宿主同名配置优先级更高,不产生冲突。

09常见问题

  • 冷启动要多久?首装需释放并校验物料,进度经 Initializing 可见;非首装为秒级。discovery 空窗(t≈5–12s)已由 awaitReady 内建重试吸收。
  • 初始化 Failed 怎么办?readRuntimeErrorReport() 取五字段诊断(含 diagnosticsPath),按报告指引修复后重新 initialize();init 幂等,可断点续做。
  • 删除会话为何不是物理删除?deleteSession 是归档语义(转录移入 archive),保证可审计与误删可恢复;幂等,重复删除不报错。
  • 重命名重启后丢了?renameSession 为进程内存语义,跨重启持久化归 App 层,重启后以持久化值重放一次即可。
  • 会话列表里有幽灵会话?预热会话由 warmupMcpConnections 产生,id 返回给 App;请在 UI 过滤并持久化该 id,下次调用传回 previousId
  • 能在主线程调用吗?全部为 suspend / Flow,请在协程域(viewModelScope / lifecycleScope)消费;不要在主线程阻塞等待。

10版本与支持

  • 当前版本 0.1.1;版本号在 SDK 根 build 单源维护,宿主关于页经 BuildConfig.SDK_VERSION 自动跟随。
  • 现阶段以 composite build / publishToMavenLocal 分发;私有仓库坐标与集成支持随接入开通提供。
  • 行为规格以仓库内 spec 文档为准(A1-QwenAndroid/agent-runtime-sdk-native-android.md);本文档与其冲突时以 spec 为准。