为什么这很重要:当工具可以访问 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

AI项目博客






