도구 호출

도구 호출(함수 호출이라고도 함)은 LLM에 이를 호출한 애플리케이션에 다시 요청할 수 있는 기능을 제공하는 구조화된 방법입니다. 개발자는 모델에 제공할 도구를 정의하고 모델은 개발자가 제공하는 프롬프트를 실행하는 데 필요에 따라 앱에 도구를 요청합니다.

도구 호출의 사용 사례는 일반적으로 다음과 같은 몇 가지 주제에 해당합니다.

학습되지 않은 정보에 LLM이 액세스하도록 허용

  • 주식 가격이나 현재 날씨와 같이 자주 변경되는 정보
  • 제품 정보 또는 사용자 프로필과 같이 앱 도메인에만 해당하는 정보

LLM이 사실에 기반한 정보를 생성에 통합할 수 있는 방법이기도 한 검색 증강 생성(RAG)과 중복되는 부분에 유의하세요. RAG는 대용량 정보가 있거나 프롬프트와 가장 관련성이 높은 정보가 모호한 경우에 가장 적합한 무거운 솔루션입니다. 반면에 LLM에 필요한 정보를 가져오는 것이 간단한 함수 호출이나 데이터베이스 조회인 경우 도구 호출이 더 적절합니다.

LLM 워크플로에 결정성 정도 도입

  • LLM이 자체적으로 안정적으로 완료할 수 없는 계산을 수행합니다.
  • 앱 서비스 약관에 관한 질문에 답변할 때와 같이 특정 상황에서 LLM이 그대로 텍스트를 생성하도록 강제합니다.

LLM에서 시작된 경우 작업 수행

  • LLM 기반 홈 어시스턴트에서 조명 켜기 및 끄기
  • LLM 지원 레스토랑 에이전트에서 테이블 예약하기

시작하기 전에

이 페이지의 코드 예시를 실행하려면 먼저 시작하기 가이드의 단계를 완료하세요. 모든 예시에서는 Genkit 종속 항목이 설치된 프로젝트를 이미 설정했다고 가정합니다.

이 페이지에서는 Genkit 모델 추상화의 고급 기능 중 하나를 설명합니다. 따라서 너무 깊이 들어가기 전에 AI 모델로 콘텐츠 생성 페이지의 콘텐츠를 숙지해야 합니다. 또한 입력 및 출력 스키마를 정의하는 Genkit의 시스템을 숙지해야 합니다. 이 시스템은 플로우 페이지에서 설명합니다.

도구 호출 개요

대략적으로 LLM과 일반적인 도구 호출 상호작용은 다음과 같습니다.

  1. 호출 애플리케이션은 요청을 포함하는 프롬프트를 LLM에 표시하고 LLM이 응답을 생성하는 데 사용할 수 있는 도구 목록도 프롬프트에 포함합니다.
  2. LLM은 완전 응답을 생성하거나 특정 형식의 도구 호출 요청을 생성합니다.
  3. 호출자가 완전 응답을 수신하면 요청이 처리되고 상호작용이 종료됩니다. 하지만 호출자가 도구 호출을 수신하면 적절한 로직을 수행하고 원래 프롬프트 또는 그 변형과 도구 호출의 결과가 포함된 새 요청을 LLM에 전송합니다.
  4. LLM은 2단계에서와 같이 새 프롬프트를 처리합니다.

이렇게 하려면 다음과 같은 몇 가지 요구사항을 충족해야 합니다.

  • 프롬프트를 완료하는 데 필요한 경우 도구 요청을 하도록 모델을 학습시켜야 합니다. Gemini와 같은 웹 API를 통해 제공되는 대부분의 대규모 모델은 이를 수행할 수 있지만 더 작은 규모의 특화된 모델은 수행할 수 없는 경우가 많습니다. 지원하지 않는 모델에 도구를 제공하려고 하면 Genkit에서 오류가 발생합니다.
  • 호출 애플리케이션은 모델에 예상되는 형식으로 도구 정의를 제공해야 합니다.
  • 호출 애플리케이션은 모델에 애플리케이션이 예상하는 형식으로 도구 호출 요청을 생성하도록 프롬프트해야 합니다.

Genkit를 사용한 도구 호출

Genkit는 이를 지원하는 모델을 사용하여 도구를 호출하기 위한 단일 인터페이스를 제공합니다. 각 모델 플러그인은 위 기준 중 마지막 두 가지가 충족되도록 하고 genkit.Generate() 함수는 앞에서 설명한 도구 호출 루프를 자동으로 실행합니다.

모델 지원

도구 호출 지원은 모델, 모델 API, Genkit 플러그인에 따라 다릅니다. 관련 문서를 참고하여 도구 호출이 지원될 가능성이 있는지 확인합니다. 또한 다음 사항도 적용됩니다.

  • 지원하지 않는 모델에 도구를 제공하려고 하면 Genkit에서 오류가 발생합니다.
  • 플러그인이 모델 참조를 내보내는 경우 ModelInfo.Supports.Tools 속성은 도구 호출을 지원하는지 나타냅니다.

도구 정의

genkit.DefineTool() 함수를 사용하여 도구 정의를 작성합니다.

import (
    "context"
    "log"

    "github.com/firebase/genkit/go/ai"
    "github.com/firebase/genkit/go/genkit"
    "github.com/firebase/genkit/go/plugins/googlegenai"
)

func main() {
    ctx := context.Background()

    g, err := genkit.Init(ctx,
        genkit.WithPlugins(&googlegenai.GoogleAI{}),
        genkit.WithDefaultModel("googleai/gemini-2.0-flash"),
    )
    if err != nil {
      log.Fatal(err)
    }

    getWeatherTool := genkit.DefineTool(
        g, "getWeather", "Gets the current weather in a given location",
        func(ctx *ai.ToolContext, location string) (string, error) {
            // Here, we would typically make an API call or database query. For this
            // example, we just return a fixed value.
            return fmt.Sprintf("The current weather in %s is 63°F and sunny.", location);
        })
}

여기서 구문은 genkit.DefineFlow() 구문과 똑같지만 설명을 작성해야 합니다. 설명의 문구와 서술에 특히 주의하세요. LLM이 적절하게 사용할지 결정하는 데 중요한 요소입니다.

도구 사용

콘텐츠를 생성하는 프롬프트에 정의된 도구를 포함합니다.

생성

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("What is the weather in San Francisco?"),
    ai.WithTools(getWeatherTool),
)

DefinePrompt

weatherPrompt, err := genkit.DefinePrompt(g, "weatherPrompt",
    ai.WithPrompt("What is the weather in {{location}}?"),
    ai.WithTools(getWeatherTool),
)
if err != nil {
    log.Fatal(err)
}

resp, err := weatherPrompt.Execute(ctx,
    with.Input(map[string]any{"location": "San Francisco"}),
)

프롬프트 파일

---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
  schema:
    location: string
---

What is the weather in {{location}}?

그런 다음 다음과 같이 코드에서 프롬프트를 실행할 수 있습니다.

// Assuming prompt file named weatherPrompt.prompt exists in ./prompts dir.
weatherPrompt := genkit.LookupPrompt("weatherPrompt")
if weatherPrompt == nil {
    log.Fatal("no prompt named 'weatherPrompt' found")
}

resp, err := weatherPrompt.Execute(ctx,
    ai.WithInput(map[string]any{"location": "San Francisco"}),
)

LLM이 getWeather 도구를 사용하여 프롬프트에 대답해야 하는 경우 Genkit에서 도구 호출을 자동으로 처리합니다.

도구 호출을 명시적으로 처리

더 복잡한 로직을 적용하는 등 이 도구 호출 루프를 완전히 제어하려면 WithReturnToolRequests() 옵션을 true로 설정하세요. 이제 모든 도구 요청이 처리되도록 하는 것은 개발자의 책임입니다.

getWeatherTool := genkit.DefineTool(
    g, "getWeather", "Gets the current weather in a given location",
    func(ctx *ai.ToolContext, location string) (string, error) {
        // Tool implementation...
    })

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("What is the weather in San Francisco?"),
    ai.WithTools(getWeatherTool),
    ai.WithReturnToolRequests(true),
)
if err != nil {
    log.Fatal(err)
}

parts := []*Part{}
for _, req := range resp.ToolRequests() {
    tool := genkit.LookupTool(g, req.Name)
    if tool == nil {
        log.Fatalf("tool %q not found", req.Name)
    }

    output, err := tool.RunRaw(ctx, req.Input)
    if err != nil {
        log.Fatalf("tool %q execution failed: %v", err)
    }

    parts = append(parts,
        ai.NewToolResponsePart(&ai.ToolResponse{
            Name:   req.Name,
            Ref:    req.Ref,
            Output: output,
        }))
}

resp, err = genkit.Generate(ctx, g,
    ai.WithMessages(resp.History()..., NewMessage(ai.RoleTool, nil, parts...)),
)
if err != nil {
    log.Fatal(err)
}