flutter实现Function Call

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

一、选用大模型

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

讯飞星火大模型:Spark 4.0Ultra、Max 现已支持system 、Function 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}
相关推荐
goehou4 小时前
MCP 查数实战:让 LLM 安全地查数据库(只读账号、SQL 校验、参数漂移)
数据库·ai·llm·教程·mcp·function calling
桃西西呀8 小时前
LangGraph4j之一:客服请求分诊既要循环又要分流,我用 LangGraph4j 把控制流抽成了数据
人工智能·llm·ai编程
用户7217465882610 小时前
默认校验只覆盖 3.18%:bl dataset validate 抽样窗与 capability 三种返回态的字段级拆解
llm·agent·ai编程
大龄秃头程序员10 小时前
Riverpod 深度解析:从响应式本质到最小可运行闭环
flutter
程序员大狐狸11 小时前
Ultra X7 358H 笔记本电脑,寻找本地用于编码的最强大模型,实测 21.0 tok/s,上下文 256K
llm·ai编程
用户83145509803111 小时前
如一 Agent 架构解读(四):异步整理——压缩不该堵住用户
人工智能·llm
曹小强wxx11 小时前
让 AI 写代码不“翻车”:用 Claude Code + Codex 给 Flutter 项目搭一套工程规范
flutter·ai编程·claude
feasibility.11 小时前
“美版DeepSeek”等海外开放模型,能夺回生态入口吗?——中国开放权重领先下的2026全球AI分水岭
人工智能·开源·大模型·llm·minimax·deepseek·beam
M--Y13 小时前
LangChain 提示工程:少样本提示与输出解析器
python·langchain·大模型·llm·输出解析器·少样本提示
西西学代码14 小时前
像素和颜色之间的转换(Flutter)
前端·javascript·flutter