AI agent开发入门:基于eino开发agent(五)

ADK应用:a excel agent

Posted by pandaychen on February 11, 2026

0x00 前言

Eino ADK 参考 Google-ADK 的设计,提供了 Go 语言 的 Agents 开发的灵活组合框架,即 Agent、特别是是Multi-Agent 开发框架,并为多 Agent 交互场景沉淀了通用的上下文传递、事件流分发和转换、任务控制权转让、中断与恢复、通用切面等能力

Eino ADK 中的 Agent

Eino ADK 抽象设计:

type Agent interface {
    Name(ctx context.Context) string
    Description(ctx context.Context) string
    Run(ctx context.Context, input *AgentInput) *AsyncIterator[*AgentEvent]
}

基于 Agent 抽象,ADK 提供了三大类基础拓展:

  • ChatModel Agent: 应用程序的思考部分,利用 LLM 作为核心,理解自然语言,进行推理、规划、生成响应,并动态决定如何执行或使用哪些工具
  • Workflow Agents:应用程序的协调管理部分,基于预定义的逻辑,按照自身类型(顺序 / 并发 / 循环)控制子 Agent 执行流程。Workflow Agents 产生确定性的,可预测的执行模式,不同于 ChatModel Agent 生成的动态随机的决策
    • 顺序(Sequential Agent):按顺序依次执行子 Agents
    • 循环(Loop Agent):重复执行子 Agents,直至满足特定的终止条件
    • 并行(Parallel Agent):并行执行多个子 Agents
  • Custom Agent:通过接口实现自己的 Agent,允许定义高度定制的复杂 Agent

Eino 内置了几种开箱即用的 Multi-Agent 最佳范式:

  • Supervisor: 监督者模式,监督者 Agent 控制所有通信流程和任务委托,并根据当前上下文和任务需求决定调用哪个 Agent
  • Plan-Execute:计划-执行模式,Plan Agent 生成含多个步骤的计划,Execute Agent 根据用户 query 和计划来完成任务。Execute 后会再次调用 Plan,决定完成任务 / 重新进行规划(前文已介绍)

0x0 excel agent实现解读

graph TB
    subgraph TOP["SequentialAgent (顶层入口)"]
        direction TB
        START_TOP((START))

        subgraph PER["① plan_execute_replan (SequentialAgent)"]
            direction TB

            subgraph PLANNER["Planner (Chain)"]
                P_IN["Input"] --> P_L1["Lambda: GenInputFn"]
                P_L1 --> P_CM["ChatModel<br/>JSON Schema 输出"]
                P_CM --> P_L2["Lambda: CollectStream"]
                P_L2 --> P_L3["Lambda: Parse → Plan<br/>→ Session"]
            end

            subgraph LOOP["execute_replan (LoopAgent, ≤20轮)"]
                direction TB

                subgraph EXECUTOR["Executor (ChatModelAgent)"]
                    E_GEN["Lambda: GenModelInput<br/>plan + step + executed_steps"]
                    subgraph E_REACT["ReAct Graph"]
                        E_CM["ChatModel"] --> E_BR{"hasToolCalls?"}
                        E_BR -->|否| E_END["→ Output"]
                        E_BR -->|是| E_TN["ToolNode"]
                        E_TN -->|继续| E_CM

                        subgraph E_TOOLS["Tools"]
                            AT_CA["AgentTool:<br/>CodeAgent"]
                            AT_WS["AgentTool:<br/>WebSearchAgent"]
                        end
                        E_TN --- E_TOOLS
                    end
                    E_GEN --> E_REACT
                end

                subgraph REPLANNER["Replanner (Chain)"]
                    R_L1["Lambda: GenInput<br/>executed_steps +<br/>remaining_steps"]
                    R_CM["ChatModel<br/>ToolChoiceForced"]
                    R_L2["Lambda: CollectStream"]
                    R_DECIDE{"Lambda: 判断 ToolCall"}
                    R_L1 --> R_CM --> R_L2 --> R_DECIDE
                    R_DECIDE -->|create_plan| R_PLAN["更新 Plan → Session"]
                    R_DECIDE -->|submit_result| R_BREAK["BreakLoopAction"]
                end

                EXECUTOR --> REPLANNER
                R_PLAN -->|"继续循环"| EXECUTOR
            end

            PLANNER --> LOOP
        end

        subgraph REPORT["② ReportAgent (ChatModelAgent)"]
            direction TB
            RP_GEN["Lambda: GenModelInput<br/>file_path + work_dir<br/>+ plan + files"]
            subgraph RP_REACT["ReAct Graph"]
                RP_CM["ChatModel"] --> RP_BR{"hasToolCalls?"}
                RP_BR -->|否| RP_END["→ Output"]
                RP_BR -->|是| RP_TN["ToolNode"]
                RP_TN -->|继续| RP_CM
                RP_TN -->|submit_result<br/>ReturnDirectly| RP_CVT["→ 直接返回"]
                RP_CVT --> RP_END

                subgraph RP_TOOLS["Tools"]
                    RPT1["bash"]
                    RPT2["tree"]
                    RPT3["read_file"]
                    RPT4["edit_file"]
                    RPT5["submit_result"]
                    RPT6["image_reader?"]
                end
                RP_TN --- RP_TOOLS
            end
            RP_GEN --> RP_REACT
        end

        START_TOP --> PER --> REPORT --> END_TOP((END))
    end

    subgraph CA_DETAIL["CodeAgent内部(ChatModelAgent)"]
        CA_GEN["Lambda: GenModelInput<br/>working_dir + user_query"]
        subgraph CA_REACT["ReAct Graph"]
            CA_CM["ChatModel"] --> CA_BR{"hasToolCalls?"}
            CA_BR -->|否| CA_END["→ Output"]
            CA_BR -->|是| CA_TN["ToolNode"]
            CA_TN -->|继续| CA_CM
            CA_TN --- CA_T1["python_runner"]
            CA_TN --- CA_T2["bash"]
            CA_TN --- CA_T3["read_file"]
            CA_TN --- CA_T4["edit_file"]
            CA_TN --- CA_T5["tree"]
        end
        CA_GEN --> CA_REACT
    end

    AT_CA -.->|"展开"| CA_DETAIL

    style TOP fill:#fafafa,stroke:#424242
    style PER fill:#e3f2fd,stroke:#1565c0
    style PLANNER fill:#e8f5e9,stroke:#2e7d32
    style LOOP fill:#fff3e0,stroke:#e65100
    style EXECUTOR fill:#fce4ec,stroke:#c62828
    style E_REACT fill:#ffebee,stroke:#d32f2f
    style REPLANNER fill:#fff9c4,stroke:#f9a825
    style REPORT fill:#e0f7fa,stroke:#00838f
    style RP_REACT fill:#e0f2f1,stroke:#00695c
    style CA_DETAIL fill:#f3e5f5,stroke:#6a1b9a
    style CA_REACT fill:#ede7f6,stroke:#4527a0

0x0 参考