Google Search로 Grounding

Google Search로 Grounding

Google Search로 Grounding(Grounding with Google Search)은 Gemini 모델을 실시간 웹 콘텐츠에 연결하며 모든 지원 언어에서 동작해요. 이를 통해 Gemini는 지식 컷오프를 넘어선 주제에서도 더 정확한 답변을 제공하고 검증 가능한 출처를 인용할 수 있어요.

Grounding은 다음을 할 수 있는 애플리케이션을 구축하는 데 도움을 줘요:

  • 사실 정확도 향상: 실제 세계 정보를 바탕으로 응답해 모델 환각(hallucination)을 줄여요.
  • 실시간 정보 접근: 최근 사건과 주제에 대한 질문에 답해요.
  • 인용 제공: 모델 주장의 출처를 보여줘 사용자 신뢰를 구축해요.

출처: 원문

본문

Python

from google import genai

client = genai.Client()

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input="Who won the euro 2024?",
    tools=[{"type": "google_search"}]
)

print(interaction.output_text)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const interaction = await client.interactions.create({
    model: "gemini-3.8-flash",
    input: "Who won the euro 2024?",
    tools: [{ type: "google_search" }]
});

console.log(interaction.output_text);

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.GoogleSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;

Client client = new Client();

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Who won the euro 2024?"))
        .tools(Arrays.asList(GoogleSearch.builder().build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

System.out.println(interaction.outputText().orElse(""));

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Who won the euro 2024?"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.GoogleSearch{}),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(resp.Interaction.GetOutputText())
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: *** \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.8-flash",
    "input": "Who won the euro 2024?",
    "tools": [{"type": "google_search"}]
  }'

Google Search Grounding의 동작 방식

google_search 도구를 활성화하면 모델이 검색, 처리, 인용의 전체 워크플로를 자동으로 처리해요.

  1. 사용자 프롬프트: 애플리케이션이 google_search 도구를 활성화한 채 사용자 프롬프트를 Gemini API에 보내요.
  2. 프롬프트 분석: 모델이 프롬프트를 분석하고 Google 검색이 답변을 개선할 수 있는지 판단해요.
  3. Google 검색: 필요하면 모델이 하나 또는 여러 검색 쿼리를 자동 생성하고 실행해요.
  4. 검색 결과 처리: 모델이 검색 결과를 처리하고 정보를 종합해 응답을 구성해요.
  5. Grounded 응답: API가 검색 결과에 근거한 최종 사용자 친화적 응답을 반환해요. 이 응답에는 인용이 담긴 인라인 annotations가 있는 모델의 텍스트 답변과, 검색 쿼리와 검색 제안이 담긴 google_search_call, google_search_result 단계가 포함돼요.

Grounding 응답 이해하기

응답이 성공적으로 grounding되면 모델의 텍스트 출력에는 텍스트 콘텐츠 블록에 직접 인라인 annotations가 포함돼요. 이러한 주석은 응답의 일부를 출처에 연결하는 인용 정보를 제공해요.

{
  "steps": [
    {
      "type": "thought",
      "summary": [
        {
          "type": "text",
          "text": "The user is asking for the winner of Euro 2024. I need to search for the result of the Euro 2024 final."
        }
      ],
      "signature": "CoMDAXLI2nynRYojJIy6B1Jh9os2crpWLfB0..."
    },
    {
      "type": "google_search_call",
      "arguments": {
        "queries": ["UEFA Euro 2024 winner"]
      }
    },
    {
      "type": "google_search_result",
      "call_id": "search_001",
      "result": [
        {
          "search_suggestions": "<!-- HTML and CSS for the search widget -->"
        }
      ]
    },
    {
      "type": "model_output",
      "content": [
        {
          "type": "text",
          "text": "Spain won Euro 2024, defeating England 2-1 in the final. This victory marks Spain's record fourth European Championship title.",
          "annotations": [
            {
              "type": "url_citation",
              "url": "https://www.aljazeera.com/sports/euro-2024-final",
              "title": "aljazeera.com",
              "start_index": 0,
              "end_index": 56
            },
            {
              "type": "url_citation",
              "url": "https://www.uefa.com/euro2024/news/spain-wins-euro-2024",
              "title": "uefa.com",
              "start_index": 57,
              "end_index": 124
            }
          ]
        }
      ]
    }
  ]
}

응답의 핵심 필드:

  • google_search_call: 모델이 실행한 검색 queries를 포함해요.
  • google_search_result: UI에서 검색 제안을 렌더링하기 위한 HTML 스니펫인 search_suggestions를 포함해요. 전체 사용 요건은 서비스 약관에 설명되어 있어요.
  • annotations가 있는 text: 인라인 인용이 포함된 모델의 종합 답변이에요. 각 url_citation 주석은 텍스트 세그먼트(start_index와 end_index로 정의)를 소스 URL에 연결해요. 이것이 인라인 인용을 구축하는 핵심이에요.

Google Search로 Grounding은 URL context 도구와 함께 사용해 공개 웹 데이터와 사용자가 제공한 특정 URL 모두에서 응답을 grounding할 수도 있어요.

인라인 인용으로 출처 표시

API는 텍스트 콘텐츠 블록에 인라인 url_citation 주석을 반환해서 사용자 인터페이스에서 출처를 표시하는 방법을 완전히 제어할 수 있게 해줘요. 각 주석에는 인용하는 텍스트 부분을 식별하는 start_index와 end_index가 포함돼요. 추출하고 표시하는 방법은 다음과 같아요.

Python

for step in interaction.steps:
    if step.type == "model_output":
        for content_block in step.content:
            if content_block.type == "text":
                print(content_block.text)
                if content_block.annotations:
                    print("\nCitations:")
                    for annotation in content_block.annotations:
                        if annotation.type == "url_citation":
                            cited_text = content_block.text[annotation.start_index:annotation.end_index]
                            print(f"  [{annotation.title}]({annotation.url})")
                            print(f"    Cited text: \"{cited_text}\"")

JavaScript

for (const step of interaction.steps) {
  if (step.type === 'model_output') {
    for (const contentBlock of step.content) {
      if (contentBlock.type === 'text') {
        console.log(contentBlock.text);
        if (contentBlock.annotations) {
          console.log("\nCitations:");
          for (const annotation of contentBlock.annotations) {
            if (annotation.type === 'url_citation') {
              const citedText = contentBlock.text.slice(annotation.startIndex, annotation.endIndex);
              console.log(`  [${annotation.title}](${annotation.url})`);
              console.log(`    Cited text: "${citedText}"`);
            }
          }
        }
      }
    }
  }
}

Java

import com.google.genai.Client;
import com.google.genai.gaos.models.interactions.Annotation;
import com.google.genai.gaos.models.interactions.Content;
import com.google.genai.gaos.models.interactions.CreateModelInteraction;
import com.google.genai.gaos.models.interactions.GoogleSearch;
import com.google.genai.gaos.models.interactions.Interaction;
import com.google.genai.gaos.models.interactions.InteractionsInput;
import com.google.genai.gaos.models.interactions.Model;
import com.google.genai.gaos.models.interactions.ModelOutputStep;
import com.google.genai.gaos.models.interactions.Step;
import com.google.genai.gaos.models.interactions.TextContent;
import com.google.genai.gaos.models.interactions.URLCitation;
import com.google.genai.gaos.models.operations.CreateInteractionRequestBody;
import java.util.Arrays;

Client client = new Client();

CreateModelInteraction params =
    CreateModelInteraction.builder()
        .model(Model.of("gemini-3.8-flash"))
        .input(InteractionsInput.of("Who won the euro 2024?"))
        .tools(Arrays.asList(GoogleSearch.builder().build()))
        .build();

Interaction interaction =
    client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get();

if (interaction.steps().isPresent()) {
  for (Step step : interaction.steps().get()) {
    if (step instanceof ModelOutputStep) {
      ModelOutputStep outputStep = (ModelOutputStep) step;
      if (outputStep.content().isPresent()) {
        for (Content contentBlock : outputStep.content().get()) {
          if (contentBlock instanceof TextContent) {
            TextContent textContent = (TextContent) contentBlock;
            String text = textContent.text().orElse("");
            System.out.println(text);
            if (textContent.annotations().isPresent()
                && !textContent.annotations().get().isEmpty()) {
              System.out.println("\nCitations:");
              for (Annotation annotation : textContent.annotations().get()) {
                if (annotation instanceof URLCitation) {
                  URLCitation citation = (URLCitation) annotation;
                  int start = citation.startIndex().orElse(0);
                  int end = citation.endIndex().orElse(0);
                  String citedText =
                      (start >= 0 && end <= text.length() && start <= end)
                          ? text.substring(start, end)
                          : "";
                  System.out.printf(
                      "  [%s](%s)%n", citation.title().orElse(""), citation.url().orElse(""));
                  System.out.printf("    Cited text: \"%s\"%n", citedText);
                }
              }
            }
          }
        }
      }
    }
  }
}

Go

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(
            interactions.CreateModelInteraction{
                Model: interactions.Model("gemini-3.8-flash"),
                Input: interactions.NewInteractionsInput("Who won the euro 2024?"),
                Tools: []interactions.Tool{
                    interactions.NewTool(interactions.GoogleSearch{}),
                },
            },
        ),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, step := range resp.Interaction.Steps {
        if step.ModelOutputStep != nil {
            for _, content := range step.ModelOutputStep.Content {
                if content.TextContent != nil {
                    text := content.TextContent.Text
                    fmt.Println(text)
                    if len(content.TextContent.Annotations) > 0 {
                        fmt.Println("\nCitations:")
                        for _, annotation := range content.TextContent.Annotations {
                            if annotation.URLCitation != nil {
                                c := annotation.URLCitation
                                start := 0
                                if c.StartIndex != nil {
                                    start = *c.StartIndex
                                }
                                end := 0
                                if c.EndIndex != nil {
                                    end = *c.EndIndex
                                }
                                citedText := ""
                                if start >= 0 && end <= len(text) && start <= end {
                                    citedText = text[start:end]
                                }
                                title := ""
                                if c.Title != nil {
                                    title = *c.Title
                                }
                                url := ""
                                if c.URL != nil {
                                    url = *c.URL
                                }
                                fmt.Printf("  [%s](%s)\n", title, url)
                                fmt.Printf("    Cited text: %q\n", citedText)
                            }
                        }
                    }
                }
            }
        }
    }
}

출력은 텍스트 다음에 인용을 보여줘요:

Spain won Euro 2024, defeating England 2-1 in the final. This victory marks Spain's record fourth European Championship title.

Citations:
  [aljazeera.com](https://www.aljazeera.com/sports/euro-2024-final)
    Cited text: "Spain won Euro 2024, defeating England 2-1 in the final."
  [uefa.com](https://www.uefa.com/euro2024/news/spain-wins-euro-2024)
    Cited text: "This victory marks Spain's record fourth European Championship title."

가격(Pricing)

Gemini 3와 함께 Google Search Grounding을 사용할 때, 프로젝트는 모델이 실행하기로 결정한 각 검색 쿼리에 대해 청구돼요. 모델이 단일 프롬프트에 답하기 위해 여러 검색 쿼리를 실행하기로 결정하면(예: 같은 API 호출에서 "UEFA Euro 2024 winner"와 "Spain vs England Euro 2024 final score"를 검색), 해당 요청의 도구 사용이 두 번 청구되는 것으로 계산돼요. 청구 목적상 고유 쿼리를 셀 때 빈 웹 검색 쿼리는 무시해요. 이 청구 모델은 Gemini 3 모델에만 적용돼요. Gemini 2.5 또는 이전 모델로 검색 grounding을 사용하면 프로젝트가 프롬프트당 청구돼요.

자세한 가격 정보는 Gemini API 가격 페이지를 참고하세요.

지원 모델

전체 기능은 모델 개요 페이지에서 확인할 수 있어요.

모델 Google Search Grounding
Gemini 3.8 Flash ✔️
Gemini 3.7 Flash ✔️
Gemini 3.6 Flash ✔️
Gemini 3.5 Flash-Lite ✔️
Gemini 3.5 Flash ✔️
Gemini 3.1 Flash Image Preview ✔️
Gemini 3.1 Pro Preview ✔️
Gemini 3 Pro Image Preview ✔️
Gemini 3 Flash Preview ✔️
Gemini 2.5 Pro ✔️
Gemini 2.5 Flash ✔️
Gemini 2.5 Flash-Lite ✔️
Gemini 2.0 Flash ✔️

참고: 이전 모델은 google_search_retrieval 도구를 사용해요. 모든 현재 모델에는 예시와 같이 google_search 도구를 사용하세요.

지원 도구 조합

Google Search Grounding은 코드 실행, URL context, Google Maps Grounding(Gemini 3.5 Flash 이후 모델에서 지원) 같은 다른 도구와 함께 사용해 더 복잡한 사용 사례를 구현할 수 있어요. Gemini 3 모델은 이러한 내장 도구를 커스텀 도구(함수 호출)와 결합하는 것도 지원해요. 도구 조합 페이지에서 자세히 알아보세요.

더 알아보기 (Learn more)