Skip to content

Commit ef2ad4d

Browse files
committed
feat(observability): Refactor content observation mechanism to support both logging and tracing
This commit refactors the content observation mechanism by adding support for trace recording without altering the original logging functionality. The motivation for this change is to ensure complete context availability in scenarios such as integration with Langfuse, which is essential for proper functionality. Main changes: 1. New configuration options: 1. `trace-prompt`: Enables recording prompts to trace 2. `trace-completion` : Enables recording completions to trace 3. `trace-prompt-size` : Limits the length of prompt context 4. `content-formatter` : Handles content formatting, currently supporting both 'text' and 'langfuse' modes 2. Added two handlers, ChatModelCompletionObservationTraceHandler and ChatModelPromptContentObservationTraceHandler, to support recording context to trace. 3. Introduced the MessageFormatter interface and its subclasses to support formatting for prompt and completion content. 4. Rolled back parts of the code and dependencies from commit ca843e8. Signed-off-by: tingchuan.li <[email protected]>
1 parent e23bf1a commit ef2ad4d

File tree

19 files changed

+1354
-32
lines changed

19 files changed

+1354
-32
lines changed

auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/main/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationAutoConfiguration.java

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@
2626
import org.springframework.ai.chat.client.advisor.observation.AdvisorObservationContext;
2727
import org.springframework.ai.chat.client.observation.ChatClientObservationContext;
2828
import org.springframework.ai.chat.model.ChatModel;
29-
import org.springframework.ai.chat.observation.ChatModelCompletionObservationHandler;
30-
import org.springframework.ai.chat.observation.ChatModelMeterObservationHandler;
31-
import org.springframework.ai.chat.observation.ChatModelObservationContext;
32-
import org.springframework.ai.chat.observation.ChatModelPromptContentObservationHandler;
29+
import org.springframework.ai.chat.observation.*;
3330
import org.springframework.ai.embedding.observation.EmbeddingModelObservationContext;
3431
import org.springframework.ai.image.observation.ImageModelObservationContext;
3532
import org.springframework.ai.model.observation.ErrorLoggingObservationHandler;
@@ -70,6 +67,16 @@ private static void logCompletionWarning() {
7067
"You have enabled logging out the completion content with the risk of exposing sensitive or private information. Please, be careful!");
7168
}
7269

70+
private static void tracePromptContentWarning() {
71+
logger.warn(
72+
"You have enabled tracing out the prompt content with the risk of exposing sensitive or private information. Please, be careful!");
73+
}
74+
75+
private static void traceCompletionWarning() {
76+
logger.warn(
77+
"You have enabled tracing out the completion content with the risk of exposing sensitive or private information. Please, be careful!");
78+
}
79+
7380
@Bean
7481
@ConditionalOnMissingBean
7582
@ConditionalOnBean(MeterRegistry.class)
@@ -104,6 +111,30 @@ TracingAwareLoggingObservationHandler<ChatModelObservationContext> chatModelComp
104111
return new TracingAwareLoggingObservationHandler<>(new ChatModelCompletionObservationHandler(), tracer);
105112
}
106113

114+
@Bean
115+
@ConditionalOnMissingBean(value = ChatModelPromptContentObservationTraceHandler.class,
116+
name = "chatModelPromptContentObservationTraceHandler")
117+
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "trace-prompt",
118+
havingValue = "true")
119+
TracingAwareLoggingObservationHandler<ChatModelObservationContext> chatModelPromptContentObservationTraceHandler(
120+
ChatObservationProperties properties, Tracer tracer) {
121+
tracePromptContentWarning();
122+
return new TracingAwareLoggingObservationHandler<>(new ChatModelPromptContentObservationTraceHandler(
123+
properties.getContentFormatter(), properties.getTracePromptSize()), tracer);
124+
}
125+
126+
@Bean
127+
@ConditionalOnMissingBean(value = ChatModelCompletionObservationTraceHandler.class,
128+
name = "chatModelCompletionObservationTraceHandler")
129+
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "trace-completion",
130+
havingValue = "true")
131+
TracingAwareLoggingObservationHandler<ChatModelObservationContext> chatModelCompletionObservationTraceHandler(
132+
ChatObservationProperties properties, Tracer tracer) {
133+
traceCompletionWarning();
134+
return new TracingAwareLoggingObservationHandler<>(
135+
new ChatModelCompletionObservationTraceHandler(properties.getContentFormatter()), tracer);
136+
}
137+
107138
@Bean
108139
@ConditionalOnMissingBean
109140
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "include-error-logging",
@@ -139,6 +170,27 @@ ChatModelCompletionObservationHandler chatModelCompletionObservationHandler() {
139170
return new ChatModelCompletionObservationHandler();
140171
}
141172

173+
@Bean
174+
@ConditionalOnMissingBean()
175+
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "trace-prompt",
176+
havingValue = "true")
177+
ChatModelPromptContentObservationTraceHandler chatModelPromptContentObservationTraceHandler(
178+
ChatObservationProperties properties) {
179+
tracePromptContentWarning();
180+
return new ChatModelPromptContentObservationTraceHandler(properties.getContentFormatter(),
181+
properties.getTracePromptSize());
182+
}
183+
184+
@Bean
185+
@ConditionalOnMissingBean()
186+
@ConditionalOnProperty(prefix = ChatObservationProperties.CONFIG_PREFIX, name = "trace-completion",
187+
havingValue = "true")
188+
ChatModelCompletionObservationTraceHandler chatModelCompletionObservationTraceHandler(
189+
ChatObservationProperties properties) {
190+
traceCompletionWarning();
191+
return new ChatModelCompletionObservationTraceHandler(properties.getContentFormatter());
192+
}
193+
142194
}
143195

144196
}

auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation/src/main/java/org/springframework/ai/model/chat/observation/autoconfigure/ChatObservationProperties.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.ai.model.chat.observation.autoconfigure;
1818

19+
import org.springframework.ai.chat.observation.trace.AiObservationContentFormatterName;
1920
import org.springframework.boot.context.properties.ConfigurationProperties;
2021

2122
/**
@@ -40,6 +41,26 @@ public class ChatObservationProperties {
4041
*/
4142
private boolean logPrompt = false;
4243

44+
/**
45+
* Whether to trace the completion content in the observations.
46+
*/
47+
private boolean traceCompletion = false;
48+
49+
/**
50+
* Whether to trace the prompt content in the observations.
51+
*/
52+
private boolean tracePrompt = false;
53+
54+
/**
55+
* prompt size in trace, smaller than 1 is unlimit
56+
*/
57+
private int tracePromptSize = 10;
58+
59+
/**
60+
* prompt and completion formatter
61+
*/
62+
private AiObservationContentFormatterName contentFormatter = AiObservationContentFormatterName.TEXT;
63+
4364
/**
4465
* Whether to include error logging in the observations.
4566
*/
@@ -61,6 +82,38 @@ public void setLogPrompt(boolean logPrompt) {
6182
this.logPrompt = logPrompt;
6283
}
6384

85+
public boolean isTraceCompletion() {
86+
return traceCompletion;
87+
}
88+
89+
public void setTraceCompletion(boolean traceCompletion) {
90+
this.traceCompletion = traceCompletion;
91+
}
92+
93+
public boolean isTracePrompt() {
94+
return tracePrompt;
95+
}
96+
97+
public void setTracePrompt(boolean tracePrompt) {
98+
this.tracePrompt = tracePrompt;
99+
}
100+
101+
public int getTracePromptSize() {
102+
return tracePromptSize;
103+
}
104+
105+
public void setTracePromptSize(int tracePromptSize) {
106+
this.tracePromptSize = tracePromptSize;
107+
}
108+
109+
public AiObservationContentFormatterName getContentFormatter() {
110+
return contentFormatter;
111+
}
112+
113+
public void setContentFormatter(AiObservationContentFormatterName contentFormatter) {
114+
this.contentFormatter = contentFormatter;
115+
}
116+
64117
public boolean isIncludeErrorLogging() {
65118
return this.includeErrorLogging;
66119
}

0 commit comments

Comments
 (0)