12_Agent的Hook补充+控制Agent+流式输出+总结

视频版:space.bilibili.com/2012289471

源码:github.com/yinqqm/spri...

控制Agent

通过Hooks来控制Agent的迭代,防止无限循环导致过度成本。

java 复制代码
 @Test
    public void test19() throws GraphRunnerException {
        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();
        ToolCallback chunkTool = FunctionToolCallback.builder("chunkTool", new ChunkTool())
                .description("根据索引返回一段内容,方便agent 通过多轮 tool 调用逐步获得所有内容")
                .inputType(SearchToolInput.class)
                .build();
        ModelLoggingHook modelLoggingHook = new ModelLoggingHook();
        ReactAgent modelHook = ReactAgent.builder()
                .name("model_hook")
                .model(chatModel)
                .tools(chunkTool)
                //配置一次agent call最多只能调用7次LLM
                .hooks(ModelCallLimitHook.builder().runLimit(7).build(),modelLoggingHook)
                .build();
        AssistantMessage message = modelHook.call("""
                请严格按照顺序完成:
                1.依次调用chunkTool的apply方法,从SearchToolInput的query属性的值从0到7.
                2.每次只处理一段,不要跳步.
                3.最后用中文总结所有内容.
                """);
        System.out.println(message.getText());

    }

流式输出

前面有简单介绍了一下流式输出,这里再详细介绍一下。

流式输出的调用方式,通过reactAgent.stream()方法来调用实现。返回的结果是Flux类,该类是Reactor库的核心类,可以用来发射0到N个元素,非阻塞,支持AI有数据返回就能输出结果,无需等待AI全部返回数据。

这里通过subscribe方法来处理数据,它的定义如下:

java 复制代码
	public final Disposable subscribe(
			@Nullable Consumer<? super T> consumer,
			@Nullable Consumer<? super Throwable> errorConsumer,
			@Nullable Runnable completeConsumer) {
		return subscribe(consumer, errorConsumer, completeConsumer, (Context) null);
	}

第一个参数consumer表示正常消费数据执行的方法。

第二个参数errorConsumer表示获取数据错误时执行的方法。

第三个参数completeConsumer,通过方法名也能看出这是完成时执行的方法。

所以我们的注意力主要集中在一个方法的实现上。

先看第一个例子:

这个例子测试了下面的outputType

OutputType 说明
AGENT_MODEL_STREAMING 模型推理的流式增量内容
AGENT_MODEL_FINISHED 模型推理完成,可获取全量内容
AGENT_TOOL_STREAMING 工具调用的流式增量内容
AGENT_TOOL_FINISHED 工具调用完成
AGENT_HOOK_STREAMING Hook 节点的流式增量内容
AGENT_HOOK_FINISHED Hook 节点完成
java 复制代码
public void test20() throws GraphRunnerException, InterruptedException {
        //创建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)
                .hooks(new LoggingHook())
                .build();


        Flux<NodeOutput> stream = metaDataTool.stream("今天发生了什么新闻");

        CountDownLatch countDownLatch = new CountDownLatch(1);

        stream.subscribe(
                output -> {
                    // 检查是否为 StreamingOutput 类型
                    if (output instanceof StreamingOutput streamingOutput) {
                        OutputType type = streamingOutput.getOutputType();

                        // 处理模型推理的流式输出
                        if (type == OutputType.AGENT_MODEL_STREAMING) {
                            // 流式增量内容,逐步显示
                            System.out.print("<<<<<流式增量内容,逐步显示:>>>>" + streamingOutput.message().getText());
                        } else if (type == OutputType.AGENT_MODEL_FINISHED) {
                            // 模型推理完成,可获取完整响应
                            System.out.println("\n模型输出完成");
                        }

                        if (type == OutputType.AGENT_TOOL_STREAMING) {
                            System.out.println("<<<Tool增量内容>>> " + streamingOutput.message().getText());
                        }

                        // 处理工具调用完成(目前不支持 STREAMING)
                        if (type == OutputType.AGENT_TOOL_FINISHED) {
                            System.out.println("工具调用完成: " + output.node());
                        }
                        if (type == OutputType.AGENT_HOOK_STREAMING) {
                            System.out.println("<<<<Hook增量内容>>>> " + streamingOutput.message().getText());
                        }
                        // 对于 Hook 节点,通常只关注完成事件(如果Hook没有有效输出可以忽略)
                        if (type == OutputType.AGENT_HOOK_FINISHED) {
                            System.out.println("Hook 执行完成: " + output.node());
                        }
                    }
                },
                error -> {
                    System.err.println("错误: " + error);
                },
                () -> {
                    countDownLatch.countDown();
                }
        );
        countDownLatch.await();
    }

第二个例子

通过创建OpenAI的Model,这里使用的是DeepSeek的deepseek-v4-flash 模型,主要是测试Thinking的message。

java 复制代码
public void test21() throws GraphRunnerException, InterruptedException {

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

        ChatModel openAIModel = CreateChatClient.createOpenAIModel();
        ReactAgent thinkingAgent = ReactAgent.builder()
                .model(openAIModel)
                .name("thinking_agent")
                .tools(searchTool)
                .build();

        Flux<NodeOutput> stream = thinkingAgent.stream("今天发生了什么新闻");

        CountDownLatch countDownLatch = new CountDownLatch(1);
        stream.subscribe(output -> {
                    if (output instanceof StreamingOutput streamingOutput) {
                        OutputType type = streamingOutput.getOutputType();
                        Message message = streamingOutput.message();

                        // 处理模型流式输出
                        if (type == OutputType.AGENT_MODEL_STREAMING) {
                            if (message instanceof AssistantMessage assistantMessage) {
                                // 检查是否为 Thinking 消息
                                Object reasoningContent = assistantMessage.getMetadata().get("reasoningContent");
                                if (reasoningContent != null && !reasoningContent.toString().isEmpty()) {
                                    System.out.print("[Thinking] " + reasoningContent);
                                } else {
                                    // 普通模型响应(增量内容)
                                    System.out.print(assistantMessage.getText());
                                }
                            }
                        }
                        // 处理模型输出完成
                        else if (type == OutputType.AGENT_MODEL_FINISHED) {
                            if (message instanceof AssistantMessage assistantMessage) {
                                if (assistantMessage.hasToolCalls()) {
                                    // 工具调用请求
                                    assistantMessage.getToolCalls().forEach(toolCall -> {
                                        System.out.println("[Tool Call] " + toolCall.name() + ": " + toolCall.arguments());
                                    });
                                } else {
                                    // 模型完整响应
                                    System.out.println("\n[Model Finished]");
                                }
                            }
                        }
                        // 处理工具执行结果
                        else if (type == OutputType.AGENT_TOOL_FINISHED) {
                            if (message instanceof ToolResponseMessage toolResponse) {
                                toolResponse.getResponses().forEach(response -> {
                                    System.out.println("[Tool Result] " + response.name() + ": " + response.responseData());
                                });
                            }
                        }
                    }
                },
                error -> {
                    System.err.println("错误: " + error);
                }, () -> {
                    countDownLatch.countDown();
                });
        countDownLatch.await();
    }

总结

ReactAgent的定义,React(Reasoning+Acting)是结合了推理和行动的Agent的。它的功能:

1.Reasoning(思考):分析问题,决定下一步做什么。

2.Acting(行动):调用工具或生成最终的回答。

3.Observation(观察):接收工具执行的结果。

4.Iteration(迭代):基于观察结果继续思考和行动,直到完成任务。

基于上面的能力,Agent就能将复杂问题分解为多个步骤,基于中间结果动态调整策略,可以借助外部工具实现模型本身局限的功能。

Graphs的介绍: Agent 的执行路径由模型实时决策,具有动态分支和循环能力,因此需要 Graph 来描述和管理这种非固定执行流程。基于上面的知识点我们知道模型的流程是不固定的,无法使用固定流程来控制。Graph就是来解决这个问题的。注意:Agent是不能生成新的节点,这是描述Graphs容易犯的错误,它是流程是灵活的非固定的。

它是由三部分构成:

Edge(边):Node之间的流转关系,通过边来表示。有固定边和还有条件边(这是Agent的核心能力),这里是通过LLM驱动的条件边。 条件边允许根据State内容动态决定下一步执行路径,是实现Agent自主决策能力的重要机制。

Node(节点):执行单元,调用模型、Tools、Memory 查询、End节点、人工干预节点。

State(状态):共享的数据源,所有节点必须通过State交互,可以认为是OverAllState 类,通过state驱动模型走哪一条边。

Model:介绍了模型的参数配置,可以控制模型生成数据的效果。

Tools工具:定义工具的一种方式,Agent配置Tool。

Interceptor 拦截器:ModelInterceptor拦截器和 ToolInterceptor

SystemPromt 系统提示词:定义模型行为特性,有SystemPromt一般的指令和instruction更加详细的指令。

Agent的调用:基础调用call,通过invoke 调用可以获取完整状态OverAllState,它是节点间传递消息的存储介质,每个key都有自定义的更新策略。

RunnableConfig: 传递运行时的配置,可以使用threadId:区分会话。通过mate来配置系统变量和环境参数。

结构化输出: Output和OutputSchema,Output是固定的,OutputSchema更加灵活。

Memory:用来持久化上下文,默认内存。

Hook:ModelHook和AgentHook,通过Hook可以控制模型,提前结束,总结Message、日志记录等。

流式输出:可以监控模型的整个流程。

相关推荐
触底反弹1 小时前
5 个 Step,让你的前端代码连上 AI 大模型
javascript·人工智能·面试
深圳市机智人激光雷达1 小时前
激光雷达:智慧港口自动化升级的核心感知基石
运维·人工智能·机器人·自动化·自动驾驶·无人机·激光雷达
哈哈,柳暗花明1 小时前
人工智能专业术语详解(F)
人工智能·专业术语
PKUMOD1 小时前
SIGMOD2026 | NeuSO:面向子图查询的学习型优化器
人工智能
linge_sun1 小时前
SpringAI 功能体验之SQL智能助手:用自然语言查询数据库
java·人工智能·ai编程
Hotchip_MEMS2 小时前
旧路由器拆出“功臣芯片”:AMS1117在高温下工作8年,只消耗2mA静态电流
网络·人工智能·物联网·智能路由器
Alluxio2 小时前
造父智能(哈啰robotaxi)在阿里云环境下构建极致透明的训练加速层
人工智能·机器学习·缓存·系统架构·自动驾驶·模型训练
金融Tech趋势派2 小时前
2026企业微信SCRM与服务商测评:私域获客、会话存档、AI能力全维度评估
人工智能·dubbo·企业微信
qq_411262422 小时前
esp32-s3的编译链和环境
人工智能