Azure / azure-sdk-for-java

This repository is for active development of the Azure SDK for Java. For consumers of the SDK we recommend visiting our public developer docs at https://docs.microsoft.com/java/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-java.
MIT License
2.31k stars 1.97k forks source link

[BUG] Azure OpenAI > 1.0.0-beta.8 (starting from beta 9) causes JSON streaming payload issues #41164

Open timostark opened 2 months ago

timostark commented 2 months ago

Describe the bug After the change to azure-json in beta 9 there are assertions when using function calling with streaming. Everything is still working, but ofc the console errors are not OK.

Exception or Stack Trace ChatCompletionsToolCall.java public static ChatCompletionsToolCall fromJson(JsonReader jsonReader) throws IOException

--> throws (>20 times)

2024-07-16T12:08:10.913+02:00 ERROR 33620 --- [oundedElastic-1] c.a.c.i.MethodHandleReflectiveInvoker    : Unexpected end-of-input in field name at [Source: (byte[])"{"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"funct"; line: 1, column: 72]
2024-07-16T12:08:10.913+02:00 ERROR 33620 --- [oundedElastic-1] c.a.c.i.s.DefaultJsonSerializer          : com.azure.json.implementation.jackson.core.io.JsonEOFException: Unexpected end-of-input in field name at [Source: (byte[])"{"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"funct"; line: 1, column: 72]

To Reproduce Steps to reproduce the behavior - Use the code snippet below from the official documentation

Code Snippet

    ChatCompletionsOptions optionsPure = new ChatCompletionsOptions(List.of(new ChatRequestUserMessage("What is " +
            "the " +
            "weather at the Tokio?")));

    var func = new FunctionDefinition("getCurrentWeather");
    func.setDescription("Get the current weather for a location");
    func.setParameters(BinaryData.fromString("""
            {"$schema":"https://json-schema.org/draft/2020-12/schema","description":"Weather API request","type":"object","properties":{"location":{"type":"string","description":"The city and state e.g. San Francisco, CA"},"unit":{"type":"string","enum":["C","F"],"description":"Temperature unit"}},"required":["location","unit"]}
            """));

    optionsPure.setTools(List.of(
            new ChatCompletionsFunctionToolDefinition(func)));
    optionsPure.setStream(true);

    this.openAIClient.getChatCompletionsStream(options.getModel(), optionsPure)
            .forEach(chatCompletions -> {
                if (CoreUtils.isNullOrEmpty(chatCompletions.getChoices())) {
                    return;
                }
                ChatResponseMessage delta = chatCompletions.getChoices().get(0).getDelta();
                if (delta.getRole() != null) {
                    System.out.println("Role = " + delta.getRole());
                }
                if (delta.getContent() != null) {
                    String content = delta.getContent();
                    System.out.print(content);
                }
            });

Expected behavior No error messages,,

junan-trustarc commented 2 months ago

Same issue for me as well, functions are working but just dirty error logs. can you fix it

timostark commented 2 months ago

issue is reproducible using your own example (StreamingChatSample.java).

joshfree commented 1 month ago

@alzimmermsft please follow up on this azure-json error in OpenAI

alzimmermsft commented 1 month ago

Thanks for filing this issue @timostark.

@mssfang / @jpalvarezl this appears to be a bug in OpenAIServerSentEvents and how they're being processed. I see a few possible issues here:

Here's a code sample to reproduce this without needing to call Azure OpenAI:

Flux<ByteBuffer> source = Flux.fromIterable(Arrays.asList(
    ByteBuffer.wrap("data: {\"choices\":[{\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"}".getBytes(StandardCharsets.UTF_8)),
    ByteBuffer.wrap(",\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}},\"delta\":{\"content\":\" par\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1724446441,\"id\":\"id\",\"model\":\"model\",\"object\":\"chat.completion.chunk\",\"system_fingerprint\":\"fingerprint\"}".getBytes(StandardCharsets.UTF_8))));
OpenAIServerSentEvents parser = new OpenAIServerSentEvents(source, ChatCompletions.class);

parser.getEvents().blockLast();
alzimmermsft commented 1 month ago

Forgot to add, when running the reproduction sample, while I didn't see exceptions being thrown anywhere, they are logged (as mentioned by this issue). Add an environment variable of AZURE_LOG_LEVEL=debug to see these logs happening without needing to add an SLF4J logging implementation.

williamspindox commented 2 days ago

Any news?