面向采购业务的多用户、多 Agent 智能协作系统。项目将 Vue 3 聊天前端、FastAPI 聚合 API、DeepAgents/LangGraph 多 Agent 编排、FastMCP 业务工具、OpenSandbox 用户隔离沙箱、MongoDB 持久化和外部 Java ERP 数据源组合成一套完整的采购智能助手。
它不只是“给大模型接几个工具”:系统将简单问答、同步订单操作和耗时采购分析分成不同执行路径,对写操作加入两阶段 Human-in-the-Loop(HITL)保护,对长任务提供后台异步执行与前端状态追踪,并用“工具分组 + 26 合 1 + Skills 渐进加载 + 大结果文件卸载 + 对话摘要”共同控制上下文规模。
仓库边界:当前仓库包含 Agent、Web API、前端、MCP Server、OpenSandbox/MongoDB 编排和 MySQL 初始化数据,但不包含 Java ERP 源码。运行完整系统前,需要另行启动兼容本文接口的 Java ERP 服务(默认
http://127.0.0.1:8080/api)。
推荐Java ERP:https://github.com/KagaribiDev/java-erp
- 核心能力
- 总体架构
- 服务与端口
- 快速启动
- 完整启动方式
- 多 Agent 架构
- 异步 Agent 完整链路
- MCP 架构与上下文优化
- Middleware 中间件栈
- Skills 技能系统
- OpenSandbox 核心机制
- SSE 事件流与 HITL
- 认证与多用户隔离
- 存储架构
- 前端架构
- API 说明与示例
- 项目目录
- 测试与性能报告
- 如何扩展项目
- 生产部署建议
- 故障排查
- 已知边界
- 开源许可与贡献
开发者如需按目录逐文件复习实现,请阅读 代码库结构与复习指南。
- 多 Agent 分工:主 Agent 只负责理解、路由和汇总;采购订单与采购分析由专业子 Agent 执行。
- 同步与异步并存:订单操作走同步子 Agent;耗时分析通过 Agent Protocol 后台运行,立即返回
task_id。 - 真实 ERP 数据:本地 FastMCP 将 Java ERP REST API 转换为 8 个业务工具。
- 采购分析:支持供应商、零部件、历史订单、库存预警、外部价格和市场信息的联合分析。
- 可视化:对接第三方 MCP 的 26 类图表/地图/关系图,并统一成一个可路由工具。
- HITL 安全控制:缺少订单字段时暂停补充;真正创建或修改订单前再次请求批准/拒绝。
- 用户级沙箱:每个登录用户拥有独立 OpenSandbox,同一用户的多条会话共享自己的沙箱。
- 异步任务隔离:异步任务通过短时签名绑定
user_id + sandbox_id + task_id,报告写入任务专属目录。 - 自动恢复:沙箱失效后自动重建,并通过稳定代理热替换底层实例;连续错误触发熔断。
- 长上下文治理:MCP 分组、图表工具合并、Skills 渐进加载、工具大结果 offload、自动/主动摘要共同降低上下文成本。
- 多层持久化:MongoDB 保存账户、会话归属、LangGraph checkpoint、展示消息、长期记忆、技能、沙箱绑定和异步任务元数据。
- 实时前端:Vue 3 消费 SSE,实时渲染 token、工具调用、子 Agent 来源、HITL 中断和后台任务状态。
flowchart LR
U[浏览器用户] -->|Vue 3 / Fetch| FE[前端 :3000]
FE -->|JWT + REST/SSE| API[FastAPI Web API :8090]
API --> AUTH[认证与会话归属]
API --> LOADER[AgentLoader]
LOADER --> MAIN[主 Agent Graph]
MAIN --> ORDER[同步 procurement-order]
MAIN -->|start_async_task| PROTO[Agent Protocol :2024]
PROTO --> ANALYST[异步 procurement-analyst]
ORDER --> MCP[FastMCP ERP Server :8000]
ANALYST --> MCP
MCP -->|HTTP| JAVA[外部 Java ERP :8080]
JAVA --> MYSQL[(MySQL motorparts_db)]
MAIN --> CHART[第三方可视化 MCP]
ANALYST --> CHART
MAIN --> SEARCH[智谱 Web Search]
ANALYST --> SEARCH
LOADER --> SANDBOX[OpenSandbox Server :8100]
SANDBOX --> S1[用户 A 沙箱]
SANDBOX --> S2[用户 B 沙箱]
API --> MONGO[(MongoDB :27017)]
MAIN --> MONGO
PROTO --> MONGO
一次普通请求的核心路径如下:
sequenceDiagram
participant B as Browser
participant F as FastAPI
participant L as AgentLoader
participant S as User Sandbox
participant A as Main Agent
participant M as MCP/ERP
B->>F: POST /api/chat/stream + JWT
F->>F: 校验 JWT 与 thread 所有权
F->>L: get_agent_for_user(user_id)
L->>S: 获取/重连/创建用户沙箱
L->>A: 创建绑定该沙箱的请求级 Graph
A-->>B: SSE token/tool_start/tool_args
A->>M: 委派子 Agent 并调用业务工具
M-->>A: 真实 ERP 结果
A-->>B: SSE tool_result/token/done
F->>F: 保存 checkpoint 与展示消息
| 服务 | 默认地址 | 作用 | 启动方式 |
|---|---|---|---|
| Vue 前端 | http://127.0.0.1:3000 |
登录、聊天、历史、工具面板、HITL、异步任务抽屉 | npm run dev 或 start_web.py |
| FastAPI Web API | http://127.0.0.1:8090 |
认证、会话、SSE、任务查询、Agent 生命周期 | uvicorn 或 start_web.py |
| LangGraph Agent Protocol | http://127.0.0.1:2024 |
异步采购分析 thread/run 执行 | langgraph dev 或 start_web.py |
| FastMCP ERP Server | http://127.0.0.1:8000/mcp |
将 Java ERP REST API 暴露为 MCP 工具 | 独立启动 |
| Java ERP(外部) | http://127.0.0.1:8080/api |
供应商、零件、库存、订单业务数据源 | 由外部 Java 项目启动 |
| OpenSandbox | http://127.0.0.1:8100 |
创建、连接、销毁隔离执行容器 | Docker Compose |
| MongoDB | mongodb://127.0.0.1:27017 |
Agent、会话、用户、技能、任务持久化 | Docker Compose |
| MySQL(外部) | 通常 127.0.0.1:3306 |
Java ERP 业务数据库 | 使用 motorparts_db.sql 初始化 |
注意:start_web.py 会启动 Agent Protocol、FastAPI 和前端,但不会启动 Docker、Java ERP 或 FastMCP。FastMCP 必须在 FastAPI 初始化 Agent 前可用,否则核心 ERP 工具加载会失败。
- Python
3.11+(pyproject.toml要求<4.0) - Node.js
18+与 npm - Docker Desktop / Docker Engine,支持 Docker Compose v2
- MySQL 8(SQL 文件来源版本为 8.0.21)
- 一个兼容的 Java ERP 服务,监听
127.0.0.1:8080 - DeepSeek/OpenAI 兼容模型服务密钥
- 智谱 API Key(用于 Web Search)
Windows 是当前主要开发环境;Linux/macOS 也可运行,但需将虚拟环境激活命令替换为对应平台写法。
推荐使用 uv:
uv sync或使用标准虚拟环境:
python -m venv .venv
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
# Linux/macOS
source .venv/bin/activate
pip install -r requirements.txt在项目根目录创建 .env。不要把真实密钥提交到 GitHub。
# 主模型与摘要模型使用 OpenAI-compatible 接口
DEEPSEEK_API_KEY=your_deepseek_compatible_api_key
DEEPSEEK_BASE_URL=https://your-provider.example.com/v1
# web_search 工具
ZHIPU_API_KEY=your_zhipu_api_key
# 生产环境必须更换,并保证 Web API 与 Agent Protocol 进程一致
JWT_SECRET_KEY=replace-with-a-long-random-secret
# 可选覆盖
MONGODB_URI=mongodb://root:123456@127.0.0.1:27017/?authSource=admin
ASYNC_AGENT_PROTOCOL_URL=http://127.0.0.1:2024
JWT_EXPIRE_HOURS=12
SANDBOX_IMAGE=erp-openclaw-sandbox:v1
SANDBOX_RUNTIME_INSTALL_FALLBACK=false
APP_ENV=development当前模型名称在 src/agent/core/config.py 中配置:
- 主模型:
deepseek-v4-pro - 摘要模型:
deepseek-v4-flash - 备用模型:
glm-5.1(当前主流程未自动切换到备用模型)
如果你的服务商没有这些模型名,请在 src/agent/core/config.py 中替换为其 OpenAI-compatible 模型名称。
当前项目同时存在环境变量配置和代码常量配置。使用默认本地端口时无需调整;部署到远程主机或修改账号时,应同时检查下表,避免只改 .env 但某个子系统仍连接旧地址。
| 配置 | 默认值/是否必需 | 读取位置 | 说明 |
|---|---|---|---|
DEEPSEEK_API_KEY |
必需 | agent/core/env_utils.py |
主模型和摘要模型密钥 |
DEEPSEEK_BASE_URL |
必需 | agent/core/env_utils.py |
OpenAI-compatible base URL |
ZHIPU_API_KEY |
Web Search 必需 | agent/core/env_utils.py |
智谱搜狗搜索工具 |
ZHIPU_BASE_URL |
仅备用模型需要 | agent/core/env_utils.py |
GLM OpenAI-compatible URL |
JWT_SECRET_KEY |
有开发默认值 | web_config.py、core/async_sandbox_claims.py |
登录 JWT 与异步沙箱 claim 共用;生产必须覆盖 |
JWT_EXPIRE_HOURS |
12 |
web_config.py |
登录 token 有效期 |
ASYNC_AGENT_PROTOCOL_URL |
http://127.0.0.1:2024 |
graphs/main_agent.py、api/tasks.py |
启动和查询异步任务 |
MONGODB_URI |
本地 root URI | web_config.py |
认证、展示消息、沙箱管理和任务 API |
SANDBOX_IMAGE |
erp-openclaw-sandbox:v1 |
sandbox_setup.py |
新沙箱镜像 |
SANDBOX_RUNTIME_INSTALL_FALLBACK |
false |
sandbox_setup.py |
是否允许损坏环境现场装包 |
APP_ENV |
development |
graphs/main_agent.py |
production 时日志写入 erp_agent.log |
目前以下连接信息仍是代码常量:
| 常量 | 默认值 | 文件 |
|---|---|---|
| Java ERP base URL | http://127.0.0.1:8080/api |
src/mcp_server/server_config.py |
| 本地 ERP MCP URL | http://127.0.0.1:8000/mcp |
src/agent/tools/mcp_client.py |
| 第三方分析 MCP URL | ModelScope MCP URL | src/agent/tools/mcp_client.py |
| OpenSandbox URL | http://127.0.0.1:8100 |
src/agent/core/config.py |
| Agent Store/checkpoint Mongo URI | 本地 root URI | src/agent/core/config.py |
| 模型名称与参数 | deepseek-v4-pro/flash |
src/agent/core/config.py |
特别注意:MONGODB_URI 环境变量由 Web API 配置读取,但 Agent 的 MongoDBStore 和 MongoDBSaver 当前仍使用 src/agent/core/config.py 中的 URI 常量。若不使用默认 MongoDB 地址,必须同步修改该常量,或在二次开发时将它统一改为读取同一个环境变量。
docker compose -f docker/docker-compose.yml up -d --build
docker compose -f docker/docker-compose.yml ps首次执行会构建 erp-openclaw-sandbox:v1。该镜像预装 pandas、numpy、matplotlib、requests、BeautifulSoup、lxml 和 markdownify,避免每个新用户首次使用时在线安装依赖。
健康检查:
curl http://127.0.0.1:8100/health
docker compose -f docker/docker-compose.yml exec mongodb mongosh --quiet \
-u root -p 123456 --authenticationDatabase admin \
--eval "db.adminCommand('ping')"- 创建 MySQL 数据库并导入 motorparts_db.sql:
mysql -u root -p < motorparts_db.sql- 启动兼容的 Java ERP,确保基础地址为:
http://127.0.0.1:8080/api
- 至少需要实现 MCP 所依赖的这些 REST API:
| 方法 | 路径 | 用途 |
|---|---|---|
GET |
/suppliers/search?name= |
模糊查询供应商 |
GET |
/parts/page |
分页/条件查询零部件 |
GET |
/parts/search?name= |
按名称查询零部件 |
GET |
/parts/supplier/{id} |
查询供应商对应零部件 |
GET |
/inventory/warning |
查询库存预警 |
GET |
/orders/search-details |
查询订单明细 |
POST |
/orders/create |
创建采购订单 |
PUT |
/orders/update/{id} |
更新采购订单 |
验证示例:
curl "http://127.0.0.1:8080/api/parts/search?name=火花塞"python src/mcp_server/server_main.pyMCP Server 使用一个生命周期级 httpx.AsyncClient 连接池访问 Java ERP,避免每次工具调用重新建立连接。
另开终端,在项目根目录执行:
uv run python start_web.py启动器会依次:
- 启动
langgraph dev,等待http://127.0.0.1:2024/ok; - 启动 FastAPI,等待
http://127.0.0.1:8090/health; - 检查并安装前端依赖,然后启动 Vite;
- 在
Ctrl+C时停止这三个子进程。
浏览器打开:
http://127.0.0.1:3000
API 文档:
- FastAPI:
http://127.0.0.1:8090/docs - Agent Protocol:
http://127.0.0.1:2024/docs
需要分别观察日志或部署到不同主机时,可以手工启动各服务。
langgraph dev --host 127.0.0.1 --port 2024 \
--no-browser --no-reload --allow-blockinglanggraph.json 将图 procurement_analyst_async 映射到:
./src/agent/graphs/async_analyst.py:create_procurement_analyst
Windows PowerShell:
$env:PYTHONPATH = "$PWD\src"
python -m uvicorn api_view.web_main:app --host 127.0.0.1 --port 8090Linux/macOS:
PYTHONPATH=src python -m uvicorn api_view.web_main:app \
--host 127.0.0.1 --port 8090cd frontend
npm install
npm run devVite 将 /api 代理到 http://localhost:8090。
# 保留 MongoDB/OpenSandbox 命名卷
docker compose -f docker/docker-compose.yml down
# 危险:同时删除 MongoDB 和 OpenSandbox 持久化卷
docker compose -f docker/docker-compose.yml down -v| Agent | 执行方式 | 责任 | 主要工具 |
|---|---|---|---|
| 主 Agent | 请求内同步 | 理解意图、读取偏好、任务路由、结果汇总、技能管理、普通问答 | task、异步任务工具、web_search、assign_skill、文件工具 |
procurement-order |
同步子 Agent | 订单查询、字段校验、信息补充、创建/修改和审批 | 订单 MCP、request_order_info、web_search |
procurement-analyst |
Agent Protocol 后台异步 | 库存、供应商、行情、比价、成本评估、图表和报告 | 分析 MCP、可视化、Web Search、采购 Skills、沙箱文件系统 |
主 Agent 的关键原则是“协调者,不是业务执行者”。涉及 ERP 数据的分析任务必须交给分析 Agent;订单意图必须交给订单 Agent。这样可以限制每个 Agent 所见工具,降低误调用概率,并让提示词、Skills 和调用上限按业务独立配置。
AgentLoader.initialize() 在 FastAPI 启动时只做一次重操作:
- 初始化 MongoDB 与沙箱管理器;
- 连接 MCP Server 并加载工具;
- 将 26 个图表工具合并成统一入口;
- 读取子 Agent YAML;
- 启动一个后台预热沙箱。
这些结果存入 PrecomputedContext。每次用户请求只执行轻量的请求级 Graph 创建:获取该用户稳定沙箱代理、构建 CompositeBackend、创建沙箱相关工具、组装 Middleware,并调用 create_deep_agent()。
这一设计同时满足:
- MCP 工具不在每个请求中重复发现;
- 每个请求仍能绑定正确用户的沙箱和上下文;
- 沙箱重建后 Graph 与工具引用不失效;
- 不同用户不会共用同一个执行容器。
子 Agent 位于 src/agent/subagents/configs/:
procurement_order.yamlprocurement_analyst.yaml
每个配置包含 name、description、system_prompt、tools、可选 skills、model、interrupt_on。loader.py 根据工具名称子串解析实际工具对象并去重。
新增子 Agent 时,不需要把长系统提示词塞进 graphs/main_agent.py;新增 YAML 后,再决定它是同步加入主 Graph,还是像分析 Agent 一样发布成独立 Agent Protocol graph。
订单流程:
flowchart TD
A[用户提出订单需求] --> B[主 Agent 委派 procurement-order]
B --> C{必填字段齐全?}
C -- 否 --> D[request_order_info 中断]
D --> E[用户补充自由文本]
E --> C
C -- 是 --> F[准备 order_create/order_update]
F --> G{HITL 最终审批}
G -- reject --> H[终止,不写 ERP]
G -- approve --> I[调用 MCP 写入 Java ERP]
I --> J[校验并返回订单结果]
第一层中断用于补齐 partId、quantity、unitPrice 等必要信息;第二层 interrupt_on 在执行 order_create 或 order_update 前要求用户批准。中断状态由 MongoDB checkpoint 保存,因此一次 HTTP 流结束后可以通过 /resume 接着执行。
耗时采购分析不能阻塞主对话。项目使用 DeepAgents AsyncSubAgentMiddleware 与 LangGraph Agent Protocol 实现后台任务。
sequenceDiagram
participant U as 用户
participant M as 主 Agent
participant W as Web API/Middleware
participant P as Agent Protocol
participant A as Async Analyst
participant S as 用户私有沙箱
participant DB as MongoDB
participant F as 前端
U->>M: 请求库存分析/比价/报告
M->>W: start_async_task(description)
W->>P: 创建 thread + run
W->>W: 签名 user_id+sandbox_id+task_id
W->>DB: 保存 async_tasks 元数据
W-->>M: task_id
M-->>U: 立即返回任务 ID
P->>A: 创建 procurement_analyst graph
A->>A: 验证 sandbox_claim
A->>S: 连接原用户沙箱并续期 2 小时
A->>S: mkdir /analysis/tasks/{task_id}
A->>S: 查询、分析、生成报告
loop 每 5 秒
F->>W: GET /api/tasks
W->>P: 查询 run 状态/最终 thread state
W-->>F: running/success/error + result
end
task_id 同时是 Agent Protocol 的 thread ID,也是任务工作目录标识。主对话只负责启动任务并立即返回,不在同一轮里等待或反复查询。用户可以继续聊天;前端右侧抽屉每 5 秒刷新任务状态,完成后自动显示结果。
中间件保留标准异步工具集:
start_async_task:启动任务;list_async_tasks:列出当前 Graph 跟踪的任务;check_async_task:检查状态与结果;update_async_task:追加要求,并用multitask_strategy="interrupt"更新运行;cancel_async_task:取消任务。
项目替换了标准 start_async_task 和 update_async_task 的实现,用于注入可信用户/沙箱绑定;其余任务工具沿用框架实现。
浏览器和模型都不能任意指定 sandbox_id。Web 后端使用 JWT_SECRET_KEY 生成 6 小时有效的 HS256 claim,包含:
sub/user_id + sandbox_id + task_id + purpose + iat + exp
Agent Protocol 必须验证:
- 签名正确;
purpose == async-user-sandbox;- claim 中的
task_id与当前任务一致; - 用户和沙箱标识非空。
验签后才连接沙箱。每个任务只能写入 /analysis/tasks/{task_id}/,从而形成“用户级容器隔离 + 任务级目录隔离”两层边界。
async_tasks 集合记录 task_id、user_id、sandbox_id、run_id、状态和时间。GET /api/tasks 只按 JWT 用户查询,并向 Agent Protocol 刷新状态。对于功能上线前创建的旧任务,系统还会从该用户的展示消息中提取历史 UUID 并迁移元数据。
src/mcp_server/server_main.py 使用 FastMCP 的 Streamable HTTP 传输发布 8 个工具:
| 分组前缀 | 工具 | Java ERP 映射 | 写操作 |
|---|---|---|---|
supplier_ |
supplier_query |
GET /suppliers/search |
否 |
part_ |
part_query |
GET /parts/page |
否 |
part_ |
part_search |
GET /parts/search |
否 |
part_ |
part_by_supplier |
GET /parts/supplier/{id} |
否 |
inventory_ |
inventory_warning |
GET /inventory/warning |
否 |
order_ |
order_search_details |
GET /orders/search-details |
否 |
order_ |
order_create |
POST /orders/create |
是,受 HITL 保护 |
order_ |
order_update |
PUT /orders/update/{id} |
是,受 HITL 保护 |
MCP lifespan 只创建一个 httpx.AsyncClient,配置最大 100 个连接和 20 个 keep-alive 连接;每个工具通过 Context 获取这个客户端。
Agent 客户端按名称前缀分组:
分析类:supplier_* / part_* / inventory_*
订单类:order_*
图表类:generate_*
然后只把匹配的工具交给对应子 Agent。分组的价值不仅是代码整洁,还包括:
- 减少模型每次决策时看到的工具数量;
- 缩短工具 Schema 占用的上下文;
- 避免分析 Agent 获得订单写权限;
- 降低名称相似工具之间的误选择概率。
第三方分析 MCP 通常返回 27 个 generate_* 工具,其中 26 个是图表、地图和关系图,另一个是 spreadsheet。直接把 26 套完整 JSON Schema 全部放进模型上下文会带来明显的 token 浪费。
chart_generator.py 的处理方式:
- 启动时读取第三方工具;
- 将
generate_bar_chart、generate_line_chart等映射到chart_type; - 对外只暴露:
generate_visualization(chart_type, chart_config)
- 工具描述中只保留约一页的紧凑速查;
- 完整参数说明存放在
/skills/procurement/chart_params.md; - Agent 只有在不确定参数时才读取该文件;读取一次后可连续生成多张图。
支持的可视化包括柱状图、折线图、饼图、面积图、雷达图、箱线图、直方图、漏斗图、桑基图、瀑布图、词云、地图、流程图、网络图、鱼骨图和思维导图等。
项目不是依赖单一摘要机制,而是分层治理:
| 层级 | 机制 | 作用 |
|---|---|---|
| 工具发现 | MCP 仅在启动时预计算一次 | 避免每次请求重复拉取和解析 Schema |
| 工具权限 | 按业务前缀分组 | 每个 Agent 只看到必要工具 |
| 工具数量 | 26 个图表工具合并成 1 个路由工具 | 大幅减少工具描述长度 |
| 参数文档 | 完整 Schema 写入 Skill 文件 | 用到时再加载,渐进式披露 |
| 工具结果 | DeepAgents 自动 offload 大于约 20k token 的结果 | 上下文仅保留文件路径和预览 |
| 对话历史 | 上下文接近约 85% 时自动摘要 | 防止长会话超过模型窗口 |
| 主动压缩 | compact_conversation |
子 Agent 返回长报告后主动压缩 |
| 最终交付 | 报告/图表写入沙箱文件 | 回复只返回摘要、结论和路径 |
| 调用上限 | Model/Tool Call Limit | 防止循环调用导致成本和上下文失控 |
第三方可视化 MCP 不可用时,启动流程会降级图表能力并保留 ERP 核心工具;本地 ERP MCP 加载失败则视为核心依赖失败。
主 Agent 按以下顺序组装 Middleware:
| 顺序 | Middleware | 作用 |
|---|---|---|
| 1 | SandboxHealthMiddleware |
请求前执行 echo ok,失败时自动重建用户沙箱并重新上传 AGENTS.md |
| 2 | ContextInjectionMiddleware |
把可信 user_id、用户名和偏好路径注入系统消息 |
| 3 | SkillsSyncMiddleware |
计算本地技能文件 MD5,只上传新增/变化内容 |
| 4 | UserSkillsRestoreMiddleware |
从用户私有 Store namespace 恢复动态技能到沙箱 |
| 5 | SummarizationToolMiddleware |
自动摘要,并提供 compact_conversation 主动摘要工具 |
| 6 | MemoryUpdateMiddleware |
ERP 对话后用摘要模型提取供应商与查询主题,更新长期记忆 |
| 7 | SandboxCircuitBreakerMiddleware |
连续沙箱工具错误达到阈值后跳转结束,阻止无限恢复循环 |
| 8 | AsyncSubAgentMiddleware |
提供后台任务工具并注入签名用户/沙箱绑定 |
| 9 | ModelCallLimitMiddleware |
主运行最多 50 次模型调用 |
| 10 | ToolCallLimitMiddleware |
主运行最多 200 次工具调用 |
订单子 Agent 另有更紧的上限:20 次模型调用、50 次工具调用。分析 Agent 的提示词、Skills 和异步进程承担长任务,不占用主聊天请求。
MemoryUpdateMiddleware 只处理有采购含义的对话:
- 找最后一条用户消息;
- 跳过问候和无意义模式;
- 检查采购关键词或子 Agent 调用;
- 使用摘要模型提取供应商和查询摘要;
- 合并最近 10 个供应商、最近 5 条查询;
- 写回用户偏好文件。
内部摘要调用带 internal-memory-update tag,SSE 桥会过滤这些 token,避免把维护用 JSON 泄漏给用户。
Skills 不是一次性塞进 system prompt 的长文本,而是沙箱中的文件化操作手册。Agent 先发现技能目录,再按任务读取具体 SKILL.md 和脚本。
| Agent | Scope | 沙箱路径 |
|---|---|---|
| 主 Agent | main |
/skills/main/ |
procurement-analyst |
procurement |
/skills/procurement/ |
procurement-order |
order |
/skills/order/ |
仓库预置技能:
| 技能 | 用途 |
|---|---|
skill-management |
下载/创建、验证、分配和持久化用户技能 |
procurement-analysis |
采购分析五步流程、图表选择和报告模板 |
supplier-price-urls |
供应商/零件到报价页面的 URL 映射 |
web-scraper |
在沙箱内直接抓取页面并转换为 Markdown |
web-content-fetcher |
常规抓取失败时使用第三方 Markdown 转换服务 |
flowchart LR
LOCAL["src/skills 预置技能"] -->|SkillsSyncMiddleware| SB["/skills/... 沙箱"]
USER["用户下载/创建技能"] --> TEST["沙箱内测试"]
TEST --> ASSIGN["assign_skill"]
ASSIGN --> STORE[(MongoDB Store)]
STORE -->|UserSkillsRestoreMiddleware| SB
- 预置技能:来自仓库
src/skills/,新沙箱初始化时播种,运行前通过 MD5 增量同步。 - 用户技能:先进入
/skills/main/{name},在沙箱内测试,通过后复制到目标 scope,并持久化到("users", user_id, "skills")namespace。
- 下载 ZIP 或由 Agent 创建
SKILL.md; - 在沙箱内检查 frontmatter、语法和脚本入口;
- 通过
assign_skill(skill_name, agent_name)分配; - 持久化每个技能文件;
- 清理压缩包;
- 新会话开始时自动恢复到同一用户沙箱。
未验证的技能代码不在宿主机执行。需要额外依赖时,安装发生在用户沙箱的 /opt/skills-venv 中。
沙箱机制是本项目最重要的安全和可靠性基础。
DeepAgents 可以执行 shell、Python、文件读写和技能脚本。如果直接在 Web API 宿主机运行,模型生成的命令可能接触应用源码、密钥、其他用户文件和系统进程。OpenSandbox 把这些能力放进独立 Docker 容器中,并通过受控 SDK 暴露 execute/read/write/edit/upload/download。
Docker Compose 中的 opensandbox-server:
- 宿主机
8100映射容器内8090; - 挂载
/var/run/docker.sock创建沙箱容器; - 使用
opensandbox.toml配置 Docker runtime; - 状态保存到
opensandbox-data命名卷中的 SQLite; - 默认 bridge 网络;
- 端口范围
40000-60000; - 启用
no_new_privileges; - 丢弃
NET_ADMIN、NET_RAW、SYS_ADMIN、SYS_PTRACE等高风险 capabilities; - 每个容器
pids_limit=4096。
本地开发通过 OPENSANDBOX_INSECURE_SERVER=YES 允许无 API Key 启动。该模式不能直接暴露到公网。
每个用户一个沙箱,同一用户的多条聊天 thread 共享它。生命周期状态:
stateDiagram-v2
[*] --> MemoryCache: 已在进程缓存
MemoryCache --> Ready: ping 成功
MemoryCache --> Recreate: ping 失败
[*] --> MongoReconnect: MongoDB 有 sandbox_id
MongoReconnect --> Ready: connect + ping 成功
MongoReconnect --> Recreate: 过期/不可达
[*] --> WarmReserve: 新用户且预热池可用
WarmReserve --> Ready: 认领并持久化
[*] --> Create: 无记录且无预热沙箱
Create --> Ready
Recreate --> Ready: 创建新实例并更新 MongoDB
关键实现:
sandbox_registry保存user_id -> sandbox_id;- 每个用户有独立异步锁,避免并发请求重复创建;
- 服务启动时预热一个沙箱;新用户认领后后台补充新的预热实例;
- 老用户优先重连自己的持久化沙箱,绝不会错误认领预热实例覆盖绑定;
- Web API 关闭时只清理本地连接和预热实例,已分配用户沙箱保留以供重启重连。
Graph、工具和 CompositeBackend 都持有沙箱对象引用。如果底层容器过期后简单创建新对象,旧引用仍会指向失效容器。
SandboxBackendProxy 显式代理 SandboxBackendProtocol 的同步/异步方法,并提供:
replace_backend(new_backend)
恢复时只替换代理内部 backend,Graph、工具和 Middleware 继续使用同一个稳定代理对象。这让沙箱健康恢复对上层透明。
docker/sandbox-image/Dockerfile 基于 OpenSandbox Code Interpreter 镜像构建:
- Python 3.11 venv:
/opt/skills-venv; - 预装分析/抓取依赖;
- 预创建
/analysis/temp、/analysis/tasks、/data; - 写入镜像 marker;
- 非交互 shell 执行时把 Python、Node、Go、Java 路径注入
PATH。
每个新沙箱默认资源:2 CPU、4 GiB 内存、2 小时 TTL。创建后只做 marker/import 快速检查。只有显式设置 SANDBOX_RUNTIME_INSTALL_FALLBACK=true 才允许依赖损坏时现场安装;生产环境建议保持 false,让错误快速暴露。
主 Agent 使用 CompositeBackend:
| 虚拟路径 | 实际后端 | 隔离方式 | 用途 |
|---|---|---|---|
默认路径,如 /analysis、/data、/skills |
用户 OpenSandbox | 每用户独立容器 | 脚本、报告、图表、技能运行 |
/memories/ |
MongoDB StoreBackend |
namespace 为用户 ID | 长期偏好和近期业务记忆 |
/persisted-skills/ |
MongoDB StoreBackend |
users/{user_id}/skills |
用户动态技能跨会话恢复 |
对 Agent 来说它们都是文件路径;对系统来说,执行文件在沙箱,长期数据在 MongoDB。这避免沙箱 TTL 到期后丢失记忆和已安装技能。
- 每轮前
echo ok健康检查; - 失败则创建新沙箱;
- 通过稳定代理热替换;
- 重新播种目录、Skills、Python 环境和
AGENTS.md; - 更新 MongoDB 中的实际 sandbox ID;
- 连续沙箱错误达到阈值时熔断并结束本轮,避免无限循环。
聊天请求需要 POST body、JWT、实时 token、工具进度和中断事件。前端使用 fetch + ReadableStream 消费 text/event-stream,而不是浏览器 EventSource,因为 EventSource 不方便发送 POST JSON 和 Authorization header。
后端调用:
agent.astream(
stream_mode=["messages", "values"],
subgraphs=True,
version="v2"
)
messages 流用于 token/工具渲染,values 流用于检测 LangGraph interrupt。subgraphs=True 允许同步子 Agent 的输出进入同一条 SSE;namespace 中的 tools:{subagent} 用于标记消息来源。
每个事件格式为:
data: {JSON}\n\n
type |
关键字段 | 前端行为 |
|---|---|---|
token |
content, source |
追加主 Agent/子 Agent 文本 |
tool_start |
tool_call_id, tool_name, source |
创建工具调用卡片 |
tool_args |
args, source |
流式追加工具参数 |
tool_result |
text, images, source |
填充工具结果与图片 |
tool_end |
tool_call_id, tool_name |
将工具状态标记为完成 |
interrupt |
interrupt_type, 业务字段 |
显示补充信息或审批 UI |
done |
thread_id, content, interrupted |
结束加载状态并保存会话 |
error |
message |
显示错误 |
后端维护工具调用栈,支持“主 Agent 调子 Agent、子 Agent 再调 MCP”的嵌套结构。工具结果不会重复作为 AI token 输出。
两种中断:
order_info_supplement:展示缺失字段和已收集数据,用户输入自由文本;hitl_approval:展示待执行的订单动作,用户选择 approve 或 reject。
恢复请求:
{"resume": {"supplement": "物料 ID=1,数量=10,单价=12.5"}}或:
{"resume": {"decisions": [{"type": "approve"}]}}后端使用 Command(resume=...) 从 MongoDB checkpoint 恢复原 Graph,而不是启动一个新对话。
LangGraph checkpoint 保存可恢复的执行状态,但前端还需要主/子 Agent 来源、工具参数、图片和调用状态。项目将完整展示消息逐条写入 session_display_messages:
- 每条消息一个 MongoDB 文档,避免整段会话逼近 16 MB;
- 单字段超过 500,000 字符时截断;
- 中断时也保存当前 UI 状态;
- 历史页优先读取展示消息,旧会话可回退 checkpoint 序列化逻辑。
- 用户保存在 MongoDB
users; - 用户名允许 3-32 位中文、字母、数字、下划线或连字符;
- 密码要求 8-128 位;
- 使用
hashlib.scrypt,参数N=16384, r=8, p=1,每个用户随机 16 字节 salt; - 登录成功签发 HS256 JWT,默认 12 小时;
- 前端把 token 保存到
sessionStorage,浏览器标签页会话结束后失效; - 收到 401 时前端清除 token 并回到登录页。
| 数据/能力 | 隔离键 |
|---|---|
| 用户账户 | MongoDB _id |
| 会话访问 | session_owners.thread_id + user_id |
| Checkpoint | thread_id,访问前额外校验 owner |
| 展示消息 | thread_id + user_id |
| 长期记忆 | Store namespace (user_id,) |
| 动态 Skills | ("users", user_id, "skills") |
| OpenSandbox | sandbox_registry.user_id |
| 异步任务 | async_tasks.user_id + 签名 claim |
| 异步文件 | 用户沙箱 + /analysis/tasks/{task_id} |
客户端不能通过请求体覆盖 user_id。所有身份都来自已验证 JWT;复用其他用户的 thread_id 会被拒绝。
默认数据库:langchain_db。
| 集合 | 内容 | 关键索引/特点 |
|---|---|---|
users |
用户名、显示名、scrypt 密码哈希、状态 | username_normalized 唯一 |
session_owners |
thread 与用户归属 | thread_id 唯一;用户+更新时间索引 |
checkpoints |
LangGraph 对话状态、HITL 中断状态 | 由 MongoDBSaver 管理 |
checkpoint_writes 等 |
checkpoint 增量写入 | 由 LangGraph MongoDB saver 管理 |
session_display_messages |
前端需要的完整消息和工具状态 | 每条消息独立文档,按 thread/index 排序 |
store_items |
用户长期记忆与动态技能 | namespace_path + key 唯一 |
sandbox_registry |
用户与 OpenSandbox ID 的稳定绑定 | user_id 唯一 |
async_tasks |
异步任务元数据与最终状态 | task_id 唯一;用户+创建时间索引 |
自定义 MongoDBStore 使用 JSON 标量 namespace_path,而不是直接对 namespace 数组建立复合唯一索引。这样 ("users", "A", "skills") 和 ("users", "B", "skills") 不会因共享数组元素而发生 MongoDB multikey 唯一索引冲突。
当前 Store 实现支持精确 namespace/filter 查询,不提供向量语义搜索。
- OpenSandbox 服务自身状态:Docker 命名卷
opensandbox-data; - 每用户执行文件:对应沙箱容器生命周期内;
- 需要长期保存的偏好和 Skills:转存 MongoDB;
- 后端下载的报告:宿主机
src/download/。
motorparts_db.sql 包含:
customer, inventory, logistics, order_detail,
part, purchase_order, supplier, user
该数据库属于外部 Java ERP,不与 Agent 的 MongoDB 混用。MCP Server 是两套系统之间的边界适配层。
| Key | 存储 | 作用 |
|---|---|---|
erp_agent_access_token |
sessionStorage |
当前登录 JWT |
erp_async_tasks_collapsed |
localStorage |
记住后台任务抽屉展开/收起状态 |
前端采用 Vue 3 Composition API,无额外状态管理库。
主要组件:
| 组件 | 作用 |
|---|---|
App.vue |
认证状态、会话、SSE、任务轮询、中断恢复的总协调 |
AuthScreen.vue |
注册/登录 |
Sidebar.vue |
用户信息、会话搜索、切换、新建和删除 |
ChatArea.vue |
混合渲染用户、Agent 和工具消息 |
MessageItem.vue |
单条消息展示 |
ToolCallPanel.vue |
工具名称、参数、结果和图片 |
InterruptBanner.vue |
数据补充与订单审批 |
AsyncTaskPanel.vue |
右侧可收缩后台任务抽屉 |
InputArea.vue |
发送、停止、显示/隐藏工具调用 |
MarkdownRenderer.vue |
Markdown、代码高亮和结果内容 |
异步任务面板每 5 秒请求 /api/tasks。展开时固定在画面右侧并独立滚动;收起后只保留任务数量入口,不参与聊天区域布局。
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
POST |
/api/auth/register |
否 | 注册并返回 JWT |
POST |
/api/auth/login |
否 | 登录并返回 JWT |
GET |
/api/auth/me |
是 | 获取当前用户 |
POST |
/api/chat/stream |
是 | 新消息 SSE 流 |
POST |
/api/chat/{thread_id}/resume |
是 | 恢复 HITL 中断 |
GET |
/api/chat/{thread_id} |
是 | 当前 checkpoint 消息 |
GET |
/api/chat/{thread_id}/history |
是 | Graph 状态历史 |
GET |
/api/history |
是 | 当前用户会话列表 |
GET |
/api/history/{thread_id}/messages |
是 | 前端展示消息 |
DELETE |
/api/history/{thread_id} |
是 | 删除会话及消息 |
PATCH |
/api/history/{thread_id} |
是 | 标题更新预留接口 |
GET |
/api/tasks |
是 | 当前用户异步任务状态与结果 |
GET |
/health |
否 | Web API 健康检查 |
curl -X POST http://127.0.0.1:8090/api/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"demo_user","password":"DemoPass2026","display_name":"演示用户"}'响应:
{
"access_token": "<JWT>",
"token_type": "bearer",
"expires_in": 43200,
"user": {
"user_id": "<MongoDB ObjectId>",
"username": "demo_user",
"display_name": "演示用户"
}
}curl -N -X POST http://127.0.0.1:8090/api/chat/stream \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"message":"查询当前库存预警并给出采购建议","thread_id":null}'典型事件:
data: {"type":"token","content":"我会启动后台分析任务。","source":"main"}
data: {"type":"tool_start","tool_call_id":"...","tool_name":"start_async_task","source":"main"}
data: {"type":"done","thread_id":"...","content":"..."}
curl http://127.0.0.1:8090/api/tasks?limit=50 \
-H "Authorization: Bearer <JWT>"curl -N -X POST http://127.0.0.1:8090/api/chat/<THREAD_ID>/resume \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"resume":{"supplement":"物料 ID=1,数量=10,单价=12.5"}}'curl -N -X POST http://127.0.0.1:8090/api/chat/<THREAD_ID>/resume \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"resume":{"decisions":[{"type":"approve"}]}}'procurepilot/
├── docker/
│ ├── docker-compose.yml # MongoDB、OpenSandbox、沙箱镜像编排
│ ├── opensandbox.toml # OpenSandbox Docker runtime/security 配置
│ └── sandbox-image/ # 项目专用预构建沙箱镜像
├── docs/ # 联调、压力与多用户 API 文档
├── frontend/
│ ├── src/api/ # auth/chat/history/tasks API 客户端
│ ├── src/components/ # Vue UI 组件
│ └── src/App.vue # 前端总状态协调
├── reports/ # 自动化基准 JSON/Markdown 报告
├── scripts/
│ ├── run_benchmark.py # 健康、并发、可选 SSE 基准
│ ├── generate_report.py # JSON 转 Markdown 报告
│ ├── run_agent_smoke.py # Agent 交互式冒烟诊断
│ └── run_mcp_smoke.py # MCP/Agent 客户端连接诊断
├── src/
│ ├── agent/
│ │ ├── backends/ # OpenSandbox adapter、proxy、生命周期
│ │ ├── core/ # 配置、环境变量、Schema 与异步签名
│ │ ├── graphs/ # 主 Graph 与异步分析 Graph Factory
│ │ ├── memory/ # 主提示词与 AGENTS.md
│ │ ├── middlewares/ # 上下文、记忆、Skills、沙箱、异步等
│ │ ├── stores/ # MongoDB Store 与异步任务元数据
│ │ ├── subagents/configs/ # YAML 子 Agent
│ │ └── tools/ # MCP 客户端、图表路由、HITL、下载等
│ ├── api_view/
│ │ ├── api/ # FastAPI 路由
│ │ ├── agent_loader.py # 请求级 Graph 与会话管理
│ │ └── auth_service.py # scrypt + JWT
│ ├── mcp_server/ # Java ERP -> FastMCP 适配层
│ └── skills/ # 预置 Skills 和脚本
├── tests/ # 单元、隔离、API、SSE、MCP 与 Agent 集成测试
├── langgraph.json # Agent Protocol graph 配置
├── motorparts_db.sql # 外部 Java ERP 的 MySQL 业务数据
├── pyproject.toml # Python 包与依赖声明
├── requirements.txt # uv 导出的固定依赖
├── start_web.py # 三服务一键启动器
└── README.md
不启动外部服务也可以执行:
pytest -q默认配置会排除 integration 和 live 测试,只运行 sandbox claim、Skills 隔离、MongoDB namespace 和沙箱环境检查等离线回归测试。
先确保 MongoDB、OpenSandbox、Java ERP、MCP 和 Web API 已启动。
pytest tests -m integration该命令覆盖认证、未授权拒绝和 MCP 只读查询。认证测试会创建随机 qa_auto_* 用户;在共享环境运行后应按测试账号前缀清理。
pytest tests -m "not integration and not live"其中包含:
- 异步 sandbox claim 防重放;
- 用户 Skills namespace 隔离;
- MongoDB Store namespace 索引;
- 沙箱预构建环境;
- MCP 工具;
- 用户/任务沙箱绑定。
默认跳过,避免无意消耗模型额度:
Windows PowerShell:
$env:RUN_LIVE_LLM_TESTS = "1"
pytest tests/test_sse_stream.py -m live -sLinux/macOS:
RUN_LIVE_LLM_TESTS=1 pytest tests/test_sse_stream.py -m live -s写测试会真实创建/修改 Java ERP 数据,必须显式开启:
$env:RUN_ERP_WRITE_TESTS = "1"
pytest tests/test_all_tools.py -m integration -s建议只在可回滚测试库运行。
cd frontend
npm run build只读 HTTP 基准:
python scripts/run_benchmark.py --concurrency 5 --samples 10包含真实模型/SSE:
python scripts/run_benchmark.py --concurrency 2 --samples 5 --include-llm生成 Markdown:
python scripts/generate_report.py reports/benchmark-YYYYMMDD-HHMMSS.json仓库现有验收报告见:
截至 2026-08-21 的一次真实只读基准:10/10 成功,平均约 0.107 秒,P95 约 0.155 秒。该数字只代表当次本地环境,不应作为生产 SLA。
- 在
src/mcp_server/tools/选择或新增业务分组文件; - 用
@mcp.tool(name="group_action")定义工具; - 从
ctx.request_context.lifespan_context获取共享http_client; - 在
server_main.py注册分组; - 如果属于现有前缀,
mcp_client.py会自动分组;否则增加新的前缀规则; - 在对应子 Agent YAML 的
tools中添加名称模式; - 增加只读测试,写工具同时接入 HITL。
推荐命名规则:
supplier_* 供应商
part_* 零部件
inventory_* 库存
order_* 订单
- 在
src/agent/subagents/configs/新建 YAML; - 填写职责、工具模式、系统提示词和 Skills scope;
- 如需专属 Middleware,在
middlewares/factories.py创建工厂; - 在
graphs/main_agent.py的extra_middleware中绑定; - 确保主 Agent 提示词中有明确路由规则;
- 运行工具解析和真实对话测试。
- 在 YAML 中定义该 Agent 的工具与提示词;
- 新建 Agent Protocol graph factory;
- 在
langgraph.json注册 graph ID; - 为任务建立可信用户资源 claim;
- 创建 task 专属工作目录;
- 在主 Agent 中配置 AsyncSubAgent spec 和启动规则;
- 把任务元数据写入用户级存储并提供前端查询 API。
不能只把同步 Agent 放到后台线程:可靠的异步任务还需要独立 thread/run、状态持久化、取消/更新、资源绑定和结果恢复。
src/skills/{scope}/{skill-name}/SKILL.md
SKILL.md 至少包含:
---
name: your-skill
description: 何时使用、解决什么问题
---可以附带 Python/Shell 脚本和 data/ 文件。新沙箱会自动播种;已有沙箱在下一轮由 SkillsSyncMiddleware 增量同步。
在 src/agent/core/config.py 调整 MAIN_MODEL 和 SUMMARY_MODEL。主模型需要可靠的 tool calling;摘要模型应使用低温度、低成本配置。修改上下文长度时,同时重新评估自动摘要阈值、工具调用上限和供应商接口的 max_tokens。
- Checkpoint:替换
MongoDBSaver; - 长期 KV:实现 LangGraph
BaseStore; - 语义记忆:为
search(query=...)接入向量检索; - 异步任务:保持
task_id + user_id访问边界,不要只依赖前端过滤。
当前默认配置面向本地开发。上线前至少完成以下事项:
- 更换 MongoDB 默认账号密码和
JWT_SECRET_KEY; .env加入.gitignore,确认 Git 历史中没有密钥;- OpenSandbox 配置
api_key,移除OPENSANDBOX_INSECURE_SERVER=YES; - 不把 Docker socket 暴露给非受信任服务;
- 启用并收紧 OpenSandbox
network_policy,默认拒绝不必要的外联; - 将 FastAPI CORS 从
*改为真实前端域名; - 所有服务置于 TLS 反向代理之后;
- 审计 Skills 来源,未验证技能不得分配给生产用户;
- 对 MCP 写工具继续保留 HITL,不允许主 Agent 直接获得写工具。
当前 start_web.py 使用 langgraph dev,适合本地开发,不是生产任务平台。生产环境应:
- 使用带持久化队列的 Agent Protocol 部署;
- 配置多个 worker;
- 为任务服务增加认证;
- 定义重试、超时、死信和取消策略;
- 持久化 run/thread 状态;
- 监控任务成功率、排队时长和执行时长。
- 固定
opensandbox/server、execd 和 egress 镜像版本,避免latest漂移; - 把
erp-openclaw-sandbox:v1推送到私有镜像仓库; - 为 CPU、内存、磁盘、进程数和网络设置租户配额;
- 对过期容器和孤儿容器建立定时清理;
- 为
sandbox_registry与真实容器状态建立巡检。
- 反向代理关闭 SSE buffering;Nginx 需保持
proxy_buffering off; - 增大长任务相关的读取超时,但不要无限超时;
- Web API 多实例部署时,进程内 Agent/沙箱缓存不能作为唯一状态源;
- 会话归属、checkpoint、任务和沙箱映射必须继续落到共享 MongoDB;
- 对
/api/tasks轮询增加退避或改为服务端推送,以降低大规模用户下的查询压力。
建议至少采集:
- HTTP/SSE 请求量、首 token 延迟、完整响应耗时;
- 模型调用次数、token、失败率和费用;
- MCP 各工具调用次数、P95、错误率;
- 异步任务排队、运行、成功、取消、超时;
- 沙箱创建、预热命中、自动重建、熔断;
- MongoDB checkpoint/store 延迟与容量;
- Java ERP 写操作审批通过率和失败原因。
检查:
curl http://127.0.0.1:8080/api/parts/search?name=火花塞
python src/mcp_server/server_main.py确认 MCP 地址仍是 http://127.0.0.1:8000/mcp。本地 ERP MCP 是核心依赖,必须先于 FastAPI 启动。
系统会降级到无图表模式,ERP 查询仍应正常。检查网络和 src/agent/tools/mcp_client.py 中的第三方 URL。不要把第三方临时故障误判为 Java ERP 故障。
docker compose -f docker/docker-compose.yml ps
docker compose -f docker/docker-compose.yml logs -f opensandbox-server
curl http://127.0.0.1:8100/health还应确认 Docker socket 挂载、项目镜像 erp-openclaw-sandbox:v1 存在,以及 Docker Desktop 可以创建容器。
重新构建镜像:
docker compose -f docker/docker-compose.yml build sandbox-image
docker compose -f docker/docker-compose.yml up -d开发排障可临时设置:
SANDBOX_RUNTIME_INSTALL_FALLBACK=true
生产环境不建议依赖现场安装。
默认连接:
mongodb://root:123456@127.0.0.1:27017/?authSource=admin
如果 MongoDB 命名卷已经存在,修改 Compose 中的初始化账号不会重置旧账号。请使用原凭据,或在确认不需要数据后重建卷。
- 检查
sessionStorage中的 token 是否过期; - 重新登录;
- 确认前端
/api代理指向 8090; - 确认所有 Web API 实例使用同一
JWT_SECRET_KEY。
- 检查代理是否缓冲
text/event-stream; - 保留
X-Accel-Buffering: no; - 使用
curl -N验证; - 检查模型服务和 MCP 是否仍有未完成调用;
- 查看系统临时目录下的
deepagent_debug/stream_*.log。
依次检查:
http://127.0.0.1:2024/ok;- Agent Protocol 日志;
/api/tasks返回的status_error;- 用户 sandbox ID 是否仍有效;
- 分析报告是否写入
/analysis/tasks/{task_id}/; - 开发版 Agent Protocol 是否因单 worker 排队。
创建/修改订单需要两步:字段齐全,然后 approve。选择 reject 或尚未恢复 HITL 时,系统按设计不会写入。检查 SSE 中是否收到 hitl_approval,以及恢复请求是否使用正确 thread ID。
这是 Vite 的体积警告,不影响功能。生产优化可对 Markdown/highlight 依赖和大型组件使用动态 import,并配置 Rollup manualChunks。
- 当前仓库没有 Java ERP 源码;完整复现需要外部服务实现约定 REST API。
langgraph dev是开发运行时,异步任务的生产持久性和水平扩展需要独立部署方案。MongoDBStore没有语义向量搜索,只适合当前确定路径/namespace 的记忆和技能访问。- OpenSandbox 本地配置未开启 API Key,且网络策略示例仍处于注释状态。
- 异步任务前端目前使用 5 秒轮询,不是 WebSocket/SSE 主动推送。
- FastAPI CORS 当前允许所有来源,只适合本地开发。
- 后端文件下载工具把文件保存到
src/download/,当前没有独立的鉴权文件下载 HTTP 路由;对公网提供下载前应增加用户/任务归属校验。 - 会话标题 PATCH 是预留接口,当前不会真正持久化自定义标题。
- 前端主 bundle 仍有进一步拆包空间。
procurepilot 的自有代码采用 MIT License。Java ERP、第三方 MCP、模型服务、外部 API 和素材仍分别受其自身许可与服务条款约束,不因本仓库使用 MIT License 而改变。
- 参与开发前请阅读 CONTRIBUTING.md。
- 安全问题请按 SECURITY.md 私密报告,不要在公开 Issue 中披露利用细节或真实凭据。
- 本地配置请从 .env.example 复制;
.env与任何真实密钥都不应提交到 Git。