You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/openai-chat.adoc
+39-1Lines changed: 39 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -270,6 +270,11 @@ NOTE: Adhere to the OpenAI link:https://platform.openai.com/docs/guides/structur
270
270
271
271
You can leverage existing xref::api/structured-output-converter.adoc#_bean_output_converter[BeanOutputConverter] utilities to automatically generate the JSON Schema from your domain objects and later convert the structured response into domain-specific instances:
val content = response.getResult().getOutput().getContent()
337
+
338
+
val mathReasoning = outputConverter.convert(content)
339
+
----
340
+
======
341
+
--
304
342
305
-
NOTE: Ensure you use the `@JsonProperty(required = true,...)` annotation.
343
+
NOTE: Ensure you use the `@JsonProperty(required = true,...)` annotation (`@get:JsonProperty(required = true,...)` with Kotlin in order to generate the annotation on the related getters, see link:https://kotlinlang.org/docs/annotations.html#annotation-use-site-targets[related documentation]).
306
344
This is crucial for generating a schema that accurately marks fields as `required`.
307
345
Although this is optional for JSON Schema, OpenAI link:https://platform.openai.com/docs/guides/structured-outputs/all-fields-must-be-required[mandates] it for the structured response to function correctly.
Copy file name to clipboardExpand all lines: spring-ai-docs/src/main/antora/modules/ROOT/pages/api/functions.adoc
+95-3Lines changed: 95 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -56,8 +56,13 @@ When the model needs to answer a question such as `"What’s the weather like in
56
56
57
57
Our function calls some SaaS-based weather service API and returns the weather response back to the model to complete the conversation. In this example, we will use a simple implementation named `MockWeatherService` that hard-codes the temperature for various locations.
58
58
59
-
The following `MockWeatherService.java` represents the weather service API:
59
+
The following `MockWeatherService` class represents the weather service API:
60
60
61
+
--
62
+
[tabs]
63
+
======
64
+
Java::
65
+
+
61
66
[source,java]
62
67
----
63
68
public class MockWeatherService implements Function<Request, Response> {
@@ -71,20 +76,39 @@ public class MockWeatherService implements Function<Request, Response> {
71
76
}
72
77
}
73
78
----
79
+
Kotlin::
80
+
+
81
+
[source,kotlin]
82
+
----
83
+
class MockWeatherService : Function1<Request, Response> {
84
+
override fun invoke(request: Request) = Response(30.0, Unit.C)
85
+
}
86
+
87
+
enum class Unit { C, F }
88
+
data class Request(val location: String, val unit: Unit) {}
89
+
data class Response(val temp: Double, val unit: Unit) {}
90
+
----
91
+
======
92
+
--
74
93
75
94
=== Registering Functions as Beans
76
95
77
96
Spring AI provides multiple ways to register custom functions as beans in the Spring context.
78
97
79
98
We start by describing the most POJO-friendly options.
80
99
81
-
==== Plain Java Functions
100
+
==== Plain Functions
82
101
83
102
In this approach, you define a `@Bean` in your application context as you would any other Spring managed object.
84
103
85
104
Internally, Spring AI `ChatModel` will create an instance of a `FunctionCallbackWrapper` that adds the logic for it being invoked via the AI model.
86
105
The name of the `@Bean` is used function name.
87
106
107
+
--
108
+
[tabs]
109
+
======
110
+
Java::
111
+
+
88
112
[source,java]
89
113
----
90
114
@Configuration
@@ -98,31 +122,75 @@ static class Config {
98
122
99
123
}
100
124
----
125
+
Kotlin::
126
+
+
127
+
[source,kotlin]
128
+
----
129
+
@Configuration
130
+
class Config {
131
+
132
+
@Bean
133
+
@Description("Get the weather in location") // function description
134
+
fun currentWeather(): (Request) -> Response = MockWeatherService()
135
+
136
+
}
137
+
----
138
+
======
139
+
--
101
140
102
141
The `@Description` annotation is optional and provides a function description that helps the model understand when to call the function. It is an important property to set to help the AI model determine what client side function to invoke.
103
142
104
143
Another option for providing the description of the function is to use the `@JsonClassDescription` annotation on the `MockWeatherService.Request`:
105
144
145
+
--
146
+
[tabs]
147
+
======
148
+
Java::
149
+
+
106
150
[source,java]
107
151
----
108
152
@Configuration
109
153
static class Config {
154
+
110
155
@Bean
111
156
public Function<Request, Response> currentWeather() { // bean name as function name
112
157
return new MockWeatherService();
113
158
}
114
159
}
115
160
116
-
@JsonClassDescription("Get the weather in location") // // function description
161
+
@JsonClassDescription("Get the weather in location") // function description
117
162
public record Request(String location, Unit unit) {}
118
163
----
164
+
Kotlin::
165
+
+
166
+
[source,kotlin]
167
+
----
168
+
@Configuration
169
+
class Config {
170
+
171
+
@Bean
172
+
fun currentWeather(): (Request) -> Response { // bean name as function name
173
+
return MockWeatherService()
174
+
}
175
+
}
176
+
177
+
@JsonClassDescription("Get the weather in location") // function description
178
+
data class Request(val location: String, val unit: Unit)
179
+
----
180
+
======
181
+
--
119
182
120
183
It is a best practice to annotate the request object with information such that the generated JSON schema of that function is as descriptive as possible to help the AI model pick the correct function to invoke.
121
184
122
185
==== FunctionCallback Wrapper
123
186
124
187
Another way to register a function is to create a `FunctionCallbackWrapper` like this:
0 commit comments