Bug description

404 - {"timestamp":1739777658784,"status":404,"error":"Not Found","path":"//v1/chat/completions"}

Environment

<dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
            <version>1.0.0-M6</version>
        </dependency>

Steps to reproduce set application.yml

    openai:
      base-url: https://api.chatanywhere.tech/v1

run the program

@GetMapping("/ai/generate")
    public Map<String,String> generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", this.chatModel.call(message));
    }

Expected behavior a right response

Error

404 - {"timestamp":1739777658784,"status":404,"error":"Not Found","path":"//v1/chat/completions"}

Problem Explanation

I encountered an issue while trying to solve a problem with the OpenAI API integration. After some investigation, I found that the problem stems from the method internalCall() in the OpenAiChatModel class, and the method chatCompletionEntity() in OpenAiApi.

The root cause is that the uri() method used in the chatCompletionEntity() does not handle the removal of redundant slashes correctly. Specifically, the method does not remove the /v1 portion of the URL when constructing the final URI. As a result, it leads to an incorrect path: //v1/chat/completions, which triggers the 404 Not Found error.

Code Snippet

return ((RestClient.RequestBodySpec)((RestClient.RequestBodySpec)this.restClient.post().uri(this.completionsPath, new Object[0]))
        .headers((headers) -> headers.addAll(additionalHttpHeader)))
        .body(chatRequest)
        .retrieve()
        .toEntity(ChatCompletion.class);

Investigation and Next Steps

  • The key issue is how the uri() method constructs the URI. It leaves an extra slash (/) at the beginning of the path, resulting in an invalid endpoint (//v1/chat/completions).
  • I need to understand how the URI is being constructed and how to properly allocate the correct path. Specifically, I am wondering how to modify this logic to ensure that redundant slashes are removed, and the correct endpoint is used.

Solution Consideration

To resolve this, I may need to ensure that the base path and the completionsPath are combined correctly, removing any extra slashes in the process. I could modify the logic in the uri() method or handle the path manipulation before it is passed to the RestClient.

Comment From: dev-jonghoonpark

What happens if I remove the /v1 part of the openai.base-url in application.yml? Is there any reason to add the /v1 part?

Comment From: apappascs

Please remove the versioning from the base url https://docs.spring.io/spring-ai/reference/api/chat/openai-chat.html

Property Description Default
spring.ai.openai.chat.enabled Enable OpenAI chat model. true
spring.ai.openai.chat.base-url Optional override for the spring.ai.openai.base-url property to provide a chat-specific URL. -
spring.ai.openai.chat.completions-path The path to append to the base URL. /v1/chat/completions

Comment From: colommar

What happens if I remove the /v1 part of the openai.base-url in application.yml? Is there any reason to add the /v1 part?

It works cause there is a completionsPath = "/v1/chat/completions" which will be added after the base url. The reason why I think it can be added because the openai in python can solve this situation.

Comment From: apappascs

Thanks for confirming, @colommar. I think the issue can be closed if there’s nothing else.