[Flutter] Firebase Vertex AI: Function Calling 사용예제

이건선·2025년 1월 22일
0

Flutter

목록 보기
30/30

소개

공식 문서 확인하기

요약

함수 호출 기능은 모델이 API 및 함수와 같은 외부 도구를 사용하여 최종 응답을 생성할 수 있도록 지원합니다.


시나리오

  1. 유저 질의: "2024년 10월 17일 보스턴 날씨는 어땠나요?"
  2. AI 동작: 유저의 질문을 이해하고 Mock API 호출.
  3. API 결과 반환: Mock API 응답 데이터를 기반으로 유저에게 답변 제공.

코드 설명

1. 함수 선언 정의


  static final fetchWeatherTool = FunctionDeclaration(
    'fetchWeather',
    'Get the weather conditions for a specific city on a specific date.',
    Schema.object(properties: {
      'location': Schema.object(
        description:
        'The name of the city and its state for which to get'
            'the weather. Only cities in the USA are supported.',
        properties: {
          'city': Schema.string(
              description: 'The city of the location.'
          ),
          'state': Schema.string(
              description: 'The US state of the location.'
          ),
        },
      ),
      'date': Schema.string(
          description:
          'The date for which to get the weather. Date must be in the format: YYYY-MM-DD.'
      ),
    }),
  );

FunctionDeclaration 주요 파라미터

  • name: 함수 이름
  • description: 유저 입력 데이터를 이해하고 처리하기 위한 함수 설명
  • parameters: 입력 데이터에 기반한 구조화된 데이터 스키마 생성

자세히 알아보기

2. 모델 초기화 시 함수 선언 추가


  final model = FirebaseVertexAI.instance.generativeModel(
    tools: [
      Tool(functionDeclarations: [fetchWeatherTool])
    ],
    model: 'gemini-1.5-flash',
  );

3. 외부 API 호출 (Mock API)


  Future<Map<String, Object?>> fetchWeather(
     Location location, String date
     ) async {

   // TODO(developer): Write a standard function that would call to an external weather API.

   // For demo purposes, this hypothetical response is hardcoded here in the expected format.
   final apiResponse = {
     'temperature': 38,
     'chancePrecipitation': '56%',
     'cloudConditions': 'partlyCloudy',
   };
   return apiResponse;
 }

4. 함수 호출로 외부 API 호출 연결


onPressed: () async {
 final chat = model.startChat();
 const prompt = 'What was the weather in Boston on October 17, 2024?';

 // 유저 입력 전송
 var response = await chat.sendMessage(Content.text(prompt));
 final functionCalls = response.functionCalls.toList();

 if (functionCalls.isNotEmpty) {
   final functionCall = functionCalls.first;
   if (functionCall.name == 'fetchWeather') {
     Map<String, dynamic> location = functionCall.args['location'] as Map<String, dynamic>;
     var date = functionCall.args['date'] as String;
     var city = location['city'] as String;
     var state = location['state'] as String;

     // Mock API 호출
     final functionResult = await fetchWeather(Location(city: city, state: state), date);

     // 모델에 결과 전달
     response = await chat.sendMessage(Content.functionResponse(functionCall.name, functionResult));

     print(response.text);
   } else {
     throw UnimplementedError('Function not declared: ${functionCall.name}');
   }
 }
}

결과


전체 코드



class Location {
  final String city;
  final String state;

  Location({required this.city, required this.state});
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  static final fetchWeatherTool = FunctionDeclaration(
    'fetchWeather',
    'Get the weather conditions for a specific city on a specific date.',
    Schema.object(properties: {
      'location': Schema.object(
        description:
        'The name of the city and its state for which to get'
            'the weather. Only cities in the USA are supported.',
        properties: {
          'city': Schema.string(
              description: 'The city of the location.'
          ),
          'state': Schema.string(
              description: 'The US state of the location.'
          ),
        },
      ),
      'date': Schema.string(
          description:
          'The date for which to get the weather. Date must be in the format: YYYY-MM-DD.'
      ),
    }),
  );

// This function calls a hypothetical external API that returns
// a collection of weather information for a given location on a given date.
// `location` is an object of the form { city: string, state: string }
  Future<Map<String, Object?>> fetchWeather(
      Location location, String date
      ) async {

    // TODO(developer): Write a standard function that would call to an external weather API.

    // For demo purposes, this hypothetical response is hardcoded here in the expected format.
    final apiResponse = {
      'temperature': 38,
      'chancePrecipitation': '56%',
      'cloudConditions': 'partlyCloudy',
    };
    return apiResponse;
  }

  final model = FirebaseVertexAI.instance.generativeModel(
    tools: [
      Tool(functionDeclarations: [fetchWeatherTool])
    ],
    model: 'gemini-1.5-flash',
  );

  String showData = '';

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(showData),
            ElevatedButton(
                onPressed: () async {
                  final chat = model.startChat();
                  const prompt = 'What was the weather in Boston on October 17, 2024?';

                  // 유저 입력 전송
                  var response = await chat.sendMessage(Content.text(prompt));
                  final functionCalls = response.functionCalls.toList();

                  if (functionCalls.isNotEmpty) {
                    final functionCall = functionCalls.first;
                    if (functionCall.name == 'fetchWeather') {
                      Map<String, dynamic> location = functionCall.args['location'] as Map<String, dynamic>;
                      var date = functionCall.args['date'] as String;
                      var city = location['city'] as String;
                      var state = location['state'] as String;

                      // Mock API 호출
                      final functionResult = await fetchWeather(Location(city: city, state: state), date);

                      // 모델에 결과 전달
                      response = await chat.sendMessage(Content.functionResponse(functionCall.name, functionResult));

                      print(response.text);
                    } else {
                      throw UnimplementedError('Function not declared: ${functionCall.name}');
                    }
                  }
                },
                child: Text("생성"))
          ],
        ),
      ),
    );
  }
}
profile
멋지게 기록하자

0개의 댓글