从范式到工程:Plan & Execute + Nacos MCP 构建 AI Agent 的实践之路

这篇博文的"理论线"参考了 《AI Agent 设计范式的演进之路:从工具调用到多智能体协作》,"工程线"基于开源项目 nacos-learn-example 的实际代码。读者可以对照源码阅读本文。

一、背景:为什么是 Plan & Execute?

那篇理论文章 梳理了 AI Agent 的一条清晰演进链:

复制代码
Tool Calling (地基)
    ↓
ReAct --- 边想边做
    ↓
Plan & Execute --- 先计划后执行  ← 我们在这里
    ↓
Reflection --- 自我反思
    ↓
Multi-Agent --- 多角色协作

文中说:"理解这条演进路径,远比死记硬背概念更重要。" 而我们的项目正是沿着这条路径走到了 Plan & Execute(第二范式),原因很直接:

  • 用户请求是明确的多步骤任务(查天气 → 计算温差 → 生成报告),而非开放式探索
  • 需要流程可追溯------用户想看到"AI 打算怎么做"之后再执行
  • 追求稳定性------纯 ReAct 不设边界时,LLM 可能在 10 轮 tool call 后迷路

那篇文章的工程原则说得好:"从不复杂的范式开始,随着需求增长逐步演进。"

二、架构全景:四层 + 三阶段

整个系统跨越四个独立模块,源码见 agentic/nacos-mcp-router/mcp-server/agentic-ui/

复制代码
┌──────────────────────────────────────────────────────────────┐
│                     agentic-ui (Vue 3)                        │
│               WebSocket 流式渲染 / REST 对话管理               │
└──────────────────────┬───────────────────────────────────────┘
                       │ WS /api/ws
                       ▼
┌──────────────────────────────────────────────────────────────┐
│                 agentic (Python + FastAPI)                    │
│                                                              │
│   ┌──────────┐   ┌──────────┐   ┌──────────┐               │
│   │ Planner  │──▶│Validator │──▶│ Executor │               │
│   │ (拆解)   │   │(校验)    │   │(逐步执行)  │               │
│   └──────────┘   └──────────┘   └────┬─────┘               │
│                                       │                     │
│         ToolRegistry ◀── McpRouterClient                    │
│         (预发现工具)         (SSE 长连接)                    │
└──────────────────────┬───────────────────────────────────────┘
                       │ MCP Protocol (SSE)
                       ▼
┌──────────────────────────────────────────────────────────────┐
│              nacos-mcp-router (Docker)                       │
│            Nacos 服务发现代理层 --- 三大元工具:                   │
│    search_mcp_server / add_mcp_server / use_tool             │
└────┬─────────────────────────────────────────────────────┬───┘
     │ Nacos 注册                                         │
     ▼                                                    ▼
┌────────────────┐                              ┌──────────────────┐
│  mcp-server    │                              │  更多 MCP 服务   │
│  (Python)      │                              │  (Java/Go/...)   │
│  hello         │                              │                  │
│  calculator    │                              │                  │
│  weather       │                              │                  │
└────────────────┘                              └──────────────────┘

三阶段的执行流

系统遵循 Plan → Validate → Execute → Summarize 四阶段流水线,这与那篇文章描述的 Plan & Execute 核心流程一致:

那篇文章:"Planner:将用户目标拆解为有序的子任务列表 → Executor:依次执行每个子任务 → Replanner:当执行失败或信息变化时,重新生成计划"

我们增加了一个Validate 阶段作为"代码门禁"------这是那篇文章没有讨论到的工程实践:

复制代码
用户: "北京和深圳今天的气温差多少?"

Phase 1 --- Plan (agentic/src/agentic/planner.py)
  LLM 思考(流式输出 thinking token)→ 调用 submit_plan 函数提交结构计划
  ┌─────────────────────────────────────────────┐
  │ Step 1: 查北京的天气    → get_weather(北京)  │
  │ Step 2: 查深圳的天气    → get_weather(深圳)  │
  │ Step 3: 计算温差        → calculator(减法)   │
  │ Step 4: 生成报告        → (无需工具)         │
  └─────────────────────────────────────────────┘

Phase 1.5 --- Validate (agentic/src/agentic/validator.py)
  代码级检查:每一步的 suggested_tool 是否在 ToolRegistry 中?
  → 如果工具不可用,触发 replan(最多 2 次)
  → 如果全部不可用,直接返回错误

Phase 2 --- Execute (agentic/src/agentic/executor.py)
  ┌─ Step 1 ──────────────────────────────────────┐
  │ LLM 收到完整上下文 + 当前步骤描述              │
  │ → 调用 weather("北京") → 得到 27℃             │
  │ → 确认完成                                     │
  └───────────────────────────────────────────────┘
  ┌─ Step 2 ──────────────────────────────────────┐
  │ → 调用 weather("深圳") → 得到 32℃              │
  │ → 确认完成                                     │
  └───────────────────────────────────────────────┘
  ┌─ Step 3 ──────────────────────────────────────┐
  │ → 调用 calculator(27, 32, "subtract") → 得到 -5│
  │ → 或通过 modify_plan 动态调整后续步骤          │
  └───────────────────────────────────────────────┘

Phase 3 --- Summarize (agentic/src/agentic/executor.py:summarize)
  LLM 不加载工具,基于所有步骤结果生成自然语言回复
  "北京 27℃,深圳 32℃,温差 5℃,深圳比北京暖和一些~"

💡 那篇文章提到 Eino ADK 的 Plan & Execute 使用了三个独立的 Agent(Planner、Executor、Replanner)。我们的项目选择了更轻量的方式------同一条 LLM 换 prompt 切换角色,降低了通信复杂度和 token 成本。这是工程权衡的结果。

三、关键设计决策

3.1 外圈代码驱动 + 内圈 LLM 驱动

这是本项目最有特色的设计模式。那篇文章描述 Plan & Execute 时提到"规划与执行分离",但没有讨论"分离的粒度"。我们的答案是:

复制代码
外圈 (代码驱动):   while plan.pointer < len(plan.steps):
                       执行单步
                       plan.pointer += 1

内圈 (LLM 驱动):    for turn in range(max_turns):
                        LLM 推理 → 调用工具 → 观察结果 → 继续推理
                        直到 LLM 不再调用工具就 break

这两种驱动方式的对比:

维度 纯 LLM 驱动(Eino ADK 风格) 代码 + LLM 混合(我们的方案)
步骤边界 LLM 自行约束 代码强制保障
单步复杂度 可能一口气做太多 限定为原子操作
可观察性 中间状态模糊 每一步开始/结束/状态清晰可见
错误恢复 依赖 LLM 自省 代码级 retry + 自动跳过不可用步骤

那篇文章的演进全景图将 ReAct 和 Plan & Execute 列为不同的范式,但在我们的实践中,它们不是互斥的,而是嵌套的

复制代码
Plan & Execute (外层,代码控制)
    └── ReAct (内层,每步 LLM 驱动)
        └── Tool Calling (原子动作)
            └── MCP Protocol (基础设施)

那篇文章在后来的"组合使用"章节也补充了这一点:"这些范式不是互斥的,而是可以组合使用。" 这恰好印证了我们的架构选择。

3.2 两阶段 Prompt 设计

同一个 LLM,在不同阶段看到不同的工具信息:

复制代码
Planner 看到:  "  • get_weather --- 查询指定城市的实时天气
                 • calculator --- 执行四则运算"           ← 紧凑描述

Executor 看到:  {name: "get_weather", parameters: {city: {type: "string"}}}  ← 完整定义

规划阶段不需要参数细节,执行阶段才需要精确的函数签名。分离后,规划 prompt 更短更专注------这是一个容易被忽视的 token 优化手段。

3.3 验证器(Validator)作为代码门禁

在 Planner 和 Executor 之间,插入纯代码验证层

复制代码
Planner 输出计划
    │
    ▼
Validator 检查: suggested_tool 都在 ToolRegistry 中?
    │               │
    │ 全部可用       │ 部分不可用
    ▼               ▼
  进入 Execute    触发 Replan(告知 LLM 哪些不可用,重规划)
    │
    │ 重试 2 次后仍有不可用工具
    ▼
  返回错误:"当前不支持此工作"

那篇文章提到 Plan & Execute 时没有讨论"工具可用性校验"这一环节。在 MCP 生态中,工具可用性是运行时基础设施问题,不是推理问题------代码门禁比 LLM 自省更适合处理它。

3.4 预发现(Pre-discovery)

系统启动时自动连接 nacos-mcp-router,全量拉取所有已注册 MCP 服务的工具定义。源码在 agentic/src/agentic/api.py 的 lifespan 阶段:

python 复制代码
services = await mcp_client.discover_services()
for server_name in services:
    tools = await mcp_client.fetch_service_tools_via_add(server_name)
    for tool_name, description, input_schema in tools:
        tool_registry.register(server_name, tool_name, description, input_schema)

这与那篇文章的案例不同------那篇文章假设工具已经就绪,而在实际 MCP 生态中,工具发现是启动时的基础设施操作,不应让 LLM 在运行时分心。

四、Nacos MCP 生态的角色分工

mcp-server(工具生产者)

源码见 mcp-server/src/mcp_server/main.py。通过 NacosMCP SDK 自动注册到 Nacos MCP Hub:

python 复制代码
@mcp.tool()
def weather(city: str) -> str:
    """查询指定城市的实时天气"""
    return fetch_weather(city, api_key)

nacos-mcp-router(工具代理 + 服务发现)

Docker 部署,作为 Nacos MCP 生态的代理网关,对外暴露三个元工具:

元工具 功能
search_mcp_server 搜索 Nacos 上已注册的 MCP 服务
add_mcp_server 获取特定服务的工具定义
use_tool 代理调用某个服务的某个工具

启动方式(docker-compose.yml 见 nacos-mcp-router/):

bash 复制代码
docker compose -f nacos-mcp-router/docker-compose.yml up -d

agentic(工具消费者 + LLM 编排)

Plan & Execute 的核心。同时承担两个角色:

  1. MCP Client:启动时通过 SSE 连接 router,拉取工具定义
  2. LLM Orchestrator:将工具定义注入 LLM,编排 Plan → Execute → Summarize 流程

工具调用链路:

复制代码
LLM 决定调用 "get_weather"
    → ToolRegistry.lookup("get_weather") → server_name="mcp-server-python"
    → agentic 调用 router 的 use_tool
    → router 转发给 mcp-server-python
    → mcp-server 执行 get_weather("北京")
    → 结果一路返回给 LLM

五、与范式理论的对照

那篇文章的演进全景表,映射到我们的项目:

演进阶段 核心范式 项目中的体现
地基 Tool Calling OpenAI function calling → MCP Router → MCP 服务
第一阶 ReAct agent.py:stream_llm() 每步最多 10 轮 Thought→Action→Observation
第二阶 Plan & Execute Orchestrator 四阶段流水线(主导范式)
第三阶 Reflection 轻量:Executor 把所有步骤结果 + 错误反馈喂给 LLM
第四阶 Multi-Agent 未使用(单一 LLM 换 prompt 切换角色,见文末讨论)

为什么不走 Multi-Agent?

那篇文章介绍了 AutoGen、CrewAI 等多个 Multi-Agent 框架。我们选择不走 Multi-Agent,原因在那篇文章中其实已经给出了答案:

💡 工程原则:从不复杂的范式开始,随着需求增长逐步演进。不要一开始就搭建 Multi-Agent,那很可能是过度设计。

单一 LLM 已经能通过换 prompt 胜任 Planner、Executor、Summarizer 三个角色。引入三个独立 Agent 会带来通信复杂度和成本翻倍------当前阶段不值得。

六、一些有用的工程细节

6.1 动态修改计划

那篇文章提到 Plan & Execute 需要 Replanner 角色。我们在执行阶段提供了 modify_plan 工具(见 executor.py),允许 LLM 在执行中动态追加/跳过/替换步骤:

复制代码
LLM 发现 Step 3 的结果不符合预期
    → 调用 modify_plan(action="append", new_step={...})
    → 计划在 Step 3 后追加 Step 4
    → 继续执行

这是那篇文章中 Replanner 角色的具体实现------不是独立的 Agent,而是一个元工具

6.2 Retry 策略

  • 单步 retry:最多 3 次,每次重试时 LLM 看到上一次的错误信息
  • Replan retry:最多 2 次,通知 LLM 哪些工具不可用,要求绕过

七、总结

我们从一段 Agent 范式理论出发,走通了一条从理论到工程的完整路径:

复制代码
理论范式  →  架构设计  →  模块实现  →  服务部署
Plan &     Orchestrator  agentic/       Docker +
Execute    四阶段流水线    + MCP 工具     Nacos 注册

开始探索

bash 复制代码
git clone https://gitee.com/bytesifter/nacos-learn-example.git
cd nacos-learn-example

# 启动 Nacos MCP Router
docker compose -f nacos-mcp-router/docker-compose.yml up -d

# 启动 MCP Server
cd mcp-server && uv run mcp-server

# 启动 Agentic 后端
cd agentic && uv run uvicorn agentic.api:app

# 启动前端
cd agentic-ui && bun dev

核心收获

  1. Plan & Execute 适合明确的多步骤任务------提供可追溯、可控的执行流程
  2. 代码 + LLM 混合驱动比纯 LLM 驱动更稳定------代码管边界,LLM 管内容(对照那篇文章的 Plan & Execute 案例,这是我们的差异化实践)
  3. MCP 协议天然适配 Plan & Execute------工具发现是启动时的基础设施操作,执行阶段 LLM 只需专注"调用什么"
  4. 范式不是单选题------Plan & Execute 的外圈包裹 ReAct 的内圈,正如那篇文章总结的:"这些范式可以组合使用"

参考资源

相关推荐
工一木子3 小时前
Browser MCP:让 Cursor 直接操控你的真实浏览器
人工智能
宋哥转AI4 小时前
Java搭RAG实战(三):检索问答全链路,从架构分层到SSE流式
java·agent
测试员周周4 小时前
【Appium 系列】第17节-XMind用例转换 — 从思维导图到 YAML
java·服务器·人工智能·单元测试·appium·测试用例·xmind
ujainu4 小时前
CANN pto-isa:AI 编译为什么需要虚拟指令集
人工智能
AI周红伟4 小时前
通用业务智能体OpenClaw+Skills+RAG+Agent构建案例实操
大数据·人工智能·windows·百度·copilot
Fleshy数模4 小时前
基于 CSV 数据分析的课堂教学问题诊断与改进建议系统
数据库·人工智能·大模型·llm
甲维斯4 小时前
Claude Code 桌面版 和 CLI 自动模式和跳过所有授权!
人工智能
NiceCloud喜云4 小时前
Claude API PDF 文档问答实战:从原生解析到分页引用的完整方案
java·服务器·前端·网络·数据库·人工智能·pdf
老王谈企服4 小时前
2026企业数字化转型:从规则脚本到实在Agent智能体进化全解析
人工智能·ai