2026年7月5日 3 分钟阅读

Dart Agent Core 实战教程:在 Flutter 应用中集成 AI Agent,给移动端加上智能对话能力

tinyash 0 条评论

当你的 Flutter 应用需要 AI 能力时,常规做法是写一个后端服务(Python 或 Node.js),然后在移动端调用 API。但有了 Dart Agent Core,你可以在 Dart/Flutter 中直接运行完整的 AI Agent 循环——工具调用、多轮记忆、技能系统、子代理,全在客户端完成,不需要后端。

为什么在 Flutter 中直接运行 Agent?

大部分 AI Agent 框架都是 Python 或 Node.js 生态的,在移动端部署意味着:

  • 需要额外搭建一个后端 Proxy 服务
  • 网络延迟增加,离线场景完全不可用
  • 状态管理复杂,会话上下文跨网络传输慢

Dart Agent Core(GitHub,MIT,31⭐)直接解决了这些问题。它实现了完整的 Agent 循环状态机——LLM 调用、工具执行、多轮对话、技能管理、子代理调度,全部在 Dart 中运行。支持 OpenAI、Gemini、Claude 等主流模型,覆盖 Android、iOS、Web、Windows、macOS、Linux 全部六平台,WebAssembly 兼容。

快速上手:一个天气 Agent

安装依赖后,创建一个带工具调用的天气查询 Agent 只需要几十行代码。

dependencies:
  dart_agent_core: ^2.0.4
import 'dart:io';
import 'package:dart_agent_core/dart_agent_core.dart';

String getWeather(String location) {
  if (location.toLowerCase().contains('tokyo')) return 'Sunny, 25°C';
  return 'Weather data not available for this location';
}

void main() async {
  final apiKey = Platform.environment['OPENAI_API_KEY'] ?? '';
  final client = OpenAIClient(apiKey: apiKey);
  final modelConfig = ModelConfig(model: 'gpt-4o-mini');

  final weatherTool = Tool(
    name: 'get_weather',
    description: 'Get the current weather for a city.',
    executable: getWeather,
    parameters: {
      'type': 'object',
      'properties': {
        'location': {
          'type': 'string',
          'description': 'City name, e.g. Tokyo',
        },
      },
      'required': ['location'],
    },
  );

  final agent = StatefulAgent(
    name: 'weather_agent',
    client: client,
    tools: [weatherTool],
    modelConfig: modelConfig,
    state: AgentState.empty(),
    systemPrompts: ['You are a helpful assistant.'],
  );

  final responses = await agent.run([
    UserMessage.text('What is the weather like in Tokyo right now?'),
  ]);

  print((responses.last as ModelMessage).textOutput);
}

执行逻辑很清晰:Agent 收到用户消息 → LLM 决定调用 get_weather 工具 → Dart 函数执行 → 结果返回给 LLM → LLM 生成自然语言回复。整个过程在同一 Dart 进程中完成,零网络跳转。

在 Web 环境中运行

Dart Agent Core 的一大亮点是 WebAssembly 兼容。在 Web 平台上,Platform.environment 不可用,需要通过浏览器 localStorage 读取 API Key:

import 'package:web/web.dart' as web;
import 'package:dart_agent_core/dart_agent_core.dart';

void main() async {
  final apiKey = web.window.localStorage.getItem('OPENAI_API_KEY') ?? '';
  final client = OpenAIClient(apiKey: apiKey);
  // 其余代码与 Quick Start 相同
}

Web 环境下使用 package:web(WASM 兼容),避免已废弃的 dart:html。状态存储改用 localStorage 或内存存储,而非 FileStateStorage

多模型支持:一套 API,多个 Provider

不需要为每个模型写不同的接入逻辑。Dart Agent Core 统一了 LLMClient 接口:

// OpenAI Chat Completions
final client = OpenAIClient(
  apiKey: Platform.environment['OPENAI_API_KEY'] ?? '',
);

// OpenAI Responses API(状态化接口,自动传递 previous_response_id)
final client = ResponsesClient(
  apiKey: Platform.environment['OPENAI_API_KEY'] ?? '',
);

// Google Gemini
final client = GeminiClient(
  apiKey: Platform.environment['GEMINI_API_KEY'] ?? '',
);

// Claude(直接调用 Anthropic Messages API)
final client = ClaudeClient(
  apiKey: Platform.environment['ANTHROPIC_API_KEY'] ?? '',
);

// AWS Bedrock(Claude,使用 SigV4 认证)
final client = BedrockClaudeClient(
  region: 'us-east-1',
  accessKeyId: Platform.environment['AWS_ACCESS_KEY_ID'] ?? '',
  secretAccessKey: Platform.environment['AWS_SECRET_ACCESS_KEY'] ?? '',
);

此外还支持 Kimi(Moonshot AI)、Qwen(阿里 DashScope)、Zhipu GLM、豆包 Seed、MiniMax 等国产模型,以及 Ollama(本地模型)和 OpenRouter(统一路由)。

技能系统:让 Agent 按需加载能力

Dart Agent Core 支持两种技能模式,让 Agent 能动态加载和卸载能力模块,避免上下文窗口被无关 prompt 占满。

Pure Dart Skills 将系统 prompt 和工具绑定在一起:

class CodeReviewSkill extends Skill {
  CodeReviewSkill() : super(
    name: 'code_review',
    description: 'Review code for bugs and style issues.',
    systemPrompt: 'You are an expert code reviewer...',
    tools: [readFileTool, lintTool],
  );
}

final agent = StatefulAgent(
  skills: [CodeReviewSkill(), DataAnalysisSkill()],
);

技能默认是惰性激活的——Agent 通过内置的 activate_skills / deactivate_skills 工具,在需要时动态启用。也可以设置 forceActivate: true 让技能常驻。

文件系统技能则从本地目录加载 SKILL.md 文件,支持 JavaScript 脚本执行:

final agent = StatefulAgent(
  skillDirectoryPath: '/path/to/skills_root',
  javaScriptRuntime: NodeJavaScriptRuntime(),
);

当配置了 javaScriptRuntime 时,框架会暴露 RunJavaScript 工具,让 Agent 能执行本地 JS 脚本。在 Flutter 中,可以通过 flutter_js 包实现:

final agent = StatefulAgent(
  javaScriptRuntime: FlutterJavaScriptRuntime(
    runtime: flutter_js.getJavascriptRuntime(),
  ),
);

// 注册桥接通道,让 JS 调用 native 能力
agent.registerJavaScriptBridgeChannel('local.greeting', (payload, context) {
  final name = (payload['name'] ?? 'friend').toString();
  return {'message': 'Hello, $name'};
});

子代理调度:多 Agent 协作

复杂任务可以拆解给多个子代理并行处理。每个子代理有自己的隔离状态:

final agent = StatefulAgent(
  subAgents: [
    SubAgent(
      name: 'researcher',
      description: 'Searches the web and summarizes findings.',
      agentFactory: (parent) => StatefulAgent(
        name: 'researcher',
        client: parent.client,
        modelConfig: parent.modelConfig,
        state: AgentState.empty(),
        tools: [webSearchTool],
        isSubAgent: true,
      ),
    ),
  ],
);

主 Agent 通过内置 delegate_task 工具调度任务:assignee: 'clone' 克隆当前 Agent 的副本,assignee: 'researcher' 使用指定的子代理。

流式输出与实时 UI

在 Flutter 中做实时 UI 更新,使用 runStream() 替代 run()

await for (final event in agent.runStream([UserMessage.text('Hello')])) {
  switch (event.eventType) {
    case StreamingEventType.modelChunkMessage:
      // 流式文本逐块更新 UI
      break;
    case StreamingEventType.functionCallRequest:
      // 模型请求调用工具
      break;
    case StreamingEventType.functionCallResult:
      // 工具执行完成
      break;
  }
}

Agent Hooks:在管线中插一脚

如果你需要在 Agent 执行的特定阶段插入自定义逻辑,Agent Hooks 是最灵活的方式。支持的钩子点包括:beforeRunbeforeModelCallafterModelCallbeforeToolCallafterToolCall 等。

class DeleteFilePolicyHook extends AgentHook {
  @override
  ToolCallHookResult beforeToolCall(ToolCallHookContext context) {
    if (context.call.name != 'delete_file') {
      return ToolCallHookResult.proceed(context.call);
    }
    return ToolCallHookResult.deny(
      content: [TextPart('delete_file is blocked by local policy.')],
    );
  }
}

final agent = StatefulAgent(
  hooks: [DeleteFilePolicyHook()],
);

这个例子展示了如何在工具调用之前进行安全策略拦截——对于生产环境的 Agent 来说,这是必不可少的能力。

会话压缩与长期记忆

长时间运行的 Agent 会积累大量上下文。Dart Agent Core 的 LLMBasedContextCompressor 能在 token 数超过阈值时自动压缩旧消息为情景记忆:

final agent = StatefulAgent(
  compressor: LLMBasedContextCompressor(
    client: client,
    modelConfig: ModelConfig(model: 'gpt-4o-mini'),
    totalTokenThreshold: 64000,
    keepRecentMessageSize: 10,
  ),
);

Agent 可以通过内置的 retrieve_memory 工具在被压缩的记忆中检索原始信息,兼顾长上下文和 token 成本。

适合哪些场景?

Dart Agent Core 最适合的用法不是替代后端服务,而是在移动端或桌面端直接运行轻量 Agent的场景:

  • 本地助手:在 Flutter 桌面应用中嵌入一个能操作本地文件的 AI 助手
  • 离线优先:搭配 Ollama 等本地模型,在网络不稳定的环境中运行
  • 原型验证:快速在移动端验证 Agent 交互流程,确认后再考虑后端化
  • Web 嵌入式工具:在 WASM 环境中运行单次工具调用,零服务器成本

如果你正在用 Flutter 开发,并且想让你的应用拥有一个真正的 AI Agent(不只是调 API 聊天),Dart Agent Core 提供了一个完整的、纯 Dart 的解决方案。MIT 许可证,31⭐,文档完善,上手门槛很低。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。