You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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为何会两次解析模板变量?是否有预定义方法来转义用户输入?


原因分析

  1. 第一次解析:调用promptTemplate.create()时,PromptTemplate会替换模板中的{userInput}变量,生成包含用户输入内容的Prompt。
  2. 第二次解析:当通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 10:34:51