spring-projects / spring-ai

An Application Framework for AI Engineering
https://docs.spring.io/spring-ai/reference/index.html
Apache License 2.0
3.21k stars 812 forks source link

ZhiPu AI use ChatClient setting defaultSystem error #1157

Open lwgCodePlus opened 3 months ago

lwgCodePlus commented 3 months ago

image image

lwgCodePlus commented 3 months ago

@mxsl-gr

mxsl-gr commented 3 months ago

@mxsl-gr

Got it. I'll test this case later.

mxsl-gr commented 3 months ago

i just tested this case.

    @Test
    void defaultSystemPromptTest() {
        String systemPrompt = "You are a helpful assistant, your name is Bob.";
        String userPrompt = "hi, what's your name?";
        ChatClient chatClient = ChatClient.builder(chatModel).defaultSystem(systemPrompt).build();

        Flux<ChatResponse> response1 = chatClient.prompt().user(userPrompt).stream().chatResponse();

        // build messages:
        // [0]: { role:System, text: 'You are a helpful assistant, your name is Bob.' }
        // [1]: { role:User, text: 'hi, what's your name?' }

        String content = Objects.requireNonNull(response1.collectList().block())
                .stream()
                .map(ChatResponse::getResults)
                .flatMap(List::stream)
                .map(Generation::getOutput)
                .map(AssistantMessage::getContent)
                .collect(Collectors.joining());
        assertThat(content).containsAnyOf("Bob");

        List<Message> messages = List.of(new UserMessage(userPrompt));
        Flux<ChatResponse> response2 = chatClient.prompt().messages(messages).stream().chatResponse();

        // build messages:
        // [0]: { role:User, text: 'hi, what's your name?' }
        // [1]: { role:System, text: 'You are a helpful assistant, your name is Bob.' }
        // [2]: { role:User, text: '' }

        String content2 = Objects.requireNonNull(response2.collectList().block())
                .stream()
                .map(ChatResponse::getResults)
                .flatMap(List::stream)
                .map(Generation::getOutput)
                .map(AssistantMessage::getContent)
                .collect(Collectors.joining());
        assertThat(content2).containsAnyOf("Bob");
    }

response1 is worked, the request messages:

[{ "role": "System", "text": "You are a helpful assistant, your name is Bob." }, { "role": "User", "text": "hi, what's your name?" }]

but response2 get an error, the request messages:

[{ "role": "User", "text": "hi, what's your name?" }, { "role": "System", "text": "You are a helpful assistant, your name is Bob." }, { "role": "User", "text": "" }]

check the code, the messages field in ChatClientRequestSpec takes precedence over system and user messages, acting more like chat history of the conversation.

i think is might not an exclusive issue with ZhiPu. it's just that ZhiPu's API validation is stricter and doesn't allow empty user message.

i'm not sure what your business, but i looking at your code, maybe it could use user, like this:

...
chatClient.prompt().user(userPrompt)
...
markpollack commented 2 months ago

Does the current PR fix the issues observed in this conversation?

https://github.com/spring-projects/spring-ai/pull/1188