From 03bae6424ef74c2285198e0b1d0133c285350994 Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Sat, 25 Apr 2026 00:11:57 +0800 Subject: [PATCH] fix(openai-provider): ensure structured chat adds JSON instruction when missing --- .../openai/OpenAiCompatibleProvider.java | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/model/provider/openai/OpenAiCompatibleProvider.java b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/model/provider/openai/OpenAiCompatibleProvider.java index 8154789b..5ae7f4eb 100644 --- a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/model/provider/openai/OpenAiCompatibleProvider.java +++ b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/model/provider/openai/OpenAiCompatibleProvider.java @@ -17,10 +17,7 @@ import work.slhaf.partner.framework.agent.model.provider.ProviderOverride; import work.slhaf.partner.framework.agent.support.Result; import java.time.Duration; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class OpenAiCompatibleProvider extends ModelProvider { @@ -103,7 +100,7 @@ public class OpenAiCompatibleProvider extends ModelProvider { return executeWithRetry( "OpenAI-compatible provider failed to complete the structured chat request after 3 attempts.", () -> { - StructuredChatCompletionCreateParams params = buildParams(messages).toBuilder() + StructuredChatCompletionCreateParams params = buildParams(ensureJsonInstruction(messages)).toBuilder() .responseFormat(responseType) .build(); return extractStructured(client.chat().completions().create(params)); @@ -111,6 +108,35 @@ public class OpenAiCompatibleProvider extends ModelProvider { ); } + private List ensureJsonInstruction(List messages) { + boolean containsJsonInstruction = messages.stream() + .map(Message::getContent) + .filter(content -> !content.isBlank()) + .anyMatch(content -> content.toLowerCase(Locale.ROOT).contains("json")); + if (containsJsonInstruction) { + return messages; + } + + String jsonInstruction = "Return only a valid JSON object that matches the requested response schema."; + List patched = new ArrayList<>(messages.size() + 1); + boolean merged = false; + for (Message message : messages) { + if (!merged && message.getRole() == Message.Character.SYSTEM) { + patched.add(new Message( + Message.Character.SYSTEM, + message.getContent() + "\n\n" + jsonInstruction + )); + merged = true; + continue; + } + patched.add(message); + } + if (!merged) { + patched.addFirst(new Message(Message.Character.SYSTEM, jsonInstruction)); + } + return patched; + } + private ChatCompletionCreateParams buildParams(List messages) { ChatCompletionCreateParams.Builder paramsBuilder = ChatCompletionCreateParams.builder() .model(model)