[WIP] Add possibility to register functions in a type-safe manner
Goal: The goal of this PR is to extend the existing function registration methods to also accept types of beans. The advantage would be that this is type-safe. A type-safe interface improves intelli-sense and refactoring
Things to Do:
- [ ] Testing, before implementing any tests I would be interest in receiving feedback the approach in general
Discussion Points for this PR:
Should there be multiple factory methods for the ChatClient.Builder? So far I've overloaded the existing factory method and provided a SimpleNameResolver for use in existing calls
General Design Question:
At a higher level I am also wondering about how to register functions in general. The existing model make heavy use of annotations and conventions (e.g. a function must be a java.util.Function). This clearly works, however issues non-obvious issues (e.g. missing @Description annotation) are discovered at runtime. Personally I feel that this is not a great developer experience, especially for people new to the using spring-ai. My preference would be to surface this kind of errors as quickly as possible. A way to address this could be to provide an interface that has to be implemented by beans that should be available as functions for the LLM
Hi Christian (@tzolov),
As discussed i've updated the PR with a way to define functions via a factory class. Compared to my initial implementation using the BeanNameResolver this feels like a more consistent approach.
However, as I mentioned in my comment (see Tools) the different ways that functions are currently handled by the ChatClient makes this more difficult to do. I think a discussion around how we can have a more consistent approach to adding functions to the ChatClient might be helpful
If you have some time to discuss this just let me know (also open to jumping on a call)
Thanks for your PR! Declarative tool definition via annotation has been introduced in https://github.com/spring-projects/spring-ai/pull/2064, making it possible to pass to ChatClient an object containing @Tool-annotated methods. Does that handle your use case?
Example:
class MyTools {
@Tool(description = "Get the list of books written by the given author available in the library")
List<Book> booksByAuthor(String author) {
return bookService.getBooksByAuthor(new Author(author));
}
}
@GetMapping("/chat")
String chat(String authorName) {
return chatClient.prompt()
.user("What books written by %s are available in the library?".formatted(authorName))
.tools(myTools)
.call()
.content();
}
Closing as I believe the new featues in Spring AI address this use case. Thanks for the contribution @pgerhard , please let us know if some use-case is not addressed in the current code base.