Agent常用架构

随着ai学习的深入,慢慢接触到了常用架构,这篇文章用流程图的方式,简单介绍一下agent的四种常用架构。

目录

RactAgent

针对用户的提问,LLM会先进行思考(Thought),指定行动计划,行动计划中包括使用哪些工具,接着进行工具执行(Action),在工具执行之后,观察(Observation)工具执行的结果,基于结果继续思考后续的行动计划。如果需要执行工具就继续执行,直到LLM认为所有行动都做完了为止。

graph TD
    classDef startEnd fill:#F3F4F6,stroke:#4B5563,stroke-width:2px,rx:10,ry:10,color:#1F2937,font-weight:bold;
    classDef process fill:#DBEAFE,stroke:#3B82F6,stroke-width:2px,rx:5,ry:5,color:#1E3A8A;
    classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:2px,rx:5,ry:5,color:#92400E;
    classDef llm fill:#D1FAE5,stroke:#10B981,stroke-width:2px,rx:5,ry:5,color:#065F46;
    classDef tool fill:#FCE7F3,stroke:#EC4899,stroke-width:2px,rx:5,ry:5,color:#9D174D;
    classDef memory fill:#E0E7FF,stroke:#6366F1,stroke-width:2px,rx:5,ry:5,color:#3730A3;

    Start(["开始调用 call 或 stream"]):::startEnd
    EndLoop(["结束任务, 返回最终答案"]):::startEnd

    subgraph Phase1 ["🚀 阶段一:上下文初始化"]
        InitContext["加载系统和自定义 Prompt"]:::process
        LoadMem["加载历史会话记忆"]:::memory
        AddUser["追加 User 问题"]:::process
        SaveUserMem["将 User 问题存入记忆"]:::memory
        
        Start --> InitContext --> LoadMem --> AddUser --> SaveUserMem
    end

    subgraph Phase2 ["🔄 阶段二:ReAct 核心推理循环"]
        LoopStart(("进入新轮次 (Round)")):::process
        SaveUserMem --> LoopStart
        
        CheckMaxRounds{"当前轮次 > maxRounds?"}:::decision
        LoopStart --> CheckMaxRounds

        CallLLM["调用大模型进行<br/> Reasoning (推理)"]:::llm
        CheckMaxRounds -- 否 --> CallLLM

        HasToolCall{"响应中包含 Action<br/>(ToolCall) 吗?"}:::decision
        CallLLM --> HasToolCall
    end

    subgraph Phase3 ["🛑 触发最大轮次限制"]
        ForceFinalPrompt["追加强制回答 Prompt<br/>(禁工具)"]:::process
        CallLLMForce["调用 LLM 获取最终总结"]:::llm
        
        CheckMaxRounds -- 是 --> ForceFinalPrompt --> CallLLMForce
    end

    subgraph Phase4 ["🛠️ 阶段三:Action与Observation (工具调用)"]
        AddToolCallMsg["Action: 记录模型要调用的工具"]:::process
        ExecuteTools["执行回调工具<br/>并处理逻辑"]:::tool
        AddToolResult["Observation: 将工具结果封装<br/>为 Message 并回传"]:::tool

        HasToolCall -- 是 --> AddToolCallMsg --> ExecuteTools --> AddToolResult
        AddToolResult -. 返回下一轮次进行评估 .-> LoopStart
    end

    subgraph Phase5 ["🏁 阶段四:任务完成与输出"]
        SaveFinalMem["将最终答案存入会话记忆"]:::memory
        
        HasToolCall -- "否 (判定上下文已充分<br/>直接解答)" --> SaveFinalMem
        CallLLMForce --> SaveFinalMem
    end

    SaveFinalMem --> EndLoop

alt text

ReflectionAgent

它是一种让模型自我批判、自我修正的策略。其核心思想是:让大语言模型(LLM)在完成任务后,对其自身的行为或输出进行批判性反思,并基于反思结果进行改进。

graph TD
    classDef startEnd fill:#F3F4F6,stroke:#4B5563,stroke-width:2px,rx:10,ry:10,color:#1F2937,font-weight:bold;
    classDef process fill:#DBEAFE,stroke:#3B82F6,stroke-width:2px,rx:5,ry:5,color:#1E3A8A;
    classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:2px,rx:5,ry:5,color:#92400E;
    classDef llm fill:#D1FAE5,stroke:#10B981,stroke-width:2px,rx:5,ry:5,color:#065F46;
    classDef tool fill:#FCE7F3,stroke:#EC4899,stroke-width:2px,rx:5,ry:5,color:#9D174D;
    classDef memory fill:#E0E7FF,stroke:#6366F1,stroke-width:2px,rx:5,ry:5,color:#3730A3;

    Start(["开始调用 call 或 stream"]):::startEnd
    EndLoop(["结束任务, 返回最终答案"]):::startEnd

    subgraph Phase1 ["🚀 阶段一:上下文初始化"]
        InitContext["加载系统和自定义 Prompt"]:::process
        LoadMem["加载历史会话记忆"]:::memory
        AddUser["追加 User 问题"]:::process
        SaveUserMem["将 User 问题存入记忆"]:::memory
        
        Start --> InitContext --> LoadMem --> AddUser --> SaveUserMem
    end

    subgraph Phase2 ["🔄 阶段二:ReAct 核心推理循环"]
        LoopStart(("进入新轮次")):::process
        SaveUserMem --> LoopStart
        
        CheckMaxRounds{"当前轮次 > maxRounds?"}:::decision
        LoopStart --> CheckMaxRounds

        CallLLM["调用大模型获取当前响应"]:::llm
        CheckMaxRounds -- 否 --> CallLLM

        HasToolCall{"响应包含 ToolCall?"}:::decision
        CallLLM --> HasToolCall
    end

    subgraph Phase3 ["🛑 触发最大轮次限制"]
        ForceFinalPrompt["追加强制回答Prompt(禁工具)"]:::process
        CallLLMForce["调用 LLM 获取最终总结"]:::llm
        
        CheckMaxRounds -- 是 --> ForceFinalPrompt --> CallLLMForce
    end

    subgraph Phase4 ["🛠️ 阶段三:Action 工具执行"]
        AddToolCallMsg["ToolCall 记录追加到上下文"]:::process
        ExecuteTools["遍历执行调用工具(Callback)"]:::tool
        AddToolResult["工具结果封为Message并追加"]:::tool

        HasToolCall -- 是 --> AddToolCallMsg --> ExecuteTools --> AddToolResult
        AddToolResult -. 返回下一轮次重新推理 .-> LoopStart
    end

    subgraph Phase5 ["🧠 阶段四:Reflection 反思与输出"]
        CheckReflection{"拦截器判断触发 Reflection?"}:::decision
        HasToolCall -- 否 --> CheckReflection

        CheckRefMaxRounds{"反思轮次 >= max?"}:::decision
        CheckReflection -- 是 --> CheckRefMaxRounds

        InjectFeedback["注入Feedback引导重新规划"]:::process
        CheckRefMaxRounds -- 否 --> InjectFeedback
        InjectFeedback -. 返回下一轮次重新规划 .-> LoopStart

        SaveFinalMem["将最终答案存入记忆"]:::memory
        
        CheckRefMaxRounds -- 是 --> SaveFinalMem
        CheckReflection -- 否 --> SaveFinalMem
        CallLLMForce --> SaveFinalMem
    end

    SaveFinalMem --> EndLoop

alt text

PlanExecuteAgent

围绕全局状态反复的迭代执行。它的核心目标不是尽快给出答案,而是在复杂、多步骤任务中,保证每一步的决策、执行和结果都可控、可追踪、可修正。整个流程可以抽象拆分为:规划、执行、批判、压缩、迭代与总结这6个阶段。

graph TD
    classDef startEnd fill:#F3F4F6,stroke:#4B5563,stroke-width:2px,rx:10,ry:10,color:#1F2937,font-weight:bold;
    classDef process fill:#DBEAFE,stroke:#3B82F6,stroke-width:2px,rx:5,ry:5,color:#1E3A8A;
    classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:2px,rx:5,ry:5,color:#92400E;
    classDef llm fill:#D1FAE5,stroke:#10B981,stroke-width:2px,rx:5,ry:5,color:#065F46;
    classDef tool fill:#FCE7F3,stroke:#EC4899,stroke-width:2px,rx:5,ry:5,color:#9D174D;
    classDef memory fill:#E0E7FF,stroke:#6366F1,stroke-width:2px,rx:5,ry:5,color:#3730A3;

    Start(["开始调用 PlanExecuteAgent"]):::startEnd
    EndLoop(["返回最终分析报告 / 结果"]):::startEnd

    subgraph Phase1 [🚀 阶段一:初始化上下文]
        CreateState["创建 OverAllState<br/>状态管理器"]:::process
        LoadMem["加载历史会话记忆"]:::memory
        AddUser["追加 User 问题到上下文"]:::process
        SaveUserMem["将 User 问题存入记忆"]:::memory

        Start --> CreateState
        CreateState --> LoadMem
        LoadMem --> AddUser
        AddUser --> SaveUserMem
    end

    subgraph Phase2 [📝 阶段二:Plan 生成计划]
        LoopStart(("进入新轮次 (Round)")):::process
        CheckRounds{"当前轮次 ><br/>maxRounds?"}:::decision
        GenPlan["调用大模型生成执行计划<br/>返回任务列表 PlanTask"]:::llm
        CheckPlan{"计划为空 或<br/>无有效任务?"}:::decision

        SaveUserMem --> LoopStart
        LoopStart --> CheckRounds
        CheckRounds -- "否" --> GenPlan
        GenPlan --> CheckPlan
    end

    subgraph Phase3 [⚙️ 阶段三:Execute 执行计划]
        GroupTasks["将任务按 Order 字段分组<br/>(同组并发,异组串行)"]:::process
        ExecAsync["调用 SimpleReactAgent<br/>并发执行任务 (带重试机制)"]:::tool
        SaveResults["将 Task 执行结果<br/>汇总并追加到上下文"]:::process

        CheckPlan -- "否" --> GroupTasks
        GroupTasks --> ExecAsync
        ExecAsync --> SaveResults
    end

    subgraph Phase4 [🧐 阶段四:Critique批判与压缩]
        CritiqueLLM["调用大模型评估 (Critique)<br/>当前任务是否已达成目标"]:::llm
        CheckPassed{"Critique 判定<br/>是否通过?"}:::decision
        AddFeedback["将失败的 Feedback<br/>追加到上下文"]:::process
        CheckSize{"上下文总字符 ><br/>contextCharLimit?"}:::decision
        Compress["调用大模型压缩上下文<br/>生成精简 Snapshot"]:::llm

        SaveResults --> CritiqueLLM
        CritiqueLLM --> CheckPassed
        
        CheckPassed -- "否 (未达成目标)" --> AddFeedback
        AddFeedback --> CheckSize
        
        CheckSize -- "是 (需要压缩)" --> Compress
        Compress -. "返回下一轮重新规划" .-> LoopStart
        CheckSize -. "否 (无需压缩)" .-> LoopStart
    end

    subgraph Phase5 [🏁 阶段五:Summarize 总结输出]
        FinalSummary["调用大模型<br/>根据所有轨迹总结最终答案"]:::llm
        SaveFinalMem["将最终答案存入会话记忆"]:::memory

        CheckRounds -- "是 (强制结束)" --> FinalSummary
        CheckPlan -- "是 (无需执行)" --> FinalSummary
        CheckPassed -- "是 (目标已达成)" --> FinalSummary

        FinalSummary --> SaveFinalMem
        SaveFinalMem --> EndLoop
    end

alt text

HITLReactAgent

Human-in-the-Loop(简称 HITL) 指的是在 AI 系统中的自动决策或执行过程中,引入人类用户作为“必要参与者”,在关键节点对 AI 的行为和结果进行审查、确认或修正,而不是让模型完全自动完成端到端的执行。在 Agent 场景下,HITL 的核心并不是用户参与推理,而是:在用户允许的边界内,让 Agent 自动运行;一旦即将执行高风险或高不确定性的动作,必须经过人工确认。HITL 本质上是一种 流程控制机制。

graph TD
    classDef startEnd fill:#F3F4F6,stroke:#4B5563,stroke-width:2px,rx:10,ry:10,color:#1F2937,font-weight:bold;
    classDef process fill:#DBEAFE,stroke:#3B82F6,stroke-width:2px,rx:5,ry:5,color:#1E3A8A;
    classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:2px,rx:5,ry:5,color:#92400E;
    classDef llm fill:#D1FAE5,stroke:#10B981,stroke-width:2px,rx:5,ry:5,color:#065F46;
    classDef tool fill:#FCE7F3,stroke:#EC4899,stroke-width:2px,rx:5,ry:5,color:#9D174D;
    classDef human fill:#FFEDD5,stroke:#EA580C,stroke-width:2px,rx:5,ry:5,color:#9A3412,stroke-dasharray: 5 5;

    StartCall(["首次调用 call(question)"]):::startEnd
    EndFinish(["返回 AgentFinished<br/>(任务最终结果)"]):::startEnd

    subgraph ClientSide [👤 外部客户端 / 人工审批环节]
        InterruptState(["获取到 AgentInterrupted<br/>(包含挂起状态与待处理工具)"]):::process
        HumanInput{"Scanner 人工审批<br/>同意 还是 拒绝?"}:::human
        ApproveAdd["feedbacks.add(tc.approve())"]:::process
        RejectAdd["feedbacks.add(tc.reject())"]:::process
        CallResume(["带入 interrupted 和 feedbacks<br/>再次调用 agent.resume()"]):::startEnd

        InterruptState --> HumanInput
        HumanInput -- "同意" --> ApproveAdd
        HumanInput -- "拒绝" --> RejectAdd
        ApproveAdd -. 循环全部待处理工具 .-> CallResume
        RejectAdd -. 循环全部待处理工具 .-> CallResume
    end

    subgraph Phase1 [🚪 阶段一:Agent 上下文与状态恢复]
        InitState["创建上下文 & HITLState<br/>追加 User 问题"]:::process
        RestoreState["从 interrupted 恢复上下文<br/>过滤掉已经被消费的工具"]:::process
        ProcessFeedbacks["将 feedbacks 注入上下文:<br/>同意则执行工具,拒绝则<br/>写入拒绝原因"]:::tool

        StartCall --> InitState
        CallResume --> RestoreState
        RestoreState --> ProcessFeedbacks
    end

    subgraph Phase2 [🤖 阶段二:大模型推理循环]
        LoopStart(("进入 run() 循环")):::process
        CheckRounds{"当前轮次 ><br/>maxRounds?"}:::decision
        CallLLM["调用大模型 ChatClient<br/>获取下一轮响应"]:::llm

        InitState --> LoopStart
        ProcessFeedbacks --> LoopStart
        LoopStart --> CheckRounds
        CheckRounds -- "否" --> CallLLM
    end

    subgraph Phase3 [⏸️ 阶段三:HITL 拦截触发]
        CheckHITL{"上下文标记<br/>HITL_REQUIRED?"}:::decision
        ExecNonIntercept["提取并自动执行<br/>无需拦截的安全工具"]:::tool

        CallLLM --> CheckHITL
        CheckHITL -- "是 (触发拦截)" --> ExecNonIntercept
        
        %% 连接回客户端的挂起状态
        ExecNonIntercept -->|抛出中断信号| InterruptState
    end

    subgraph Phase4 [🛠️ 阶段四:自动化执行 无拦截]
        CheckTools{"响应中是否包含<br/>ToolCall?"}:::decision
        ExecAllTools["遍历并执行工具<br/>结果追加至上下文"]:::tool

        CheckHITL -- "否" --> CheckTools
        CheckTools -- "是" --> ExecAllTools
        ExecAllTools -. "返回下一轮次" .-> LoopStart
    end

    subgraph Phase5 [🏁 阶段五:任务完成]
        CheckRounds -- "是 (强制结束)" --> EndFinish
        CheckTools -- "否 (判定已解答)" --> EndFinish
    end

alt text