AgentScope Java ReActAgent 核心循环深度解析

项目地址:https://github.com/agentscope-ai/agentscope-java

本文结合 agentscope-core 中 ReActAgent.java(4305 行)的源码,用伪代码 + 文字描述拆解 Agent Loop 的执行流程。每个方法附带简短功能说明,逻辑用自然语言阐述,方便快速理解全貌。


1. 架构概览:Core 与 Harness 的分层

HarnessAgent(生产壳层)

  • 13 个中间件(沙箱、记忆、压缩、子 Agent、Plan Mode...)
  • WorkspaceManager / DistributedStore
  • AbstractFilesystem + ShellExecuteTool
  • 通过 delegate 模式持有

ReActAgent(Core 引擎)

  • ReAct 迭代循环(reasoning ↔ acting ↔ iterate
  • 模型流式调用 / 工具执行 / 权限门控 / HITL
  • 状态管理 / 中断处理 / 事件流
  • 5 条中间件钩子点
    一句话总结:ReActAgent 提供 agent loop 抽象与所有底层原子能力,HarnessAgent 提供保障效果、稳定、分布式部署、长期运行的一站式解决方案。

ReActAgent 提供的原子能力

类别 能力
循环控制 ReAct 迭代、maxiters 守卫、summarizing 兜底
模型交互 流式调用 model.stream()、系统提示词组装、GenerateOptions 合并
工具执行 分发、并行 / 串行、错误容错(异常→error result)、suspend/resume
结构化输出 原生 response_format + fallback generate_response tool
权限 / HITL ALLOW/ASK/DENY 三态门控、暂停等待确认、恢复执行
状态管理 (userid, sessionid) 多 slot 隔离、AgentStateStore 持久化
中断处理 每个 session 协作式中断、优雅停机
事件流 28 种 AgentEvent 类型、块级事件发射
中间件链 5 条链:onAgent / onSystemPrompt / onReasoning / onActing / onModelCall

2. 完整循环流程图

复制代码
┌─────────────────────────────────────┐
│         doCallInner(msgs)           │
│     根据会话状态选择执行路径          │
└───────────────┬─────────────────────┘
                ↓
┌─────────────────────────────────────┐
│         reasoning(iter)             │
├─────────────────────────────────────┤
│ 1. iter >= maxIters? ───→ summarizing() 退出
│ 2. checkInterrupted()
│ 3. firePreReasoning hook
│ 4. 构建模型输入:
│    · prependSystemMsg()      ← 系统提示词前置
│    · getToolSchemas()        ← 收集工具定义
│ 5. onReasoning 中间件链
│    └─ model.stream()         ← 唯一LLM调用
│ 6. buildFinalMessage()       ← 累积chunk成消息
└───────────────┬─────────────────────┘
                ↓
┌─────────────────────────────────────┐
│    runPostReasoningPipeline()       │
│        决定下一步走向(四选一)         │
├─────────────────────────────────────┤
│ A. Hook请求停止 → return
│ B. gotoReasoning
│ C. isFinished → return          ← 无工具调用=完成
│ D. 有工具 → acting(iter)
└───────────────┬─────────────────────┘
                ↓
┌─────────────────────────────────────┐
│         acting(iter)                │
├─────────────────────────────────────┤
│ 1. extractPendingToolCalls()  ← 取出待执行工具
│ 2. evaluatePermissions()      ← ALLOW/ASK/DENY
│    · ASK → 暂停等待用户确认
│    · DENY → 写入拒绝结果
│ 3. onActing 中间件链
│    └─ toolkit.callTools()      ← 实际执行工具
│ 4. 分区结果:
│    · suspended → 挂起返回
│    · success → PostActing hook
└───────────────┬─────────────────────┘
                ↓
┌─────────────────────────────────────┐
│      iter < maxIters ?              │
├─────────────────────────────────────┤
│ YES → executeIteration(iter+1)      │
│        (回到 reasoning(iter+1))     │
│ NO  → summarizing()                 │
└─────────────────────────────────────┘

> HITL暂停 / 中间件Stop / ToolSuspend → 提前返回,不进入下一轮迭代

3. 入口路由:doCallInner()

复制代码
ReActAgent.java line 1408-1495

每次 call()的实际入口。不是直接进入循环,而是根据当前回话状态选择执行路径。

执行路径

复制代码
doCallInner(msgs)
# 停机去重: 上次被shutdown中断? → 丢弃重复输入
# Pending修复: 有孤立工具调用? → 自动生成error result
pendingIds = getPendingToolUseIds()

# 【A】pendingIds为空
└─ addToContext(msgs) → coreAgent()
        ↳ 正常新对话,从iter=0开始ReAct核心循环

# 【B】存在ASKING工具(需要用户确认才能继续)
└─ extractConfirmResults(msgs)
    ├─ 无确认结果 → throw 详细错误
    └─ 有确认结果 → applyConfirmResults()
            └─ resumeAgent()
                    ↳ 跳过推理,直接acting()

# 【C】有pending + 无新输入
└─ resumeAgent()
        ↳ 跳过推理,直接acting()

# 【D】有pending + 外部工具结果
└─ validateAndAddToolResults()
    ├─ 还有pending → resumeAgent()
    └─ 全部完成 → coreAgent()

# 【×】以上都不满足
└─ throw "不可恢复的错误状态"

伪代码

复制代码
doCallInner(msgs):
    // 如果上次 call 被 JVM shutdown 中断,丢弃重复的用户输入,从保存的上下文恢复
    if 上次被停机中断:
        msgs = []

    // 如果上次 call 崩溃留下了"已发出但没结果"的工具调用,自动生成 error result 修复
    if enablePendingToolRecovery:
        maybePatchPendingToolCalls(msgs)

    pendingIds = 获取当前所有有待处理的工具调用ID()

    // ====== 四路径分支 ======
    // 【A】没有待处理工具 → 正常新对话
    if pendingIds 为空:
        addToContext(msgs)        // 把用户消息追加到对话历史
        return coreAgent()         // 从 iter=0 开始 ReAct 循环

    // 【B】有待处理工具且处于 ASKING 状态 → HITL 人机协同恢复
    // 上次 Agent 在执行工具前暂停了(需要用户审批),这次必须携带确认结果
    if 存在 ASKING 状态的工具:
        confirmResults = 从消息metadata提取确认结果(msgs)
        if confirmResults 为空:
            throw "需要携带 ConfirmResult 才能恢复"
        applyConfirmResults(confirmResults)  // 将确认/拒绝应用到对应工具上
        return resumeAgent()                  // 跳过推理,直接执行工具

    // 【C】有待处理工具但没有新输入 → 直接执行
    if msgs 为空:
        return resumeAgent()

    // 【D】有待处理工具 + 用户提供了外部工具结果
    // 典型场景: 工具在 Agent 外部执行(如浏览器), 结果由调用方传入
    providedResults = msgs中提取ToolResultBlock
    if providedResults 不为空:
        validateAndAddToolResults(msgs, pendingIds)  // 校验并加入上下文
        return 还有pending ? resumeAgent() : coreAgent()

    // 以上都不满足 → 不可恢复
    throw "存在未完成的工具调用,请启用自动修复或提供工具结果"

涉及的方法

方法 功能
addToContext(msgs) 将消息列表追加到当前 session 的对话历史(state.contextMutable()
coreAgent() 新对话入口 → executeIteration()reasoning()
resumeAgent() 恢复入口 → acting(),跳过推理直接执行待处理工具
getPendingToolUseIds() 扫描上下文中最近的 assistant 消息,找出还没有对应结果的 ToolUseBlock ID
maybePatchPendingToolCalls(msgs) 为孤立的 pending 工具调用自动生成 error result,防止 session 卡死
askingToolCalls() 筛选出状态为 ASKING(等待用户确认)的工具调用列表
extractConfirmResults(msgs) 从消息 metadata 的 METADATA_CONFIRM_RESULTS 键中提取 ConfirmResult 列表
applyConfirmResults(results) 将用户的确认 / 拒绝决定写入对应的 ToolUseBlock,更新其状态为 ALLOWED 或 DENIED
validateAndAddToolResults(msgs, ids) 校验外部传入的工具结果与 pending IDs 匹配后,加入对话上下文

4. 推理阶段:reasoning()

复制代码
ReActAgent.java line 1835-1961

ReAct 循环中最核心的方法:调用 LLM,然后根据回复决定下一步。

执行路径

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                    reasoning(iter, ignoreMaxIters)                   │
├─────────────────────────────────────────────────────────────────────┤
│ ├─ iter >= maxIters? ────────────────────────────────▶ summarizing() │
│ │                                                      超限纯文本总结,不带工具
│ ├─ checkInterrupted()                                 ← session被中断? → 抛异常
│ ├─ firePreReasoning hook                               ← Hook可修改输入/选项
│ ├─ 构建模型输入:
│ │    ├─ buildGenerateOptions()      ← 合并生成配置
│ │    ├─ prependSystemMsg()          ← 系统提示词前置(不入context)
│ │    ├─ getToolSchemas()            ← 收集工具定义
│ │    └─ soTool? → 临时追加schema    ← 结构化输出专用工具
│ ├─ onReasoning 中间件链
│ │    └─ reasoningStream()
│ │         └─ onModelCall 中间件链
│ │             └─ modelCallStream()
│ │                 └─ model.stream() ← 唯一LLM调用点
│ │                     └─ 每个chunk → processChunk() + emitBlockEvents()
│ ├─ buildFinalMessage()               ← 累积chunk成完整消息
│ ├─ 中间件请求停止? ──────────────────▶ return msg(MIDDLEWARE_STOP_REQUESTED)
│ │                                     持久化到context,下次可恢复
│ └─ runPostReasoningPipeline(msg, iter)
│    ├─【出口1】Hook请求停止 ──────────▶ return msg(REASONING_STOP_REQUESTED)
│    ├─【出口2】gotoReasoning ─────────▶ reasoning(iter+1, ignoreMaxIters=true)
│    │           Hook请求重新推理(自我纠正)    不计入迭代上限
│    ├─【出口3】isFinished? ───────────▶ return msg
│    │           无ToolUseBlock = 任务完成     循环自然终止
│    └─【出口4】有工具调用 ─────────────▶ checkInterrupted() → acting(iter)
│                                          进入行动阶段执行工具
└─────────────────────────────────────────────────────────────────────┘

伪代码

复制代码
reasoning(iter, ignoreMaxIters):
    // ====== 超限检查 ======
    if not ignoreMaxIters and iter >= maxIters:
        return summarizing()  // 达到最大迭代次数,转入纯文本总结

    context = new ReasoningContext()  // 用于累积流式 chunk 的容器
    checkInterrupted()                // 检查当前 session 是否被中断
    event = firePreReasoning(...)     // Hook 可修改输入消息、系统提示词、生成选项

    // ====== 构建模型调用参数 ======
    options = event的选项 ?? buildGenerateOptions()  // 合并生成配置
    if 配置了结构化输出:
        options.merge(responseFormat())             // 注入 JSON Schema

    modelInput = prependSystemMsg(context.messages, systemMsg)  // 系统提示词前置(不入context)
    tools = toolkit.getToolSchemas(激活的工具组)                // 收集工具定义
    if 需要结构化输出:
        tools.add(generate_response工具的schema)               // 临时追加工具

    // ====== 通过中间件链执行推理 ======
    // onReasoning 中间件链包裹内层的 reasoningStream()
    stream = MiddlewareChain(onReasoning).apply(modelInput, tools, options)
    //    reasoningStream()
    //      ↳ onModelCall 中间件链包裹 modelCallStream()
    //          ↳ model.stream(messages, tools, options) ← 唯一的 LLM 调用点
    //              每个 chunk → context.processChunk() + emitBlockEvents()

    finalMsg = context.buildFinalMessage()  // 从流式 chunk 累积出完整消息

    if 中间件请求停止:
        state.context.add(finalMsg)         // 持久化到上下文(下次可恢复)
        return finalMsg(MIDDLEWARE_STOP_REQUESTED)

    // ====== 后处理管线 ======
    return runPostReasoningPipeline(finalMsg, iter)

runPostReasoningPipeline --- 四个出口

复制代码
runPostReasoningPipeline(msg, iter):
    event = firePostReasoning(msg)          // Hook 可修改推理结果
    state.context.add(event的消息)          // 推理消息加入对话历史

    // 【出口1】Hook 请求停止
    if event.isStopRequested():
        return msg(REASONING_STOP_REQUESTED)

    // 【出口2】Hook 请求重新推理(如自我纠正),ignoreMaxIters=true 不计入上限
    if event.isGotoReasoningRequested():
        state.context.addAll(event的附加消息)
        return reasoning(iter + 1, ignoreMaxIters=true)

    // 【出口3】LLM 回复中没有 ToolUseBlock → 任务完成
    if isFinished(msg):                     // 即 msg.getContentBlocks(ToolUseBlock).isEmpty()
        return msg

    // 【出口4】有工具调用 → 进入 Acting 阶段
    checkInterrupted()
    return acting(iter)

涉及的方法

方法 功能
checkInterrupted() 读取当前 session 的中断标志,若已中断则抛出 InterruptedException
buildGenerateOptions() 从 Builder 配置构建 LLM 生成参数(temperature、maxTokens、topP 等)
prependSystemMsg(msgs, sysMsg) 将系统提示词拼接到消息列表最前面(仅本次调用使用,不存入对话历史)
toolkit.getToolSchemas(groups) 根据激活的工具组,返回对应的 ToolSchema 列表供 LLM 使用
MiddlewareChain.build(...) 将所有中间件的某个子方法(如 onReasoning)串成一条洋葱模型执行链
reasoningStream(...) 用 onModelCall 中间件链包裹实际的模型调用
modelCallStream(...) 整个 ReActAgent 中唯一调用 LLM 的地方:model.stream() + chunk 累积 + 事件发射
context.processChunk(chunk) 将每个流式 chunk 累积到 ReasoningContext 中
context.buildFinalMessage() 将所有累积的 chunk 拼接成一条完整的 Msg
emitBlockEvents(chunk) 将 chunk 中的内容块转换为细粒度事件(TextDelta/ToolCallDelta 等)发射
isFinished(msg) 判断 LLM 回复中是否包含 ToolUseBlock,不包含则认为任务完成

5. 行动阶段:acting()

复制代码
ReActAgent.java line 2167-2248

执行 LLM 请求的工具调用,将结果反馈给下一轮推理。

执行路径

复制代码
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                                      acting(iter)                                    │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ ├─ extractPendingToolCalls()                          ← 取出待执行的ToolUseBlock
│ │    └─ 为空? ───────────────────────────────────────▶ executeIteration(iter+1)
│ │                                                       直接下一轮推理
│ ├─ firePreActing hook                                  ← Hook可修改工具调用列表
│ ├─ onActing 中间件链
│ │    └─ actingStream()
│ │         └─ evaluatePermissions()                      ← 权限门控
│ │             ├─ ALLOW → 加入待执行列表
│ │             ├─ ASK → emit RequireUserConfirmEvent
│ │             │           + RequestStopEvent → 暂停
│ │             └─ DENY → writeAutoDeniedResult()
│ │                         写入拒绝结果,不执行
│ │         └─ runToolBatch(approved)                    ← 批量执行已批准的工具
│ │             └─ toolkit.callTools()                    ← Toolkit层分发执行工具方法
│ │                 └─ 每个工具: ToolResultStart → deltas → ToolResultEnd
│ ├─ 中间件请求停止? ───────────────────────────────────▶ return buildStopMsg()
│ ├─ 分区结果:
│ │    ├─ successPairs (成功完成)
│ │    └─ pendingPairs (挂起等待)
│ ├─ 全部suspended? ───────────────────────────────────▶ return buildSuspendedMsg()
│ │                                                         等待外部完成后恢复
│ ├─ for each successPair:
│ │    └─ firePostActing hook
│ │         └─ Hook请求停止? ─────────────────────────▶ return msg(ACTING_STOP_REQUESTED)
│ ├─ 有pendingPairs? ───────────────────────────────────▶ return buildSuspendedMsg()
│ │                                                         部分挂起
│ └─ *所有工具执行完毕* ────────────────────────────────▶ executeIteration(iter+1)
│                                                           进入下一轮 Reasoning-Acting 迭代
└─────────────────────────────────────────────────────────────────────────────────────┘

伪代码

复制代码
acting(iter):
    pendingToolCalls = extractPendingToolCalls()  // 从上下文中取待执行的 ToolUseBlock
    if pendingToolCalls 为空:
        return executeIteration(iter + 1)          // 没有工具要执行,直接下一轮推理

    event = firePreActing(pendingToolCalls)         // Hook 可修改工具调用列表

    // ====== 通过中间件链执行工具 ======
    results = MiddlewareChain(onActing).apply(toolCalls)
    //    actingStream()
    //      ↳ evaluatePermissions()  // 权限门控
    //          ALLOW → 加入待执行列表
    //          ASK → 发射 RequireUserConfirmEvent + RequestStopEvent → 暂停
    //          DENY → writeAutoDeniedResult() 写入拒绝结果(不执行)
    //      ↳ runToolBatch(approved) // 批量执行已批准的工具
    //          ↳ toolkit.callTools() // 实际调用工具方法
    //              每个工具: ToolResultStart → deltas → ToolResultEnd

    if 中间件请求停止:
        return buildStopMsg(results, reason)

    // 分区处理结果
    successPairs = results.filter(not suspended)  // 成功完成的
    pendingPairs = results.filter(suspended)       // 挂起等待外部的

    if successPairs 为空 and pendingPairs 不为空:
        return buildSuspendedMsg(pendingPairs)     // 全部挂起,等待外部恢复

    for each (tool, result) in successPairs:
        event = firePostActing(tool, result)       // Hook 可检查/修改工具结果
        if event.isStopRequested():
            return msg(ACTING_STOP_REQUESTED)

    if pendingPairs 不为空:
        return buildSuspendedMsg(pendingPairs)     // 部分挂起

    // 所有工具执行完毕 → 进入下一轮 Reasoning-Acting 迭代
    return executeIteration(iter + 1)

涉及的方法

方法 功能
extractPendingToolCalls() 从最近一条 assistant 消息中提取还没有对应 ToolResultBlock 的 ToolUseBlock
evaluatePermissions(toolCalls) 对每个工具调用进行 ALLOW/ASK/DENY 三态权限判定
publishEvent(RequireUserConfirmEvent) 通知调用方哪些工具需要人工确认
writeAutoDeniedResult(id) 为被自动拒绝的工具写入 DENIED 状态的 ToolResultBlock
runToolBatch(toolCalls, replyId, holder) 批量执行工具并将结果写入 holder 引用
toolkit.callTools(toolCalls, config, agent, rc) Toolkit 层分发执行工具方法,支持并行 / 串行
buildSuspendedMsg(pairs) 构建包含挂起工具信息的消息,标记 GenerateReason.TOOL_SUSPENDED
buildStopMsg(results, reason) 构建中间件 Hook 请求停止的消息
notifyPostActingHook(pair) 触发 PostActing Hook,允许检查或修改工具执行结果
executeIteration(iter) 简单包装:return reasoning(iter, false)

6. 超限总结:summarizing()

复制代码
ReActAgent.java line 2838-2908

iter >= maxIters时触发,独立的LLM调用,不带任何工具,只生成纯文本总结

执行路径

复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                                 summarizing()                              │
│        当 iter >= maxIters 时触发。独立的 LLM 调用,不带任何工具,只生成纯文本总结。
├─────────────────────────────────────────────────────────────────────────────┤
│ ├─ hasPendingToolUse()?
│ │    └─ YES → for each pendingTool:
│ │           buildErrorToolResult("Tool cancelled: max iterations reached")
│ │           state.context.add(errorResult)      ← 为残余工具生成error结果
│ ├─ prepareSummaryMessages()                     ← 追加"max iterations reached"提示消息
│ ├─ publishEvent(ExceedMaxItersEvent)            ← 可观测性事件
│ ├─ firePreSummary hook                          ← Hook可修改总结输入
│ ├─ prependSystemMsg()                           ← 拼接系统提示词
│ ├─ summaryStream()                              ← 不带工具的LLM调用
│ │    └─ model.stream(msgs, NO_TOOLS, options)
│ │        └─ 每个chunk → processChunk()
│ ├─ buildFinalMessage()                          ← 累积chunk成完整总结消息
│ ├─ firePostSummary hook                         ← Hook可修改总结内容
│ ├─ finalMsg.generateReason = MAX_ITERATIONS      ← 标记终止原因
│ ├─ state.context.add(finalMsg)                  ← 持久化到对话历史
│ └─ return finalMsg                              ← 返回给调用方
└─────────────────────────────────────────────────────────────────────────────┘

伪代码

复制代码
summarizing():
    // 处理残余的 pending 工具:为它们生成 error result 加入上下文
    if hasPendingToolUse():
        for each pendingTool:
            errorResult = "Tool cancelled: max iterations reached"
            state.context.add(errorResult)

    // 准备总结专用的消息列表(含 "max iterations reached" 提示)
    messageList = prepareSummaryMessages()
    publishEvent(ExceedMaxItersEvent)  // 可观测性事件

    event = firePreSummary(messageList, ...)
    messages = prependSystemMsg(event的消息, event的系统提示词)

    // 调用 LLM 生成纯文本总结(不带工具 schema)
    summaryStream(context, messages, options)
    //   ↳ model.stream(messages, NO_TOOLS, options)
    //       每个 chunk → processChunk()

    finalMsg = context.buildFinalMessage()
    event = firePostSummary(finalMsg, ...)
    finalMsg.generateReason = MAX_ITERATIONS
    state.context.add(finalMsg)
    return finalMsg

涉及的方法

方法 功能
hasPendingToolUse() 检查上下文中是否存在还没有结果的工具调用
buildErrorToolResult(id, message) 构建一个错误类型的 ToolResultBlock
prepareSummaryMessages() 在对话历史末尾追加一条 "maximum iterations reached" 的用户消息
summaryStream(context, msgs, opts) 调用 LLM 生成总结(不带工具),累积 chunk 到 context
handleSummaryError(error) 总结阶段的错误兜底处理

7. 关键设计决策

# 设计 为什么这样做
1 系统提示词不入 context prependSystemMsg() 仅在每次模型调用前拼接。避免系统提示词被工具结果污染,节省 token
2 递归而非 while 循环 executeIteration(iter+1) 通过 Reactive flatMap 链式调用。兼容 Project Reactor 响应式模型,支持背压和取消
3 中间件包裹每个阶段 Harness 层无需修改 Core 代码即可注入沙箱、记忆压缩、追踪等横切关注点
4 gotoReasoning 忽略 maxIters Hook 可能需要额外推理轮次(如自我纠正),不应被 maxIters 截断
5 工具错误不抛异常 catch 所有异常 → errorToolResultBlock。让 LLM 看到错误信息并自行决定重试 / 切换策略
6 Pending Tool 自动修复 上次 call 崩溃后不至于整个 session 卡死,提升鲁棒性
7 HITL 有明确恢复协议 RequireUserConfirmEvent + ConfirmResult metadata。典型安全的确认 / 拒绝机制,不是粗糙的 "等待输入"
8 Suspend 与 HITL 分离 Suspend 是工具自身需要异步完成(如等待外部 API),HITL 是需要人审批。两者触发不同的 GenerateReason

8. 方法速查表

按执行顺序排列,覆盖 Agent Loop 全链路:

阶段 方法 一句话功能
入口 doCallInner(msgs) 根据会话状态路由到四条执行路径
入口 maybePatchPendingToolCalls(msgs) 为孤立的 pending 工具自动生成 error result
入口 getPendingToolUseIds() 获取所有还没有结果的工具 ID
入口 addToContext(msgs) 将消息追加到对话历史
入口 coreAgent() 新对话入口 → executeIteration()
入口 resumeAgent() 恢复入口 → acting(),跳过推理
入口 extractConfirmResults(msgs) 从 metadata 提取 HITL 确认结果
入口 applyConfirmResults(msgs) 将确认 / 拒绝写入 ToolUseBlock 状态
入口 validateAndAddToolResults(msgs, ids) 校验外部工具结果并加入上下文
推理 reasoning(iter, ignoreMaxIters) 调用 LLM 并根据回复决定下一步
推理 checkInterrupted() 检查 session 中断标志
推理 buildGenerateOptions() 构建 LLM 生成参数
推理 prependSystemMsg(msg, sysMsg) 系统提示词前置(不入 context)
推理 toolkit.getToolSchemas(groups) 收集激活工具的 schema
推理 MiddlewareChain.build(...) 将中间件串成洋葱模型执行链
推理 reasoningStream(...) onModelCall 中间件包裹模型调用
推理 modelCallStream(...) 唯一 LLM 调用点:model.stream()
推理 context.processChunk(chunk) 累积流式 chunk
推理 context.buildFinalMessage() chunk 拼接成完整 Msg
推理 emitBlockEvents(chunk) 发射 TextDelta/ToolCallDelta 等细粒度事件
后处理 runPostReasoningPipeline(msg, iter) 四出口决策:停止 / 重推理 / 完成 / 进入 Acting
后处理 isFinished(msg) 无 ToolUseBlock = 任务完成
行动 acting(iter) 执行工具并将结果反馈给下一轮推理
行动 extractPendingToolCalls() 提取待执行的 ToolUseBlock
行动 evaluatePermissions(toolCalls) ALLOW/ASK/DENY 三态权限判定
行动 runToolBatch(toolCalls, ...) 批量执行已批准的工具
行动 toolkit.callTools(...) Toolkit 层分发执行工具方法
行动 buildSuspendedMsg(pairs) 构建工具挂起消息
超限 summarizing() 达到最大迭代次数时生成纯文本总结

9. 源码索引

文件 关键内容
core/.../ReActAgent.java 完整 Agent Loop(4305 行),内部类 CallExecution 包含所有循环逻辑
core/.../AgentBase.java 调用生命周期模板、Hook 管理、中断、tracing
core/.../middleware/MiddlewareBase.java 中间件接口:onAgent/onReasoning/onActing/onModelCall/onSystemPrompt
core/.../middleware/MiddlewareChain.java 中间件构造器,将多个中间件串成一条执行链
core/.../model/Model.java LLM 接口:stream(messages, tools, options) → Flux
core/.../tool/Toolkit.java 工具注册、schema 生成、callTools() 分发执行
core/.../permission/PermissionEngine.java ALLOW/ASK/DENY 三态权限判定
core/.../state/AgentState.java 会话状态:context(消息列表)、summary、permissionContext、toolContext
core/.../state/AgentStateStore.java 状态持久化接口:save/get/delete,按 (userid, sessionid) 键寻址
core/.../agent/RuntimeContext.java 每次调用的运行时上下文:userid, sessionid, attributes
相关推荐
952361 小时前
RabbitMQ - 高级特性
java·spring boot·分布式·后端·rabbitmq
SNKXD_11 小时前
2026年五款AI数字人系统效果差异:基于多维度横评的实证比较
大数据·人工智能
Lucky_5566881 小时前
山东捷瑞检测科技有限公司:政务信息化项目监理要点与收费标准解析
大数据·人工智能
2zcode1 小时前
低采样率ISAR成像的稀疏重建方法及其实时实现
图像处理·人工智能·计算机视觉
2501_930296991 小时前
驾驭大模型的对话艺术:深度拆解 OpenAI 官方 Prompt 指南与全场景实战心法
人工智能·prompt
weilaieqi11 小时前
行业前列!CASAMANIA HORM富森美高端意式沙发标杆
开发语言
DS随心转小程序1 小时前
deepseek 生成 word 文档指令搭配 AI 导出鸭高效完成各类文档批量输出
人工智能·word·豆包·deepseek·ai导出鸭
小墨同学boy1 小时前
WorkBuddy零基础教程进阶篇
人工智能·github·aigc
尽兴-2 小时前
传统 Java/Vue 系统如何一步步接入 AI 维护
java·vue.js·人工智能·ai·大模型