spring-ai advisors 运用与源码分析

advisors
spring-ai v1.0.3

为什么要用 Advisors?

Spring AI Advisors API提供了一种灵活而强大的方式来拦截、修改和增强Spring应用程序中AI驱动的交互。通过利用Advisors API,开发人员可以创建更复杂、可重用和可维护的AI组件。
常见的使用场景

  • 统一拦截:把日志、memory、tool调用、检索、审计等横切逻辑从业务中剥离。
  • 解放双手:原生 OpenAI 的 tool_calls 需要你手写循环(解析→调用→回补→再问);Advisor 帮你自动闭环。

源码分析

核心接口

在这里插入图片描述

BaseAdvisor

public interface BaseAdvisor extends CallAdvisor, StreamAdvisor {
@Override
default ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
//1. do - before call
ChatClientRequest processedChatClientRequest = before(chatClientRequest, callAdvisorChain);
//2. execute call
ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(processedChatClientRequest);
//3. do - after call
return after(chatClientResponse, callAdvisorChain);
}
default Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest,
  StreamAdvisorChain streamAdvisorChain) {/*略...*/}
  ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain);
  ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain);
  }

自定义MessageChatMemoryAdvisor - 源码分析

定义JDBC ChatMemory

JdbcChatMemoryRepository chatMemoryRepository = ...; //3
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository) //2
.maxMessages(10)
.build();
ChatClient chatClient = ChatClient.builder(openAiChatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) // 1
.build();

BaseChatMemoryAdvisor & MessageChatMemoryAdvisor

public interface BaseChatMemoryAdvisor extends BaseAdvisor {
default String getConversationId(Map<String, Object> context, String defaultConversationId) {
  //ChatMemory.CONVERSATION_ID = "chat_memory_conversation_id" 
  return context.containsKey(ChatMemory.CONVERSATION_ID) ? context.get(ChatMemory.CONVERSATION_ID).toString()
  : defaultConversationId;
  }
  }
  public final class MessageChatMemoryAdvisor implements BaseChatMemoryAdvisor {
  //constructor 注入
  private final ChatMemory chatMemory;
  public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {
  //0.获取converstationId
  String conversationId = getConversationId(chatClientRequest.context(), this.defaultConversationId);
  // 1. 从chatMemory获取当前conversationId的messages -- todo
  List<Message> memoryMessages = this.chatMemory.get(conversationId);
    // 2. 将#1和promote中message合并
    List<Message> processedMessages = new ArrayList<>(memoryMessages);
      processedMessages.addAll(chatClientRequest.prompt().getInstructions());
      // 3.更新request中的message
      ChatClientRequest processedChatClientRequest = chatClientRequest.mutate()
      .prompt(chatClientRequest.prompt().mutate().messages(processedMessages).build())
      .build();
      // 4. Add the new user message to the conversation memory.
      UserMessage userMessage = processedChatClientRequest.prompt().getUserMessage();
      this.chatMemory.add(conversationId, userMessage);
      return processedChatClientRequest;
      }
      public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
      List<Message> assistantMessages = new ArrayList<>();
        if (chatClientResponse.chatResponse() != null) {
        assistantMessages = chatClientResponse.chatResponse()
        .getResults()
        .stream()
        .map(g -> (Message) g.getOutput())
        .toList();
        }
        //添加message 至chatMemory
        this.chatMemory.add(this.getConversationId(chatClientResponse.context(), this.defaultConversationId),
        assistantMessages);
        return chatClientResponse;
        }
        }

ChatMemory & MessageWindowChatMemory

public interface ChatMemory {
String CONVERSATION_ID = "chat_memory_conversation_id";
void add(String conversationId, List<Message> messages);
  List<Message> get(String conversationId);
    void clear(String conversationId);
    }
    public final class MessageWindowChatMemory implements ChatMemory {
    private final ChatMemoryRepository chatMemoryRepository;
    private final int maxMessages;//单个conversationId,最大的messages 条数
    public List<Message> get(String conversationId) {
      return this.chatMemoryRepository.findByConversationId(conversationId);
      }
      public void clear(String conversationId) {
      this.chatMemoryRepository.deleteByConversationId(conversationId);
      }
      public void add(String conversationId, List<Message> messages) {
        List<Message> memoryMessages = this.chatMemoryRepository.findByConversationId(conversationId);
          List<Message> processedMessages = process(memoryMessages, messages); //process
            this.chatMemoryRepository.saveAll(conversationId, processedMessages);
            }
            private List<Message> process(List<Message> memoryMessages, List<Message> newMessages) {
              //合并memoryMessages + newMessages, 若超过maxMessages,则需要按照规则remove历史message
              }
              }

ChatMemoryRepository & JdbcChatMemoryRepository

public final class JdbcChatMemoryRepository implements ChatMemoryRepository {
public List<Message> findByConversationId(String conversationId) {
  //执行this.dialect.getSelectMessagesSql()中定义的sql
  return this.jdbcTemplate.query(this.dialect.getSelectMessagesSql(), new MessageRowMapper(), new Object[]{conversationId});
  }
  //findConversationIds(),saveAll(),deleteByConversationId()方法略...
  }

JdbcChatMemoryRepositoryDialect & PostgresChatMemoryRepositoryDialect

public interface JdbcChatMemoryRepositoryDialect {
String getSelectMessagesSql();
String getInsertMessageSql();
String getSelectConversationIdsSql();
String getDeleteMessagesSql();
}
public class PostgresChatMemoryRepositoryDialect implements JdbcChatMemoryRepositoryDialect {
public String getSelectMessagesSql() {
return "SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY \"timestamp\"";
}
public String getInsertMessageSql() {
return "INSERT INTO SPRING_AI_CHAT_MEMORY (conversation_id, content, type, \"timestamp\") VALUES (?, ?, ?, ?)";
}
public String getSelectConversationIdsSql() {
return "SELECT DISTINCT conversation_id FROM SPRING_AI_CHAT_MEMORY";
}
public String getDeleteMessagesSql() {
return "DELETE FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ?";
}
}


ChatModelCallAdvisor & ChatModelStreamAdvisor(略)

public final class ChatModelCallAdvisor implements CallAdvisor {
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
Assert.notNull(chatClientRequest, "the chatClientRequest cannot be null");
ChatClientRequest formattedChatClientRequest = augmentWithFormatInstructions(chatClientRequest);
//调用chat-model去执行request
ChatResponse chatResponse = this.chatModel.call(formattedChatClientRequest.prompt());
return ChatClientResponse.builder()
.chatResponse(chatResponse)
.context(Map.copyOf(formattedChatClientRequest.context()))
.build();
}
}

ChatClient执行advisors全流程

完整实例

@Test
public void test_jdbc() {
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
ChatClient chatClient = ChatClient.builder(openAiChatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
String conversationId = "007";
ChatResponse response = chatClient.prompt()
.user("who am i?")
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId)) //在context中定义CONVERSATION_ID
.call() // 1
.chatResponse(); //2
log.info("response: " + response);
}

chatClient.prompt()…call()

public class DefaultChatClient implements ChatClient {
public static class DefaultChatClientRequestSpec implements ChatClientRequestSpec {
private final List<Advisor> advisors = new ArrayList<>();
  private final Map<String, Object> advisorParams = new HashMap<>();
    //1.advisor
    public ChatClientRequestSpec advisors(Consumer<ChatClient.AdvisorSpec> consumer) {
      var advisorSpec = new DefaultAdvisorSpec();
      consumer.accept(advisorSpec); //添加param -> DefaultAdvisorSpec
      this.advisorParams.putAll(advisorSpec.getParams()); // param -> advisorParams
      this.advisors.addAll(advisorSpec.getAdvisors());
      return this;
      }
      //2
      public CallResponseSpec call() {
      //2.1 build advisorChain by using :advisors + ChatModelCallAdvisor , ChatModelStreamAdvisor
      BaseAdvisorChain advisorChain = buildAdvisorChain();
      //2.2 DefaultChatClientUtils.toChatClientRequest(this)
      //2.3 build DefaultCallResponseSpec
      return new DefaultCallResponseSpec(DefaultChatClientUtils.toChatClientRequest(this),
      advisorChain,this.observationRegistry, this.observationConvention);
      }
      //2.1
      private BaseAdvisorChain buildAdvisorChain() {
      // At the stack bottom add the model call advisors.
      // They play the role of the last advisors in the advisor chain.
      this.advisors.add(ChatModelCallAdvisor.builder().chatModel(this.chatModel).build());
      this.advisors.add(ChatModelStreamAdvisor.builder().chatModel(this.chatModel).build());
      return DefaultAroundAdvisorChain.builder(this.observationRegistry)
      .pushAll(this.advisors)
      .templateRenderer(this.templateRenderer)
      .build();
      }
      }
      }
      //2.2
      final class DefaultChatClientUtils {
      static ChatClientRequest toChatClientRequest(DefaultChatClient.DefaultChatClientRequestSpec inputRequest) {
      List<Message> processedMessages = new ArrayList<>();
        // System Text => First in the list
        String processedSystemText = inputRequest.getSystemText();
        if (StringUtils.hasText(processedSystemText)) {
        processedMessages.add(new SystemMessage(processedSystemText));
        }
        // Messages => In the middle of the list
        if (!CollectionUtils.isEmpty(inputRequest.getMessages())) {
        processedMessages.addAll(inputRequest.getMessages());
        }
        // User Text => Last in the list
        String processedUserText = inputRequest.getUserText();
        if (StringUtils.hasText(processedUserText)) {
        processedMessages.add(UserMessage.builder().text(processedUserText).media(inputRequest.getMedia()).build());
        }
        //tools 相关.. SKIP....
        return ChatClientRequest.builder()
        .prompt(Prompt.builder().messages(processedMessages).chatOptions(processedChatOptions).build())
        .context(new ConcurrentHashMap<>(inputRequest.getAdvisorParams())) //将avisorParams 放至 contxt
          .build();
          }
          }

chatClient.prompt()…call().chatResponse

public class DefaultChatClient implements ChatClient {
public static class DefaultChatClientRequestSpec implements ChatClientRequestSpec {
//3.
public ChatResponse chatResponse() {
return doGetObservableChatClientResponse(this.request).chatResponse(); //3.1
}
//3.1
private ChatClientResponse doGetObservableChatClientResponse(ChatClientRequest chatClientRequest,
@Nullable String outputFormat) {
//context中添加OUTPUT_FORMAT
if (outputFormat != null) {
chatClientRequest.context().put(ChatClientAttributes.OUTPUT_FORMAT.getKey(), outputFormat);
}
ChatClientObservationContext observationContext = ChatClientObservationContext.builder()
.request(chatClientRequest)
.advisors(this.advisorChain.getCallAdvisors())
.stream(false)
.format(outputFormat)
.build();
var observation = ChatClientObservationDocumentation.AI_CHAT_CLIENT.observation(this.observationConvention,
DEFAULT_CHAT_CLIENT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry);
var chatClientResponse = observation.observe(() -> {
//4 advisorChain.nextCall
return this.advisorChain.nextCall(chatClientRequest);
});
return chatClientResponse != null ? chatClientResponse : ChatClientResponse.builder().build();
}
}
}

ChatClientObservationDocumentation & ChatClientObservationContext – 略…

advisorChain.nextCall(chatClientRequest)

public class DefaultAroundAdvisorChain implements BaseAdvisorChain {
public ChatClientResponse nextCall(ChatClientRequest chatClientRequest) {
var advisor = this.callAdvisors.pop(); //pop advisor
var observationContext = AdvisorObservationContext.builder()
.advisorName(advisor.getName())
.chatClientRequest(chatClientRequest)
.order(advisor.getOrder())
.build();
return AdvisorObservationDocumentation.AI_ADVISOR
.observation(null, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, this.observationRegistry)
.observe(() -> advisor.adviseCall(chatClientRequest, this)); //advisor.adviseCall().
}
}


Tools源码分析

完整实例

定义Tool

public class DateTimeTools {
@Tool(description = "Get the current date and time in the user's timezone")
String getCurrentDateTime() {
return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
}
}

示例

@Test
public void test_tools() {
String response = ChatClient.create(openAiChatModel)
.prompt("What day is tomorrow?")
.tools(new DateTimeTools())
.call()
.content();
System.out.printf("response: %s%n", response); //response: Today is October 30, 2025. Therefore, tomorrow will be October 31, 2025. If you need to know the day of the week for tomorrow, please let me know!
}

manual执行tool

上述例子中,tool不需要人工的接入,会被自动的调用,如何设置为manual执行呢?

@Test
public void test_tools_manual() {
ChatOptions opts = ToolCallingChatOptions.builder()
.toolCallbacks(ToolCallbacks.from(new DateTimeTools()))
.internalToolExecutionEnabled(false)
.build();
ChatResponse response = ChatClient.create(openAiChatModel)
.prompt("What day is tomorrow?")
.options(opts)
.tools(new DateTimeTools())
.call()
.chatResponse();
System.out.println(response.getResults().get(0).getOutput());
}

输出

AssistantMessage [messageType=ASSISTANT, toolCalls=[ToolCall[id=call_dVZAUN1LsodBQYhLjjb8MjYB, type=function, name=getCurrentDateTime, arguments={}]], textContent=null, metadata={role=ASSISTANT, messageType=ASSISTANT, finishReason=TOOL_CALLS, refusal=, index=0, annotations=[], id=chatcmpl-CWJFVxCDmBjGAupsZ6QPghBUS3FGP}]

这个才是我们所期待的输出,spring-ai什么样的机制让ToolCall自动执行了呢?

ToolCallingChatOptions

类图

在这里插入图片描述

SetUp ToolCallingChatOptions

上文我们已经分析过DefaultChatClientUtils.toChatClientRequest(),其中tool部分前文没有过多解读,在这里我们分析下:

final class DefaultChatClientUtils {
static ChatClientRequest toChatClientRequest(DefaultChatClient.DefaultChatClientRequestSpec inputRequest) {
//..... SKIP
//for Tools -- 将request中的 toolnames, callbacks,toolContext 存放到request.chatOptions即ToolCallingChatOptions
ChatOptions processedChatOptions = inputRequest.getChatOptions(); //OpenAiChatOptions
if (processedChatOptions instanceof ToolCallingChatOptions toolCallingChatOptions) {
if (!inputRequest.getToolNames().isEmpty()) {
Set<String> toolNames = ToolCallingChatOptions
  .mergeToolNames(new HashSet<>(inputRequest.getToolNames()), toolCallingChatOptions.getToolNames());
    toolCallingChatOptions.setToolNames(toolNames);
    }
    if (!inputRequest.getToolCallbacks().isEmpty()) {
    List<ToolCallback> toolCallbacks = ToolCallingChatOptions
      .mergeToolCallbacks(inputRequest.getToolCallbacks(), toolCallingChatOptions.getToolCallbacks());
      ToolCallingChatOptions.validateToolCallbacks(toolCallbacks);
      toolCallingChatOptions.setToolCallbacks(toolCallbacks);
      }
      if (!CollectionUtils.isEmpty(inputRequest.getToolContext())) {
      Map<String, Object> toolContext = ToolCallingChatOptions.mergeToolContext(inputRequest.getToolContext(),
        toolCallingChatOptions.getToolContext());
        toolCallingChatOptions.setToolContext(toolContext);
        }
        }
        //将request.chatOptions即ToolCallingChatOptions  --> prompt.options
        return ChatClientRequest.builder()
        .prompt(Prompt.builder().messages(processedMessages).chatOptions(processedChatOptions).build())
        .context(new ConcurrentHashMap<>(inputRequest.getAdvisorParams()))
          .build();
          }
          }

Using ToolCallingChatOptions (ChatModelCallAdvisor#call())

ToolCallingChatOptions会在ChatModelCallAdvisor#call())中会被调用.

public class OpenAiChatModel implements ChatModel {
public ChatResponse call(Prompt prompt) {
Prompt requestPrompt = buildRequestPrompt(prompt); //1.build new prompt with requestOptions
return this.internalCall(requestPrompt, null);//2
}
//1
Prompt buildRequestPrompt(Prompt prompt) {
// Process runtime options
OpenAiChatOptions runtimeOptions = null;
if (prompt.getOptions() != null) {
if (prompt.getOptions() instanceof ToolCallingChatOptions toolCallingChatOptions) {
runtimeOptions = ModelOptionsUtils.copyToTarget(toolCallingChatOptions, ToolCallingChatOptions.class,OpenAiChatOptions.class);
}else {
runtimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), ChatOptions.class,OpenAiChatOptions.class);
}
}
// Define request options by merging runtime options and default options
OpenAiChatOptions requestOptions = ModelOptionsUtils.merge(runtimeOptions, this.defaultOptions,OpenAiChatOptions.class);
// set **options
requestOptions.setHttpHeaders(this.defaultOptions.getHttpHeaders());
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
requestOptions.setToolNames(this.defaultOptions.getToolNames());
requestOptions.setToolCallbacks(this.defaultOptions.getToolCallbacks());
requestOptions.setToolContext(this.defaultOptions.getToolContext());
//set
return new Prompt(prompt.getInstructions(), requestOptions);
}
//2.
public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatResponse) {
ChatCompletionRequest request = createRequest(prompt, false);
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
.prompt(prompt)
.provider(OpenAiApiConstants.PROVIDER_NAME)
.build();
//2.1 call open ai 
ChatResponse response = ChatModelObservationDocumentation.CHAT_MODEL_OPERATION
.observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
this.observationRegistry)
.observe(() -> {
//open-ai do request
ResponseEntity<ChatCompletion> completionEntity = this.retryTemplate
  .execute(ctx -> this.openAiApi.chatCompletionEntity(request, getAdditionalHttpHeaders(prompt)));
  var chatCompletion = completionEntity.getBody();
  List<Choice> choices = chatCompletion.choices();
    List<Generation> generations = choices.stream().map(choice -> {
      Map<String, Object> metadata = Map.of(
        "id", chatCompletion.id() != null ? chatCompletion.id() : "",
        "role", choice.message().role() != null ? choice.message().role().name() : "",
        "index", choice.index() != null ? choice.index() : 0,
        "finishReason", getFinishReasonJson(choice.finishReason()),
        "refusal", StringUtils.hasText(choice.message().refusal()) ? choice.message().refusal() : "",
        "annotations", choice.message().annotations() != null ? choice.message().annotations() : List.of(Map.of()));
        return buildGeneration(choice, metadata, request);
        }).toList();
        // Current usage,rateLimit,....
        ChatResponse chatResponse = new ChatResponse(generations,
        from(chatCompletion, rateLimit, accumulatedUsage));
        return chatResponse;
        });
        /**
        * 2.2 DefaultToolExecutionEligibilityPredicate
        * - isInternalToolExecutionEnabled is true
        * - and response.hasToolCalls
        */
        if (this.toolExecutionEligibilityPredicate.isToolExecutionRequired(prompt.getOptions(), response)) {
        //2.3 DefaultToolCallingManager.executeToolCalls
        var toolExecutionResult = this.toolCallingManager.executeToolCalls(prompt, response);
        if (toolExecutionResult.returnDirect()) {
        // Return tool execution result directly to the client.
        return ChatResponse.builder()
        .from(response)
        .generations(ToolExecutionResult.buildGenerations(toolExecutionResult))
        .build();
        }
        else {
        // Send the tool execution result back to the model.
        return this.internalCall(new Prompt(toolExecutionResult.conversationHistory(), prompt.getOptions()),
        response);
        }
        }
        return response;
        }
        }
DefaultToolExecutionEligibilityPredicate.isToolExecutionRequired()
public interface ToolExecutionEligibilityPredicate extends BiPredicate<ChatOptions, ChatResponse> {
  default boolean isToolExecutionRequired(ChatOptions promptOptions, ChatResponse chatResponse) {
  return test(promptOptions, chatResponse);//sub-class
  }
  }
  public class DefaultToolExecutionEligibilityPredicate implements ToolExecutionEligibilityPredicate {
  public boolean test(ChatOptions promptOptions, ChatResponse chatResponse) {
  return ToolCallingChatOptions.isInternalToolExecutionEnabled(promptOptions) && chatResponse != null
  && chatResponse.hasToolCalls();
  }
  }
DefaultToolCallingManager.executeToolCalls()
public final class DefaultToolCallingManager implements ToolCallingManager {
//2.3
public ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse) {
Optional<Generation> toolCallGeneration = chatResponse.getResults()
  .stream()
  .filter(g -> !CollectionUtils.isEmpty(g.getOutput().getToolCalls()))
  .findFirst();
  AssistantMessage assistantMessage = toolCallGeneration.get().getOutput();
  //2.3.1 build tool-context-map
  ToolContext toolContext = buildToolContext(prompt, assistantMessage);
  //2.3.2
  InternalToolExecutionResult internalToolExecutionResult = executeToolCall(prompt, assistantMessage,toolContext);
  List<Message> conversationHistory = buildConversationHistoryAfterToolExecution(prompt.getInstructions(),
    assistantMessage, internalToolExecutionResult.toolResponseMessage());
    return ToolExecutionResult.builder()
    .conversationHistory(conversationHistory)
    .returnDirect(internalToolExecutionResult.returnDirect())
    .build();
    }
    //2.3.1
    private static ToolContext buildToolContext(Prompt prompt, AssistantMessage assistantMessage) {
    Map<String, Object> toolContextMap = Map.of();
      if (prompt.getOptions() instanceof ToolCallingChatOptions toolCallingChatOptions
      && !CollectionUtils.isEmpty(toolCallingChatOptions.getToolContext())) {
      //init with tool-context
      toolContextMap = new HashMap<>(toolCallingChatOptions.getToolContext());
        //add history messages
        toolContextMap.put(ToolContext.TOOL_CALL_HISTORY,
        buildConversationHistoryBeforeToolExecution(prompt, assistantMessage));
        }
        return new ToolContext(toolContextMap);
        }
        //2.3.2
        private InternalToolExecutionResult executeToolCall(Prompt prompt, AssistantMessage assistantMessage,
        ToolContext toolContext) {
        //2.3.2.1. 加载定义的callbacks
        List<ToolCallback> toolCallbacks = toolCallingChatOptions.getToolCallbacks();
          List<ToolResponseMessage.ToolResponse> toolResponses = new ArrayList<>();
            Boolean returnDirect = null;
            for (AssistantMessage.ToolCall toolCall : assistantMessage.getToolCalls()) {
            String toolName = toolCall.name();
            String toolInputArguments = toolCall.arguments();
            //构造tool的 inputArguments
            final String finalToolInputArguments = toolInputArguments;
            //根据toolname找到对应的callback
            ToolCallback toolCallback = toolCallbacks.stream()
            .filter(tool -> toolName.equals(tool.getToolDefinition().name()))
            .findFirst()
            .orElseGet(() -> this.toolCallbackResolver.resolve(toolName));
            // returnDirect是在Callback.ToolMetadata中定义的,用来表明无论response是什么,都直接返回
            returnDirect = returnDirect && toolCallback.getToolMetadata().returnDirect();
            String toolCallResult = ToolCallingObservationDocumentation.TOOL_CALL
            .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
            this.observationRegistry)
            .observe(() -> {
            //执行callback
            String toolResult = toolCallback.call(finalToolInputArguments, toolContext);
            return toolResult;
            });
            toolResponses.add(new ToolResponseMessage.ToolResponse(toolCall.id(), toolName,toolCallResult != null ? toolCallResult : ""));
            }
            return new InternalToolExecutionResult(new ToolResponseMessage(toolResponses, Map.of()), returnDirect);
            }
            }
posted @ 2025-11-28 10:48  clnchanpin  阅读(151)  评论(0)    收藏  举报