Spring AI为何两次解析模板变量?如何转义用户输入?
Spring AI模板变量二次解析问题及转义方案
我开发了一个调用OpenAI Chat的应用,用户输入的文本会被用于生成Prompt,期望返回Java对象(基于Structured Output Converter机制)。但Spring AI会对模板中的变量进行两次解析,当用户输入包含特殊字符时会引发错误。
代码示例
@SpringBootApplication public class MyTestApp { public static void main(String[] args) { SpringApplication.run(MyTestApp.class, args); } @Data class Result { private String text; } @Controller @AllArgsConstructor class MyTestService { private final ChatClient chatClient; @GetMapping("/test") public void test() { final PromptTemplate promptTemplate = new PromptTemplate("{userInput}"); final Prompt prompt = promptTemplate.create(Map.of("userInput", "{test}")); final Result result = chatClient.prompt(prompt).advisors(new SimpleLoggerAdvisor()).call().entity(Result.class); } } }
错误日志
java.lang.IllegalStateException: Not all template variables were replaced. Missing variable names are [test] at org.springframework.ai.chat.prompt.PromptTemplate.validate(PromptTemplate.java:232) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.prompt.PromptTemplate.render(PromptTemplate.java:125) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.advisor.api.AdvisedRequest.toPrompt(AdvisedRequest.java:171) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.DefaultChatClient$DefaultChatClientRequestSpec$1.aroundCall(DefaultChatClient.java:675) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.lambda$nextAroundCall$1(DefaultAroundAdvisorChain.java:98) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at io.micrometer.observation.Observation.observe(Observation.java:564) ~[micrometer-observation-1.14.3.jar:1.14.3] at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.nextAroundCall(DefaultAroundAdvisorChain.java:98) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor.aroundCall(SimpleLoggerAdvisor.java:99) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.lambda$nextAroundCall$1(DefaultAroundAdvisorChain.java:98) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at io.micrometer.observation.Observation.observe(Observation.java:564) ~[micrometer-observation-1.14.3.jar:1.14.3] at org.springframework.ai.chat.client.advisor.DefaultAroundAdvisorChain.nextAroundCall(DefaultAroundAdvisorChain.java:98) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doGetChatResponse(DefaultChatClient.java:488) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.lambda$doGetObservableChatResponse$1(DefaultChatClient.java:477) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at io.micrometer.observation.Observation.observe(Observation.java:564) ~[micrometer-observation-1.14.3.jar:1.14.3] at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doGetObservableChatResponse(DefaultChatClient.java:477) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.doSingleWithBeanOutputConverter(DefaultChatClient.java:451) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5] at org.springframework.ai.chat.client.DefaultChatClient$DefaultCallResponseSpec.entity(DefaultChatClient.java:446) ~[spring-ai-core-1.0.0-M5.jar:1.0.0-M5]
问题
Spring AI为何会两次解析模板变量?是否有预定义方法来转义用户输入?
原因分析
- 第一次解析:调用
promptTemplate.create()时,PromptTemplate会替换模板中的{userInput}变量,生成包含用户输入内容的Prompt。 - 第二次解析:当通过
chatClient发起请求时,ChatClient的Advisor链(比如你使用的SimpleLoggerAdvisor)会再次对Prompt内容执行模板解析逻辑,此时用户输入里的{test}会被识别为未定义的模板变量,从而抛出变量缺失的异常。
解决方案
1. 转义特殊字符
Spring AI的PromptTemplate支持用双大括号{{}}转义单个大括号。修改用户输入的格式,将{test}改为{{test}},这样第一次解析后会保留为{test},第二次解析时不会被当作模板变量:
final Prompt prompt = promptTemplate.create(Map.of("userInput", "{{test}}"));
2. 直接构造Prompt对象
跳过PromptTemplate的二次解析环节,直接构造Prompt对象传递用户输入:
// 直接创建UserMessage并构造Prompt,避免模板解析逻辑 final Prompt prompt = new Prompt(new UserMessage("{test}"));
3. 配置模板解析规则
部分版本的Spring AI支持通过PromptTemplate.setEscapeVariables(true)开启自动转义,或者自定义模板解析器的分隔符,避免与用户输入的特殊字符冲突。
内容的提问来源于stack exchange,提问作者dur
相关产品推荐
相关产品推荐

