AI项目博客
记录 AI 工程实践与大模型应用

Spring AI Alibaba 14|Tools 工具 · 访问上下文

为什么这很重要:当工具可以访问 Agent 状态、运行时上下文和长期记忆时,它们最强大。这使工具能够做出上下文感知的决策、个性化响应并在对话中维护信息。

工具可以通过 ToolContext 参数访问运行时信息,该参数提供:

  • State(状态) – 通过执行流动的可变数据(消息、计数器、自定义字段)
  • Context(上下文) – 不可变配置,如用户 ID、会话详细信息或应用程序特定配置
  • Store(存储) – 跨对话的持久长期记忆
  • Config(配置) – 执行的 RunnableConfig
  • Tool Call ID – 当前工具调用的 ID

ToolContext

使用 ToolContext 在单个参数中访问所有运行时信息。只需将 ToolContext 添加到你的工具签名中,它将自动注入而不会暴露给 LLM。

访问状态:

工具可以使用 ToolContext 访问当前的 Graph 状态:

import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.ai.chat.messages.Message;
import java.util.function.BiFunction;
import java.util.List;
import java.util.Map;

// 访问当前对话状态
public class ConversationSummaryTool implements BiFunction<String, ToolContext, String> {

  @Override
  public String apply(String input, ToolContext toolContext) {
      OverAllState state = (OverAllState) toolContext.getContext().get("state");
      RunnableConfig config = (RunnableConfig) toolContext.getContext().get("config");
      // update to extraState will be returned to the Agent loop.
      Map<String, Object> extraState = (Map<String, Object>) toolContext.getContext().get("extraState");

      // 从 state 中获取消息
      List<Message> messages = (List<Message>) state.get("messages", new ArrayList<>());

      if (messages == null) {
          return "No conversation history available";
      }

      long userMsgs = messages.stream()
          .filter(m -> m.getMessageType().getValue().equals("user"))
          .count();
      long aiMsgs = messages.stream()
          .filter(m -> m.getMessageType().getValue().equals("assistant"))
          .count();
      long toolMsgs = messages.stream()
          .filter(m -> m.getMessageType().getValue().equals("tool"))
          .count();

      return String.format(
          "Conversation has %d user messages, %d AI responses, and %d tool results",
          userMsgs, aiMsgs, toolMsgs
      );
  }
}

// 创建工具
ToolCallback summaryTool = FunctionToolCallback
  .builder("summarize_conversation", new ConversationSummaryTool())
  .description("Summarize the conversation so far")
  .inputType(String.class)
  .build();

警告:toolContext 参数对模型是隐藏的。对于上面的示例,模型只看到 input 在工具模式中 – toolContext 不包含在请求中。

更新状态:

在 Spring AI Alibaba 中,你可以通过 Hook 或在工具执行后返回的信息来更新 Agent 的状态。

// 在 Hook 中更新状态
import com.alibaba.cloud.ai.graph.agent.hook.ModelHook;
import com.alibaba.cloud.ai.graph.agent.hook.HookPosition;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import java.util.concurrent.CompletableFuture;

public class UpdateStateHook extends ModelHook {

  @Override
  public String getName() {
      return "update_state";
  }

  @Override
  public HookPosition[] getHookPositions() {
      return new HookPosition[]{HookPosition.AFTER_MODEL};
  }

  @Override
  public CompletableFuture<Map<String, Object>> afterModel(OverAllState state, RunnableConfig config) {
      // 更新状态
      return CompletableFuture.completedFuture(Map.of(
          "user_name", "Alice",
          "last_updated", System.currentTimeMillis()
      ));
  }
}

Context(上下文)

通过 ToolContext 访问不可变配置和上下文数据,如用户 ID、会话详细信息或应用程序特定配置。

import org.springframework.ai.chat.model.ToolContext;
import java.util.function.BiFunction;
import java.util.Map;

public class AccountInfoTool implements BiFunction<String, ToolContext, String> {

  private static final Map<String, Map<String, Object>> USER_DATABASE = Map.of(
      "user123", Map.of(
          "name", "Alice Johnson",
          "account_type", "Premium",
          "balance", 5000,
          "email", "alice@example.com"
      ),
      "user456", Map.of(
          "name", "Bob Smith",
          "account_type", "Standard",
          "balance", 1200,
          "email", "bob@example.com"
      )
  );

  @Override
  public String apply(String query, ToolContext toolContext) {
  	// 在 agent 调用时设置 user_id,在工具中可以拿到参数
  	// RunnableConfig config = RunnableConfig.builder().addMetadata("user_id", "1");
  	// agent.call("", config);
              RunnableConfig config = (RunnableConfig) toolContext.getContext().get("config");
              String userId = (String) config.metadata("user_id").orElse(null);

      if (userId == null) {
          return "User ID not provided";
      }

      Map<String, Object> user = USER_DATABASE.get(userId);
      if (user != null) {
          return String.format(
              "Account holder: %s
Type: %s
Balance: $%d",
              user.get("name"),
              user.get("account_type"),
              user.get("balance")
          );
      }

      return "User not found";
  }
}

ToolCallback accountTool = FunctionToolCallback
  .builder("get_account_info", new AccountInfoTool())
  .description("Get the current user's account information")
  .inputType(String.class)
  .build();

// 在 ReactAgent 中使用
ReactAgent agent = ReactAgent.builder()
  .name("financial_assistant")
  .model(chatModel)
  .tools(accountTool)
  .systemPrompt("You are a financial assistant.")
  .build();

// 调用时传递上下文
// 注意:需要通过适当的方式传递上下文数据
RunnableConfig config = RunnableConfig.builder().addMetadata("user_id", "1");
agent.call("question", config);

Memory(存储)

使用存储访问跨对话的持久数据。在 Spring AI Alibaba 中,你可以使用 checkpointer 来实现长期记忆。

import com.alibaba.cloud.ai.graph.checkpoint.savers.RedisSaver;

// 配置持久化存储
RedisSaver redisSaver = new RedisSaver(redissonClient);

// 创建带有持久化记忆的 Agent
ReactAgent agent = ReactAgent.builder()
  .name("my_agent")
  .model(chatModel)
  .tools(saveUserInfoTool, getUserInfoTool)
  .saver(redisSaver)
  .build();

// 第一个会话:保存用户信息
RunnableConfig config1 = RunnableConfig.builder()
  .threadId("session_1")
  .build();

agent.call("Save user: userid: abc123, name: Foo, age: 25, email: foo@example.com", config1);

// 第二个会话:获取用户信息
RunnableConfig config2 = RunnableConfig.builder()
  .threadId("session_2")
  .build();

agent.call("Get user info for user with id 'abc123'", config2);
// 输出:Here is the user info for user with ID "abc123":
// - Name: Foo
// - Age: 25
// - Email: foo@example.com

ReactAgent 提供了多种方式来提供和使用工具。根据你的使用场景,可以选择最适合的方式。

本文整理自 Spring AI Alibaba 官方文档《Tools 工具》:https://java2ai.com/docs/frameworks/agent-framework/tutorials/tools

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 14|Tools 工具 · 访问上下文

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册