flutter实现Function Call

根据Function Call实现用大模型来调用方法。以下实现用操作空调。

一、选用大模型

阿里云百炼:筛选具有Function Call能力的模型

讯飞星火大模型Spark 4.0Ultra、Max 现已支持systemFunction Call功能

二、代码实现(通义千问3-Max)

dart 复制代码
import 'dart:convert';

import 'package:dio/dio.dart';

class FunctionCallService {
  static const String _tag = "FunctionCallService";

  static final FunctionCallService instance = FunctionCallService._();

  FunctionCallService._();

  factory FunctionCallService.getInstance() {
    return instance;
  }

  final List<Map<String, dynamic>> tools = [
    {
      "type": "function",
      "function": {
        "name": "controlAirConditioner",
        "description": "打开空调并设置参数",
        "parameters": {
          "type": "object",
          "properties": {
            "action": {"type": "bool", "description": "打开或关闭"},
            "room": {"type": "string", "description": "空调所在房间"},
            "name": {"type": "string", "description": "空调名称"},
            "temperature": {"type": "number", "description": "目标温度 (16-45摄氏度)"},
            "mode": {
              "type": "string",
              "description": "运行模式",
              "enum": ["cool", "heat", "fan", "dry", "auto"]
            },
            "fan_speed": {
              "type": "string",
              "description": "风速",
              "enum": ["low", "medium", "high", "auto"]
            }
          },
          "required": ["name"]
        },
      }
    }
  ];

  final apiUrl =
      "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";
  // apiKey获取地址:https://bailian.console.aliyun.com/?spm=a2ty02.30268951.0.0.21ae74a17iekVZ&tab=model#/api-key
  final apiKey = "sk-xxx";
  final model = "qwen3-max";

  Future<String> controlAirConditioner(
      {required bool action,
      String? room,
      String? name,
      double? temperature,
      String? mode,
      String? fanSpeed}) async {
    // 实际操作
    return '操作成功';
  }

  final Dio _dio = Dio();

  void handleFunctionCall() async {
    var messages = [];
    messages.add({
      'role': "system",
      "content": "不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息。"
    });
    messages.add({"role": "user", "content": "打开客厅空调到38度"});

    print('$_tag 开始调用模型');
    Response response = await _dio.post(apiUrl,
        data: {'model': model, 'messages': messages, 'tools': tools},
        options: Options(
          headers: {'Authorization': 'Bearer $apiKey'},
        ));
    print('$_tag 第一次调用模型的请求参数:$messages');
    print('$_tag 第一次调用模型的回答结果:${response.data['choices'][0]['message']}');
    messages.add(response.data['choices'][0]['message']);
    parseFunctionCall(
        response.data['choices'][0]['message']['tool_calls'][0]['function'],
        messages);
  }

  void parseFunctionCall(Map toolCall, List messages) async {
    if (toolCall['name'] == 'controlAirConditioner') {
      var arguments = toolCall['arguments'];
      var args = jsonDecode(arguments);
      var content = await controlAirConditioner(
          action: args['action'],
          room: args['room'],
          name: args['name'],
          mode: args['mode'],
          fanSpeed: args['fan_speed'],
          temperature: args['temperature'] != null
              ? double.parse(args['temperature'].toString())
              : null);
      messages.add({'role': 'tool', 'content': content});
      Response response = await _dio.post(apiUrl,
          data: {'model': model, 'messages': messages, 'tools': tools},
          options: Options(
            headers: {'Authorization': 'Bearer $apiKey'},
          ));
      print('$_tag 第二次调用模型的请求参数:$messages');
      print('$_tag 第二次调用模型的回答结果:${response.data['choices'][0]['message']}');
    }
  }
}

📌 运行结果

dart 复制代码
I/flutter (23387): FunctionCallService 开始调用模型
I/flutter (23387): FunctionCallService 第一次调用模型的请求参数:[{role: system, content: 不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息。}, {role: user, content: 打开客厅空调到38度}]
I/flutter (23387): FunctionCallService 第一次调用模型的回答结果:{content: , role: assistant, tool_calls: [{function: {arguments: {"name": "客厅空调", "temperature": 38, "action": true}, name: controlAirConditioner}, id: call_58b2365bdd4e4d9da6f65fb1, index: 0, type: function}]}
I/flutter (23387): FunctionCallService 第二次调用模型的请求参数:[{role: system, content: 不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息。}, {role: user, content: 打开客厅空调到38度}, {content: , role: assistant, tool_calls: [{function: {arguments: {"name": "客厅空调", "temperature": 38, "action": true}, name: controlAirConditioner}, id: call_58b2365bdd4e4d9da6f65fb1, index: 0, type: function}]}, {role: tool, content: 操作成功}]
I/flutter (23387): FunctionCallService 第二次调用模型的回答结果:{content: 客厅空调已成功打开,并设置温度为38度。, role: assistant}
相关推荐
Together_CZ11 小时前
DeepSeek-V4.1-Flash:Pushing the Limits of KV Cache Compression——推动 KV 缓存压缩的极限
缓存·llm·compression·kv cache·deepseek·v4.1-flash·推动 kv 缓存压缩的极限
桃西西呀15 小时前
你拍的一堆硬币,手机怎么一眼数出有几枚?聊聊边缘、轮廓和模板匹配
人工智能·llm·图像识别
slacker-kian17 小时前
[实践]-让 SAP 工程 Skill 脱离 opencode跑在自定义Agent 上
ai·llm·sap·agent·abap·adt·opencode
武子康20 小时前
CLAUDE.md 越写越长,哪些规则该放到子目录?
人工智能·llm·agent
ZFJ_张福杰20 小时前
【Flutter】Flutter 中有哪些耗时操作?从 UI 卡顿到 Isolate 性能优化
flutter·性能优化·卡顿·isolate
武子康21 小时前
两台机器跑 vLLM,什么时候才值得引入 Ray?
人工智能·llm·agent
桃西西呀21 小时前
Agent说做完了,其实什么都没改:静默失败原因拆解
人工智能·llm·agent
sakiko_21 小时前
Flutter:Dart学习笔记1:基础UI组件等
flutter
9765033351 天前
iOS 上架 4.3a 被拒【uniapp专讲】
flutter·ios·objective-c·uniapp·swift
传奇开心果编程2 天前
【Flutter入门练中学】第2课:布局系统
学习·flutter·ui