問題描述
候選人使用 Gemini thinking 模型(如 gemini-3.1-flash-lite-preview)搭配 AI tool calling 時,後端回傳 400 錯誤: Function call is missing a thought_signature.
根本原因
上游 bug:spring-projects/spring-ai#5466 GoogleGenAiChatModel.responseCandidateToGeneration()(line 655)使用 allMatch 判斷是否為 function call:
boolean isFunctionCall = parts.stream().allMatch(part -> part.functionCall().isPresent());
Gemini 3 thinking 模型回傳混合型 parts:[thought_part, functionCall_part]。
- allMatch = false → tool call 被整個丟棄
- 下一次請求中 function call 缺少 thought_signature → Gemini API 回 400
目前解法
▎ 已實作於 PatchedGoogleGenAiChatModel.java,參考 spring-projects/spring-ai#5489
繼承 GoogleGenAiChatModel,override responseCandidateToGeneration(),修改判斷邏輯:
// 修復:anyMatch 取代 allMatch
// 混合回應(thinking + function call)時,只要有任意 functionCall part 就視為 tool call
boolean hasFunctionCall = parts.stream().anyMatch(part -> part.functionCall().isPresent());
同時:
- 提取非 function call 的 text parts(thinking summary)合併為 AssistantMessage content
- 保留父類別的 thoughtSignatures 提取與重新附加邏輯,確保 thought_signature 正確傳遞
AiModelRegistry 的 google-genai case 改用 PatchedGoogleGenAiChatModel constructor 直接建立(因 GoogleGenAiChatModel.Builder.build() 固定回傳父類別實例):
PatchedGoogleGenAiChatModel chatModel = new PatchedGoogleGenAiChatModel(
genAiClient,
GoogleGenAiChatOptions.builder().model(entry.id()).build()
);
移除條件
Spring AI 發布包含 spring-projects/spring-ai#5489 修復的版本(預計 2.0.0-M3 或更高)後:
- 升級 Spring AI 版本
- 刪除 PatchedGoogleGenAiChatModel.java
- AiModelRegistry 改回使用 GoogleGenAiChatModel.builder()
- 驗證 Gemini thinking 模型 + tool call 正常運作
參考
問題描述
候選人使用 Gemini thinking 模型(如
gemini-3.1-flash-lite-preview)搭配 AI tool calling 時,後端回傳 400 錯誤: Function call is missing a thought_signature.根本原因
上游 bug:spring-projects/spring-ai#5466
GoogleGenAiChatModel.responseCandidateToGeneration()(line 655)使用allMatch判斷是否為 function call:Gemini 3 thinking 模型回傳混合型 parts:[thought_part, functionCall_part]。
目前解法
▎ 已實作於 PatchedGoogleGenAiChatModel.java,參考 spring-projects/spring-ai#5489
繼承 GoogleGenAiChatModel,override responseCandidateToGeneration(),修改判斷邏輯:
// 修復:anyMatch 取代 allMatch
// 混合回應(thinking + function call)時,只要有任意 functionCall part 就視為 tool call
boolean hasFunctionCall = parts.stream().anyMatch(part -> part.functionCall().isPresent());
同時:
AiModelRegistry 的 google-genai case 改用 PatchedGoogleGenAiChatModel constructor 直接建立(因 GoogleGenAiChatModel.Builder.build() 固定回傳父類別實例):
移除條件
Spring AI 發布包含 spring-projects/spring-ai#5489 修復的版本(預計 2.0.0-M3 或更高)後:
參考