Einführung in Funktionsaufrufe

Funktionsaufrufe, auch als Tool-Nutzung bezeichnet, stellen dem LLM Definitionen externer Tools zur Verfügung, z. B. eine get_current_weather-Funktion. Bei der Verarbeitung eines Prompts ermittelt das Modell intelligent, ob ein Tool erforderlich ist. Wenn ja, gibt es strukturierte Daten aus, die das aufzurufende Tool und seine Parameter angeben (z. B. get_current_weather(location='Boston')). Ihre Anwendung führt dieses Tool dann aus und gibt das Ergebnis an das Modell zurück, sodass es seine Antwort mit dynamischen, realen Informationen oder dem Ergebnis einer Aktion vervollständigen kann. So wird das LLM effektiv mit Ihren Systemen verbunden und seine Funktionen werden erweitert.

Interaktion mit Funktionsaufruf 

Funktionsaufrufe ermöglichen zwei primäre Anwendungsfälle:

  • Daten abrufen: Aktuelle Informationen für Modellantworten abrufen, z. B. aktuelles Wetter, Währungsumrechnung oder bestimmte Daten aus Wissensdatenbanken und APIs (RAG).

  • Aktionen ausführen: Führen Sie externe Vorgänge aus, z. B. Formulare senden, den Anwendungsstatus aktualisieren oder Agent-basierte Workflows koordinieren (z. B. Übergabe von Unterhaltungen).

Weitere Anwendungsfälle und Beispiele, die auf Funktionsaufrufen basieren, finden Sie unter Anwendungsfälle.

Funktionen und Einschränkungen

Anwendung für Funktionsaufrufe erstellen

So verwenden Sie Funktionsaufrufe:

  1. Funktionsdeklarationen und Prompt an das Modell senden.
  2. API-Ausgabe für das Modell übergeben.

Schritt 1: Prompt und Funktionsdeklarationen an das Modell senden

Deklarieren Sie ein Tool in einem Schemaformat, das mit dem OpenAPI-Schema kompatibel ist. Weitere Informationen finden Sie unter Schema-Beispiele.

In den folgenden Beispielen werden ein Prompt und eine Funktionsdeklaration an die Gemini-Modelle gesendet.

REST

PROJECT_ID=myproject
LOCATION=us-central1
MODEL_ID=gemini-2.0-flash-001

curl -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/google/models/${MODEL_ID}:generateContent \
  -d '{
    "contents": [{
      "role": "user",
      "parts": [{
        "text": "What is the weather in Boston?"
      }]
    }],
    "tools": [{
      "functionDeclarations": [
        {
          "name": "get_current_weather",
          "description": "Get the current weather in a given location",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city name of the location for which to get the weather.",
                "default": {
                  "string_value": "Boston, MA"
                }
              }
            },
            "required": [
              "location"
            ]
          }
        }
      ]
    }]
  }'

Python

Sie können das Schema entweder manuell mit einem Python-Wörterbuch oder automatisch mit der Hilfsfunktion from_func angeben. Das folgende Beispiel zeigt, wie eine Funktion manuell deklariert wird.

import vertexai
from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerationConfig,
    GenerativeModel,
    Part,
    Tool,
    ToolConfig
)

# Initialize Vertex AI
# TODO(developer): Update the project
vertexai.init(project="PROJECT_ID", location="us-central1")

# Initialize Gemini model
model = GenerativeModel(model_name="gemini-2.0-flash")

# Manual function declaration
get_current_weather_func = FunctionDeclaration(
    name="get_current_weather",
    description="Get the current weather in a given location",
    # Function parameters are specified in JSON schema format
    parameters={
        "type": "object",
        "properties": {
            "location": {
              "type": "string",
              "description": "The city name of the location for which to get the weather.",
              "default": {
                "string_value": "Boston, MA"
              }
           }
        },
    },
)

response = model.generate_content(
    contents = [
      Content(
        role="user",
          parts=[
              Part.from_text("What is the weather like in Boston?"),
          ],
      )
    ],
    generation_config = GenerationConfig(temperature=0),
    tools = [
      Tool(
        function_declarations=[get_current_weather_func],
      )
    ]
)

Alternativ können Sie die Funktion automatisch mit der Hilfsfunktion from_func deklarieren, wie im folgenden Beispiel gezeigt:

def get_current_weather(location: str = "Boston, MA"):
  """
  Get the current weather in a given location

  Args:
      location: The city name of the location for which to get the weather.

  """
  # This example uses a mock implementation.
  # You can define a local function or import the requests library to call an API
  return {
    "location": "Boston, MA",
    "temperature": 38,
    "description": "Partly Cloudy",
    "icon": "partly-cloudy",
    "humidity": 65,
    "wind": {
        "speed": 10,
        "direction": "NW"
    }
  }
get_current_weather_func = FunctionDeclaration.from_func(get_current_weather)

Node.js

Dieses Beispiel zeigt ein Textszenario mit einer Funktion und einem Prompt.

Node.js

Bevor Sie dieses Beispiel anwenden, folgen Sie den Node.js-Einrichtungsschritten in der Vertex AI-Kurzanleitung zur Verwendung von Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Vertex AI Node.js API.

Richten Sie zur Authentifizierung bei Vertex AI Standardanmeldedaten für Anwendungen ein. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

const {
  VertexAI,
  FunctionDeclarationSchemaType,
} = require('@google-cloud/vertexai');

const functionDeclarations = [
  {
    function_declarations: [
      {
        name: 'get_current_weather',
        description: 'get weather in a given location',
        parameters: {
          type: FunctionDeclarationSchemaType.OBJECT,
          properties: {
            location: {type: FunctionDeclarationSchemaType.STRING},
            unit: {
              type: FunctionDeclarationSchemaType.STRING,
              enum: ['celsius', 'fahrenheit'],
            },
          },
          required: ['location'],
        },
      },
    ],
  },
];

const functionResponseParts = [
  {
    functionResponse: {
      name: 'get_current_weather',
      response: {name: 'get_current_weather', content: {weather: 'super nice'}},
    },
  },
];

/**
 * TODO(developer): Update these variables before running the sample.
 */
async function functionCallingStreamContent(
  projectId = 'PROJECT_ID',
  location = 'us-central1',
  model = 'gemini-2.0-flash-001'
) {
  // Initialize Vertex with your Cloud project and location
  const vertexAI = new VertexAI({project: projectId, location: location});

  // Instantiate the model
  const generativeModel = vertexAI.getGenerativeModel({
    model: model,
  });

  const request = {
    contents: [
      {role: 'user', parts: [{text: 'What is the weather in Boston?'}]},
      {
        role: 'ASSISTANT',
        parts: [
          {
            functionCall: {
              name: 'get_current_weather',
              args: {location: 'Boston'},
            },
          },
        ],
      },
      {role: 'USER', parts: functionResponseParts},
    ],
    tools: functionDeclarations,
  };
  const streamingResp = await generativeModel.generateContentStream(request);
  for await (const item of streamingResp.stream) {
    console.log(item.candidates[0].content.parts[0].text);
  }
}

Go

Dieses Beispiel zeigt ein Textszenario mit einer Funktion und einem Prompt.

Informationen zum Installieren oder Aktualisieren von Go

Weitere Informationen finden Sie in der SDK-Referenzdokumentation.

Umgebungsvariablen für die Verwendung des Gen AI SDK mit Vertex AI festlegen:

# Replace the `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION` values
# with appropriate values for your project.
export GOOGLE_CLOUD_PROJECT=GOOGLE_CLOUD_PROJECT
export GOOGLE_CLOUD_LOCATION=global
export GOOGLE_GENAI_USE_VERTEXAI=True

import (
	"context"
	"fmt"
	"io"

	genai "google.golang.org/genai"
)

// generateWithFuncCall shows how to submit a prompt and a function declaration to the model,
// allowing it to suggest a call to the function to fetch external data. Returning this data
// enables the model to generate a text response that incorporates the data.
func generateWithFuncCall(w io.Writer) error {
	ctx := context.Background()

	client, err := genai.NewClient(ctx, &genai.ClientConfig{
		HTTPOptions: genai.HTTPOptions{APIVersion: "v1"},
	})
	if err != nil {
		return fmt.Errorf("failed to create genai client: %w", err)
	}

	weatherFunc := &genai.FunctionDeclaration{
		Description: "Returns the current weather in a location.",
		Name:        "getCurrentWeather",
		Parameters: &genai.Schema{
			Type: "object",
			Properties: map[string]*genai.Schema{
				"location": {Type: "string"},
			},
			Required: []string{"location"},
		},
	}
	config := &genai.GenerateContentConfig{
		Tools: []*genai.Tool{
			{FunctionDeclarations: []*genai.FunctionDeclaration{weatherFunc}},
		},
		Temperature: genai.Ptr(float32(0.0)),
	}

	modelName := "gemini-2.5-flash"
	contents := []*genai.Content{
		{Parts: []*genai.Part{
			{Text: "What is the weather like in Boston?"},
		},
			Role: "user"},
	}

	resp, err := client.Models.GenerateContent(ctx, modelName, contents, config)
	if err != nil {
		return fmt.Errorf("failed to generate content: %w", err)
	}

	var funcCall *genai.FunctionCall
	for _, p := range resp.Candidates[0].Content.Parts {
		if p.FunctionCall != nil {
			funcCall = p.FunctionCall
			fmt.Fprint(w, "The model suggests to call the function ")
			fmt.Fprintf(w, "%q with args: %v\n", funcCall.Name, funcCall.Args)
			// Example response:
			// The model suggests to call the function "getCurrentWeather" with args: map[location:Boston]
		}
	}
	if funcCall == nil {
		return fmt.Errorf("model did not suggest a function call")
	}

	// Use synthetic data to simulate a response from the external API.
	// In a real application, this would come from an actual weather API.
	funcResp := &genai.FunctionResponse{
		Name: "getCurrentWeather",
		Response: map[string]any{
			"location":         "Boston",
			"temperature":      "38",
			"temperature_unit": "F",
			"description":      "Cold and cloudy",
			"humidity":         "65",
			"wind":             `{"speed": "10", "direction": "NW"}`,
		},
	}

	// Return conversation turns and API response to complete the model's response.
	contents = []*genai.Content{
		{Parts: []*genai.Part{
			{Text: "What is the weather like in Boston?"},
		},
			Role: "user"},
		{Parts: []*genai.Part{
			{FunctionCall: funcCall},
		}},
		{Parts: []*genai.Part{
			{FunctionResponse: funcResp},
		}},
	}

	resp, err = client.Models.GenerateContent(ctx, modelName, contents, config)
	if err != nil {
		return fmt.Errorf("failed to generate content: %w", err)
	}

	respText := resp.Text()

	fmt.Fprintln(w, respText)

	// Example response:
	// The weather in Boston is cold and cloudy with a temperature of 38 degrees Fahrenheit. The humidity is ...

	return nil
}

C#

Dieses Beispiel zeigt ein Textszenario mit einer Funktion und einem Prompt.

C#

Bevor Sie dieses Beispiel anwenden, folgen Sie den C#-Einrichtungsschritten in der Vertex AI-Kurzanleitung zur Verwendung von Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Vertex AI C# API.

Richten Sie zur Authentifizierung bei Vertex AI Standardanmeldedaten für Anwendungen ein. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.


using Google.Cloud.AIPlatform.V1;
using System;
using System.Threading.Tasks;
using Type = Google.Cloud.AIPlatform.V1.Type;
using Value = Google.Protobuf.WellKnownTypes.Value;

public class FunctionCalling
{
    public async Task<string> GenerateFunctionCall(
        string projectId = "your-project-id",
        string location = "us-central1",
        string publisher = "google",
        string model = "gemini-2.0-flash-001")
    {
        var predictionServiceClient = new PredictionServiceClientBuilder
        {
            Endpoint = $"{location}-aiplatform.googleapis.com"
        }.Build();

        // Define the user's prompt in a Content object that we can reuse in
        // model calls
        var userPromptContent = new Content
        {
            Role = "USER",
            Parts =
            {
                new Part { Text = "What is the weather like in Boston?" }
            }
        };

        // Specify a function declaration and parameters for an API request
        var functionName = "get_current_weather";
        var getCurrentWeatherFunc = new FunctionDeclaration
        {
            Name = functionName,
            Description = "Get the current weather in a given location",
            Parameters = new OpenApiSchema
            {
                Type = Type.Object,
                Properties =
                {
                    ["location"] = new()
                    {
                        Type = Type.String,
                        Description = "Get the current weather in a given location"
                    },
                    ["unit"] = new()
                    {
                        Type = Type.String,
                        Description = "The unit of measurement for the temperature",
                        Enum = {"celsius", "fahrenheit"}
                    }
                },
                Required = { "location" }
            }
        };

        // Send the prompt and instruct the model to generate content using the tool that you just created
        var generateContentRequest = new GenerateContentRequest
        {
            Model = $"projects/{projectId}/locations/{location}/publishers/{publisher}/models/{model}",
            GenerationConfig = new GenerationConfig
            {
                Temperature = 0f
            },
            Contents =
            {
                userPromptContent
            },
            Tools =
            {
                new Tool
                {
                    FunctionDeclarations = { getCurrentWeatherFunc }
                }
            }
        };

        GenerateContentResponse response = await predictionServiceClient.GenerateContentAsync(generateContentRequest);

        var functionCall = response.Candidates[0].Content.Parts[0].FunctionCall;
        Console.WriteLine(functionCall);

        string apiResponse = "";

        // Check the function name that the model responded with, and make an API call to an external system
        if (functionCall.Name == functionName)
        {
            // Extract the arguments to use in your API call
            string locationCity = functionCall.Args.Fields["location"].StringValue;

            // Here you can use your preferred method to make an API request to
            // fetch the current weather

            // In this example, we'll use synthetic data to simulate a response
            // payload from an external API
            apiResponse = @"{ ""location"": ""Boston, MA"",
                    ""temperature"": 38, ""description"": ""Partly Cloudy""}";
        }

        // Return the API response to Gemini so it can generate a model response or request another function call
        generateContentRequest = new GenerateContentRequest
        {
            Model = $"projects/{projectId}/locations/{location}/publishers/{publisher}/models/{model}",
            Contents =
            {
                userPromptContent, // User prompt
                response.Candidates[0].Content, // Function call response,
                new Content
                {
                    Parts =
                    {
                        new Part
                        {
                            FunctionResponse = new()
                            {
                                Name = functionName,
                                Response = new()
                                {
                                    Fields =
                                    {
                                        { "content", new Value { StringValue = apiResponse } }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            Tools =
            {
                new Tool
                {
                    FunctionDeclarations = { getCurrentWeatherFunc }
                }
            }
        };

        response = await predictionServiceClient.GenerateContentAsync(generateContentRequest);

        string responseText = response.Candidates[0].Content.Parts[0].Text;
        Console.WriteLine(responseText);

        return responseText;
    }
}

Java

Java

Bevor Sie dieses Beispiel anwenden, folgen Sie den Java Schritten zur Einrichtung in der Vertex AI-Kurzanleitung zur Verwendung von Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Vertex AI Java API.

Richten Sie zur Authentifizierung bei Vertex AI Standardanmeldedaten für Anwendungen ein. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

import com.google.cloud.vertexai.VertexAI;
import com.google.cloud.vertexai.api.Content;
import com.google.cloud.vertexai.api.FunctionDeclaration;
import com.google.cloud.vertexai.api.GenerateContentResponse;
import com.google.cloud.vertexai.api.Schema;
import com.google.cloud.vertexai.api.Tool;
import com.google.cloud.vertexai.api.Type;
import com.google.cloud.vertexai.generativeai.ChatSession;
import com.google.cloud.vertexai.generativeai.ContentMaker;
import com.google.cloud.vertexai.generativeai.GenerativeModel;
import com.google.cloud.vertexai.generativeai.PartMaker;
import com.google.cloud.vertexai.generativeai.ResponseHandler;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;

public class FunctionCalling {
  public static void main(String[] args) throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-google-cloud-project-id";
    String location = "us-central1";
    String modelName = "gemini-2.0-flash-001";

    String promptText = "What's the weather like in Paris?";

    whatsTheWeatherLike(projectId, location, modelName, promptText);
  }

  // A request involving the interaction with an external tool
  public static String whatsTheWeatherLike(String projectId, String location,
                                           String modelName, String promptText)
      throws IOException {
    // Initialize client that will be used to send requests.
    // This client only needs to be created once, and can be reused for multiple requests.
    try (VertexAI vertexAI = new VertexAI(projectId, location)) {

      FunctionDeclaration functionDeclaration = FunctionDeclaration.newBuilder()
          .setName("getCurrentWeather")
          .setDescription("Get the current weather in a given location")
          .setParameters(
              Schema.newBuilder()
                  .setType(Type.OBJECT)
                  .putProperties("location", Schema.newBuilder()
                      .setType(Type.STRING)
                      .setDescription("location")
                      .build()
                  )
                  .addRequired("location")
                  .build()
          )
          .build();

      System.out.println("Function declaration:");
      System.out.println(functionDeclaration);

      // Add the function to a "tool"
      Tool tool = Tool.newBuilder()
          .addFunctionDeclarations(functionDeclaration)
          .build();

      // Start a chat session from a model, with the use of the declared function.
      GenerativeModel model = new GenerativeModel(modelName, vertexAI)
          .withTools(Arrays.asList(tool));
      ChatSession chat = model.startChat();

      System.out.println(String.format("Ask the question: %s", promptText));
      GenerateContentResponse response = chat.sendMessage(promptText);

      // The model will most likely return a function call to the declared
      // function `getCurrentWeather` with "Paris" as the value for the
      // argument `location`.
      System.out.println("\nPrint response: ");
      System.out.println(ResponseHandler.getContent(response));

      // Provide an answer to the model so that it knows what the result
      // of a "function call" is.
      Content content =
          ContentMaker.fromMultiModalData(
              PartMaker.fromFunctionResponse(
                  "getCurrentWeather",
                  Collections.singletonMap("currentWeather", "sunny")));
      System.out.println("Provide the function response: ");
      System.out.println(content);
      response = chat.sendMessage(content);

      // See what the model replies now
      System.out.println("Print response: ");
      String finalAnswer = ResponseHandler.getText(response);
      System.out.println(finalAnswer);

      return finalAnswer;
    }
  }
}

Wenn das Modell feststellt, dass es die Ausgabe einer bestimmten Funktion benötigt, enthält die Antwort, die die Anwendung vom Modell empfängt, den Funktionsnamen und die Parameterwerte, mit denen die Funktion aufgerufen werden soll.

Das folgende Beispiel zeigt eine Modellantwort auf den Nutzer-Prompt „Wie ist das Wetter in Boston?“. Das Modell schlägt vor, die Funktion get_current_weather mit dem Parameter Boston, MA aufzurufen.

candidates {
  content {
    role: "model"
    parts {
      function_call {
        name: "get_current_weather"
        args {
          fields {
            key: "location"
            value {
              string_value: "Boston, MA"
            }
          }
        }
      }
    }
  }
  ...
}

Schritt 2: API-Ausgabe für das Modell bereitstellen

Rufen Sie die externe API auf und geben Sie die API-Ausgabe an das Modell zurück.

Im folgenden Beispiel werden synthetische Daten verwendet, um eine Antwortnutzlast von einer externen API zu simulieren, und die Ausgabe wird wieder an das Modell gesendet.

REST

PROJECT_ID=myproject
MODEL_ID=gemini-2.0-flash
LOCATION="us-central1"

curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/google/models/${MODEL_ID}:generateContent \
-d '{
"contents": [
{
  "role": "user",
  "parts": {
    "text": "What is the weather in Boston?"
  }
},
{
  "role": "model",
  "parts": [
    {
      "functionCall": {
        "name": "get_current_weather",
        "args": {
          "location": "Boston, MA"
        }
      }
    }
  ]
},
{
  "role": "user",
  "parts": [
    {
      "functionResponse": {
        "name": "get_current_weather",
        "response": {
          "temperature": 20,
          "unit": "C"
        }
      }
    }
  ]
}
],
"tools": [
{
  "function_declarations": [
    {
      "name": "get_current_weather",
      "description": "Get the current weather in a specific location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "The city name of the location for which to get the weather."
          }
        },
        "required": [
          "location"
        ]
      }
    }
  ]
}
]
}'

Python

function_response_contents = []
function_response_parts = []

# Iterates through the function calls in the response in case there are parallel function call requests
for function_call in response.candidates[0].function_calls:
    print(f"Function call: {function_call.name}")

    # In this example, we'll use synthetic data to simulate a response payload from an external API
    if (function_call.args['location'] == "Boston, MA"):
      api_response = { "location": "Boston, MA", "temperature": 38, "description": "Partly Cloudy" }
    if (function_call.args['location'] == "San Francisco, CA"):
      api_response = { "location": "San Francisco, CA", "temperature": 58, "description": "Sunny" }

    function_response_parts.append(
        Part.from_function_response(
            name=function_call.name,
            response={"contents": api_response}
        )
    )
    # Add the function call response to the contents
    function_response_contents = Content(role="user", parts=function_response_parts)

# Submit the User's prompt, model's response, and API output back to the model
response = model.generate_content(
  [
    Content( # User prompt
      role="user",
      parts=[
          Part.from_text("What is the weather like in Boston?"),
      ],
    ),
    response.candidates[0].content,  # Function call response
    function_response_contents   # API output
  ],
  tools=[
    Tool(
      function_declarations=[get_current_weather_func],
    )
  ],
)
# Get the model summary response
print(response.text)

Best Practices für den API-Aufruf finden Sie unter Best Practices – API-Aufruf.

Wenn das Modell mehrere parallele Funktionsaufrufe vorgeschlagen hat, muss die Anwendung alle Antworten an das Modell zurückgeben. Weitere Informationen finden Sie unter Beispiel für parallele Funktionsaufrufe.

Das Modell kann feststellen, dass die Ausgabe einer anderen Funktion erforderlich ist, um auf den Prompt zu reagieren. In diesem Fall enthält die Antwort, die die Anwendung vom Modell empfängt, einen anderen Funktionsnamen und einen anderen Satz von Parameterwerten.

Wenn das Modell feststellt, dass die API-Antwort ausreicht, um auf den Prompt des Nutzers zu reagieren, wird eine Antwort in natürlicher Sprache erstellt und an die Anwendung zurückgegeben. In diesem Fall muss die Anwendung die Antwort an den Nutzer zurückgeben. Hier ist ein Beispiel für eine Antwort in natürlicher Sprache:

It is currently 38 degrees Fahrenheit in Boston, MA with partly cloudy skies.

Funktionsaufrufe mit Gedanken

Wenn Sie Funktionen mit aktivierter thinking aufrufen, müssen Sie die thought_signature aus dem Modellantwortobjekt abrufen und zurückgeben, wenn Sie das Ergebnis der Funktionsausführung an das Modell zurücksenden. Beispiel:

Python

# Call the model with function declarations
# ...Generation config, Configure the client, and Define user prompt (No changes)

# Send request with declarations (using a thinking model)
response = client.models.generate_content(
  model="gemini-2.5-flash", config=config, contents=contents)

# See thought signatures
for part in response.candidates[0].content.parts:
  if not part.text:
    continue
  if part.thought and part.thought_signature:
    print("Thought signature:")
    print(part.thought_signature)

Das Ansehen von Gedanken-Signaturen ist nicht erforderlich. Sie müssen jedoch Schritt 2 anpassen, damit sie zusammen mit dem Ergebnis der Funktionsausführung zurückgegeben werden und in die endgültige Antwort einfließen können:

Python

# Create user friendly response with function result and call the model again
# ...Create a function response part (No change)

# Append thought signatures, function call and result of the function execution to contents
function_call_content = response.candidates[0].content
# Append the model's function call message, which includes thought signatures
contents.append(function_call_content)
contents.append(types.Content(role="user", parts=[function_response_part])) # Append the function response

final_response = client.models.generate_content(
    model="gemini-2.5-flash",
    config=config,
    contents=contents,
)

print(final_response.text)

Beachten Sie beim Zurückgeben von Gedanken-Signaturen die folgenden Richtlinien:

  • Das Modell gibt Signaturen in anderen Teilen der Antwort zurück, z. B. in Funktionsaufrufen oder Text-, Text- oder Gedankenübersichtsteilen. Gib die gesamte Antwort mit allen Teilen in nachfolgenden Zügen an das Modell zurück.
  • Führen Sie keinen Teil mit einer Signatur mit einem anderen Teil zusammen, der ebenfalls eine Signatur enthält. Signaturen können nicht verkettet werden.
  • Führen Sie keinen Teil mit einer Signatur mit einem anderen Teil ohne Signatur zusammen. Dadurch wird die korrekte Positionierung des Gedankens, der durch die Signatur dargestellt wird, unterbrochen.

Weitere Informationen zu Einschränkungen und zur Verwendung von Gedanken-Signaturen sowie zu Denkmodellen im Allgemeinen finden Sie auf der Seite Denken.

Parallele Funktionsaufrufe

Für Prompts wie „Wetterdetails in Boston und San Francisco?“ kann das Modell mehrere parallele Funktionsaufrufe vorschlagen. Eine Liste der Modelle, die parallele Funktionsaufrufe unterstützen, finden Sie unter Unterstützte Modelle.

REST

Dieses Beispiel zeigt ein Szenario mit einer get_current_weather-Funktion. Die Eingabeaufforderung lautet „Wetterdetails für Boston und San Francisco?“. Das Modell schlägt zwei parallele Aufrufe der Funktion get_current_weather vor: einen mit dem Parameter Boston und einen mit dem Parameter San Francisco.

Weitere Informationen zu den Anfrageparametern finden Sie unter Gemini API.

{
"candidates": [
  {
    "content": {
      "role": "model",
      "parts": [
        {
          "functionCall": {
            "name": "get_current_weather",
            "args": {
              "location": "Boston"
            }
          }
        },
        {
          "functionCall": {
            "name": "get_current_weather",
            "args": {
              "location": "San Francisco"
            }
          }
        }
      ]
    },
    ...
  }
],
...
}

Der folgende Befehl zeigt, wie Sie die Funktionsausgabe für das Modell bereitstellen können. Ersetzen Sie my-project durch den Namen Ihres Google Cloud Projekts.

Modellanfrage

PROJECT_ID=my-project
MODEL_ID=gemini-2.0-flash
LOCATION="us-central1"
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/google/models/${MODEL_ID}:generateContent \
-d '{
"contents": [
{
  "role": "user",
  "parts": {
    "text": "What is difference in temperature in Boston and San Francisco?"
  }
},
{
  "role": "model",
  "parts": [
    {
      "functionCall": {
        "name": "get_current_weather",
        "args": {
          "location": "Boston"
        }
      }
    },
    {
      "functionCall": {
        "name": "get_current_weather",
        "args": {
          "location": "San Francisco"
        }
      }
    }
  ]
},
{
  "role": "user",
  "parts": [
    {
      "functionResponse": {
        "name": "get_current_weather",
        "response": {
          "temperature": 30.5,
          "unit": "C"
        }
      }
    },
    {
      "functionResponse": {
        "name": "get_current_weather",
        "response": {
          "temperature": 20,
          "unit": "C"
        }
      }
    }
  ]
}
],
"tools": [
{
  "function_declarations": [
    {
      "name": "get_current_weather",
      "description": "Get the current weather in a specific location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "The city name of the location for which to get the weather."
          }
        },
        "required": [
          "location"
        ]
      }
    }
  ]
}
]
}'
  

Die vom Modell erstellte Antwort in natürlicher Sprache sieht in etwa so aus:

Modellantwort

[
{
    "candidates": [
        {
            "content": {
                "parts": [
                    {
                        "text": "The temperature in Boston is 30.5C and the temperature in San Francisco is 20C. The difference is 10.5C. \n"
                    }
                ]
            },
            "finishReason": "STOP",
            ...
        }
    ]
    ...
}
]
  

Python

Dieses Beispiel zeigt ein Szenario mit einer get_current_weather-Funktion. Die Eingabeaufforderung lautet „Wie ist das Wetter in Boston und San Francisco?“.

Ersetzen Sie my-project durch den Namen Ihres Google Cloud Projekts.

import vertexai
from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerationConfig,
    GenerativeModel,
    Part,
    Tool,
    ToolConfig
)

# Initialize Vertex AI
# TODO(developer): Update the project
vertexai.init(project="my-project", location="us-central1")

# Initialize Gemini model
model = GenerativeModel(model_name="gemini-2.0-flash")

# Manual function declaration
get_current_weather_func = FunctionDeclaration(
    name="get_current_weather",
    description="Get the current weather in a given location",
    # Function parameters are specified in JSON schema format
    parameters={
        "type": "object",
        "properties": {
            "location": {
              "type": "string",
              "description": "The city name of the location for which to get the weather.",
              "default": {
                "string_value": "Boston, MA"
              }
          }
        },
    },
)

response = model.generate_content(
    contents = [
      Content(
        role="user",
          parts=[
              Part.from_text("What is the weather like in Boston and San Francisco?"),
          ],
      )
    ],
    generation_config = GenerationConfig(temperature=0),
    tools = [
      Tool(
        function_declarations=[get_current_weather_func],
      )
    ]
)

Der folgende Befehl zeigt, wie Sie die Funktionsausgabe für das Modell bereitstellen können.

function_response_contents = []
function_response_parts = []

# You can have parallel function call requests for the same function type.
# For example, 'location_to_lat_long("London")' and 'location_to_lat_long("Paris")'
# In that case, collect API responses in parts and send them back to the model

for function_call in response.candidates[0].function_calls:
    print(f"Function call: {function_call.name}")

    # In this example, we'll use synthetic data to simulate a response payload from an external API
    if (function_call.args['location'] == "Boston, MA"):
      api_response = { "location": "Boston, MA", "temperature": 38, "description": "Partly Cloudy" }
    if (function_call.args['location'] == "San Francisco, CA"):
      api_response = { "location": "San Francisco, CA", "temperature": 58, "description": "Sunny" }

    function_response_parts.append(
        Part.from_function_response(
            name=function_call.name,
            response={"contents": api_response}
        )
    )
    # Add the function call response to the contents
    function_response_contents = Content(role="user", parts=function_response_parts)

function_response_contents

response = model.generate_content(
    contents = [
        Content(
        role="user",
          parts=[
              Part.from_text("What is the weather like in Boston and San Francisco?"),
          ],
        ),  # User prompt
        response.candidates[0].content,  # Function call response
        function_response_contents,  # Function response
    ],
    tools = [
      Tool(
        function_declarations=[get_current_weather_func],
      )
    ]
)
# Get the model summary response
print(response.text)

Go

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"

	"cloud.google.com/go/vertexai/genai"
)

// parallelFunctionCalling shows how to execute multiple function calls in parallel
// and return their results to the model for generating a complete response.
func parallelFunctionCalling(w io.Writer, projectID, location, modelName string) error {
	// location = "us-central1"
	// modelName = "gemini-2.0-flash-001"
	ctx := context.Background()
	client, err := genai.NewClient(ctx, projectID, location)
	if err != nil {
		return fmt.Errorf("failed to create GenAI client: %w", err)
	}
	defer client.Close()

	model := client.GenerativeModel(modelName)
	// Set temperature to 0.0 for maximum determinism in function calling.
	model.SetTemperature(0.0)

	funcName := "getCurrentWeather"
	funcDecl := &genai.FunctionDeclaration{
		Name:        funcName,
		Description: "Get the current weather in a given location",
		Parameters: &genai.Schema{
			Type: genai.TypeObject,
			Properties: map[string]*genai.Schema{
				"location": {
					Type: genai.TypeString,
					Description: "The location for which to get the weather. " +
						"It can be a city name, a city name and state, or a zip code. " +
						"Examples: 'San Francisco', 'San Francisco, CA', '95616', etc.",
				},
			},
			Required: []string{"location"},
		},
	}
	// Add the weather function to our model toolbox.
	model.Tools = []*genai.Tool{
		{
			FunctionDeclarations: []*genai.FunctionDeclaration{funcDecl},
		},
	}

	prompt := genai.Text("Get weather details in New Delhi and San Francisco?")
	resp, err := model.GenerateContent(ctx, prompt)

	if err != nil {
		return fmt.Errorf("failed to generate content: %w", err)
	}
	if len(resp.Candidates) == 0 {
		return errors.New("got empty response from model")
	} else if len(resp.Candidates[0].FunctionCalls()) == 0 {
		return errors.New("got no function call suggestions from model")
	}

	// In a production environment, consider adding validations for function names and arguments.
	for _, fnCall := range resp.Candidates[0].FunctionCalls() {
		fmt.Fprintf(w, "The model suggests to call the function %q with args: %v\n", fnCall.Name, fnCall.Args)
		// Example response:
		// The model suggests to call the function "getCurrentWeather" with args: map[location:New Delhi]
		// The model suggests to call the function "getCurrentWeather" with args: map[location:San Francisco]
	}

	// Use synthetic data to simulate responses from the external API.
	// In a real application, this would come from an actual weather API.
	mockAPIResp1, err := json.Marshal(map[string]string{
		"location":         "New Delhi",
		"temperature":      "42",
		"temperature_unit": "C",
		"description":      "Hot and humid",
		"humidity":         "65",
	})
	if err != nil {
		return fmt.Errorf("failed to marshal function response to JSON: %w", err)
	}

	mockAPIResp2, err := json.Marshal(map[string]string{
		"location":         "San Francisco",
		"temperature":      "36",
		"temperature_unit": "F",
		"description":      "Cold and cloudy",
		"humidity":         "N/A",
	})
	if err != nil {
		return fmt.Errorf("failed to marshal function response to JSON: %w", err)
	}

	// Note, that the function calls don't have to be chained. We can obtain both responses in parallel
	// and return them to Gemini at once.
	funcResp1 := &genai.FunctionResponse{
		Name: funcName,
		Response: map[string]any{
			"content": mockAPIResp1,
		},
	}
	funcResp2 := &genai.FunctionResponse{
		Name: funcName,
		Response: map[string]any{
			"content": mockAPIResp2,
		},
	}

	// Return both API responses to the model allowing it to complete its response.
	resp, err = model.GenerateContent(ctx, prompt, funcResp1, funcResp2)
	if err != nil {
		return fmt.Errorf("failed to generate content: %w", err)
	}
	if len(resp.Candidates) == 0 || len(resp.Candidates[0].Content.Parts) == 0 {
		return errors.New("got empty response from model")
	}

	fmt.Fprintln(w, resp.Candidates[0].Content.Parts[0])
	// Example response:
	// The weather in New Delhi is hot and humid with a humidity of 65 and a temperature of 42°C. The weather in San Francisco ...

	return nil
}

Erzwungene Funktionsaufrufe

Anstatt dem Modell zu erlauben, zwischen einer Antwort in natürlicher Sprache und einem Funktionsaufruf zu wählen, können Sie erzwingen, dass nur Funktionsaufrufe vorhergesagt werden. Dies wird als erzwungene Funktionsaufrufe bezeichnet. Sie können dem Modell auch einen vollständigen Satz von Funktionsdeklarationen zur Verfügung stellen, seine Antworten aber auf eine Teilmenge dieser Funktionen beschränken.

Modus Beschreibung
AUTO Das Standardverhalten des Modells. Das Modell entscheidet, ob Funktionsaufrufe oder eine Antwort in natürlicher Sprache vorhergesagt werden sollen.
ANY Das Modell ist darauf beschränkt, immer einen Funktionsaufruf vorherzusagen. Wenn allowed_function_names nicht angegeben ist, wählt das Modell aus allen verfügbaren Funktionsdeklarationen aus. Wenn allowed_function_names angegeben wird, wählt das Modell aus der Menge der zulässigen Funktionen aus.
NONE Das Modell darf keine Funktionsaufrufe vorhersagen. Dieses Verhalten entspricht einer Modellanfrage ohne zugehörige Funktionsdeklarationen.

Im folgenden Beispiel wird das Modell gezwungen, nur get_weather-Funktionsaufrufe vorherzusagen.

Python

response = model.generate_content(
    contents = [
      Content(
        role="user",
          parts=[
              Part.from_text("What is the weather like in Boston?"),
          ],
      )
    ],
    generation_config = GenerationConfig(temperature=0),
    tools = [
      Tool(
        function_declarations=[get_weather_func, some_other_function],
      )
    ],
    tool_config=ToolConfig(
        function_calling_config=ToolConfig.FunctionCallingConfig(
            # ANY mode forces the model to predict only function calls
            mode=ToolConfig.FunctionCallingConfig.Mode.ANY,
            # Allowed function calls to predict when the mode is ANY. If empty, any of
            # the provided function calls will be predicted.
            allowed_function_names=["get_weather"],
        )
    )
)

Beispiele für Funktionsschemas

Funktionsdeklarationen sind mit dem OpenAPI-Schema kompatibel. Wir unterstützen die folgenden Attribute: type, nullable, required, format, description, properties, items, enum, anyOf, $ref und $defs. Die verbleibenden Attribute werden nicht unterstützt.

Funktion mit Objekt- und Array-Parametern

Im folgenden Beispiel wird ein Python-Dictionary verwendet, um eine Funktion zu deklarieren, die sowohl Objekt- als auch Array-Parameter akzeptiert:

extract_sale_records_func = FunctionDeclaration(
  name="extract_sale_records",
  description="Extract sale records from a document.",
  parameters={
      "type": "object",
      "properties": {
          "records": {
              "type": "array",
              "description": "A list of sale records",
              "items": {
                  "description": "Data for a sale record",
                  "type": "object",
                  "properties": {
                      "id": {"type": "integer", "description": "The unique id of the sale."},
                      "date": {"type": "string", "description": "Date of the sale, in the format of MMDDYY, e.g., 031023"},
                      "total_amount": {"type": "number", "description": "The total amount of the sale."},
                      "customer_name": {"type": "string", "description": "The name of the customer, including first name and last name."},
                      "customer_contact": {"type": "string", "description": "The phone number of the customer, e.g., 650-123-4567."},
                  },
                  "required": ["id", "date", "total_amount"],
              },
          },
      },
      "required": ["records"],
  },
)
  

Funktion mit Enum-Parameter

Im folgenden Beispiel wird ein Python-Wörterbuch verwendet, um eine Funktion zu deklarieren, die einen enum-Parameter vom Typ „integer“ akzeptiert:

set_status_func = FunctionDeclaration(
  name="set_status",
  description="set a ticket's status field",
  # Function parameters are specified in JSON schema format
  parameters={
      "type": "object",
      "properties": {
        "status": {
          "type": "integer",
          "enum": [ "10", "20", "30" ],   # Provide integer (or any other type) values as strings.
        }
      },
  },
)
  

Funktion mit ref und def

In der folgenden JSON-Funktionsdeklaration werden die Attribute ref und defs verwendet:

{
  "contents": ...,
  "tools": [
    {
      "function_declarations": [
        {
          "name": "get_customer",
          "description": "Search for a customer by name",
          "parameters": {
            "type": "object",
            "properties": {
              "first_name": { "ref": "#/defs/name" },
              "last_name": { "ref": "#/defs/name" }
            },
            "defs": {
              "name": { "type": "string" }
            }
          }
        }
      ]
    }
  ]
}
  

Verwendungshinweise:

  • Im Gegensatz zum OpenAPI-Schema müssen Sie ref und defs ohne das Symbol $ angeben.
  • ref muss auf ein direkt untergeordnetes Element von defs verweisen. Externe Verweise sind nicht zulässig.
  • Die maximale Tiefe verschachtelter Schemas beträgt 32.
  • Die Rekursionstiefe in defs (Selbstreferenz) ist auf zwei begrenzt.

from_func mit Array-Parameter

Im folgenden Codebeispiel wird eine Funktion deklariert, die ein Array von Zahlen multipliziert und from_func verwendet, um das FunctionDeclaration-Schema zu generieren.

from typing import List

# Define a function. Could be a local function or you can import the requests library to call an API
def multiply_numbers(numbers: List[int] = [1, 1]) -> int:
  """
  Calculates the product of all numbers in an array.

  Args:
      numbers: An array of numbers to be multiplied.

  Returns:
      The product of all the numbers. If the array is empty, returns 1.
  """

  if not numbers:  # Handle empty array
      return 1

  product = 1
  for num in numbers:
      product *= num

  return product

multiply_number_func = FunctionDeclaration.from_func(multiply_numbers)

"""
multiply_number_func contains the following schema:

{'name': 'multiply_numbers',
  'description': 'Calculates the product of all numbers in an array.',
  'parameters': {'properties': {'numbers': {'items': {'type': 'INTEGER'},
    'description': 'list of numbers',
    'default': [1.0, 1.0],
    'title': 'Numbers',
    'type': 'ARRAY'}},
  'description': 'Calculates the product of all numbers in an array.',
  'title': 'multiply_numbers',
  'property_ordering': ['numbers'],
  'type': 'OBJECT'}}
"""
  

Best Practices für Funktionsaufrufe

Klare und detaillierte Funktionsnamen, Parameterbeschreibungen und Anleitungen verfassen

  • Funktionsnamen müssen mit einem Buchstaben oder einem Unterstrich beginnen und dürfen nur die Zeichen a–z, A–Z, 0–9, Unterstriche, Punkte oder Bindestriche enthalten. Die maximale Länge beträgt 64 Zeichen.

  • Funktionsbeschreibungen sollten klar und ausführlich sein. Eine book_flight_ticket-Funktion könnte beispielsweise die Beschreibung book flight tickets after confirming users' specific requirements, such as time, departure, destination, party size and preferred airline haben.

Stark typisierte Parameter verwenden

Wenn die Parameterwerte aus einem endlichen Set stammen, fügen Sie das Feld enum hinzu, anstatt den Wertesatz in die Beschreibung einzufügen. Wenn der Parameterwert immer eine Ganzzahl ist, legen Sie den Typ auf integer anstatt auf number fest.

Systemanweisung verwenden

Wenn Sie Funktionen mit Datums-, Zeit- oder Standortparametern verwenden, geben Sie in der Systemanweisung das aktuelle Datum, die aktuelle Uhrzeit oder die relevanten Standortinformationen (z. B. Stadt und Land) an. So erhält das Modell den erforderlichen Kontext, um die Anfrage genau zu verarbeiten, auch wenn der Prompt des Nutzers nicht detailliert genug ist.

Nutzer-Prompt aktualisieren

Für optimale Ergebnisse sollten Sie dem Nutzer-Prompt die folgenden Details voranstellen:

  • Zusätzlicher Kontext für das Modell, z. B. You are a flight API assistant to help with searching flights based on user preferences.
  • Details oder Anleitungen zur Verwendung der Funktionen, z. B. Don't make assumptions on the departure or destination airports. Always use a future date for the departure or destination time.
  • Eine Anleitung, um klärende Fragen zu stellen, wenn Nutzerabfragen mehrdeutig sind, z. B. Ask clarifying questions if not enough information is available.

Generierungskonfiguration verwenden

Verwenden Sie für den Temperaturparameter 0 oder einen anderen niedrigen Wert. Dadurch wird das Modell angewiesen, zuverlässigere Ergebnisse zu generieren, und Halluzinationen werden reduziert.

API-Aufruf validieren

Wenn das Modell den Aufruf einer Funktion vorschlägt, die eine Bestellung senden, eine Datenbank aktualisieren oder anderweitig erhebliche Konsequenzen haben würde, validieren Sie den Funktionsaufruf vor der Ausführung mit dem Nutzer.

Gedankensignaturen verwenden

Gedankensignaturen sollten immer in Verbindung mit Funktionsaufrufen verwendet werden, um optimale Ergebnisse zu erzielen.

Preise

Die Preise für Funktionsaufrufe basieren auf der Anzahl der Zeichen in den Textein- und -ausgaben. Weitere Informationen finden Sie unter Vertex AI-Preise.

Hier bezieht sich die Texteingabe (Prompt) auf den Nutzerprompt für die aktuelle Unterhaltungsrunde, die Funktionsdeklarationen für die aktuelle Unterhaltungsrunde und den Verlauf der Unterhaltung. Der Verlauf der Unterhaltung umfasst die Abfragen, die Funktionsaufrufe und die Funktionsantworten vorheriger Unterhaltungsrunden. Vertex AI kürzt den Verlauf der Unterhaltung auf 32.000 Zeichen.

Die Textausgabe (Antwort) bezieht sich auf die Funktionsaufrufe und die Textantworten für die aktuelle Unterhaltungsrunde.

Anwendungsfälle von Funktionsaufrufen

Sie können Funktionsaufrufe für die folgenden Aufgaben verwenden:

Anwendungsfall Beispielbeschreibung Beispiellink
In externe APIs einbinden Wetterinformationen über eine meteorologische API abrufen Notebook-Tutorial
Adressen in Längen- und Breitengradangaben umwandeln Notebook-Tutorial
Währungen mit einer Währungsumrechnungs-API umrechnen Codelab
Erweiterte Chatbots erstellen Kundenfragen zu Produkten und Dienstleistungen beantworten Notebook-Tutorial
Einen Assistenten erstellen, der Finanz- und Nachrichtenfragen zu Unternehmen beantwortet Notebook-Tutorial
Funktionsaufrufe strukturieren und steuern Strukturierte Entitäten aus Rohprotokolldaten extrahieren Notebook-Tutorial
Einzelne oder mehrere Parameter aus der Nutzereingabe extrahieren Notebook-Tutorial
Listen und verschachtelte Datenstrukturen in Funktionsaufrufen verarbeiten Notebook-Tutorial
Verhalten bei Funktionsaufrufen verarbeiten Parallele Funktionsaufrufe und Antworten verarbeiten Notebook-Tutorial
Festlegen, wann und welche Funktionen das Modell aufrufen kann Notebook-Tutorial
Datenbanken mit natürlicher Sprache abfragen Fragen in natürlicher Sprache in SQL-Abfragen für BigQuery umwandeln Beispiel-App
Multimodale Funktionsaufrufe Bilder, Videos, Audio und PDFs als Eingabe verwenden, um Funktionsaufrufe auszulösen Notebook-Tutorial

Weitere Anwendungsfälle:

  • Sprachbefehle interpretieren: Erstellen Sie Funktionen, die den Aufgaben im Fahrzeug entsprechen. Sie können beispielsweise Funktionen erstellen, die das Radio einschalten oder die Klimaanlage aktivieren. Senden Sie Audiodateien mit den Sprachbefehlen des Nutzers an das Modell und bitten Sie es, die Audiodaten in Text umzuwandeln und die Funktion zu identifizieren, die der Nutzer aufrufen möchte.

  • Workflows auf der Grundlage von Umgebungstriggern automatisieren: Funktionen zur Darstellung von Prozessen erstellen, die automatisiert werden können. Stellen Sie dem Modell Daten von Umgebungssensoren bereit und bitten Sie es, die Daten zu parsen und zu verarbeiten, um festzustellen, ob einer oder mehrere Workflows aktiviert werden sollen. Ein Modell könnte zum Beispiel Temperaturdaten in einem Lager verarbeiten und eine Sprinklerfunktion aktivieren.

  • Zuweisung von Support-Tickets automatisieren: Stellen Sie dem Modell Support-Tickets, Logs und kontextsensible Regeln zur Verfügung. Bitten Sie das Modell, alle diese Informationen zu verarbeiten, um zu ermitteln, wem das Ticket zugewiesen werden soll. Rufen Sie eine Funktion auf, um das Ticket der vom Modell vorgeschlagenen Person zuzuweisen.

  • Informationen aus einer Wissensdatenbank abrufen: Erstellen Sie Funktionen, mit denen akademische Artikel zu einem bestimmten Thema abgerufen und zusammengefasst werden. Befähigen Sie das Modell, Fragen zu akademischen Themen zu beantworten und die Antworten mit Zitaten zu versehen.

Nächste Schritte