생각 서명

사고 서명은 모델의 내부 사고 프로세스를 암호화한 표현이며, 멀티턴 상호작용 전반에서 추론 컨텍스트를 유지하는 데 사용됩니다. 사고 모델 (예: Gemini 3 및 2.5 시리즈)을 사용하는 경우 API는 응답의 콘텐츠 파트 내에 thoughtSignature 필드를 반환할 수 있습니다 (예: text 또는 functionCall 부분).

일반적으로 모델 응답에서 사고 서명을 수신한 경우 다음 턴에서 대화 기록을 전송할 때 수신한 그대로 다시 전달해야 합니다. Gemini 3 Pro를 사용하는 경우 함수 호출 중에 사고 서명을 다시 전달해야 합니다. 그렇지 않으면 검증 오류가 발생합니다 (4xx 상태 코드).

작동 방식

아래 그래픽은 Gemini API의 함수 호출과 관련된 '턴'과 '단계'의 의미를 시각화합니다. '턴'은 사용자와 모델 간의 대화에서 완전한 단일 교환입니다. '단계'는 모델이 실행하는 더 세부적인 작업 또는 작업으로, 턴을 완료하기 위한 더 큰 프로세스의 일부인 경우가 많습니다.

함수 호출 턴 및 단계 다이어그램

이 문서에서는 Gemini 3 Pro의 함수 호출 처리에 중점을 둡니다. 2.5와의 차이점은 모델 동작 섹션을 참고하세요.

Gemini 3 Pro는 함수 호출을 통해 모든 모델 응답 (API의 응답)에 대한 사고 서명을 반환합니다. 생각 서명은 다음과 같은 경우에 표시됩니다.

  • 병렬 함수 호출이 있는 경우 모델 응답에서 반환된 첫 번째 함수 호출 부분에 생각 서명이 있습니다.
  • 순차적 함수 호출 (다단계)이 있는 경우 각 함수 호출에는 서명이 있으며 모든 서명을 다시 전달해야 합니다.
  • 함수 호출이 없는 모델 응답은 모델에서 반환된 마지막 부분 내에 생각 서명을 반환합니다.

다음 표에서는 턴과 단계의 정의를 위에 소개된 서명 개념과 결합하여 다단계 함수 호출을 시각화합니다.

켜기

단계

사용자 요청

모델 응답

FunctionResponse

1

1

request1 = user_prompt FC1 + signature FR1

1

2

request2 = request1 + (FC1 + signature) + FR1 FC2 + signature FR2

1

3

request3 = request2 + (FC2 + signature) + FR2 text_output

(no FCs)

없음

함수 호출 파트의 서명

Gemini가 functionCall를 생성할 때 다음 턴에서 도구의 출력을 올바르게 처리하기 위해 thought_signature를 사용합니다.

  • 동작:
    • 단일 함수 호출: functionCall 부분에 thought_signature이 포함됩니다.
    • 병렬 함수 호출: 모델이 응답에서 병렬 함수 호출을 생성하는 경우 thought_signature첫 번째 functionCall 부분에만 연결됩니다. 동일한 대답의 후속 functionCall 부분에는 서명이 포함되지 않습니다.
  • 요구사항: 대화 기록을 다시 보낼 때 수신된 정확한 부분에 이 서명을 반환해야 합니다.
  • 유효성 검사: 현재 턴 내의 모든 함수 호출에 엄격한 유효성 검사가 적용됩니다 . (현재 턴만 필요하며 이전 턴은 검증하지 않음)
    • API는 기록 (최신에서 오래된 순)으로 돌아가 표준 콘텐츠 (예: text) ( 현재 턴의 시작) functionResponsebe.
    • 해당 특정 사용 메시지 이후에 발생하는 모든 모델 functionCall은 턴의 일부로 간주됩니다.
    • 현재 턴의 각 단계에 있는 첫 번째 functionCall 부분에는 thought_signature가 포함되어야 합니다.
    • 현재 턴의 단계에서 첫 번째 functionCall 부분의 thought_signature를 생략하면 400 오류가 발생하여 요청이 실패합니다.
  • 적절한 서명이 반환되지 않는 경우 오류가 발생하는 방식은 다음과 같습니다.
    • gemini-3-pro-preview: 서명을 포함하지 않으면 400 오류가 발생합니다. 문구는 다음 형식입니다.
      • <index of contents array> 콘텐츠 블록의 <Function Call> 함수 호출에 thought_signature가 누락되었습니다. 예를 들어 1. 콘텐츠 블록의 FC1 함수 호출에 thought_signature이 누락되었습니다.

순차적 함수 호출 예시

이 섹션에서는 사용자가 여러 작업이 필요한 복잡한 질문을 하는 여러 함수 호출의 예를 보여줍니다.

사용자가 여러 작업이 필요한 복잡한 질문("Check flight status for AA100 and book a taxi if delayed")을 하는 멀티턴 함수 호출 예를 살펴보겠습니다.

켜기

단계

사용자 요청

모델 응답

FunctionResponse

1

1

request1="Check flight status for AA100 and book a taxi 2 hours before if delayed." FC1 ("check_flight") + signature FR1

1

2

request2 = request1 + FC1 ("check_flight") + signature + FR1 FC2("book_taxi") + signature FR2

1

3

request3 = request2 + FC2 ("book_taxi") + signature + FR2 text_output

(no FCs)

None

다음 코드는 위 표의 시퀀스를 보여줍니다.

1턴, 1단계 (사용자 요청)

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
        }
      ]
    }
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "check_flight",
          "description": "Gets the current status of a flight",
          "parameters": {
            "type": "object",
            "properties": {
              "flight": {
                "type": "string",
                "description": "The flight number to check"
              }
            },
            "required": [
              "flight"
            ]
          }
        },
        {
          "name": "book_taxi",
          "description": "Book a taxi",
          "parameters": {
            "type": "object",
            "properties": {
              "time": {
                "type": "string",
                "description": "time to book the taxi"
              }
            },
            "required": [
              "time"
            ]
          }
        }
      ]
    }
  ]
}

1턴, 1단계 (모델 응답)

{
"content": {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "check_flight",
              "args": {
                "flight": "AA100"
              }
            },
            "thoughtSignature": "<Signature A>"
          }
        ]
  }
}

1턴, 2단계 (사용자 응답 - 도구 출력 전송) 이 사용자 턴에는 functionResponse만 포함되어 있으므로 (새 텍스트 없음) 아직 1턴입니다. <Signature_A>을 보존해야 합니다.

{
      "role": "user",
      "parts": [
        {
          "text": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
        }
      ]
    },
    {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "check_flight",
              "args": {
                "flight": "AA100"
              }
            },
            "thoughtSignature": "<Signature A>" //Required and Validated
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "functionResponse": {
              "name": "check_flight",
              "response": {
                "status": "delayed",
                "departure_time": "12 PM"
                }
              }
            }
        ]
}

1턴, 2단계 (모델) 이제 모델이 이전 도구 출력을 기반으로 택시를 예약하기로 결정합니다.

{
      "content": {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "book_taxi",
              "args": {
                "time": "10 AM"
              }
            },
            "thoughtSignature": "<Signature B>"
          }
        ]
      }
}

1턴, 3단계 (사용자 - 도구 출력 전송) 택시 예약 확인을 전송하려면 이 루프(<Signature A> + <Signature B>)에 있는 모든 함수 호출의 서명을 포함해야 합니다.

{
      "role": "user",
      "parts": [
        {
          "text": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
        }
      ]
    },
    {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "check_flight",
              "args": {
                "flight": "AA100"
              }
            },
            "thoughtSignature": "<Signature A>" //Required and Validated
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "functionResponse": {
              "name": "check_flight",
              "response": {
                "status": "delayed",
                "departure_time": "12 PM"
              }
              }
            }
        ]
      },
      {
        "role": "model",
        "parts": [
          {
            "functionCall": {
              "name": "book_taxi",
              "args": {
                "time": "10 AM"
              }
            },
            "thoughtSignature": "<Signature B>" //Required and Validated
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "functionResponse": {
              "name": "book_taxi",
              "response": {
                "booking_status": "success"
              }
              }
            }
        ]
    }
}

병렬 함수 호출 예시

사용자가 모델이 검증을 수행하는 위치를 확인하기 위해 "Check weather in Paris and London"에 요청하는 병렬 함수 호출 예시를 살펴보겠습니다.

켜기

단계

사용자 요청

모델 응답

FunctionResponse

1

1

request1="Check the weather in Paris and London"

FC1 ('파리') + 서명

FC2 ('런던')

FR1

1

2

request2 = request1 + FC1 ('Paris') + 서명 + FC2 ('London')

text_output

(FC 없음)

없음

다음 코드는 위 표의 시퀀스를 보여줍니다.

1턴, 1단계 (사용자 요청)

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "Check the weather in Paris and London."
        }
      ]
    }
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "get_current_temperature",
          "description": "Gets the current temperature for a given location.",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city name, e.g. San Francisco"
              }
            },
            "required": [
              "location"
            ]
          }
        }
      ]
    }
  ]
}

1턴, 1단계 (모델 응답)

{
  "content": {
    "parts": [
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "location": "Paris"
          }
        },
        "thoughtSignature": "<Signature_A>"// INCLUDED on First FC
      },
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "location": "London"
          }// NO signature on subsequent parallel FCs
        }
      }
    ]
  }
}

1턴, 2단계 (사용자 응답 - 도구 출력 전송) 첫 번째 부분에서 <Signature_A>를 수신한 그대로 유지해야 합니다.

[
  {
    "role": "user",
    "parts": [
      {
        "text": "Check the weather in Paris and London."
      }
    ]
  },
  {
    "role": "model",
    "parts": [
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "city": "Paris"
          }
        },
        "thought_signature": "<Signature_A>" // MUST BE INCLUDED
      },
      {
        "functionCall": {
          "name": "get_current_temperature",
          "args": {
            "city": "London"
          }
        }
      } // NO SIGNATURE FIELD
    ]
  },
  {
    "role": "user",
    "parts": [
      {
        "functionResponse": {
          "name": "get_current_temperature",
          "response": {
            "temp": "15C"
          }
        }
      },
      {
        "functionResponse": {
          "name": "get_current_temperature",
          "response": {
            "temp": "12C"
          }
        }
      }
    ]
  }
]

functionCall이 아닌 부분의 서명

Gemini는 함수 호출이 아닌 부분의 대답 마지막 부분에 thought_signatures를 반환할 수도 있습니다.

  • 동작: 모델에서 반환된 최종 콘텐츠 부분 (text, inlineData…)에 thought_signature이 포함될 수 있습니다.
  • 권장사항: 모델이 특히 복잡한 안내 따르기 또는 시뮬레이션된 에이전트형 워크플로에서 고품질 추론을 유지하도록 이러한 서명을 반환하는 것이 권장됩니다.
  • 유효성 검사: API는 유효성 검사를 엄격하게 적용하지 않습니다. 이러한 항목을 누락해도 차단 오류가 발생하지는 않지만 성능이 저하될 수 있습니다.

텍스트/맥락 내 추론 (검증 없음)

1턴, 1단계 (모델 응답)

{
  "role": "model",
  "parts": [
    {
      "text": "I need to calculate the risk. Let me think step-by-step...",
      "thought_signature": "<Signature_C>" // OPTIONAL (Recommended)
    }
  ]
}

2턴, 1단계 (사용자)

[
  { "role": "user", "parts": [{ "text": "What is the risk?" }] },
  {
    "role": "model", 
    "parts": [
      {
        "text": "I need to calculate the risk. Let me think step-by-step...",
        // If you omit <Signature_C> here, no error will occur.
      }
    ]
  },
  { "role": "user", "parts": [{ "text": "Summarize it." }] }
]

OpenAI 호환성을 위한 서명

다음 예에서는 OpenAI 호환성을 사용하여 채팅 완성 API의 사고 서명을 처리하는 방법을 보여줍니다.

순차적 함수 호출 예시

다음은 사용자가 여러 작업이 필요한 복잡한 질문을 하는 다중 함수 호출의 예입니다.

사용자가 Check flight status for AA100 and book a taxi if delayed라고 묻는 멀티턴 함수 호출 예를 살펴보겠습니다. 사용자가 여러 작업이 필요한 복잡한 질문을 할 때 어떤 일이 일어나는지 확인할 수 있습니다.

켜기

단계

사용자 요청

모델 응답

FunctionResponse

1

1

request1="Check the weather in Paris and London" FC1 ("Paris") + signature

FC2 ("London")

FR1

1

2

request 2 = request1 + FC1 ("Paris") + signature + FC2 ("London") text_output

(no FCs)

None

다음 코드는 지정된 시퀀스를 안내합니다.

1턴, 1단계 (사용자 요청)

{
  "model": "google/gemini-3-pro-preview",
  "messages": [
    {
      "role": "user",
      "content": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "check_flight",
        "description": "Gets the current status of a flight",
        "parameters": {
          "type": "object",
          "properties": {
            "flight": {
              "type": "string",
              "description": "The flight number to check."
            }
          },
          "required": [
            "flight"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "book_taxi",
        "description": "Book a taxi",
        "parameters": {
          "type": "object",
          "properties": {
            "time": {
              "type": "string",
              "description": "time to book the taxi"
            }
          },
          "required": [
            "time"
          ]
        }
      }
    }
  ]
}

1턴, 1단계 (모델 응답)

{
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>"
              }
            },
            "function": {
              "arguments": "{\"flight\":\"AA100\"}",
              "name": "check_flight"
            },
            "id": "function-call-1",
            "type": "function"
          }
        ]
    }

1턴, 2단계 (사용자 응답 - 도구 출력 전송)

이 사용자 턴에는 functionResponse만 포함되어 있으므로 (새 텍스트 없음) 아직 턴 1에 있으며 <Signature_A>을 보존해야 합니다.

"messages": [
    {
      "role": "user",
      "content": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
    },
    {
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Required and Validated
              }
            },
            "function": {
              "arguments": "{\"flight\":\"AA100\"}",
              "name": "check_flight"
            },
            "id": "function-call-1",
            "type": "function"
          }
        ]
    },
    {
      "role": "tool",
      "name": "check_flight",
      "tool_call_id": "function-call-1",
      "content": "{\"status\":\"delayed\",\"departure_time\":\"12 PM\"}"                 
    }
  ]

1턴, 2단계 (모델)

이제 모델이 이전 도구 출력을 기반으로 택시를 예약하기로 결정합니다.

{
"role": "model",
"tool_calls": [
{
"extra_content": {
"google": {
"thought_signature": "<Signature B>"
}
            },
            "function": {
              "arguments": "{\"time\":\"10 AM\"}",
              "name": "book_taxi"
            },
            "id": "function-call-2",
            "type": "function"
          }
       ]
}

1턴, 3단계 (사용자 - 도구 출력 전송)

택시 예약 확인을 보내려면 이 루프의 모든 함수 호출 (<Signature A> + <Signature B>)에 서명을 포함해야 합니다.

"messages": [
    {
      "role": "user",
      "content": "Check flight status for AA100 and book a taxi 2 hours before if delayed."
    },
    {
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Required and Validated
              }
            },
            "function": {
              "arguments": "{\"flight\":\"AA100\"}",
              "name": "check_flight"
            },
            "id": "function-call-1d6a1a61-6f4f-4029-80ce-61586bd86da5",
            "type": "function"
          }
        ]
    },
    {
      "role": "tool",
      "name": "check_flight",
      "tool_call_id": "function-call-1d6a1a61-6f4f-4029-80ce-61586bd86da5",
      "content": "{\"status\":\"delayed\",\"departure_time\":\"12 PM\"}"                 
    },
    {
      "role": "model",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature B>" //Required and Validated
              }
            },
            "function": {
              "arguments": "{\"time\":\"10 AM\"}",
              "name": "book_taxi"
            },
            "id": "function-call-65b325ba-9b40-4003-9535-8c7137b35634",
            "type": "function"
          }
        ]
    },
    {
      "role": "tool",
      "name": "book_taxi",
      "tool_call_id": "function-call-65b325ba-9b40-4003-9535-8c7137b35634",
      "content": "{\"booking_status\":\"success\"}"
    }
  ]

병렬 함수 호출 예시

사용자가 "Check weather in Paris and London"를 요청하는 병렬 함수 호출 예시를 살펴보겠습니다. 모델이 검증을 수행하는 위치를 확인할 수 있습니다.

켜기

단계

사용자 요청

모델 응답

FunctionResponse

1

1

request1="Check the weather in Paris and London" FC1 ("Paris") + signature

FC2 ("London")

FR1

1

2

request 2 = request1 + FC1 ("Paris") + signature + FC2 ("London") text_output

(no FCs)

None

다음은 주어진 시퀀스를 안내하는 코드입니다.

1턴, 1단계 (사용자 요청)

{
  "contents": [
    {
      "role": "user",
      "parts": [
        {
          "text": "Check the weather in Paris and London."
        }
      ]
    }
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "get_current_temperature",
          "description": "Gets the current temperature for a given location.",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city name, e.g. San Francisco"
              }
            },
            "required": [
              "location"
            ]
          }
        }
      ]
    }
  ]
}

1턴, 1단계 (모델 응답)

{
"role": "assistant",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Signature returned
              }
            },
            "function": {
              "arguments": "{\"location\":\"Paris\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-f3b9ecb3-d55f-4076-98c8-b13e9d1c0e01",
            "type": "function"
          },
          {
            "function": {
              "arguments": "{\"location\":\"London\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-335673ad-913e-42d1-bbf5-387c8ab80f44",
            "type": "function" // No signature on Parallel FC
          }
        ]
}

1턴, 2단계 (사용자 응답 - 도구 출력 전송)

첫 번째 부분에서 <Signature_A>을 수신한 그대로 유지해야 합니다.

"messages": [
    {
      "role": "user",
      "content": "Check the weather in Paris and London."
    },
    {
      "role": "assistant",
        "tool_calls": [
          {
            "extra_content": {
              "google": {
                "thought_signature": "<Signature A>" //Required
              }
            },
            "function": {
              "arguments": "{\"location\":\"Paris\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-f3b9ecb3-d55f-4076-98c8-b13e9d1c0e01",
            "type": "function"
          },
          {
            "function": { //No Signature
              "arguments": "{\"location\":\"London\"}",
              "name": "get_current_temperature"
            },
            "id": "function-call-335673ad-913e-42d1-bbf5-387c8ab80f44",
            "type": "function"
          }
        ]
    },
    {
      "role":"tool",
      "name": "get_current_temperature",
      "tool_call_id": "function-call-f3b9ecb3-d55f-4076-98c8-b13e9d1c0e01",
      "content": "{\"temp\":\"15C\"}"
    },    
    {
      "role":"tool",
      "name": "get_current_temperature",
      "tool_call_id": "function-call-335673ad-913e-42d1-bbf5-387c8ab80f44",
      "content": "{\"temp\":\"12C\"}"
    }
  ]

FAQ

  1. 현재 턴과 단계에 함수 호출 부분이 있는 경우 다른 모델의 기록을 Gemini 3 Pro로 전송하려면 어떻게 해야 하나요? API에서 생성되지 않아 연결된 사고 서명이 없는 함수 호출 부분을 제공해야 하나요?

    요청에 맞춤 함수 호출 블록을 삽입하는 것은 적극 권장되지 않지만, 클라이언트에서 결정적으로 실행된 함수 호출 및 응답에 관한 정보를 모델에 제공하거나 사고 서명이 포함되지 않은 다른 모델의 트레이스를 전송하는 등 피할 수 없는 경우에는 사고 서명 필드에 "context_engineering_is_the_way_to_go" 또는 "skip_thought_signature_validator"의 더미 서명을 설정하여 유효성 검사를 건너뛸 수 있습니다.

  2. 인터리브된 병렬 함수 호출 및 응답을 다시 전송하고 있는데 API에서 400을 반환합니다. 이유가 무엇인가요?

    API가 병렬 함수 호출 'FC1 + 서명, FC2'를 반환하면 예상되는 사용자 응답은 'FC1+ 서명, FC2, FR1, FR2'입니다. 'FC1 + 서명, FR1, FC2, FR2'와 같이 인터리브된 경우 API는 400 오류를 반환합니다.

  3. 스트리밍 중이고 모델이 함수 호출을 반환하지 않으면 사고 서명을 찾을 수 없음

    스트리밍 요청이 있는 FC를 포함하지 않는 모델 응답 중에 모델은 텍스트 콘텐츠 부분이 비어 있는 부분에 생각 서명을 반환할 수 있습니다. 모델에서 finish_reason가 반환될 때까지 전체 요청을 파싱하는 것이 좋습니다.

모델 시리즈별 생각 서명 동작

Gemini 3 Pro 및 Gemini 2.5 모델은 함수 호출에서 생각 서명과 다르게 작동합니다.

  • 대답에 함수 호출이 있는 경우
    • Gemini 3 Pro에는 항상 첫 번째 함수 호출 부분에 서명이 있습니다. 이 부분을 반환하는 것은 필수입니다.
    • Gemini 2.5는 유형과 관계없이 첫 번째 부분에 서명이 있습니다. 이 부분을 반환하는 것은 선택사항입니다.
  • 대답에 함수 호출이 없으면
    • Gemini 3 Pro는 모델이 생각을 생성하는 경우 마지막 부분에 서명이 표시됩니다.
    • Gemini 2.5에는 어느 부분에도 서명이 없습니다.

Gemini 2.5 모델의 생각 서명 동작은 생각 페이지를 참고하세요.