EVA Flutter SDK
autoark_eva_client_sdk 是 AutoArk AI 提供的 EVA Flutter 端侧 SDK。
它在 Android 原生侧编排媒体、Silero VAD、会话状态、command 与 emotion,并通过固定 EVA Gateway
使用 ASR、LLM 和 TTS。Dart 侧提供稳定 facade、事件流以及可选 media SPI。
当前版本仅支持 Android;iOS 暂不支持。
安装
flutter pub add autoark_eva_client_sdk
Android 运行时已包含在 package 中。Dart facade 与 Android thin shell 以源码交付,原生运行时以经过 R8 加固的编译二进制交付;这种加固用于减少内部实现暴露,不承诺绝对防逆向。接入方只需添加 pub dependency;生产应用应锁定自己验收过的完整 pub version。
环境要求
- Flutter:
>=3.3.0;Dart SDK:^3.12.2。 - Android:
minSdk 24,支持arm64-v8a。 - Android 构建使用 Java 17 toolchain。
- 默认媒体 helper 使用
AudioRecord、AudioTrack、capture-side Android system AEC 与 CameraX。 - plugin manifest 自动声明普通权限
INTERNET,以及运行时权限RECORD_AUDIO、CAMERA。联网权限不会 弹系统授权框;宿主应用仍负责在调用相应 enable 方法前完成麦克风、相机授权与用户说明。 - plugin 随包提供 ONNX Runtime JNI 所需的 Android release shrinker rules;宿主无需手工添加 ProGuard/R8 keep 配置。
- iOS 当前不受支持。
完整 Android 语音对话示例
下面示例使用 SDK 的 Android 默认媒体 helper。applicationManagedApiKey 应由应用自己的安全配置或
后端会话流程注入,不要把真实 AK 写进源码、日志或公开构建参数。
import 'package:autoark_eva_client_sdk/autoark_eva_client_sdk.dart';
Future<void> runEva(String applicationManagedApiKey) async {
final EvaAgent agent = EvaAgent.create(
EvaAgentConfig(
apiKey: applicationManagedApiKey,
asr: const EvaAsrConfig(
model: 'ark-asr-plus',
sampleRate: 16000,
),
llm: EvaLlmConfig(
model: 'volcengine-doubao-seed-2.0-lite',
extraParameters: const <String, Object?>{
'thinking': <String, Object?>{'type': 'disabled'},
},
),
tts: const EvaTtsConfig(
model: 'ark-tts-flash',
voice: 'zh_en_male_evan',
sampleRate: 44100,
),
vad: const EvaVadConfig(
sensitivity: 0.6,
silenceThresholdMs: 400,
),
history: const EvaHistoryConfig(maxTurns: 10),
camera: const EvaCameraConfig(captureTimeoutMs: 1500),
emotion: EvaEmotionConfig(enabled: true),
),
);
final subscription = agent.events.listen((EvaAgentEvent event) {
switch (event.type) {
case EvaAgentEventType.replyPartial:
final Object? text = event.payload['text'];
if (text is String) print(text);
break;
case EvaAgentEventType.error:
print('EVA error: ${event.error?.message}');
break;
default:
break;
}
});
try {
await agent.start();
await agent.setAudioInputEnabled(true);
// Camera 默认关闭;宿主取得 CAMERA runtime permission 后再显式开启。
await agent.setCameraEnabled(true);
await agent.submitText('你好');
} finally {
await agent.stop();
await subscription.cancel();
}
}
agent.start() 不会自动打开麦克风或摄像头。调用方应在取得对应 runtime permission 后分别调用
setAudioInputEnabled(true) 和 setCameraEnabled(true)。stop() 会收束在途 turn 并释放 SDK 持有的
媒体资源。
哪些可以不选
| 项 | 是否必需 | 省略后的行为 |
|---|---|---|
apiKey、asr、llm、tts |
Agent 构造必需 | 不能省略;model、voice 与授权以 EVA Models 和租户为准。 |
vad |
可选 | 使用 sensitivity=0.5、silenceThresholdMs=200。 |
transports |
可选 | Android 使用 SDK 默认 AudioRecord/AudioTrack/system AEC/CameraX helper。 |
camera |
可选 | 使用稳定的 1500 ms capture timeout;摄像头仍保持关闭,直到显式 enable。 |
greeting、history、bargeIn |
可选 | 分别保持无问候、turn 间无额外历史、无首次播放保护窗。 |
emotion |
可选 | 不执行 emotion 旁路分类。 |
commands、metadata、systemPrompt |
可选 | 不注册 command、不附加业务 metadata、使用空 system instruction。 |
这些能力也可以在 Agent 运行期间开启或关闭:
setAudioInputEnabled()控制后续麦克风输入;setCameraEnabled()控制持续 camera session 与 turn 图片采集;setTtsEnabled()控制后续语音合成与播放。
Agent API
EvaAgent.create(config) 返回 EvaAgent。主要公共面包括:
| 成员 | 作用 |
|---|---|
events |
单一 Stream<EvaAgentEvent> 行为观察流。 |
start() |
启动 Android 原生 runtime。 |
submitText(text, options:) |
提交一个非空手动文本 turn。 |
setAudioInputEnabled(enabled) |
开启或关闭后续音频输入并等待资源转换。 |
setCameraEnabled(enabled) |
开启或关闭持续 camera session。 |
setTtsEnabled(enabled) |
控制后续 TTS 合成与播放。 |
getMessages() |
读取最终消息的不可变快照。 |
stop() |
收束在途工作并进入终态;重复调用安全。 |
Agent 停止后进入终态;需要新会话时创建新的 Agent。getMessages() 返回当前最终消息的不可变快照,
partial transcript/reply 不进入最终历史。
配置
README 介绍顶层配置及用途。字段级必填性、默认值、范围、单位和校验规则以对应类型的双语 dartdoc 与 pub.dev API reference 为准。
EvaAgentConfig:单个 Agent 的顶层托管配置。EvaAsrConfig:ASR model 与目标 PCM 采样率。EvaLlmConfig:LLM model、生成参数与扩展参数。EvaTtsConfig:TTS model、voice、语速、音高与采样率。EvaVadConfig:本地 Silero VAD 调音。EvaGreetingConfig:disabled、static、dynamic 三种启动问候策略的基类。EvaHistoryConfig:有界 LLM 对话历史。EvaCameraConfig:camera capture 时序。EvaBargeInConfig:首次 playback 后的 speech admission 保护窗。EvaEmotionConfig:emotion 旁路分类。EvaCommandsConfig:command 注册与每 turn 预算。EvaSubmitTextOptions:单次手动文本 turn 的 identity 与 metadata。
| 顶层配置 / 入口 | 控制什么 |
|---|---|
EvaAgentConfig.apiKey |
Gateway 凭证;只用于 SDK 访问 Gateway,不提供 getter 回读。 |
EvaAgentConfig.asr |
ASR model 与目标 PCM 采样率。 |
EvaAgentConfig.llm |
LLM model、temperature、token 上限与 JSON-compatible 扩展参数。 |
EvaAgentConfig.tts |
TTS model、voice、语速、音高与合成采样率。 |
EvaAgentConfig.vad |
本地 Silero VAD sensitivity 与静音阈值。 |
EvaAgentConfig.systemPrompt |
每次 LLM 请求使用的 system instruction。 |
EvaAgentConfig.greeting |
disabled、static 或 dynamic 启动问候。 |
EvaAgentConfig.history |
后续 LLM 请求最多携带多少个完整 turn。 |
EvaAgentConfig.camera |
单次图片采集等待时限,不会自动启用摄像头。 |
EvaAgentConfig.emotion |
emotion 分类开关、code 目录、业务 instructions 与输入上限。 |
EvaAgentConfig.bargeIn |
首次实际 playback 后的 speech admission 保护窗。 |
EvaAgentConfig.commands |
command definitions、Dart handlers 与每 turn raw-call 上限。 |
EvaAgentConfig.metadata |
附加到事件、消息与 command context 的稳定业务 metadata。 |
EvaAgentConfig.transports |
可选的 Dart media SPI 装配;省略时使用 Android 默认 helper。 |
EvaSubmitTextOptions |
单次手动文本 turn 的可选 identity 与 metadata。 |
EvaMediaTransports |
自定义 audio input/output、AEC 与可选 camera 四个 media role。 |
llm.extraParameters 会直接加入 LLM request body 顶层,但不能覆盖 SDK 管理的字段。可用字段和值域由
Gateway 与所选模型决定。
External configuration references / 外部配置参考
- 在 EVA 控制台 创建 API Key;也可参考 EVA Skill 和 EVA CLI。
- ASR、LLM、TTS model、TTS voice 与模型参数见 EVA Models。
model 与 voice 是服务目录中的不透明 ID。示例值用于说明配置形状,不替代租户权限和目标环境验收。
Emotion
Emotion 是默认关闭的旁路分类能力,需要在构造 Agent 时通过 EvaEmotionConfig 开启:
final EvaEmotionConfig emotion = EvaEmotionConfig(
enabled: true,
labels: <String>['happy', 'sad'],
instructions: '这是儿童陪伴场景,重点区分害怕、难过和开心。',
maxInputChars: 2000,
);
省略 labels 时使用 EvaEmotionCodes.defaults:neutral、happy、sad、angry、anxious、
confused、excited、frustrated、unknown。custom labels 会完整替换默认业务 code,必须匹配
^[a-z][a-z0-9_-]{0,63}$ 且不得为空或重复;SDK 会在缺失时补充唯一的 unknown。instructions 只用于
补充场景和业务判断背景,不是一份完整 prompt;maxInputChars 默认为 2000。
分类结果通过 emotion.detected 旁路事件上报:
agent.events.listen((EvaAgentEvent event) {
if (event.type != EvaAgentEventType.emotionDetected) return;
final EvaEmotionDetectedPayload? emotion = event.emotion;
if (emotion == null) return;
print('${emotion.emotionCode}: ${emotion.confidence}');
});
emotion.source 区分 speech 和 text,emotionCode 始终位于当前有效 code 空间内,无法可靠映射时为
unknown。confidence 若存在则位于 [0,1],它是模型自报值,不是经过校准的概率或准确率承诺;
textPreview 最多包含 100 个 Unicode code point,仍属于用户内容。
Emotion 与主回复并行,不参与 reply、history、messages 或 TTS 控制,也不保证在 reply 前或后到达。分类请求 失败会产生非致命错误,不会阻断主对话。当前没有 Emotion runtime toggle;需要改变配置时应创建新的 Agent。
Command
Command 在 Agent 构造时通过 EvaCommandsConfig.registrations 注册。definition 会发送给 Android runtime,
handler closure 始终留在 Dart App 进程执行,不经过序列化。
final EvaCommandsConfig commands = EvaCommandsConfig(
registrations: <EvaCommandRegistration>[
EvaCommandRegistration(
definition: EvaCommandDefinition(
name: 'get_store_hours',
description: '查询门店营业时间',
),
handler: (EvaCommandCall call, EvaCommandContext context) async {
return EvaCommandSuccess(message: '门店今天营业到 20:00');
},
),
],
);
maxCallsPerTurn 必须为正整数,省略时为 3。handler 收到取消信号后应尽快停止副作用;turn 结束后返回的
结果不会重新激活它。
事件、消息与错误
所有行为观察都来自 agent.events。事件具有稳定的 type、streamId、可选 turnId/sequence、
partial/finalEvent、metadata 与结构化 payload;业务代码应按 type 和身份字段归类,不依赖到达时间猜测
turn 归属。
稳定事件目录包括 speech、transcript、interruption、reply、playback、turn latency、image、emotion、
command 与 error。EvaStructuredError.source 区分 sdk、provider、gateway、media;非致命错误不一定
终止 Agent,调用方应同时检查 fatal 和业务操作结果。
getMessages() 只返回最终 user/assistant 消息。metadata 在构造或提交 turn 时递归复制,后续修改原 Map
不会改变已经进入 SDK 的快照。
Media SPI 与 Android 默认实现
省略 EvaAgentConfig.transports 时,Android 使用 SDK 提供的默认媒体实现:
- AudioRecord 麦克风采集;
- AudioTrack TTS 播放;
- capture-side Android system AEC,并把 TTS playback 同时作为 far-end reference;
- CameraX 静态图片采集。
音频帧在原生侧闭环,不通过 Dart MethodChannel。需要接入自有设备、已经处理好的音频流或特殊 camera 时,
可以实现 EvaAudioInputSource、EvaAudioOutputSink、EvaAecProcessor、EvaCameraSnapshotSource,再通过
EvaMediaTransports 注入。注入后生命周期由 SDK 独占驱动,应用不要并发调用同一 transport 的
start/stop/capture。
Camera 默认关闭;开启期间 SDK 持有一个 session,并在语音 turn 起点请求图片。权限拒绝、capture 失败或 超时会产生结构化 media error;SDK 仍会继续处理可用的文字或语音输入。
平台支持
| 项 | 0.0.1 状态 |
|---|---|
Android arm64-v8a, API 24+ |
支持 |
| Android emulator | 可用于功能开发和调试 |
| Android 物理设备 | 建议在目标设备上验收麦克风、播放、AEC 和 camera 效果 |
| iOS | 暂不支持 |
麦克风、扬声器、AEC 和 camera 效果会受到具体设备、音频路由与权限状态影响。模拟器适合功能调试,不能 替代目标 Android 真机验收。
AK、隐私与日志边界
- AK 由接入应用负责安全获取、保存、轮换与撤销;不要写入源码、日志、analytics、crash report 或公开构建参数。
- Gateway endpoint 由 SDK 固定,公共配置不提供 base URL、headers、HTTP transport 或 stage provider 注入。
emotion.detected.textPreview、transcript、message 和业务 metadata 可能包含用户内容;写日志前应按应用自己的 隐私与留存规则处理。
许可与 Gateway 服务
本 SDK 是公开下载的专有软件,并非开源软件。SDK 适用 LICENSE 中的 AutoArk AI Proprietary SDK License Agreement;EVA Gateway 是独立服务,适用 GATEWAY_TERMS.md 指向的服务条款。第三方组件适用 THIRD_PARTY_NOTICES.md 中列出的各自许可证。
Libraries
- autoark_eva_client_sdk
- EVA client SDK for Flutter.