-
Notifications
You must be signed in to change notification settings - Fork 728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Treat messages with missing variables as text #1137
base: main
Are you sure you want to change the base?
Conversation
Hi @anunnakian thanks a lot! This seems to be a bit different from what was described in #1125 This is definitely a wrong configuration: interface AiService {
@UserMessage("What is the capital of {{it}}?")
String answer();
} The case described in the issue is different: @AiService
public interface AiAssistant {
TokenStream chat(@MemoryId String chatId, @UserMessage String userMessage);
}
assistant.chat("12345", "Text containing {{it}}"); |
@langchain4j if we consider that the issue was fixed, the following tests must be green right ? @Test
void test_user_message_configuration_8() {
// given
AiService aiService = AiServices.builder(AiService.class)
.chatLanguageModel(chatLanguageModel)
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
.build();
// when
aiService.chat8("12345", "What is the capital of {{it}}?");
// then
verify(chatLanguageModel).generate(singletonList(userMessage("What is the capital of {{it}}?")));
}
@Test
void test_user_message_configuration_9() {
// given
AiService aiService = AiServices.builder(AiService.class)
.chatLanguageModel(chatLanguageModel)
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
.build();
// when
aiService.chat8("12345", "What is the capital of {{variable}}?");
// then
verify(chatLanguageModel).generate(singletonList(userMessage("What is the capital of {{variable}}?")));
} |
We should remove this test case, if the missing variable {{name}} must be treated like text, right ? @Test
void should_fail_when_value_is_missing() {
// given
PromptTemplate promptTemplate = PromptTemplate.from("My name is {{name}}.");
Map<String, Object> variables = emptyMap();
// when-then
assertThatThrownBy(() -> promptTemplate.apply(variables))
.isExactlyInstanceOf(IllegalArgumentException.class)
.hasMessage("Value for the variable 'name' is missing");
} |
@anunnakian to your first question: yes. |
@langchain4j If we treat the message as text instead of a template, we will break the case if we have two variable with one missing like the following test : interface AiService {
String chat9(@MemoryId String chatId, @UserMessage String userMessage, @V("country") String country);
}
@Test
void test_user_message_configuration_10() {
// given
AiService aiService = AiServices.builder(AiService.class)
.chatLanguageModel(chatLanguageModel)
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
.build();
// when
aiService.chat9("12345", "What is the {{it}} of {{country}}?", "Germany");
// then
verify(chatLanguageModel).generate(singletonList(userMessage("What is the {{it}} of Germany?")));
} This test must be green too at the end, right ? |
@langchain4j I found a solution to make all tests above and the following one green! interface AiService {
String chat(@MemoryId String chatId, @UserMessage String userMessage);
}
@Test
void test_user_message_configuration_9() {
// given
AiService aiService = AiServices.builder(AiService.class)
.chatLanguageModel(chatLanguageModel)
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
.build();
// when
aiService.chat("12345", "What is the {{it}} of {{var}}?");
// then
verify(chatLanguageModel).generate(singletonList(userMessage("What is the {{it}} of {{var}}?")));
} |
* Get all variables extracted from the template. | ||
* @return A set of variable names. | ||
*/ | ||
default Set<String> getAllVariables() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A make this method default
to avoid breaking changes
Should we just always treat missing variables, including If we do indeed want to support e.g. @UserMessage(value = "What is the capital of {{it}}?", templated = false)
public @interface UserMessage {
String value()
boolean templated() default true;
} If we need even further grained control, such that only some variables are excluded from templating, that could also be defined in the annotation? @UserMessage(value = "What is the capital of {{it}} in {{country}}?", excludedVariables = { "it" })
public @interface UserMessage {
String value()
String[] excludedVariables() default {};
} |
@ashimoon yes, I think you are right. We should be strict by default (as it is now). I think I rushed a bit with #1125. It can be solved by escaping @anunnakian sorry about that, let's put this PR on hold for now |
Ok! Don't panic everything is under control (just kidding... 😁) So, I'll create another PR to escape {{it}} variable tonight Thanks for your feedback @ashimoon @langchain4j 😉 |
@anunnakian I meant that the current implementation (without this PR) indeed seems to be the most reasonable. I guess that specific corner case in #1125 is actually ok and the user can escape manually, if there is a need. Whether we should support auto-escaping, it is tricky. I would take a break and return to this problem a bit later. |
@langchain4j got it ;) |
Issue
#1125
Change
When we declare an assistant as following example :
We don't throw an illegal exception like before, we treat the user message like text without resolving the
{{it}}
variable.Here is a test that explain the treatment clearly :
General checklist
Checklist for adding new model integration
Checklist for adding new embedding store integration
{NameOfIntegration}EmbeddingStoreIT
that extends from eitherEmbeddingStoreIT
orEmbeddingStoreWithFilteringIT
Checklist for changing existing embedding store integration
{NameOfIntegration}EmbeddingStore
works correctly with the data persisted using the latest released version of LangChain4j