-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add example for Mistral observability
- Loading branch information
1 parent
fcc0fa5
commit b6ac328
Showing
14 changed files
with
422 additions
and
0 deletions.
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
10-observability/observability-models-mistral-ai/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# LLM Observability: Mistral AI | ||
|
||
LLM Observability for Mistral AI. | ||
|
||
## Running the application | ||
|
||
The application relies on a Mistral AI API for providing LLMs. The application also relies on Testcontainers | ||
to provision automatically a Grafana LGTM observability stack. | ||
|
||
### When using OpenAI | ||
|
||
First, make sure you have a [Mistral AI account](https://console.mistral.ai). | ||
Then, define an environment variable with the Mistral AI API Key associated to your Mistral AI account as the value. | ||
|
||
```shell | ||
export SPRING_AI_MISTRALAI_API_KEY=<INSERT KEY HERE> | ||
``` | ||
|
||
Finally, run the Spring Boot application. | ||
|
||
```shell | ||
./gradlew bootTestRun | ||
``` | ||
|
||
## Observability Platform | ||
|
||
Grafana is listening to port 3000. Check your container runtime to find the port to which is exposed to your localhost | ||
and access Grafana from http://localhost:<port>. The credentials are `admin`/`admin`. | ||
|
||
The application is automatically configured to export metrics and traces to the Grafana LGTM stack via OpenTelemetry. | ||
In Grafana, you can query the traces from the "Explore" page, selecting the "Tempo" data source. You can also visualize metrics in "Explore > Metrics". | ||
|
||
## Calling the application | ||
|
||
You can now call the application to perform generative AI operations. | ||
This example uses [httpie](https://httpie.io) to send HTTP requests. | ||
|
||
### Chat | ||
|
||
```shell | ||
http :8080/chat | ||
``` | ||
|
||
Try passing your custom prompt and check the result. | ||
|
||
```shell | ||
http :8080/chat message=="What is the capital of Italy?" | ||
``` | ||
|
||
The next request is configured with a custom temperature value to obtain a more creative, yet less precise answer. | ||
|
||
```shell | ||
http :8080/chat/generic-options message=="Why is a raven like a writing desk? Give a short answer." | ||
``` | ||
|
||
The next request is configured with Open AI-specific customizations. | ||
|
||
```shell | ||
http :8080/chat/mistral-ai-options message=="What can you see beyond what you can see? Give a short answer." | ||
``` | ||
|
||
Finally, try a request which uses function calling. | ||
|
||
```shell | ||
http :8080/chat/functions authorName=="Philip Pullman" | ||
``` | ||
|
||
### Embedding | ||
|
||
```shell | ||
http :8080/embed | ||
``` | ||
|
||
Try passing your custom prompt and check the result. | ||
|
||
```shell | ||
http :8080/embed message=="The capital of Italy is Rome" | ||
``` | ||
|
||
The next request is configured with OpenAI-specific customizations. | ||
|
||
```shell | ||
http :8080/embed/mistral-ai-options message=="The capital of Italy is Rome" | ||
``` |
45 changes: 45 additions & 0 deletions
45
10-observability/observability-models-mistral-ai/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
plugins { | ||
id 'java' | ||
id 'org.springframework.boot' | ||
id 'io.spring.dependency-management' | ||
} | ||
|
||
group = 'com.thomasvitale' | ||
version = '0.0.1-SNAPSHOT' | ||
|
||
java { | ||
toolchain { | ||
languageVersion = JavaLanguageVersion.of(22) | ||
} | ||
} | ||
|
||
repositories { | ||
mavenLocal() | ||
mavenCentral() | ||
maven { url 'https://repo.spring.io/milestone' } | ||
maven { url 'https://repo.spring.io/snapshot' } | ||
} | ||
|
||
dependencies { | ||
implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") | ||
|
||
implementation 'org.springframework.boot:spring-boot-starter-actuator' | ||
implementation 'org.springframework.boot:spring-boot-starter-web' | ||
implementation 'org.springframework.ai:spring-ai-mistral-ai-spring-boot-starter' | ||
|
||
implementation 'io.micrometer:micrometer-tracing-bridge-otel' | ||
implementation 'io.opentelemetry:opentelemetry-exporter-otlp' | ||
implementation 'io.micrometer:micrometer-registry-otlp' | ||
implementation 'net.ttddyy.observation:datasource-micrometer-spring-boot:1.0.5' | ||
|
||
testAndDevelopmentOnly 'org.springframework.boot:spring-boot-devtools' | ||
|
||
testImplementation 'org.springframework.boot:spring-boot-starter-test' | ||
testImplementation 'org.springframework.boot:spring-boot-testcontainers' | ||
testImplementation 'org.testcontainers:junit-jupiter' | ||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher' | ||
} | ||
|
||
tasks.named('test') { | ||
useJUnitPlatform() | ||
} |
40 changes: 40 additions & 0 deletions
40
...observability-models-mistral-ai/src/main/java/com/thomasvitale/ai/spring/BookService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.thomasvitale.ai.spring; | ||
|
||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
@Service | ||
public class BookService { | ||
|
||
private static final Map<Integer,Book> books = new ConcurrentHashMap<>(); | ||
|
||
static { | ||
books.put(1, new Book("His Dark Materials", "Philip Pullman")); | ||
books.put(2, new Book("Narnia", "C.S. Lewis")); | ||
books.put(3, new Book("The Hobbit", "J.R.R. Tolkien")); | ||
books.put(4, new Book("The Lord of The Rings", "J.R.R. Tolkien")); | ||
books.put(5, new Book("The Silmarillion", "J.R.R. Tolkien")); | ||
} | ||
|
||
List<Book> getBooksByAuthor(Author author) { | ||
return books.values().stream() | ||
.filter(book -> author.name().equals(book.author())) | ||
.toList(); | ||
} | ||
|
||
Book getBestsellerByAuthor(Author author) { | ||
return switch (author.name()) { | ||
case "J.R.R. Tolkien" -> books.get(4); | ||
case "C.S. Lewis" -> books.get(2); | ||
case "Philip Pullman" -> books.get(1); | ||
default -> null; | ||
}; | ||
} | ||
|
||
public record Book(String title, String author) {} | ||
public record Author(String name) {} | ||
|
||
} |
62 changes: 62 additions & 0 deletions
62
...ervability-models-mistral-ai/src/main/java/com/thomasvitale/ai/spring/ChatController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.thomasvitale.ai.spring; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.ai.chat.model.ChatModel; | ||
import org.springframework.ai.chat.prompt.ChatOptionsBuilder; | ||
import org.springframework.ai.chat.prompt.Prompt; | ||
import org.springframework.ai.mistralai.MistralAiChatOptions; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import java.util.List; | ||
import java.util.Set; | ||
|
||
@RestController | ||
class ChatController { | ||
|
||
private final Logger logger = LoggerFactory.getLogger(ChatController.class); | ||
|
||
private final ChatModel chatModel; | ||
|
||
ChatController(ChatModel chatModel) { | ||
this.chatModel = chatModel; | ||
} | ||
|
||
@GetMapping("/chat") | ||
String chat(@RequestParam(defaultValue = "What did Gandalf say to the Balrog?") String message) { | ||
logger.info(message); | ||
return chatModel.call(message); | ||
} | ||
|
||
@GetMapping("/chat/generic-options") | ||
String chatWithGenericOptions(@RequestParam(defaultValue = "What did Gandalf say to the Balrog?") String message) { | ||
return chatModel.call(new Prompt(message, ChatOptionsBuilder.builder() | ||
.withTemperature(1.3f) | ||
.build())) | ||
.getResult().getOutput().getContent(); | ||
} | ||
|
||
@GetMapping("/chat/mistral-ai-options") | ||
String chatWithMistralAiOptions(@RequestParam(defaultValue = "What did Gandalf say to the Balrog?") String message) { | ||
return chatModel.call(new Prompt(message, MistralAiChatOptions.builder() | ||
.withMaxTokens(1500) | ||
.withStop(List.of("this-is-the-end", "addio")) | ||
.withTemperature(0.7f) | ||
.withTopP(0.1f) | ||
.build())) | ||
.getResult().getOutput().getContent(); | ||
} | ||
|
||
@GetMapping("/chat/functions") | ||
String chatWithFunctions(@RequestParam(defaultValue = "Philip Pullman") String author) { | ||
return chatModel.call(new Prompt("What books written by %s are available to read and what is their bestseller?".formatted(author), | ||
MistralAiChatOptions.builder() | ||
.withTemperature(0.3f) | ||
.withFunctions(Set.of("booksByAuthor", "bestsellerBookByAuthor")) | ||
.build())) | ||
.getResult().getOutput().getContent(); | ||
} | ||
|
||
} |
36 changes: 36 additions & 0 deletions
36
...ility-models-mistral-ai/src/main/java/com/thomasvitale/ai/spring/EmbeddingController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.thomasvitale.ai.spring; | ||
|
||
import org.springframework.ai.embedding.EmbeddingModel; | ||
import org.springframework.ai.embedding.EmbeddingRequest; | ||
import org.springframework.ai.mistralai.MistralAiEmbeddingOptions; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
class EmbeddingController { | ||
|
||
private final EmbeddingModel embeddingModel; | ||
|
||
EmbeddingController(EmbeddingModel embeddingModel) { | ||
this.embeddingModel = embeddingModel; | ||
} | ||
|
||
@GetMapping("/embed") | ||
String embed(@RequestParam(defaultValue = "And Gandalf yelled: 'You shall not pass!'") String message) { | ||
var embeddings = embeddingModel.embed(message); | ||
return "Size of the embedding vector: " + embeddings.length; | ||
} | ||
|
||
@GetMapping("/embed/mistral-ai-options") | ||
String embedWithMistralAiOptions(@RequestParam(defaultValue = "And Gandalf yelled: 'You shall not pass!'") String message) { | ||
var embeddings = embeddingModel.call(new EmbeddingRequest(List.of(message), MistralAiEmbeddingOptions.builder() | ||
.withEncodingFormat("float") | ||
.build())) | ||
.getResult().getOutput(); | ||
return "Size of the embedding vector: " + embeddings.length; | ||
} | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
...y/observability-models-mistral-ai/src/main/java/com/thomasvitale/ai/spring/Functions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.thomasvitale.ai.spring; | ||
|
||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.Description; | ||
|
||
import java.util.List; | ||
import java.util.function.Function; | ||
|
||
@Configuration(proxyBeanMethods = false) | ||
public class Functions { | ||
|
||
@Bean | ||
@Description("Get the list of available books written by the given author") | ||
public Function<BookService.Author, List<BookService.Book>> booksByAuthor(BookService bookService) { | ||
return bookService::getBooksByAuthor; | ||
} | ||
|
||
@Bean | ||
@Description("Get the bestseller book written by the given author") | ||
public Function<BookService.Author, BookService.Book> bestsellerBookByAuthor(BookService bookService) { | ||
return bookService::getBestsellerByAuthor; | ||
} | ||
|
||
} |
27 changes: 27 additions & 0 deletions
27
...vability-models-mistral-ai/src/main/java/com/thomasvitale/ai/spring/HttpClientConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.thomasvitale.ai.spring; | ||
|
||
import org.springframework.boot.web.client.ClientHttpRequestFactories; | ||
import org.springframework.boot.web.client.ClientHttpRequestFactorySettings; | ||
import org.springframework.boot.web.client.RestClientCustomizer; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.http.client.BufferingClientHttpRequestFactory; | ||
|
||
import java.time.Duration; | ||
|
||
@Configuration(proxyBeanMethods = false) | ||
public class HttpClientConfig { | ||
|
||
@Bean | ||
RestClientCustomizer restClientCustomizer() { | ||
return restClientBuilder -> { | ||
restClientBuilder | ||
.requestFactory(new BufferingClientHttpRequestFactory( | ||
ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS | ||
.withConnectTimeout(Duration.ofSeconds(60)) | ||
.withReadTimeout(Duration.ofSeconds(60)) | ||
))); | ||
}; | ||
} | ||
|
||
} |
13 changes: 13 additions & 0 deletions
13
...-ai/src/main/java/com/thomasvitale/ai/spring/ObservabilityModelsMistralAiApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.thomasvitale.ai.spring; | ||
|
||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class ObservabilityModelsMistralAiApplication { | ||
|
||
public static void main(String[] args) { | ||
SpringApplication.run(ObservabilityModelsMistralAiApplication.class, args); | ||
} | ||
|
||
} |
35 changes: 35 additions & 0 deletions
35
10-observability/observability-models-mistral-ai/src/main/resources/application.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
spring: | ||
application: | ||
name: observability-models-openai | ||
ai: | ||
chat: | ||
observations: | ||
include-completion: true | ||
include-prompt: true | ||
image: | ||
observations: | ||
include-prompt: true | ||
mistralai: | ||
api-key: ${MISTRALAI_API_KEY} | ||
chat: | ||
options: | ||
model: mistral-small-latest | ||
temperature: 0.7 | ||
embedding: | ||
options: | ||
model: mistral-embed | ||
|
||
management: | ||
endpoints: | ||
web: | ||
exposure: | ||
include: "*" | ||
metrics: | ||
tags: | ||
service.name: ${spring.application.name} | ||
tracing: | ||
sampling: | ||
probability: 1.0 | ||
otlp: | ||
tracing: | ||
endpoint: http://localhost:4318/v1/traces |
13 changes: 13 additions & 0 deletions
13
...rc/test/java/com/thomasvitale/ai/spring/ObservabilityModelsMistralAiApplicationTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.thomasvitale.ai.spring; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
|
||
@SpringBootTest | ||
class ObservabilityModelsMistralAiApplicationTests { | ||
|
||
@Test | ||
void contextLoads() { | ||
} | ||
|
||
} |
Oops, something went wrong.