Skip to content

Commit 8a32cff

Browse files
committed
docs: add FunctionCallback documentation
Add comprehensive documentation for the FunctionCallback API in Spring AI, including: - Overview of the interface and its key methods - Builder pattern usage with function and method invocation approaches - Examples for different function types (Function, BiFunction, Supplier, Consumer) - Best practices and common pitfalls - Schema generation and customization options
1 parent 99dbc83 commit 8a32cff

File tree

2 files changed

+243
-0
lines changed

2 files changed

+243
-0
lines changed

spring-ai-docs/src/main/antora/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
* xref:api/prompt.adoc[]
9898
* xref:api/structured-output-converter.adoc[Structured Output]
9999
* xref:api/functions.adoc[Function Calling]
100+
** xref:api/function-callback.adoc[FunctionCallback]
100101
* xref:api/multimodality.adoc[Multimodality]
101102
* xref:api/etl-pipeline.adoc[]
102103
* xref:api/testing.adoc[AI Model Evaluation]
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
= FunctionCallback
2+
3+
== Overview
4+
5+
The `FunctionCallback` interface in Spring AI provides a standardized way to implement Large Language Model (LLM) function calling capabilities. It allows developers to register custom functions that can be called by AI models when specific conditions or intents are detected in the prompts.
6+
7+
== FunctionCallback Interface
8+
9+
The main interface defines several key methods:
10+
11+
* `getName()`: Returns the unique function name within the AI model context
12+
* `getDescription()`: Provides a description that helps the model decide when to invoke the function
13+
* `getInputTypeSchema()`: Defines the JSON schema for the function's input parameters
14+
* `call(String functionInput)`: Handles the actual function execution
15+
* `call(String functionInput, ToolContext toolContext)`: Extended version that supports additional context
16+
17+
== Builder Pattern
18+
19+
Spring AI provides a fluent builder API for creating `FunctionCallback` implementations.
20+
21+
This is particularly useful for defining function callbacks that you can register, pragmatically, on the fly, with your `ChatClient` or `ChatModel` model calls.
22+
23+
The builders helps with complex configurations, such as custom response handling, schema types (e.g. JSONSchema or OpenAPI), and object mapping.
24+
25+
=== Function-Invoking Approach
26+
27+
Converts any `java.util.function.Function`, `BiFunction`, `Supplier` or `Consumer` into a `FunctionCallback` that can be called by the AI model.
28+
29+
NOTE: You can use lambda expressions or method references to define the function logic but you must provide the input type of the function using the `inputType(TYPE)`.
30+
31+
==== Function<I, O>
32+
33+
[source,java]
34+
----
35+
FunctionCallback callback = FunctionCallback.builder()
36+
.description("Process a new order")
37+
.function("processOrder", (Order order) -> processOrderLogic(order))
38+
.inputType(Order.class)
39+
.build();
40+
----
41+
42+
==== BiFunction<I, ToolContext, O> with ToolContext
43+
44+
[source,java]
45+
----
46+
FunctionCallback callback = FunctionCallback.builder()
47+
.description("Process a new order with context")
48+
.function("processOrder", (Order order, ToolContext context) ->
49+
processOrderWithContext(order, context))
50+
.inputType(Order.class)
51+
.build();
52+
----
53+
54+
==== Supplier<O>
55+
56+
Use `java.util.Supplier<O>` or `java.util.function.Function<Void, O>` to define functions that don't take any input:
57+
58+
[source,java]
59+
----
60+
FunctionCallback.builder()
61+
.description("Turns light onn in the living room")
62+
.function("turnsLight", () -> state.put("Light", "ON"))
63+
.inputType(Void.class)
64+
.build();
65+
----
66+
67+
==== Consumer<I>
68+
69+
Use `java.util.Consumer<I>` or `java.util.function.Function<I, Void>` to define functions that don't produce output:
70+
71+
[source,java]
72+
----
73+
record LightInfo(String roomName, boolean isOn) {}
74+
75+
FunctionCallback.builder()
76+
.description("Turns light on/off in a selected room")
77+
.function("turnsLight", (LightInfo lightInfo) -> {
78+
logger.info("Turning light to [" + lightInfo.isOn + "] in " + lightInfo.roomName());
79+
})
80+
.inputType(LightInfo.class)
81+
.build();
82+
----
83+
84+
==== Generics Input Type
85+
86+
Use the `ParameterizedTypeReference` to define functions with generic input types:
87+
88+
[source,java]
89+
----
90+
record TrainSearchRequest<T>(T data) {}
91+
92+
record TrainSearchSchedule(String from, String to, String date) {}
93+
94+
record TrainSearchScheduleResponse(String from, String to, String date, String trainNumber) {}
95+
96+
FunctionCallback.builder()
97+
.description("Schedule a train reservation")
98+
.function("trainSchedule", (TrainSearchRequest<TrainSearchSchedule> request) -> {
99+
logger.info("Schedule: " + request.data().from() + " to " + request.data().to());
100+
return new TrainSearchScheduleResponse(request.data().from(), request. data().to(), "", "123");
101+
})
102+
.inputType(new ParameterizedTypeReference<TrainSearchRequest<TrainSearchSchedule>>() {})
103+
.build();
104+
----
105+
106+
=== Method Invoking Approach
107+
108+
Enables method invocation through reflection while automatically handling JSON schema generation and parameter conversion. It’s particularly useful for integrating Java methods as callable functions within AI model interactions.
109+
110+
The method invoking implements the `FunctionCallback` interface and provides:
111+
112+
- Automatic JSON schema generation for method parameters
113+
- Support for both static and instance methods
114+
- Any number of parameters (including none) and return values (including void)
115+
- Any parameter/return types (primitives, objects, collections)
116+
- Special handling for `ToolContext` parameters
117+
118+
==== Static Method Invocation
119+
120+
You can refer to a static method in a class by providing the method name, parameter types, and the target class.
121+
122+
[source,java]
123+
----
124+
public class WeatherService {
125+
public static String getWeather(String city, TemperatureUnit unit) {
126+
return "Temperature in " + city + ": 20" + unit;
127+
}
128+
}
129+
130+
FunctionCallback callback = FunctionCallback.builder()
131+
.description("Get weather information for a city")
132+
.method("getWeather", String.class, TemperatureUnit.class)
133+
.targetClass(WeatherService.class)
134+
.build();
135+
----
136+
137+
==== Object instance Method Invocation
138+
139+
You can refer to an instance method in a class by providing the method name, parameter types, and the target object instance.
140+
141+
[source,java]
142+
----
143+
public class DeviceController {
144+
public void setDeviceState(String deviceId, boolean state, ToolContext context) {
145+
Map<String, Object> contextData = context.getContext();
146+
// Implementation using context data
147+
}
148+
}
149+
150+
DeviceController controller = new DeviceController();
151+
152+
String response = ChatClient.create(chatModel).prompt()
153+
.user("Turn on the living room lights")
154+
.functions(FunctionCallback.builder()
155+
.description("Control device state")
156+
.method("setDeviceState", String.class,boolean.class,ToolContext.class)
157+
.targetObject(controller)
158+
.build())
159+
.toolContext(Map.of("location", "home"))
160+
.call()
161+
.content();
162+
----
163+
164+
TIP: Optionally, using the `.name()`, you can set a custom function name different from the method name.
165+
166+
== Customization Options
167+
168+
== Schema Type Support
169+
170+
The framework supports different schema types for function parameter validation:
171+
172+
* JSON Schema (default)
173+
* OpenAPI Schema (for Vertex AI compatibility)
174+
175+
[source,java]
176+
----
177+
FunctionCallback.builder()
178+
.schemaType(SchemaType.OPEN_API_SCHEMA)
179+
// ... other configuration
180+
.build();
181+
----
182+
183+
=== Custom Response Handling
184+
185+
[source,java]
186+
----
187+
FunctionCallback.builder()
188+
.responseConverter(response ->
189+
customResponseFormatter.format(response))
190+
// ... other configuration
191+
.build();
192+
----
193+
194+
=== Custom Object Mapping
195+
196+
[source,java]
197+
----
198+
FunctionCallback.builder()
199+
.objectMapper(customObjectMapper)
200+
// ... other configuration
201+
.build();
202+
----
203+
204+
== Best Practices
205+
206+
=== Descriptive Names and Descriptions
207+
208+
* Provide unique function names
209+
* Write comprehensive descriptions to help the model understand when to invoke the function
210+
211+
=== Input Type & Schema
212+
213+
* For the function invoking approach, define input types explicitly and use `ParameterizedTypeReference` for generic types.
214+
* Consider using custom schema when auto-generated ones don't meet requirements.
215+
216+
=== Error Handling
217+
218+
* Implement proper error handling in function implementations and return the error message in the response
219+
* You can use the ToolContext to provide additional error context when needed
220+
221+
=== Tool Context Usage
222+
223+
* Use ToolContext when additional state or context is required that is provided from the User and not part of the function input generated by the AI model.
224+
* Use `BiFunction<I, ToolContext, O>` to access the ToolContext in the function invocation approach and add `ToolContext` parameter in the method invoking approach.
225+
226+
227+
== Notes on Schema Generation
228+
229+
* The framework automatically generates JSON schemas from Java types
230+
* For function invoking, the schema is generated based on the input type for the function that needs to be set using `inputType(TYPE)`. Use `ParameterizedTypeReference` for generic types.
231+
* Generated schemas respect Jackson annotations on model classes
232+
* You can bypass the automatic generation by providing custom schemas using `inputTypeSchema()`
233+
234+
== Common Pitfalls to Avoid
235+
236+
=== Lack of Description
237+
* Always provide explicit descriptions instead of relying on auto-generated ones
238+
* Clear descriptions improve model's function selection accuracy
239+
240+
=== Schema Mismatches
241+
* Ensure input types match the Function's input parameter types.
242+
* Use `ParameterizedTypeReference` for generic types.

0 commit comments

Comments
 (0)