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

java 复制代码
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

java 复制代码
  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

java 复制代码
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

java 复制代码
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

java 复制代码
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

java 复制代码
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(略)

java 复制代码
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全流程

完整实例

java 复制代码
@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()

java 复制代码
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

java 复制代码
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)

java 复制代码
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

java 复制代码
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();
    }
}

示例

java 复制代码
@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执行呢?

java 复制代码
   @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部分前文没有过多解读,在这里我们分析下:

java 复制代码
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())中会被调用.

java 复制代码
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()
java 复制代码
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()
java 复制代码
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);
	}

}
相关推荐
九年义务漏网鲨鱼3 小时前
【Agentic RL 专题】二、Agentic RL——Memory
人工智能·大模型·强化学习·记忆模块
美狐美颜SDK开放平台3 小时前
直播美颜sdk特效功能架构全解析:从图像处理到AI渲染的技术演进
图像处理·人工智能·算法·架构·1024程序员节·美颜sdk·直播美颜sdk
Maruko3103 小时前
【无标题】
java
青衫码上行3 小时前
【Java Web学习 | 第三篇】CSS(2) - 元素显示模式
java·前端·学习
小王不爱笑1323 小时前
Maven 进阶与私服架构
java·架构·maven
重整旗鼓~3 小时前
32.图片上传功能
java·redis
菜鸡儿齐3 小时前
ThreadLocal介绍
java·开发语言
Mrliu__3 小时前
Opencv(五): 腐蚀和膨胀
人工智能·opencv·计算机视觉
IT_陈寒3 小时前
Redis性能翻倍的5个冷门技巧,90%的开发者都不知道第3个!
前端·人工智能·后端