ERP结合多 Agent 项目技术解析文档

ERP_OPENCLAW 多 Agent 项目技术解析文档

面向学习者的源码导读。重点解释:RAG/增强生成链路、智能体通信、MCP 应用、Skill 管理、状态管理,以及项目复杂点和亮点。


1. 项目总体定位

ERP_OPENCLAW 是一个围绕"摩托车零部件采购 ERP"的多 Agent 智能助手项目。它不是单纯的聊天机器人,而是把多个系统组合成一个业务型 Agent 应用:

  • Python Agent 后端:基于 LangGraph、DeepAgents、LangChain、FastAPI。
  • 多 Agent 编排:主 Agent 负责协调,采购分析 Agent 和订单 Agent 负责具体任务。
  • MCP 工具层:把 Java ERP 后端 API 和远程可视化服务包装成 Agent 可调用工具。
  • Skill 系统:用 SKILL.md + 脚本 + 数据文件组织可复用能力。
  • 沙箱执行:用 OpenSandbox 执行脚本、读写报告、同步技能文件。
  • 状态持久化:LangGraph checkpoint 用 MongoDB,用户偏好和技能用 StoreBackend 路由。
  • 前端:Vue 3 + Vite,通过 SSE 展示流式 token、工具调用、人工中断。
  • 业务后端:Java Spring Boot + MyBatis Plus + MySQL 的 ERP 示例系统。

可以把它理解为:

text 复制代码
用户
  -> Vue 前端
  -> FastAPI SSE 接口
  -> LangGraph / DeepAgents 主 Agent
  -> 子 Agent
  -> MCP 工具
  -> Java ERP / 可视化 MCP / Web Search / 沙箱 Skill
  -> 返回分析报告、图表、订单操作结果

2. 目录地图

核心目录如下:

text 复制代码
ERP_OPENCLAW/
  langgraph.json                         LangGraph 图入口配置
  start_web.py                           一键启动 FastAPI + Vue
  requirements.txt                       Python 实际依赖快照
  pyproject.toml                         LangGraph 模板依赖
  src/
    agent/                               多 Agent 核心
      main_agent.py                      Agent 初始化总入口
      config.py                          LLM、沙箱、MongoDB、Store 配置
      memory/                            主 Agent 系统提示词和 AGENTS.md
      middlewares/                       上下文、Skill、记忆、摘要中间件
      subagents/                         子 Agent YAML 加载器与配置
      tools/                             web_search、MCP client、HITL、图表合并等
      backends/                          OpenSandbox 后端适配
    mcp_server/                          本地 FastMCP 服务
      server_main.py                     MCP Server 入口
      tools/                             ERP API 工具封装
    api_view/                            FastAPI Web API
      api/chat.py                        SSE 流式对话和中断恢复
      api/history.py                     会话历史
      agent_loader.py                    Agent 单例与 MongoDB 展示消息
    skills/                              Skill 能力包
      main/skill-management/
      procurement/procurement-analysis/
      procurement/supplier-price-urls/
      procurement/web-scraper/
      procurement/web-content-fetcher/
  frontend/                              Vue 3 前端
  Java写的ERP项目(用于手撕OpenClaw项目)/
    MotorcyclePartsProcurementSystem/    Java ERP 后端

3. 核心技术栈

层级 技术 作用
Agent 编排 LangGraph, DeepAgents 构建可 checkpoint、可流式、可子 Agent 委派的智能体图
LLM 接入 LangChain ChatOpenAI, DeepSeek, Zhipu 兼容 OpenAI 接口 主模型、摘要模型、备用模型
MCP FastMCP, langchain-mcp-adapters, MultiServerMCPClient 将外部服务暴露为工具并接入 LangChain
Web API FastAPI, Uvicorn, SSE 对前端提供流式聊天、恢复中断、历史接口
状态存储 MongoDBSaver, MongoDB, InMemoryStore, StoreBackend, CompositeBackend checkpoint、展示消息、用户记忆、技能持久化
沙箱 OpenSandbox, 自定义 OpenSandboxBackend 执行代码、同步 Skill、生成报告和图表
前端 Vue 3, Vite, markdown-it, highlight.js, fetch stream 聊天 UI、工具调用面板、HITL 中断交互
业务系统 Spring Boot 3.1.10, Java 17, MyBatis Plus, MySQL ERP 供应商、物料、订单、库存等 REST API

注意:Java 子项目 README 写的是 Spring Boot 2.7.x / JDK 1.8,但 pom.xml 实际是 Spring Boot 3.1.10、Java 17,学习时以 POM 为准。


4. 启动与初始化链路

4.1 服务启动

start_web.py 做两件事:

  1. 启动 FastAPI:
text 复制代码
uvicorn api_view.web_main:app --reload --host 0.0.0.0 --port 8090
  1. 等待 /health 就绪后启动 Vue:
text 复制代码
npm run dev

FastAPI 启动时会进入 api_view/web_main.py 的 lifespan,调用:

python 复制代码
await agent_loader.initialize()

AgentLoader 再懒加载 agent.main_agent.get_agent_async()

4.2 Agent 初始化 9 阶段

核心在 src/agent/main_agent.py:create_main_agent()

  1. 创建或连接 OpenSandbox。
  2. 上传 src/agent/memory/AGENTS.md 到沙箱 /AGENTS.md
  3. 构建 CompositeBackend,把不同路径路由到不同后端。
  4. 连接 MCP Server,加载 ERP 工具和可视化工具。
  5. 将 26 类可视化 MCP 工具合并成 generate_visualization
  6. 创建 assign_skilldownload_sandbox_file 等本地工具。
  7. 加载子 Agent YAML 配置。
  8. 给主 Agent 和子 Agent 组装中间件。
  9. 调用 create_deep_agent(...) 生成可运行图。

主 Agent 创建时传入的关键参数:

python 复制代码
create_deep_agent(
    model=MAIN_MODEL,
    system_prompt=system_prompt,
    skills=["/skills/main/"],
    memory=["/AGENTS.md"],
    tools=[web_search, assign_skill, download_sandbox_file],
    subagents=subagents,
    middleware=main_middleware,
    backend=backend,
    store=STORE,
    checkpointer=CHECKPOINTER,
    context_schema=ProcurementContext,
)

这说明主 Agent 本身只保留通用能力,ERP 业务操作主要靠子 Agent。


5. RAG 是怎么搭建的

5.1 先说结论:不是传统向量库 RAG

源码中没有发现典型传统 RAG 组件:

  • 没有 embedding 模型调用。
  • 没有 FAISS、Chroma、Milvus、pgvector 等向量库。
  • 没有 document splitter、retriever、reranker 链路。

所以这个项目的"RAG"更准确地说是"工具增强 + Skill 文档增强 + 记忆增强 + 文件系统增强"的 Agentic RAG。

它的增强来源不是向量检索,而是以下几类上下文:

增强来源 代码位置 作用
全局操作手册 src/agent/memory/AGENTS.md 规定主 Agent 生命周期、委派规则、记忆规则、安全边界
Skill 文档 src/skills/**/SKILL.md 子 Agent 按需读取专业流程说明
业务数据 MCP ERP 工具 从 Java ERP 获取供应商、零部件、订单、库存
外部报价 supplier-price-urls + web-scraper 先查 URL 映射,再抓网页转 Markdown
Web 搜索 src/agent/tools/web_search.py 市场行情、供应商背景、通用知识
长期记忆 /memories/{user_id}/preferences.md 用户偏好、最近供应商、最近查询
沙箱文件 /analysis/report_*.md, /analysis/temp/*.md 分析报告、抓取页面、临时数据

5.2 Agentic RAG 流程

以"帮我分析某零件供应商价格"为例:

text 复制代码
用户问题
  -> 主 Agent 读取 /memories/{user_id}/preferences.md
  -> 判断是采购分析任务
  -> task 委派 procurement-analyst
  -> procurement-analyst 读取 /skills/procurement/procurement-analysis/SKILL.md
  -> 调用 MCP 工具查 ERP 内部数据
  -> 读取 supplier-price-urls/data/url_mapping.yaml
  -> 命中 URL 后执行 web-scraper 抓取外部页面
  -> 运行 Python 分析脚本
  -> 调用 generate_visualization 生成图表
  -> 写 /analysis/report_xxx.md
  -> 返回报告路径、摘要、结论、建议

这类设计的核心思想是:让 Agent 自己按任务需要读取权威说明和调用工具,而不是提前把所有文档塞进向量库。

5.3 优点与限制

优点:

  • 对结构化业务系统更直接,ERP 数据直接从 API 来,不经过文本召回。
  • Skill 是可读、可维护的操作手册,适合教学和迭代。
  • 沙箱文件让大结果可 offload,不必全部塞进模型上下文。
  • 用户记忆能跨轮保留偏好,使输出越来越个性化。

限制:

  • 没有语义检索能力,无法在大量非结构化文档中按语义召回。
  • 依赖 Agent 自觉按步骤读 Skill,提示词和工具描述质量很关键。
  • URL 映射是静态 YAML,需要维护。
  • RAG 质量依赖 MCP/API/网页抓取返回质量。

6. 智能体怎么通信

项目里有三层通信。

6.1 前端与后端通信:SSE

前端 frontend/src/api/chat.jsfetch + ReadableStream 调用:

text 复制代码
POST /api/chat/stream
POST /api/chat/{thread_id}/resume

后端 src/api_view/api/chat.py 使用 StreamingResponse 持续推送 SSE:

text 复制代码
token         AI 文本片段
tool_start    工具开始调用
tool_args     工具参数流式片段
tool_result   工具执行结果
tool_end      工具结束
interrupt     人工介入中断
done          本轮结束
error         错误

前端把这些事件转换成消息列表、工具面板和中断横幅。

6.2 前端、后端、Agent 的端到端通信链路

一次普通对话从前端输入框到 Agent 再回到 UI,大致分 8 步:

text 复制代码
1. App.vue 用户点击发送
   -> handleSend(message)

2. frontend/src/api/chat.js
   -> streamChat(message, threadId, callbacks, abortSignal)
   -> POST /api/chat/stream
   -> body: { message, thread_id }

3. src/api_view/api/chat.py
   -> chat_stream(request)
   -> thread_id = request.thread_id or uuid.uuid4()
   -> StreamingResponse(stream_chat_response(...))

4. stream_chat_response()
   -> context = {"user_id": "laoxiao", "username": "laoxiao"}
   -> config = agent_loader.create_config(thread_id)
   -> current_input = {"messages": [{"role": "user", "content": message}]}

5. AgentLoader
   -> agent_loader.agent 已在 FastAPI lifespan 中初始化
   -> 底层来自 agent.main_agent.get_agent_async()

6. LangGraph / DeepAgents
   -> agent_loader.agent.astream(
        input=current_input,
        config=config,
        context=context,
        stream_mode=["messages", "values"],
        subgraphs=True,
        version="v2",
      )

7. 后端把 LangGraph chunk 转成 SSE
   -> AI token: type=token
   -> 工具调用: type=tool_start/tool_args/tool_result/tool_end
   -> 中断: type=interrupt
   -> 完成: type=done

8. 前端 _processStream() 解析 SSE
   -> onToken 更新 assistant 消息
   -> onToolStart/onToolArgs/onToolResult 更新工具消息
   -> onInterrupt 显示 InterruptBanner
   -> onDone 更新 thread_id / 会话列表

这里有几个关键设计点:

设计点 代码位置 作用
thread_id frontend/src/App.vue, src/api_view/api/chat.py, AgentLoader.create_config() 同一个会话的 LangGraph checkpoint key
context stream_chat_response() 给 Agent 注入 user_idusername,后续由 ContextInjectionMiddleware 写入 system message
stream_mode=["messages","values"] agent_loader.agent.astream(...) messages 用于展示 token/工具,values 用于检测 interrupt
subgraphs=True agent_loader.agent.astream(...) 让子 Agent 的流式输出也能被后端捕获
source extract_subagent_name(namespace) 标记消息来自 main 还是某个子 Agent
display_messages stream_chat_response() + AgentLoader.save_display_messages() 保存 UI 友好的消息顺序,包含工具和子 Agent 消息

后端并不是把 Agent 的原始状态直接丢给前端,而是在 chat.py 里做了一层"流事件适配":

text 复制代码
LangGraph chunk
  -> 后端解析 token / metadata / namespace
  -> 转成统一 SSE JSON
  -> 前端按 type 更新 UI

这个适配层非常重要。LangGraph 的 checkpoint 更适合恢复执行,前端展示则需要"用户消息、助手文本、工具调用、工具结果"按时间顺序混排,所以项目额外维护了 session_display_messages 集合来保存展示消息。

6.3 中断恢复通信:前端如何把人工输入送回 Agent

订单流程里有两种中断:

text 复制代码
order_info_supplement  缺字段,需要用户补充自然语言信息
hitl_approval          创建/修改订单前,需要用户 approve/reject

后端检测到中断时,会发送:

json 复制代码
{
  "type": "interrupt",
  "interrupt_type": "order_info_supplement",
  "missing_fields": "...",
  "collected_data": "...",
  "thread_id": "..."
}

或:

json 复制代码
{
  "type": "interrupt",
  "interrupt_type": "hitl_approval",
  "action_requests": [...],
  "review_configs": [...],
  "thread_id": "..."
}

前端 InterruptBanner.vue 根据 interrupt_type 展示不同 UI:

  • order_info_supplement:展示缺失字段和文本框,提交 { supplement: "..." }
  • hitl_approval:展示待执行订单操作,提交 { decisions: [{ type: "approve" }] } 或 reject。

恢复时链路如下:

text 复制代码
InterruptBanner.vue
  -> emit("resume", resumeData)
  -> App.vue handleResume(resumeData)
  -> frontend/src/api/chat.js resumeChat(threadId, resumeData)
  -> POST /api/chat/{thread_id}/resume
  -> chat.py chat_resume()
  -> stream_chat_response(thread_id=..., resume_data=...)
  -> current_input = Command(resume=resume_data)
  -> agent_loader.agent.astream(...) 继续原 checkpoint

这里 thread_id 很关键:恢复不是新开一轮普通对话,而是在同一个 checkpoint 上用 Command(resume=...) 继续执行被暂停的 LangGraph。

6.4 后端和 Agent 的生命周期通信

FastAPI 后端启动时通过 lifespan 初始化 Agent:

text 复制代码
web_main.py lifespan
  -> agent_loader.initialize()
  -> MongoClient(MONGODB_URI)
  -> get_agent_async()
  -> create_main_agent()

AgentLoader 是后端与 Agent 之间的门面:

方法 作用
initialize() 初始化 MongoDB 连接并懒加载 Agent
create_config(thread_id, user_id) 构造 LangGraph configurable,用于 checkpoint
get_current_messages(thread_id) 从 Agent checkpoint 获取当前消息
get_state_history(thread_id) 获取 LangGraph 状态历史
save_display_messages(thread_id, messages) 保存前端展示消息
get_display_messages(thread_id) 读取前端展示消息
delete_session(thread_id) 删除 checkpoint 和展示消息

也就是说,后端和 Agent 的通信有两条线:

text 复制代码
执行线:FastAPI -> AgentLoader.agent.astream() -> LangGraph/DeepAgents
状态线:FastAPI -> AgentLoader -> MongoDB checkpoint/display_messages

6.5 通信数据结构速记

方向 数据结构 示例
前端到后端普通对话 { message, thread_id } POST /api/chat/stream
前端到后端恢复中断 { resume: {...} } POST /api/chat/{thread_id}/resume
后端到 Agent 普通输入 {"messages": [{"role": "user", "content": message}]} current_input
后端到 Agent 恢复输入 Command(resume=resume_data) HITL 继续执行
后端到前端文本 SSE {type:"token", content, source} 流式文字
后端到前端工具 SSE {type:"tool_start/tool_args/tool_result/tool_end", ...} 工具面板
后端到前端中断 SSE {type:"interrupt", interrupt_type, ...} 人工介入 UI
后端到前端完成 SSE {type:"done", thread_id, content, interrupted} 一轮结束

6.6 主 Agent 与子 Agent 通信:DeepAgents task 工具

主 Agent 的 system_prompt 明确要求:

  • 分析类任务委派 procurement-analyst
  • 订单类任务委派 procurement-order
  • 主 Agent 自己只处理问候、功能询问、通用搜索和技能管理。

委派通过 DeepAgents 内置的 task 工具完成。主 Agent 把任务目标、用户偏好、原始需求写入 description,子 Agent 根据自己的 YAML system_prompt 和工具列表执行。

子 Agent 配置在:

text 复制代码
src/agent/subagents/configs/procurement_analyst.yaml
src/agent/subagents/configs/procurement_order.yaml

加载器 src/agent/subagents/loader.py 会把 YAML 中的工具名模式匹配为真实工具对象。

6.7 Agent 与外部系统通信:MCP 和工具调用

Agent 不直接访问 Java API,而是走 MCP:

text 复制代码
Agent
  -> MultiServerMCPClient
  -> FastMCP 本地 erp-api server
  -> httpx.AsyncClient
  -> Java ERP REST API

另外还连接远程魔塔 MCP:

text 复制代码
Agent -> ModelScope MCP -> generate_* 可视化工具

这让业务 API、可视化能力都变成 LangChain StructuredTool,统一纳入 Agent 的工具调用系统。


7. MCP 在里面的应用

7.1 MCP Server 端

入口是 src/mcp_server/server_main.py

python 复制代码
mcp = FastMCP(
    name="Java-Backend-MCP-Server",
    instructions="调用 Java 后端 REST API 的工具集,支持按业务分组访问",
    version="1.0.0",
    lifespan=mcp_lifespan,
)

它注册四类工具:

文件 工具前缀 说明
suppliers_tools.py supplier_ 供应商查询
parts_tools.py part_ 零部件分页、搜索、按供应商查询
order_tools.py order_ 创建、更新、搜索订单明细
inventory_tools.py inventory_ 库存预警

http_base.py 在 MCP lifespan 中创建共享 httpx.AsyncClient

python 复制代码
yield {"http_client": http_client}

每个工具再通过:

python 复制代码
ctx.request_context.lifespan_context.get("http_client")

复用连接池访问 Java 后端。

7.2 MCP Client 端

入口是 src/agent/tools/mcp_client.py

python 复制代码
MCP_SERVER_CONFIG = {
    "erp-api": {
        "url": "http://127.0.0.1:8000/mcp",
        "transport": "streamable_http",
    },
    "analysis": {
        "url": "https://mcp.api-inference.modelscope.net/af3893df5be041/mcp",
        "transport": "streamable_http",
    },
}

加载后按前缀分组:

  • supplier_, part_, inventory_ 给采购分析 Agent。
  • order_ 给订单 Agent。
  • generate_ 给图表工具合并器。

7.3 可视化 MCP 的二次封装

src/agent/tools/chart_generator.py 把 26 个 generate_* 工具合并成一个:

text 复制代码
generate_visualization(chart_type, chart_config)

这样可以减少 Agent 工具列表长度,避免模型在 26 个相似工具里迷路。

它还把完整参数说明写入技能文件思路中:

text 复制代码
/skills/procurement/chart_params.md

子 Agent 不确定参数时先读取参考文件,再调用统一图表工具。

这是项目非常好的一个工程化亮点:工具太多时,用"统一入口 + 参数文档"降低上下文压力。


8. Skill 是怎么管理的

8.1 Skill 的形态

Skill 通常是一个目录:

text 复制代码
skill-name/
  SKILL.md
  scripts 或 data 或 .py 文件
  _meta.json 可选

SKILL.md 包含 frontmatter:

yaml 复制代码
---
name: procurement-analysis
description: ...
---

正文是给 Agent 读的操作手册。这个项目的 Skill 不是普通文档,而是"可执行工作流说明"。

8.2 预置 Skill 同步

SkillsSyncMiddleware 在每轮 Agent 运行前扫描本地:

text 复制代码
src/skills/

然后上传到沙箱:

text 复制代码
/skills/{scope}/...

它会计算文件 MD5,避免重复上传。

8.3 动态 Skill 管理

主 Agent 有 /skills/main/skill-management/ 技能,负责:

  1. 下载 ZIP 技能包。
  2. 解压到 /skills/main/{name}/
  3. 校验 SKILL.md
  4. 在沙箱内测试。
  5. 调用 assign_skill 分配给目标 Agent。
  6. 持久化到 StoreBackend。

对应工具是 src/agent/tools/assign_skill.py

8.4 Skill 分配与 scope

scope 映射在 src/agent/config.py

python 复制代码
SCOPE_MAP = {
    "main": "main",
    "procurement-analyst": "procurement",
    "procurement-order": "order",
}

分配后路径类似:

text 复制代码
/skills/procurement/web-scraper/
/skills/order/xxx/

子 Agent YAML 中配置:

yaml 复制代码
skills:
  - /skills/procurement/

这意味着新增技能只要进入对应 scope,子 Agent 就能通过渐进式读取发现它。

8.5 持久化与恢复

动态技能会写入 StoreBackend 的 ("skills",) namespace。下一轮运行时:

text 复制代码
UserSkillsRestoreMiddleware
  -> 从 StoreBackend asearch(("skills",))
  -> 上传回沙箱 /skills/{scope}/{skill_name}/...

所以技能生命周期是:

text 复制代码
本地预置 Skill -> 沙箱
用户动态 Skill -> /skills/main -> assign_skill -> /skills/{scope}
                            -> StoreBackend 持久化
下一轮会话 -> StoreBackend 恢复到沙箱

9. 状态怎么管理

项目状态分成五类。

9.1 对话 checkpoint

src/agent/config.py 使用:

python 复制代码
CHECKPOINTER = MongoDBSaver(...)

主 Agent 创建时传入:

python 复制代码
checkpointer=CHECKPOINTER

调用时使用 thread_id

python 复制代码
config = {
    "configurable": {
        "thread_id": "...",
        "user_id": "laoxiao"
    }
}

LangGraph 通过 MongoDB 保存每轮状态快照,因此可以继续会话、恢复中断、查看状态历史。

9.2 前端展示消息

LangGraph checkpoint 中的消息不一定适合直接展示,尤其子 Agent 和工具结果容易丢失顺序。因此 AgentLoader 额外使用 MongoDB 集合:

text 复制代码
session_display_messages

并且逐条消息保存,避免 MongoDB 单文档 16MB 限制。

这是一个很实用的工程处理:checkpoint 用于恢复执行,display messages 用于 UI 展示。

9.3 用户长期记忆

路径:

text 复制代码
/memories/{user_id}/preferences.md

CompositeBackend 路由到 StoreBackend

python 复制代码
"/memories/": StoreBackend(
    runtime=rt,
    namespace=lambda rt: (getattr(rt.runtime.context, "user_id", "laoxiao"),),
)

内容包括:

yaml 复制代码
preferred_output: chart
preferred_chart_type: bar
preferred_currency: CNY
preferred_language: zh
recent_suppliers: []
recent_queries: []

ContextInjectionMiddleware 会把用户 ID、用户名、偏好文件路径注入 system message。

MemoryUpdateMiddleware 在每轮 Agent 完成后自动提取供应商和查询摘要,更新 recent_suppliersrecent_queries

9.4 Skill 持久化状态

路径:

text 复制代码
/persisted-skills/

同样由 CompositeBackend 路由到 StoreBackend,namespace 是:

python 复制代码
SKILLS_STORE_NAMESPACE = ("skills",)

动态技能不会只留在当前沙箱里,而是持久化到 Store,后续由 UserSkillsRestoreMiddleware 恢复。

9.5 Human-in-the-Loop 中断状态

订单 Agent 有两层中断:

  1. 数据不完整时,调用 request_order_info()
  2. 执行 order_create / order_update 前,interrupt_on 触发人工审批。

request_order_info 使用:

python 复制代码
interrupt({
    "type": "order_info_request",
    "missing_fields": missing_fields,
    "collected_data": collected_data,
})

审批配置在 procurement_order.yaml

yaml 复制代码
interrupt_on:
  order_create:
    allowed_decisions: ["approve", "reject"]
  order_update:
    allowed_decisions: ["approve", "reject"]

FastAPI 检测到中断后返回 SSE interrupt 事件,前端展示 InterruptBanner。用户补充或审批后调用:

text 复制代码
POST /api/chat/{thread_id}/resume

后端用:

python 复制代码
Command(resume=resume_data)

恢复 LangGraph 执行。


10. 业务流程拆解

10.1 采购分析流程

text 复制代码
用户提出分析需求
  -> 主 Agent 判断为分析类任务
  -> 委派 procurement-analyst
  -> 子 Agent 扫描 /skills/procurement/
  -> 读取 procurement-analysis/SKILL.md
  -> 调 ERP MCP 查内部数据
  -> 读取 supplier-price-urls 映射
  -> web-scraper 抓外部报价
  -> Python 脚本分析
  -> generate_visualization 生成图表
  -> 写 /analysis/report_xxx.md
  -> 返回摘要和建议

适合学习点:

  • 如何用 Skill 固化分析流程。
  • 如何组合 ERP 结构化数据和外部网页数据。
  • 如何把多图表 MCP 工具压缩成统一工具。
  • 如何让子 Agent 产出文件而不是把大 JSON 塞回对话。

10.2 采购订单流程

text 复制代码
用户提出创建/修改订单
  -> 主 Agent 委派 procurement-order
  -> 子 Agent 提取订单字段
  -> Schema 校验
  -> 缺字段则 request_order_info 中断
  -> 用户补充后 resume
  -> 调用 order_create/order_update 前 HITL 审批
  -> 用户 approve/reject
  -> approve 后 MCP 调 Java ERP API
  -> 返回操作结果

适合学习点:

  • 如何在 Agent 中做关键操作审批。
  • 如何用自然语言补全结构化字段。
  • 如何把危险业务操作限制在专门子 Agent 内。

11. 复杂点与亮点统计

11.1 架构复杂点

编号 复杂点 说明
1 多系统组合 Python Agent、Vue 前端、MCP Server、Java ERP、MongoDB、OpenSandbox 同时工作
2 多 Agent 委派 主 Agent 只做协调,子 Agent 根据 YAML 动态加载工具和技能
3 MCP 双来源 同时接本地 ERP MCP 和远程可视化 MCP
4 状态分层 checkpoint、展示消息、用户记忆、技能持久化、沙箱文件分别管理
5 HITL 恢复 需要前端、FastAPI、LangGraph checkpoint、Command resume 协同
6 沙箱与 Store 路由 CompositeBackend/memories//persisted-skills/ 和普通文件分流
7 Skill 生命周期 预置同步、动态下载、测试、分配、持久化、恢复
8 工具结果展示 SSE 中要区分 token、tool call、tool result、子 Agent source
9 长上下文控制 DeepAgents offloading + summarization + 主动 compact
10 业务安全 订单创建/更新必须数据补齐和人工审批

11.2 工程亮点

  • create_main_agent() 的初始化分阶段很清晰,是学习 Agent 工程启动链路的好入口。
  • 子 Agent 用 YAML 配置,提示词、工具、技能路径、HITL 配置都可外置。
  • MCP 工具按前缀分组,能把不同能力分配给不同子 Agent。
  • generate_visualization 把 26 个图表工具合并成一个统一入口,显著降低工具选择复杂度。
  • CompositeBackend 路由设计很漂亮:沙箱负责临时执行,StoreBackend 负责记忆和技能持久化。
  • MemoryUpdateMiddleware 自动维护最近供应商和查询摘要,减少对 Agent 自觉性的依赖。
  • session_display_messages 单独保存 UI 消息,避免直接依赖 checkpoint 展示。
  • 订单流程实现了两类人工介入:信息补充和最终审批,适合真实业务系统。
  • Skill 采用 SKILL.md + 脚本 + 数据,让 Agent 能力可文档化、可迁移、可扩展。

11.3 当前风险与可改进点

  • src/mcp_server/tools/suppliers_tools.pysupplier_query 使用了未定义的 request_params,运行时大概率会报错,应改为 {"name": name}
  • src/agent/config.pysrc/api_view/web_config.py 中包含硬编码 MongoDB、OpenSandbox、模型服务地址和密码,生产环境应改为环境变量。
  • STORE = InMemoryStore() 会导致用户记忆和技能持久化只在进程内有效;若要跨进程/重启持久化,应换成 Redis/Mongo/Postgres 等持久 Store。
  • README.md 仍是 LangGraph 模板说明,未描述真实项目。
  • Java README 与 POM 版本不一致,容易误导部署。
  • requirements.txt 中有 -e e:\my_project\project30 这种本机路径,迁移环境可能失败。
  • 测试文件偏手动验证,缺少自动化集成测试覆盖 MCP 工具、Agent 委派、HITL resume。
  • MCP 工具错误返回多为字符串,不够结构化,Agent 解析时容易不稳定。

12. 推荐学习路线

按这个顺序读源码会比较顺:

  1. langgraph.json
  2. start_web.py
  3. src/api_view/web_main.py
  4. src/api_view/agent_loader.py
  5. src/agent/main_agent.py
  6. src/agent/config.py
  7. src/agent/memory/prompts.py
  8. src/agent/memory/AGENTS.md
  9. src/agent/subagents/configs/*.yaml
  10. src/agent/subagents/loader.py
  11. src/agent/tools/mcp_client.py
  12. src/mcp_server/server_main.py
  13. src/mcp_server/tools/*.py
  14. src/agent/middlewares/*.py
  15. src/skills/**/SKILL.md
  16. src/api_view/api/chat.py
  17. frontend/src/api/chat.js
  18. frontend/src/App.vue
  19. Java ERP 的 pom.xmlapplication.yml、controller/service/mapper

13. 五个重点问题速答

RAG 怎么搭建?

没有传统向量库 RAG。项目采用 Agentic RAG:通过 AGENTS.md、Skill 手册、MCP 工具、Web Search、网页抓取、用户记忆和沙箱文件来增强生成。

智能体怎么通信?

前端和后端通过 SSE 通信;主 Agent 和子 Agent 通过 DeepAgents task 工具委派;Agent 和外部系统通过 MCP 工具通信;中断恢复通过 LangGraph Command(resume=...)

MCP 怎么应用?

本地 FastMCP 把 Java ERP REST API 包装成 supplier_part_order_inventory_ 工具;Agent 端用 MultiServerMCPClient 加载;远程 ModelScope MCP 提供可视化工具。

Skill 怎么管理?

预置 Skill 从 src/skills 同步到沙箱;动态 Skill 先放 /skills/main,测试后用 assign_skill 分配到 /skills/{scope},再写入 StoreBackend,下次会话恢复。

状态怎么管理?

LangGraph checkpoint 用 MongoDB;前端展示消息单独存 MongoDB;用户偏好走 /memories/{user_id} StoreBackend;技能走 /persisted-skills StoreBackend;临时报告和脚本结果放 OpenSandbox 文件系统。


14. 一句话总结

这个项目的核心价值不在"某个单点算法",而在把多 Agent、MCP、Skill、沙箱、业务 API、记忆、HITL 和前端流式交互拼成了一个完整业务闭环。学习它时,建议重点看"能力如何被封装成工具和 Skill、状态如何跨轮保存、主 Agent 如何把复杂任务安全地委派出去"。

相关推荐
世间一点尘1 小时前
我让 Claude Code 修一个 Bug,它却重构了半个项目
人工智能
科技林总1 小时前
大模型分类测评指标清单
人工智能·可用性测试
为码消得人憔悴1 小时前
从零开始搭建 Obsidian 知识库
人工智能·aigc·agent
EMA1 小时前
MaxKB 技术解析文档
人工智能
湘美书院--湘美谈教育1 小时前
湘美谈教育AI赋能系列经验集锦:学好唐诗宋词的点滴心得体会
大数据·人工智能·深度学习·神经网络·机器学习
迦蓝叶1 小时前
【开源自荐】JAiRouter:一个轻量级 AI 模型服务网关的开源实践
java·人工智能·spring·开源·llm-gateway·mass
Java知识技术分享2 小时前
opencode安装ui-ux-pro-max和frontend-ui-ux技能
人工智能·ui·个人开发·ai编程·ux
苏映视官方账号2 小时前
精品案例丨方寸之间,“微” 毫毕现 —— 圆刀机高精度检测工艺优化实例
人工智能·数码相机·视觉检测·制造