视频版:space.bilibili.com/2012289471 源码:github.com/yinqqm/spri…

基础调用

通过call方法实现基础调用,返回的是AssistantMessage,也就是模型输出的消息。就是普通的调用和接收响应信息。

获取完整状态

基本使用:

public void test8() throws GraphRunnerException {
        // ★ 关键:通过 Map 传入自定义状态(messages/input 之外的都是自定义状态)
        Map<String, Object> inputs = new HashMap<>();
        inputs.put("input", "帮我写一首诗");           // 预留关键字:用户输入
        inputs.put("messages", Messageutils.convertToMessages("帮我写一首诗"));
        inputs.put("custom_key", "这是我在test8中设置的值");   // ★ 自定义状态
        inputs.put("user_role", "admin");              // ★ 自定义状态
        inputs.put("session_id", "sess_001");          // ★ 自定义状态
        inputs.put("request_count", 0);                // ★ 自定义状态

        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();
        ReactAgent getAllState = ReactAgent.builder()
                .model(chatModel)
                .name("get_all_state")
               // .instruction("你是一个助手,请根据用户输入完成任务。")
                .build();
        Optional<OverAllState> result =  getAllState.invoke(inputs);
        if (result.isPresent()) {
            OverAllState overAllState = result.get();
            Optional<Object> messages = overAllState.value("messages");
            // 访问自定义状态
            Optional<Object> customData = overAllState.value("custom_key");
            if (customData.isPresent()) {
                System.out.println("获取设置的custom_key:" + customData);
            }
            System.out.println("完整状态:" + overAllState);
        }
    }

它的作用:

OverAllState 作为基于图的流水线处理管道中跨节点共享数据的中央容器。 它支持键值对数据存储,并为每个 key 配置自定义更新策略(KeyStrategy), 允许灵活的合并或替换逻辑。此类是可序列化的,适用于持久化、检查点或跨节点通信。

⚠️ 警告: 这个类不是线程安全的,在并发场景需要同步。

核心字段:

public final class OverAllState implements Serializable {

    /** ★ 核心数据存储:所有状态值的实际存放位置 */
    private final Map<String, Object> data;

    /** ★ 键策略映射:每个 key 对应一个更新策略 */
    private final Map<String, KeyStrategy> keyStrategies;

    /** ★ 长期记忆存储:用于跨执行周期的持久化 */
    private Store store;

    /** ★ 默认输入键名 */
    public static final String DEFAULT_INPUT_KEY = "input";

    /** ★ 删除标记常量 */
    public static final Object MARK_FOR_REMOVAL = new Object();
}

实际使用讲解:

实际使用场景:智能客服 + 用户画像注入

场景描述

假设你有一个智能客服 Agent,需要:

  1. 传入用户基本信息(VIP等级、偏好语言等)
  2. 传入当前订单号(用于工具查询)
  3. 在工具中读取这些自定义状态
  4. 最终从 OverAllState 中验证所有状态

最终回复:

🤖 Agent 最终回复:
尊敬的VIP客户张三您好!

关于您的订单 ORD-20260525-8899 的查询结果如下:
📦 订单状态:已发货
🚚 物流公司:顺丰速运 SF1234567890  
📅 预计送达:2026-05-27

商品明细:
- MacBook Pro 16寸 x 1台 = ¥19,999

使用配置

基本使用:

它是每次agent调用call方法执行时传入的。表示它是在agent真正执行的时候给定的参数。

AssistantMessage response = agent.call("你的问题", runnableConfig);

通过 RunnableConfig 来实现的,它的主要作用是:

会话记忆, 为不同的用户区分上下文,通过threadId来实现的。

 /**
     * 使用配置,测试threadId实现不同用户之间使用不同的上下文信息
     */
    @Test
    public void test9() throws GraphRunnerException {
        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();
        ReactAgent agent = ReactAgent.builder()
                .name("runnable_config")
                .model(chatModel)
                .saver(new MemorySaver())
                .build();
        //通过RunnableConfig 传递运行时配置
        String threadId123 = "thread_123";
        String threadId456 = "thread_456";
        RunnableConfig runnableConfig123 = RunnableConfig.builder()
                .threadId(threadId123)
                .build();
        RunnableConfig runnableConfig456 = RunnableConfig.builder()
                .threadId(threadId456)
                .build();
        agent.call("我叫123",runnableConfig123);
        agent.call("我叫456",runnableConfig456);


        AssistantMessage response123 = agent.call("我叫什么?",runnableConfig123);
        System.out.println("runnableConfig123:"+response123.getText());
        AssistantMessage response456 = agent.call("我叫什么?",runnableConfig456);
        System.out.println("runnableConfig456:"+response456.getText());

    }

存放不可变数据

通过metadata 来是实现。它是在运行期是不可变的。可以为Interceptor和tool提供参数。

在interceptor中获取:

    public void test10() throws GraphRunnerException {

        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();
        ReactAgent agent = ReactAgent.builder()
                .name("model_interceptor_agent")
                .model(chatModel)
                .interceptors(new DynamicPromptInterceptor()).build();
        //通过runnableConfig指定配置信息
        RunnableConfig runnableConfig = RunnableConfig.builder().addMetadata("user_role", "expert").build();
        AssistantMessage assistantMessage = agent.call("介绍一下Spring boot的自动注入原理。", runnableConfig);
        System.out.println(assistantMessage.getText());
    }
public class DynamicPromptInterceptor extends ModelInterceptor {
    @Override
    public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
        // 基于上下文构建动态 system prompt
        String userRole = (String) request.getContext().getOrDefault("user_role", "default");
        String dynamicPrompt = switch (userRole) {
            case "expert" -> """
                    你正在与技术专家对话。
                    - 使用专业术语
                    - 深入技术细节""";
            case "beginner" -> """
                    你正在与初学者对话。
                    - 使用简单语言
                    - 解释基础概念""";
            default -> "你是一个专业的助手,保持友好和专业。";
        };

        SystemMessage enhancedSystemMessage;
        if (request.getSystemMessage() == null) {
            enhancedSystemMessage = new SystemMessage(dynamicPrompt);
        } else {
            enhancedSystemMessage = new SystemMessage(request.getSystemMessage().getText() + dynamicPrompt);
        }

        ModelRequest modified = ModelRequest.builder(request)
                .systemMessage(enhancedSystemMessage)
                .build();
        return handler.call(modified);
    }

在Tool中获取

public void test11() throws GraphRunnerException {

        //创建tool 类
        ToolCallback searchTool = FunctionToolCallback.
                builder("search", new SearchTool()).description("通过给定的参数查询线上新闻并返回结果") //定义工具描述,提供给模型的使用指南
                .inputType(SearchToolInput.class).build();

        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();
        ReactAgent metaDataTool = ReactAgent.builder()
                .name("meta_data_tool")
                .model(chatModel)
                .tools(searchTool)
                .build();

        //创建RunnableConfig
        RunnableConfig runnableConfig = RunnableConfig.builder()
                .addMetadata("call_tool", "yes")
                .build();

        AssistantMessage assistantMessage = metaDataTool.call("今天发生了什么新闻", runnableConfig);

        System.out.println(assistantMessage.getText());

    }

SearchTool的定义

public class SearchTool implements BiFunction<SearchToolInput, ToolContext, String> {
    @Override
    public String apply(SearchToolInput query, ToolContext toolContext) {
        String callTool = (String) toolContext.getContext().getOrDefault("call_tool", "N");
        System.out.println("get data from mateData:"+callTool);


        //mock 搜索web
        return """
                    习近平就推动哲学社会科学高质量发展作出重要指示
                    习近平同美国总统特朗普在中南海小范围会晤
                    【微镜头·中美元首在北京举行会谈】“让2026年成为中美关系继往开来的历史性、标志性年份”
                    武汉票价最贵火车发车:20999元起
                    """;
    }
}

总结

OverAllStateRunnableConfig
定义全局状态,业务数据运行时配置,系统的环境配置信息
包含的数据input:用户的提问message:模型响应的结果其他自定义的key:用户自定义保存的信息threadId:区分会话metadata:在运行时不可变,可以用来配置系统变量和环境参数等。
获取和使用在Hooks中获取,后面会讲解Hooks的使用。在interceptor中,通过ModelRequest.getContext().get()或getOrDefault()获取。在Tool中,通过ToolContext.getContext().get()或getOrDefault()获取。
可变性可以变的,每个节点都可以读取它,并且它的key有对应的update strategy 更新策略。通常只读,不可变。