跳转至

快速开始:纯客户端

Agent 在自己的服务端、远程 A2A Agent 或 ACP 编码 Agent 中运行,应用渲染会话。需要 ai-elements-ui 和对应 backend;AI SDK / AG-UI 使用 ai-elements-core。

App 配置

在 src/main/AndroidManifest.xml 声明网络访问:

<uses-permission android:name="android.permission.INTERNET" />

仅测试本地参考服务时,在 debug manifest(src/debug/AndroidManifest.xml)允许 HTTP:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:usesCleartextTraffic="true" />
</manifest>

生产端点使用 HTTPS。模拟器用 10.0.2.2 访问电脑,localhost 指模拟器自己。连接失败时先检查服务 /health、bind address 和防火墙,再调整 backend。

一个 composable

在 Compose activity 的 setContent 中使用这些 imports:

import dev.ai.elements.ui.theme.AiElementsTheme
import dev.ai.elements.ui.chat.Chat
import dev.ai.elements.ui.chat.rememberChat
import dev.ai.elements.core.protocol.agui.AgUiBackend

Chat 将会话、工具、审批、子 Agent、计划和输入连接到 ChatController:

AiElementsTheme {
    Chat(rememberChat { approver -> AgUiBackend("https://agents.example.com/api/agui", approver = approver) })
}

rememberChat 向 backend 提供 approver,在对话中显示人工审批及表单。

ViewModel

正式应用在 ViewModel 中持有 controller,避免配置变化丢失会话。需要更多控制时自行组合组件:

class ChatViewModel : ViewModel() {
    // An AG-UI agent (Pydantic AI, LangGraph, CrewAI, Mastra…). Tools that need approval pause
    // the run as an AG-UI interrupt; the UI shows a Confirmation and resumes it.
    val chat = ChatController(backend = { approver ->
        AgUiBackend("https://agents.example.com/api/agui", approver = approver)
    }, scope = viewModelScope)
}

@Composable
fun ChatScreen(vm: ChatViewModel) {
    val state by vm.chat.state.collectAsStateWithLifecycle()
    var input by rememberSaveable { mutableStateOf("") }
    AiElementsTheme {
        Column(Modifier.fillMaxSize().imePadding()) {
            Conversation(
                state = state,
                modifier = Modifier.weight(1f),
                onRegenerate = vm.chat::regenerate,
                onToolApproval = vm.chat::respondToApproval,
                onToolDecision = vm.chat::respondToApproval,   // deny with a reason, edit then approve
                onInputResponse = vm.chat::respondToInput,     // forms the agent asks the user to fill
                onSelectVersion = vm.chat::selectVersion,
                onRestoreCheckpoint = vm.chat::restoreCheckpoint,
            )
            PromptInput(
                value = input,
                onValueChange = { input = it },
                onSubmit = { if (vm.chat.send(input)) input = "" },
                onStop = vm.chat::stop,
                busy = state.isBusy,
                allowQueue = true,
            )
        }
    }
}

服务端的子 Agent、计划、共享状态和活动自动渲染。例如 delegate_task 或 AG-UI SUBAGENT_* 显示为带嵌套运行的 Subagent 卡片。

选择 backend

所有 backend 都是 ChatBackend,按 Agent 协议选择:

// AI SDK 5 / 6 UI Message Stream (any `toUIMessageStreamResponse()` server)
{ approver -> UiMessageStreamBackend("https://agents.example.com/api/chat", approver = approver) },
// AG-UI 1.x (Pydantic AI, LangGraph, CrewAI, Mastra, …)
{ approver -> AgUiBackend("https://agents.example.com/api/agui", approver = approver) },
// A2A 1.0 remote agent (ai-elements-a2a)
{ _ -> A2aBackend(A2aAgent("https://agents.example.com")) },
// Agent Client Protocol coding agent (ai-elements-acp)
{ approver -> AcpBackend(AcpAgent.webSocket("wss://dev-box.example.com/acp"), approver) },
// A model API on the device, with the built-in agent loop
{ approver ->
    ProviderProfile("openai", "OpenAI", ProviderKind.OPENAI_RESPONSES, "https://api.openai.com/v1", "gpt-5.5")
        .createBackend(apiKey = "…", approver = approver)
},

协议 对比各协议及服务端接入方式。

连接参考服务

仓库的 参考服务 使用 Pydantic AI,通过全部协议提供服务,scripted model 不需要 API key:

cd server && uv sync
uv run uvicorn main:app --host 0.0.0.0 --port 8788

模拟器使用 http://10.0.2.2:8788/api/agui,真机使用电脑局域网地址。

samples/pure-client 是此模式的完整最小应用。

生命周期与错误

rememberChat 作用域为 composition,适合原型。ViewModel 保留配置变化中的状态,但不跨进程死亡:应用需保存消息,并在创建 controller 时通过 initialMessages 恢复。

在主线程调用 controller,使用 viewModelScope。Stop 取消本轮,传输错误写入 ChatState.error。Retry 发起新一轮,不从上一条流中途重连,见 保存与回放。