Skip to content

Commit c886fd8

Browse files
committed
Added pages structure for the AI module and also the Prompts section
1 parent f635dac commit c886fd8

7 files changed

Lines changed: 1823 additions & 6 deletions

File tree

documentation/modules/ROOT/nav.adoc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
** xref:kafka-and-streams.adoc[Apache Kafka with Reactive Streams]
2424
2525
* AI
26-
** xref:#[Working with prompts]
27-
** xref:#[Chains and Memory]
28-
** xref:#[Agents and Tools]
29-
** xref:#[Embedding Documents]
30-
** xref:#[Working with local models]
31-
** xref:#[Bringing Kubernetes and Kafka to the party]
26+
** xref:prompts.adoc[Working with prompts]
27+
** xref:chains_memory.adoc[Chains and Memory]
28+
** xref:agents_tools.adoc[Agents and Tools]
29+
** xref:embed_documents.adoc[Embedding Documents]
30+
** xref:local_models.adoc[Working with local models]
31+
** xref:kubernetes_kafka_ai.adoc[Bringing Kubernetes and Kafka to the party]
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
= Agents and Tools
2+
3+
Quarkus provides a novel reactive API called Mutiny, with the goal of easing the development of highly scalable, resilient, and asynchronous systems.
4+
5+
In this chapter we're going to see some examples of how Mutiny changes the design of our Quarkus applications.
6+
to online beer database (https://punkapi.com/documentation/v2) to retrieve beer information.
7+
This API does not return all beers at once, so we'll need to navigate through the pages to fetch all the information.
8+
Then we're going to filter all the beers with an ABV greater than 15.0 and return all these beers in a Reactive REST endpoint.
9+
10+
== Add the Mutiny extension
11+
12+
Create a new Quarkus project, for example using https://code.quarkus.io/ website.
13+
14+
Then open a new terminal window, and make sure you’re at the root of your `{project-name}` project, then run:
15+
16+
[tabs]
17+
====
18+
Maven::
19+
+
20+
--
21+
[.console-input]
22+
[source,bash,subs="+macros,+attributes"]
23+
----
24+
./mvnw quarkus:add-extension -Dextension=quarkus-mutiny,quarkus-rest-client-reactive-jsonb,quarkus-resteasy-reactive-jsonb
25+
----
26+
27+
--
28+
Quarkus CLI::
29+
+
30+
--
31+
[.console-input]
32+
[source,bash,subs="+macros,+attributes"]
33+
----
34+
quarkus extension add quarkus-mutiny,quarkus-rest-client-reactive-jsonb,quarkus-resteasy-reactive-jsonb
35+
----
36+
--
37+
====
38+
39+
== Create Beer POJO
40+
41+
Create a new `Beer` Java class in `src/main/java` in the `org.acme` package with the following contents:
42+
43+
[.console-input]
44+
[source,java]
45+
----
46+
package org.acme;
47+
48+
import jakarta.json.bind.annotation.JsonbCreator;
49+
50+
public class Beer {
51+
52+
private String name;
53+
private String tagline;
54+
private double abv;
55+
56+
private Beer(String name, String tagline, double abv) {
57+
this.name = name;
58+
this.tagline = tagline;
59+
this.abv = abv;
60+
}
61+
62+
@JsonbCreator
63+
public static Beer of(String name, String tagline, double abv) {
64+
return new Beer(name, tagline, abv);
65+
}
66+
67+
public String getName() {
68+
return name;
69+
}
70+
71+
public String getTagline() {
72+
return tagline;
73+
}
74+
75+
public double getAbv() {
76+
return abv;
77+
}
78+
79+
}
80+
----
81+
82+
== Create BeerService
83+
84+
Now we're going to implement a Java interface that mimics the remote REST endpoint.
85+
86+
Create a new `BeerService` Java interface in `src/main/java` in the `org.acme` package with the following contents:
87+
88+
[.console-input]
89+
[source,java]
90+
----
91+
package org.acme;
92+
93+
import java.util.List;
94+
95+
import jakarta.json.JsonArray;
96+
import jakarta.ws.rs.GET;
97+
import jakarta.ws.rs.Path;
98+
import jakarta.ws.rs.PathParam;
99+
import jakarta.ws.rs.Produces;
100+
import jakarta.ws.rs.QueryParam;
101+
import jakarta.ws.rs.core.MediaType;
102+
103+
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
104+
105+
import io.smallrye.mutiny.Uni;
106+
107+
@Path("/v2")
108+
@RegisterRestClient
109+
public interface BeerService {
110+
111+
@GET
112+
@Path("/beers")
113+
@Produces(MediaType.APPLICATION_JSON)
114+
Uni<List<Beer>> getBeers(@QueryParam("page") int page);
115+
}
116+
----
117+
118+
== Configure REST Client properties
119+
120+
Add the following properties to your `application.properties` in `src/main/resources`:
121+
122+
[.console-input]
123+
[source,properties]
124+
----
125+
org.acme.BeerService/mp-rest/url=https://api.punkapi.com
126+
----
127+
128+
== Pagination + Filtering
129+
130+
We want to query all the beers page by page and filter by its _abv_ value.
131+
132+
image::pagination.png[]
133+
134+
=== Create BeerResource
135+
136+
Create a new `BeerResource` Java class in `src/main/java` in the `org.acme` package with the following contents:
137+
138+
[.console-input]
139+
[source,java]
140+
----
141+
package org.acme;
142+
143+
import java.util.List;
144+
import java.util.concurrent.atomic.AtomicInteger;
145+
146+
import jakarta.json.Json;
147+
import jakarta.json.JsonArray;
148+
import jakarta.json.JsonMergePatch;
149+
import jakarta.json.JsonObject;
150+
import jakarta.json.JsonValue;
151+
import jakarta.ws.rs.GET;
152+
import jakarta.ws.rs.Path;
153+
import jakarta.ws.rs.PathParam;
154+
155+
import org.eclipse.microprofile.rest.client.inject.RestClient;
156+
import io.smallrye.mutiny.Multi;
157+
import io.smallrye.mutiny.Uni;
158+
159+
@Path("/beer")
160+
public class BeerResource {
161+
162+
@RestClient
163+
BeerService beerService;
164+
165+
@GET
166+
public Multi<Beer> beers() {
167+
return Multi.createBy().repeating() // <1>
168+
.uni(
169+
() -> new AtomicInteger(1),
170+
i -> beerService.getBeers(i.getAndIncrement()) // <2>
171+
)
172+
.until(List::isEmpty) // <3>
173+
.onItem().<Beer>disjoint() // <4>
174+
.select().where(b -> b.getAbv() > 15.0); // <5>
175+
}
176+
}
177+
----
178+
<1> Creates a `Multi`.
179+
<2> The supplier will start with `1` and will query the remote endpoint asking for page `i`.
180+
<3> The multi will end when the beer list returned is empty.
181+
<4> We dismember all the returned lists and create a sequence of beers.
182+
<5> And then we filter the `Multi` with beers with `ABV > 15.0`.
183+
184+
=== Invoke the endpoint
185+
186+
You can check your new implementation by pointing your browser to http://localhost:8080/beer[window=_blank]
187+
188+
You can also run the following command:
189+
190+
[.console-input]
191+
[source,bash]
192+
----
193+
curl localhost:8080/beer
194+
----
195+
196+
[.console-output]
197+
[source,json]
198+
----
199+
[
200+
{
201+
"abv": 55,
202+
"name": "The End Of History",
203+
"tagline": "The World's Strongest Beer."
204+
},
205+
{
206+
"abv": 16.5,
207+
"name": "Anarchist Alchemist",
208+
"tagline": "Triple Hopped Triple Ipa."
209+
},
210+
{
211+
"abv": 15.2,
212+
"name": "Lumberjack Stout",
213+
"tagline": "Blueberry Bacon Stout."
214+
},
215+
{
216+
"abv": 18.3,
217+
"name": "Bowman's Beard - B-Sides",
218+
"tagline": "English Barley Wine."
219+
},
220+
{
221+
"abv": 41,
222+
"name": "Sink The Bismarck!",
223+
"tagline": "IPA For The Dedicated."
224+
},
225+
{
226+
"abv": 16.2,
227+
"name": "Tokyo*",
228+
"tagline": "Intergalactic Stout. Rich. Smoky. Fruity."
229+
},
230+
{
231+
"abv": 18,
232+
"name": "AB:02",
233+
"tagline": "Triple Dry Hopped Imperial Red Ale."
234+
},
235+
{
236+
"abv": 17.2,
237+
"name": "Black Tokyo Horizon (w/Nøgne Ø & Mikkeller)",
238+
"tagline": "Imperial Stout Collaboration."
239+
},
240+
{
241+
"abv": 16.1,
242+
"name": "Dog D",
243+
"tagline": "Anniversary Imperial Stout."
244+
},
245+
{
246+
"abv": 32,
247+
"name": "Tactical Nuclear Penguin",
248+
"tagline": "Uber Imperial Stout."
249+
},
250+
{
251+
"abv": 16.1,
252+
"name": "Dog E",
253+
"tagline": "Ninth Anniversary Imperial Stout."
254+
},
255+
{
256+
"abv": 17,
257+
"name": "Dog G",
258+
"tagline": "11th Anniversary Imperial Stout."
259+
}
260+
]
261+
----
262+
263+
== Parallel Calls
264+
265+
Suppose that now, you want to query two beers by its id, (so execute two requests against the remote API), and then compare its _abv_ values.
266+
267+
image::parallel.png[]
268+
269+
=== Modify BeerService
270+
271+
Open `BeerService` interface and add the following method to get a beer:
272+
273+
[.console-input]
274+
[source,java]
275+
----
276+
@GET
277+
@Path("/beers/{id}")
278+
@Produces(MediaType.APPLICATION_JSON)
279+
Uni<JsonArray> getBeer(@PathParam("id") int id);
280+
----
281+
282+
=== Modify BeerResource
283+
284+
Open `BeerResource` class and add the following methods to do in parallel the both calls.
285+
286+
[.console-input]
287+
[source,java]
288+
----
289+
@GET
290+
@Path("/{beerA}/{beerB}")
291+
public Uni<JsonValue> compare(@PathParam("beerA") int beerA, @PathParam("beerB") int beerB) {
292+
Uni<JsonArray> beer1 = beerService.getBeer(beerA); // <1>
293+
Uni<JsonArray> beer2 = beerService.getBeer(beerB); // <2>
294+
295+
return Uni.combine()
296+
.all()
297+
.unis(beer1, beer2) // <3>
298+
.with((b1, b2) -> this.compare(b1, b2)); // <4>
299+
}
300+
301+
private JsonValue compare(JsonArray beerA, JsonArray beerB) {
302+
JsonObject source = beerA.get(0).asJsonObject();
303+
JsonObject target = beerB.get(0).asJsonObject();
304+
305+
String beerAName = source.getString("name");
306+
String beerBName = target.getString("name");
307+
308+
double beerAAbv = source.getJsonNumber("abv").doubleValue();
309+
double beerBAbv = target.getJsonNumber("abv").doubleValue();
310+
311+
return Json.createObjectBuilder()
312+
.add("source-name", beerAName)
313+
.add("target-name", beerBName)
314+
.add("source-abv", beerAAbv)
315+
.add("target-abv", beerBAbv)
316+
.build();
317+
}
318+
----
319+
<1> Executes request for first beer
320+
<2> Executes request for second beer
321+
<3> Waits until both requests returns a response
322+
<4> Compare both beers and returns an object with the result
323+
324+
=== Invoke the endpoint
325+
326+
You can check your new implementation by pointing your browser to http://localhost:8080/beer/1/2[window=_blank]
327+
328+
You can also run the following command:
329+
330+
[.console-input]
331+
[source,bash]
332+
----
333+
curl localhost:8080/beer/1/2
334+
----
335+
336+
[.console-output]
337+
[source,json]
338+
----
339+
{"source-name":"Buzz","target-name":"Trashy Blonde","source-abv":4.5,"target-abv":4.1}
340+
----

0 commit comments

Comments
 (0)