Skip to content

Commit c3a66b0

Browse files
committed
[OPIK-751] Use mustache for online scoring
1 parent 4490aaa commit c3a66b0

File tree

5 files changed

+30
-17
lines changed

5 files changed

+30
-17
lines changed

apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/events/OnlineScoringEngine.java

+7-11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.comet.opik.api.FeedbackScoreBatchItem;
44
import com.comet.opik.api.ScoreSource;
55
import com.comet.opik.api.Trace;
6+
import com.comet.opik.utils.MustacheUtils;
67
import com.fasterxml.jackson.core.JsonProcessingException;
78
import com.fasterxml.jackson.databind.JsonNode;
89
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -26,7 +27,6 @@
2627
import lombok.Builder;
2728
import lombok.experimental.UtilityClass;
2829
import lombok.extern.slf4j.Slf4j;
29-
import org.apache.commons.text.StringSubstitutor;
3030

3131
import java.util.Arrays;
3232
import java.util.Collections;
@@ -46,11 +46,11 @@
4646
@Slf4j
4747
public class OnlineScoringEngine {
4848

49-
final String SCORE_FIELD_NAME = "score";
50-
final String REASON_FIELD_NAME = "reason";
51-
final String SCORE_FIELD_DESCRIPTION = "the score for ";
52-
final String REASON_FIELD_DESCRIPTION = "the reason for the score for ";
53-
final String DEFAULT_SCHEMA_NAME = "scoring_schema";
49+
static final String SCORE_FIELD_NAME = "score";
50+
static final String REASON_FIELD_NAME = "reason";
51+
static final String SCORE_FIELD_DESCRIPTION = "the score for ";
52+
static final String REASON_FIELD_DESCRIPTION = "the reason for the score for ";
53+
static final String DEFAULT_SCHEMA_NAME = "scoring_schema";
5454

5555
/**
5656
* Prepare a request to a LLM-as-Judge evaluator (a ChatLanguageModel) rendering the template messages with
@@ -103,14 +103,10 @@ static List<ChatMessage> renderMessages(List<LlmAsJudgeMessage> templateMessages
103103
.collect(
104104
Collectors.toMap(MessageVariableMapping::variableName, MessageVariableMapping::valueToReplace));
105105

106-
// will convert all '{{key}}' into 'value'
107-
// TODO: replace with Mustache Java to be in confirm with FE
108-
var templateRenderer = new StringSubstitutor(replacements, "{{", "}}");
109-
110106
// render the message templates from evaluator rule
111107
return templateMessages.stream()
112108
.map(templateMessage -> {
113-
var renderedMessage = templateRenderer.replace(templateMessage.content());
109+
var renderedMessage = MustacheUtils.render(templateMessage.content(), replacements);
114110

115111
return switch (templateMessage.role()) {
116112
case USER -> UserMessage.from(renderedMessage);

apps/opik-backend/src/main/java/com/comet/opik/domain/PromptService.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.comet.opik.api.PromptVersion.PromptVersionPage;
77
import com.comet.opik.api.error.EntityAlreadyExistsException;
88
import com.comet.opik.infrastructure.auth.RequestContext;
9-
import com.comet.opik.utils.MustacheVariableExtractor;
9+
import com.comet.opik.utils.MustacheUtils;
1010
import com.google.inject.ImplementedBy;
1111
import io.dropwizard.jersey.errors.ErrorMessage;
1212
import jakarta.inject.Inject;
@@ -396,7 +396,7 @@ private Set<String> getVariables(String template) {
396396
return null;
397397
}
398398

399-
return MustacheVariableExtractor.extractVariables(template);
399+
return MustacheUtils.extractVariables(template);
400400
}
401401

402402
private EntityAlreadyExistsException newConflict(String alreadyExists) {

apps/opik-backend/src/main/java/com/comet/opik/infrastructure/db/PromptVersionColumnMapper.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.comet.opik.api.PromptVersion;
44
import com.comet.opik.utils.JsonUtils;
5-
import com.comet.opik.utils.MustacheVariableExtractor;
5+
import com.comet.opik.utils.MustacheUtils;
66
import com.fasterxml.jackson.databind.JsonNode;
77
import org.jdbi.v3.core.mapper.ColumnMapper;
88
import org.jdbi.v3.core.statement.StatementContext;
@@ -35,7 +35,7 @@ private PromptVersion mapObject(JsonNode jsonNode) {
3535
.template(jsonNode.get("template").asText())
3636
.metadata(jsonNode.get("metadata"))
3737
.changeDescription(jsonNode.get("change_description").asText())
38-
.variables(MustacheVariableExtractor.extractVariables(jsonNode.get("template").asText()))
38+
.variables(MustacheUtils.extractVariables(jsonNode.get("template").asText()))
3939
.createdAt(Instant.from(FORMATTER.parse(jsonNode.get("created_at").asText())))
4040
.createdBy(jsonNode.get("created_by").asText())
4141
.build();

apps/opik-backend/src/main/java/com/comet/opik/utils/MustacheVariableExtractor.java apps/opik-backend/src/main/java/com/comet/opik/utils/MustacheUtils.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@
77
import com.github.mustachejava.codes.ValueCode;
88
import lombok.experimental.UtilityClass;
99

10+
import java.io.IOException;
1011
import java.io.StringReader;
12+
import java.io.StringWriter;
13+
import java.io.UncheckedIOException;
14+
import java.io.Writer;
1115
import java.util.HashSet;
16+
import java.util.Map;
1217
import java.util.Objects;
1318
import java.util.Optional;
1419
import java.util.Set;
1520

1621
@UtilityClass
17-
public class MustacheVariableExtractor {
22+
public class MustacheUtils {
1823

1924
public static final MustacheFactory MF = new DefaultMustacheFactory();
2025

@@ -31,6 +36,18 @@ public static Set<String> extractVariables(String template) {
3136
return variables;
3237
}
3338

39+
public static String render(String template, Map<String, ?> context) {
40+
41+
Mustache mustache = MF.compile(new StringReader(template), "template");
42+
43+
try (Writer writer = mustache.execute(new StringWriter(), context)){
44+
writer.flush();
45+
return writer.toString();
46+
} catch (IOException e) {
47+
throw new UncheckedIOException("Failed to render template", e);
48+
}
49+
}
50+
3451
private static void collectVariables(Code[] codes, Set<String> variables) {
3552
for (Code code : codes) {
3653
if (Objects.requireNonNull(code) instanceof ValueCode valueCode) {

apps/opik-backend/src/test/java/com/comet/opik/api/resources/v1/events/OnlineScoringEngineTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
@Slf4j
4343
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
4444
@DisplayName("LlmAsJudge Message Render")
45-
public class OnlineScoringEngineTest {
45+
class OnlineScoringEngineTest {
4646
@Mock
4747
AutomationRuleEvaluatorService ruleEvaluatorService;
4848
@Mock

0 commit comments

Comments
 (0)