文档基于 2026-08-21 的当前成品代码整理。它面向“以后重新阅读项目时,能快速知道代码在哪里、为什么存在、从哪里开始追踪”这一目标。
本文描述的是当前仓库中的实际实现。
.venv/、node_modules/、dist/、缓存、真实.env和src/download/等本地运行产物不属于源码目录树。
第一次复习项目时,建议依次阅读:
- 本文的“系统全景”和“六条核心调用链”,先建立全局心智模型。
src/api_view/agent_loader.py,理解 Web 请求如何获得当前用户的 Agent 和沙箱。src/agent/graphs/main_agent.py,理解主 Agent、同步子 Agent、Middleware、Store 和沙箱如何组装。src/agent/middlewares/user_async_subagents.py与src/agent/graphs/async_analyst.py,理解异步分析闭环。src/agent/backends/,理解本项目最核心的用户级 OpenSandbox 机制。src/mcp_server/,理解 Agent 如何访问 Java ERP。src/api_view/api/chat.py与frontend/src/api/chat.js,从后端到浏览器追踪 SSE 事件。frontend/src/App.vue,理解前端状态机、HITL 恢复和任务轮询。
如果只想定位某个功能,可以直接跳到“按需求定位代码”章节。
procurepilot 是一个多用户、多 Agent 的采购协作系统。浏览器只连接 FastAPI;FastAPI 负责认证、会话归属、SSE 和用户 Agent 生命周期;Agent 通过 MCP 访问 Java ERP,通过 OpenSandbox 执行代码和文件操作,通过 MongoDB 保存会话、记忆、技能、任务和沙箱绑定。
flowchart LR
B[Vue 3 浏览器] -->|JWT + REST/SSE| W[FastAPI :8090]
W --> L[AgentLoader]
L --> M[主 Agent Graph]
M -->|同步 task| O[procurement-order]
M -->|start_async_task| P[Agent Protocol :2024]
P --> A[procurement-analyst]
O --> E[FastMCP ERP :8000/mcp]
A --> E
E -->|HTTP REST| J[外部 Java ERP :8080/api]
J --> Y[(MySQL)]
M --> S[用户私有 OpenSandbox]
A --> S
S --> OS[OpenSandbox Server :8100]
W --> D[(MongoDB :27017)]
M --> D
P --> D
| 服务 | 默认端口 | 代码入口 | 主要职责 |
|---|---|---|---|
| Vue 前端 | 3000 | frontend/src/main.js |
登录、聊天、历史、工具调用、HITL、异步任务抽屉 |
| FastAPI Web API | 8090 | src/api_view/web_main.py |
JWT、会话隔离、SSE、任务查询、Agent 生命周期 |
| LangGraph Agent Protocol | 2024 | langgraph.json |
执行异步采购分析 graph/thread/run |
| FastMCP ERP Server | 8000 | src/mcp_server/server_main.py |
把 Java ERP REST API 转换成 MCP 工具 |
| Java ERP | 8080 | 外部项目,不在本仓库 | 供应商、零件、库存、采购订单业务接口 |
| OpenSandbox Server | 宿主机 8100 | docker/docker-compose.yml |
创建和连接用户隔离执行容器 |
| MongoDB | 27017 | Docker Compose | 用户、checkpoint、展示消息、Store、任务、沙箱绑定 |
| MySQL | 通常 3306 | motorparts_db.sql |
Java ERP 的业务数据库 |
| Agent | 所在进程 | 执行方式 | 主要责任 |
|---|---|---|---|
| 主 Agent | FastAPI 进程 | 请求内同步 | 理解意图、读偏好、路由任务、汇总结果、管理技能 |
procurement-order |
主 Graph 的同步子 Agent | 同步 task |
查询、创建、修改采购订单;执行两层 HITL |
procurement-analyst |
Agent Protocol 进程 | 后台异步 run | ERP/外部数据收集、采购分析、图表和报告生成 |
主 Agent 是协调者。订单操作必须委派给订单子 Agent;耗时分析必须通过 start_async_task 发往 Agent Protocol,不能用同步 task 阻塞聊天请求。
以下是源码提交视角的目录树。锁文件、SQL 和图片等也列出,但依赖目录、编译缓存和真实密钥文件被排除。
procurepilot/
├── .env.example
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── langgraph.json
├── motorparts_db.sql
├── pyproject.toml
├── pytest.ini
├── requirements.txt
├── start_web.py
├── uv.lock
│
├── docker/
│ ├── docker-compose.yml
│ ├── opensandbox.toml
│ ├── README.md
│ └── sandbox-image/
│ ├── Dockerfile
│ └── requirements-sandbox.txt
│
├── docs/
│ ├── CODEBASE_GUIDE.md
│ ├── agent-backend-stress-test-report.md
│ └── frontend-multi-user-api.md
│
├── frontend/
│ ├── index.html
│ ├── package.json
│ ├── package-lock.json
│ ├── vite.config.js
│ ├── public/assets/
│ │ ├── whale-girl-hero.png
│ │ └── whale-girl-logo.png
│ └── src/
│ ├── main.js
│ ├── App.vue
│ ├── api/
│ │ ├── auth.js
│ │ ├── chat.js
│ │ ├── client.js
│ │ ├── history.js
│ │ └── tasks.js
│ ├── components/
│ │ ├── AsyncTaskPanel.vue
│ │ ├── AuthScreen.vue
│ │ ├── ChatArea.vue
│ │ ├── InputArea.vue
│ │ ├── InterruptBanner.vue
│ │ ├── MarkdownRenderer.vue
│ │ ├── MessageItem.vue
│ │ ├── Sidebar.vue
│ │ └── ToolCallPanel.vue
│ ├── config/assets.js
│ └── styles/main.css
│
├── reports/
│ ├── benchmark-20260821-141746.json
│ ├── benchmark-20260821-141746.md
│ ├── benchmark-20260821-141814.json
│ ├── benchmark-20260821-141814.md
│ ├── benchmark-20260821-141913.json
│ └── benchmark-20260821-141913.md
│
├── scripts/
│ ├── generate_report.py
│ ├── run_benchmark.py
│ ├── run_agent_smoke.py
│ └── run_mcp_smoke.py
│
├── src/
│ ├── agent/
│ │ ├── __init__.py
│ │ ├── core/
│ │ │ ├── __init__.py
│ │ │ ├── async_sandbox_claims.py
│ │ │ ├── config.py
│ │ │ ├── env_utils.py
│ │ │ └── schema.py
│ │ ├── graphs/
│ │ │ ├── __init__.py
│ │ │ ├── async_analyst.py
│ │ │ └── main_agent.py
│ │ ├── backends/
│ │ │ ├── __init__.py
│ │ │ ├── custom_opensandbox.py
│ │ │ ├── sandbox_manager.py
│ │ │ ├── sandbox_proxy.py
│ │ │ └── sandbox_setup.py
│ │ ├── memory/
│ │ │ ├── __init__.py
│ │ │ ├── AGENTS.md
│ │ │ └── prompts.py
│ │ ├── middlewares/
│ │ │ ├── __init__.py
│ │ │ ├── context_injection.py
│ │ │ ├── factories.py
│ │ │ ├── memory_update.py
│ │ │ ├── sandbox_breaker.py
│ │ │ ├── sandbox_health.py
│ │ │ ├── skills_sync.py
│ │ │ ├── tools_summarization.py
│ │ │ ├── user_async_subagents.py
│ │ │ └── user_skills_restore.py
│ │ ├── stores/
│ │ │ ├── __init__.py
│ │ │ ├── async_task_store.py
│ │ │ └── mongodb_store.py
│ │ ├── subagents/
│ │ │ ├── __init__.py
│ │ │ ├── loader.py
│ │ │ └── configs/
│ │ │ ├── __init__.py
│ │ │ ├── procurement_analyst.yaml
│ │ │ └── procurement_order.yaml
│ │ └── tools/
│ │ ├── __init__.py
│ │ ├── assign_skill.py
│ │ ├── chart_generator.py
│ │ ├── download_sandbox_file.py
│ │ ├── hitl_tools.py
│ │ ├── mcp_client.py
│ │ └── web_search.py
│ │
│ ├── api_view/
│ │ ├── __init__.py
│ │ ├── agent_loader.py
│ │ ├── auth_service.py
│ │ ├── web_config.py
│ │ ├── web_main.py
│ │ └── api/
│ │ ├── __init__.py
│ │ ├── auth.py
│ │ ├── chat.py
│ │ ├── history.py
│ │ └── tasks.py
│ │
│ ├── mcp_server/
│ │ ├── __init__.py
│ │ ├── http_base.py
│ │ ├── server_config.py
│ │ ├── server_main.py
│ │ └── tools/
│ │ ├── __init__.py
│ │ ├── inventory_tools.py
│ │ ├── order_tools.py
│ │ ├── parts_tools.py
│ │ └── suppliers_tools.py
│ │
│ ├── skills/
│ │ ├── main/skill-management/
│ │ │ ├── SKILL.md
│ │ │ └── scripts/download_skill.py
│ │ └── procurement/
│ │ ├── chart_params.md
│ │ ├── procurement-analysis/SKILL.md
│ │ ├── supplier-price-urls/
│ │ │ ├── SKILL.md
│ │ │ └── data/url_mapping.yaml
│ │ ├── web-content-fetcher/
│ │ │ ├── SKILL.md
│ │ │ ├── _meta.json
│ │ │ ├── fetch.sh
│ │ │ └── fetch_content.py
│ │ └── web-scraper/
│ │ ├── SKILL.md
│ │ ├── _meta.json
│ │ └── scrape_page.py
└── tests/
├── conftest.py
├── test_all_tools.py
├── test_async_sandbox_binding.py
├── test_auth_isolation.py
├── test_mcp_integration.py
├── test_mongodb_store_namespace.py
├── test_sandbox_prebuilt_environment.py
├── test_sse_stream.py
└── test_user_skill_isolation.py
python start_web.py
├─ 启动 langgraph dev :2024
│ └─ langgraph.json 加载 procurement_analyst_async graph
├─ 等待 /ok
├─ 启动 uvicorn api_view.web_main:app :8090
│ └─ FastAPI lifespan
│ ├─ initialize_auth()
│ ├─ sandbox_manager.initialize()
│ ├─ precompute_agent_context()
│ └─ 后台预热一个 OpenSandbox
├─ 等待 /health
└─ 启动 Vite :3000
start_web.py 不负责启动 Docker、Java ERP 和 FastMCP。它们必须提前可用,尤其 FastMCP 必须在 FastAPI 预计算 MCP 工具前启动。
AuthScreen.vue
→ frontend/src/api/auth.js
→ POST /api/auth/register 或 /api/auth/login
→ auth_service.py
├─ 用户名规范化
├─ scrypt 密码哈希/校验
├─ MongoDB users 集合
└─ 签发 HS256 JWT
→ token 保存到浏览器 sessionStorage
→ 后续 authFetch 自动添加 Authorization: Bearer
每次访问会话时还会通过 session_owners 校验 thread_id + user_id。浏览器传入别人的 thread ID 不能绕过后端归属检查。
App.vue handleSend()
→ streamChat()
→ POST /api/chat/stream
→ chat_stream()
├─ 生成/接收 thread_id
├─ claim_thread(thread_id, user_id)
└─ stream_chat_response()
├─ get_agent_for_user()
│ ├─ ensure_sandbox_for_user()
│ └─ create_main_agent()
├─ agent.astream(..., subgraphs=True, stream_mode=[messages, values])
├─ 转换 token/tool/interrupt 为 SSE
└─ 保存 session_display_messages
→ frontend/src/api/chat.js 解析 SSE
→ App.vue 更新 messages
→ ChatArea/MessageItem 渲染
flowchart TD
U[用户提出订单操作] --> M[主 Agent]
M -->|同步 task| O[procurement-order]
O --> C{必填字段齐全?}
C -- 否 --> R[request_order_info interrupt]
R --> F[前端 InterruptBanner 补充自由文本]
F -->|POST /resume| O
C -- 是 --> H{order_create/update HITL 审批}
H -- reject --> X[结束且不写 ERP]
H -- approve --> MCP[调用 FastMCP]
MCP --> J[Java ERP 写操作]
第一层由 hitl_tools.py 主动调用 interrupt();第二层由订单 YAML 中的 interrupt_on 自动拦截真正的写工具。前端统一通过 InterruptBanner.vue 收集补充或审批,并由 resumeChat() 恢复同一 LangGraph thread。
主 Agent 判断为耗时分析
→ start_async_task(description, procurement-analyst)
→ user_async_subagents.py
├─ Agent Protocol 创建 thread
├─ task_id = thread_id
├─ 创建 user_id + sandbox_id + task_id 的短期签名 claim
├─ 创建 run,目标 graph_id=procurement_analyst_async
└─ async_tasks 集合保存任务元数据
→ 主 Agent 立即向用户返回 task_id
Agent Protocol 进程
→ langgraph.json
→ async_analyst.create_procurement_analyst(config)
├─ 校验 claim,取得可信 user_id/sandbox_id
├─ 连接并续期同一用户沙箱
├─ 创建 /analysis/tasks/{task_id}/
├─ 加载采购分析工具、Skills 与提示词
└─ 后台执行分析并写入任务专属目录
浏览器
→ 每 5 秒 GET /api/tasks
→ tasks.py 查询 Agent Protocol run 状态和最终 thread messages
→ AsyncTaskPanel.vue 自动显示执行中/成功/失败
这里的 Agent Protocol 不是“只转发命令的网关”,而是异步 graph 的执行和 run/thread 管理服务。真正的文件与命令操作仍由异步 Agent 通过 OpenSandbox 客户端发送给用户沙箱。
ensure_sandbox_for_user(user_id)
├─ 内存命中 → echo ok → 直接返回
├─ MongoDB sandbox_registry 有绑定 → connect(sandbox_id)
│ ├─ 成功 → 更新实际 ID 并返回
│ └─ 失败/过期 → 创建替代沙箱
├─ 新用户且有预热沙箱 → 认领预热实例
└─ 否则 → 创建新沙箱
创建/重连后
├─ 包装为 OpenSandboxBackend
├─ 包装为 SandboxBackendProxy 稳定句柄
├─ 创建 /analysis/temp、/analysis/tasks、/data
├─ 同步预置 Skills
└─ 检查 /opt/skills-venv 预装依赖
SandboxBackendProxy 是关键设计:Graph 和工具始终持有同一个代理对象;沙箱失效重建时只替换代理内部 backend,因此不需要重建所有引用。
| 文件 | 作用 | 复习重点 |
|---|---|---|
.env.example |
无真实密钥的环境变量模板 | 模型密钥、JWT、MongoDB、Agent Protocol、沙箱镜像和测试端点 |
.gitignore |
排除密钥、依赖、缓存、构建产物、日志和下载文件 | .env 被忽略而 .env.example 被保留;src/download/ 不提交 |
README.md |
对外项目说明和部署/架构总文档 | 面向使用者;本文则面向代码复习 |
CONTRIBUTING.md |
贡献流程、验证命令和 PR 清单 | 强调 QA 数据清理、ERP 写测试显式开启 |
SECURITY.md |
漏洞报告方式和生产安全边界 | 沙箱、Docker Socket、CORS、密钥、ERP 写权限 |
LICENSE |
MIT License | 仅覆盖本项目自有代码,第三方服务与素材仍受自身条款约束 |
pyproject.toml |
Python 项目元数据、依赖、构建和 Ruff 配置 | 分发名 procurepilot;包发现覆盖 agent/api_view/mcp_server |
uv.lock |
uv 的完整可复现依赖锁 | 不手工修改,由 uv lock/uv sync 维护 |
requirements.txt |
pip 安装依赖快照 | 标准虚拟环境安装路径;版本应与 pyproject/uv.lock 协调 |
pytest.ini |
pytest 发现范围和 marker 声明 | 默认只跑离线测试;integration 需要外部服务,live 还需要真实模型服务 |
langgraph.json |
Agent Protocol graph 注册 | 把 procurement_analyst_async 指向 graphs/async_analyst.py:create_procurement_analyst |
start_web.py |
Windows/本地一键启动器 | 启动顺序、健康等待、日志转发和 Ctrl+C 清理 |
motorparts_db.sql |
Java ERP 的 MySQL 示例结构与数据 | 包含 customer、inventory、logistics、order_detail、part、purchase_order、supplier、user 八张表 |
真实 .env 只存在于本地,绝不能写入文档、日志或提交。项目当前并非所有连接配置都统一读取环境变量;复习配置时需要同时看 agent/core/config.py、api_view/web_config.py、mcp_server/server_config.py 和 tools/mcp_client.py。
| 文件 | 作用 | 关键内容 |
|---|---|---|
docker/docker-compose.yml |
编排 MongoDB、OpenSandbox Server 和一次性沙箱镜像构建任务 | MongoDB 命名卷、OpenSandbox 状态卷、Docker Socket、8100/27017 端口 |
docker/opensandbox.toml |
OpenSandbox Server 配置 | Docker runtime、bridge 网络、动态端口范围、capability drop、no-new-privileges、SQLite 状态库 |
docker/README.md |
Docker 子系统启动与排障说明 | 构建镜像、健康检查、数据卷和 Mongo URI |
docker/sandbox-image/Dockerfile |
构建项目专用 Code Interpreter 镜像 | 创建 /opt/skills-venv,安装依赖,创建分析目录并写镜像 marker |
docker/sandbox-image/requirements-sandbox.txt |
沙箱内部 Python 依赖锁 | pandas、numpy、matplotlib、requests、BeautifulSoup、lxml、markdownify |
开发配置目前使用 OPENSANDBOX_INSECURE_SERVER=YES,并将宿主机 Docker Socket 挂入 OpenSandbox Server。它适合可信本机开发,不应原样暴露公网。
| 文件 | 作用 | 关键对象/逻辑 |
|---|---|---|
web_main.py |
FastAPI 应用入口 | lifespan() 初始化认证、AgentLoader;注册 auth/chat/history/tasks 路由;提供 /health |
web_config.py |
Web API 配置 | MongoDB、JWT、API 元信息和若干历史路径常量 |
auth_service.py |
MongoDB 用户认证和 JWT 解析 | AuthenticatedUser、scrypt 哈希、注册/登录、get_current_user 依赖 |
agent_loader.py |
Web 与 Agent 之间的核心生命周期层 | 单例、启动预计算、按用户取沙箱、请求级 Graph、会话归属、展示消息持久化 |
__init__.py |
Python 包标记 | 无运行逻辑 |
AgentLoader 不把一个全局 Graph 共享给所有用户。它在启动阶段只缓存与用户无关的 MCP 工具和 YAML 配置;每个请求调用 get_agent_for_user() 时,根据用户获取稳定沙箱代理并创建请求级 Graph。
主要数据操作:
session_owners:保存 thread 所属用户,阻止跨用户访问。checkpoints:由 LangGraph/MongoDBSaver 保存 Graph 状态。session_display_messages:保存前端真正显示的 user/assistant/tool 混合消息。- 删除会话时同时删除 checkpoint、展示消息和归属记录。
- 每条展示消息独立存为一个文档,并对大文本字段截断,规避 MongoDB 16 MB 单文档上限。
| 文件 | 路由 | 作用 |
|---|---|---|
api/auth.py |
/api/auth/register、/login、/me |
Pydantic 请求校验、调用认证服务、返回 token 与公开用户信息 |
api/chat.py |
/api/chat/stream、/{thread_id}/resume、状态与 history |
将 LangGraph 流转换成 SSE;处理工具调用栈、子 Agent 来源、图片、中断和展示消息 |
api/history.py |
/api/history、/{thread_id}/messages、DELETE、PATCH |
会话列表、展示消息读取、旧 checkpoint 序列化、删除、预留标题更新 |
api/tasks.py |
/api/tasks |
按用户列出异步任务,向 Agent Protocol 刷新 run 状态并读取最终结果 |
api/__init__.py |
Python 包标记 | 无运行逻辑 |
chat.py 是整个 SSE 链路最重要的后端文件。它使用 stream_mode=["messages", "values"]:messages 用于 token 和工具事件,values 用于发现 LangGraph interrupt。subgraphs=True 让同步子 Agent 的消息也进入流。
| 文件 | 作用 | 关键内容 |
|---|---|---|
graphs/main_agent.py |
主 Agent Graph Factory | PrecomputedContext、precompute_agent_context()、create_main_agent() |
graphs/async_analyst.py |
Agent Protocol 异步采购分析 graph 工厂 | 校验 sandbox claim、连接同一用户沙箱、创建任务目录、构建 analyst |
core/async_sandbox_claims.py |
异步沙箱绑定签名 | 6 小时 HS256 claim;绑定 user_id + sandbox_id + task_id + purpose |
core/config.py |
模型、Mongo Store/checkpointer、沙箱与路径常量 | MAIN/SUMMARY/FALLBACK 模型,OpenSandbox 客户端配置,MongoDBStore/MongoDBSaver |
core/env_utils.py |
从 .env 读取模型相关环境变量 |
OpenAI、DeepSeek、智谱、MiniMax、阿里、K2、Daytona 等兼容配置 |
middlewares/factories.py |
子 Agent Middleware 工厂 | analyst 的摘要/调用限制;order 的模型/工具调用限制 |
core/schema.py |
运行时上下文、偏好、消息、会话和 SSE 类型 | ProcurementContext 是 Graph 的 context schema |
memory/prompts.py |
主 Agent 精简系统提示词 | 协调者角色、订单/分析路由、偏好文件和摘要要求 |
memory/AGENTS.md |
上传到沙箱的完整全局行为准则 | 委派模板、记忆规则、技能管理、安全边界和文件策略 |
__init__.py、core/__init__.py、graphs/__init__.py、memory/__init__.py |
包标记 | 无运行逻辑 |
backend_factory创建CompositeBackend。- 默认路径走用户 OpenSandbox。
/memories/路由到 StoreBackend,按用户保存长期偏好。/persisted-skills/路由到用户私有技能 namespace。- 上传
AGENTS.md到当前用户沙箱。 - 使用启动期缓存的 MCP、图表和 YAML 配置。
- 创建与当前沙箱绑定的
assign_skill、download_sandbox_file。 - 只把
procurement-order作为同步子 Agent;analyst 被排除并改走异步 Middleware。 - 创建主 Middleware 栈,再调用
create_deep_agent()。
主 Agent 的工具参数里只显式传入通用工具;同步子 Agent 工具由 subagents 配置持有;异步任务工具由 Middleware 注入。
| 文件 | 作用 | 关键点 |
|---|---|---|
custom_opensandbox.py |
将 OpenSandbox SDK 适配为 DeepAgents BaseSandbox |
实现命令执行、上传、下载;注入沙箱 PATH;映射超时和退出码 |
sandbox_proxy.py |
稳定代理 | 完整转发同步/异步文件与命令协议;replace_backend() 支持热替换 |
sandbox_setup.py |
创建/连接沙箱并初始化运行环境 | 目录创建、Skills 播种、预构建 venv 快速检查、可选现场安装回退 |
sandbox_manager.py |
当前正式的异步多用户沙箱管理器 | Mongo 绑定、用户锁、内存缓存、预热池、重连、重建、清理和关闭 |
__init__.py |
包标记 | 无运行逻辑 |
execute()给非交互 shell 注入 Python/Node/Go/Java 等 PATH。- 使用
RunCommandOpts(timeout=...)把超时真正传给 OpenSandbox 服务端。 - stdout 与 stderr 合并为 DeepAgents
ExecuteResponse。 - 上传和下载只接受绝对路径;返回框架定义的 FileUpload/FileDownload 响应。
新沙箱默认资源为 2 CPU、4 GiB、2 小时 TTL,镜像为 erp-openclaw-sandbox:v1。初始化阶段会创建 /analysis/temp、/analysis/tasks 和 /data,同步本地技能,并执行一次快速 import 检查。
默认不允许现场 pip install 修复损坏镜像。只有显式设置 SANDBOX_RUNTIME_INSTALL_FALLBACK=true 才进入开发回退路径。
主要全局状态:
SANDBOX_BACKENDS[user_id]:用户到稳定代理的进程内缓存。sandbox_registry:MongoDB 中用户到 sandbox ID 的持久绑定。_user_locks:每用户生命周期锁,防止并发重复创建。_warm_reserve:供真正新用户认领的预热沙箱。
应用关闭时只删除未被认领的预热沙箱;用户已分配沙箱保留,以便下次启动重连。
主 Agent 中间件顺序会影响行为。当前顺序如下:
| 顺序 | 文件/中间件 | 作用 |
|---|---|---|
| 1 | sandbox_health.py |
每轮开始前 ping 用户沙箱;失败则重建并重新上传 AGENTS.md |
| 2 | context_injection.py |
把 user_id、用户名、偏好文件路径注入 SystemMessage |
| 3 | skills_sync.py |
比较哈希,将本地 src/skills/ 增量同步到沙箱 /skills/ |
| 4 | user_skills_restore.py |
分页读取用户 Store 中持久化技能并恢复到沙箱 |
| 5 | tools_summarization.py |
自动摘要并提供 compact_conversation 主动压缩工具 |
| 6 | memory_update.py |
回合结束后识别采购实体,自动更新 recent suppliers/queries |
| 7 | sandbox_breaker.py |
连续沙箱错误达到阈值后跳到 end,防止无限恢复循环 |
| 8 | user_async_subagents.py |
提供 start/check/update/cancel/list 异步任务工具,并绑定私有沙箱 |
| 9 | 框架 ModelCallLimitMiddleware |
单次 run 最多 50 次模型调用 |
| 10 | 框架 ToolCallLimitMiddleware |
单次 run 最多 200 次工具调用 |
各文件补充说明:
context_injection.py:不直接读取偏好,而是告诉 Agent 使用虚拟文件系统读取。memory_update.py:只处理有采购关键词或发生子 Agent 委派的对话;内部摘要模型调用带internal-memory-updatetag,Web SSE 会过滤其 token。skills_sync.py:预置技能来源是本地文件,属于系统级内容。user_skills_restore.py:持久化技能来源是 Store,namespace 含用户 ID,属于用户私有内容。tools_summarization.py:压缩前的完整历史由框架写入 backend 文件系统。sandbox_breaker.py:与主动恢复配对;Health 负责恢复,Breaker 负责停止无效循环。user_async_subagents.py:替换框架默认的 start/update 工具,但保留 check/cancel/list 标准工具。middlewares/__init__.py:包标记,无运行逻辑。
| 文件 | 作用 | 关键点 |
|---|---|---|
mongodb_store.py |
LangGraph BaseStore 的 MongoDB 实现 |
支持 Get/Put/Search/ListNamespaces;不支持 TTL 和语义向量搜索 |
async_task_store.py |
异步任务元数据存储 | async_tasks 集合;按用户列任务;从历史展示消息发现旧 task ID |
__init__.py |
导出 Store 类型/包标记 | 轻量入口 |
MongoDBStore 用 JSON 字符串编码完整 namespace,并以 namespace_path + key 建唯一索引,避免 MongoDB 数组 multikey 索引让不同用户 namespace 发生碰撞。
| 文件 | 作用 | 关键点 |
|---|---|---|
loader.py |
读取 YAML、校验必填字段、解析工具名 | 工具使用子串匹配并去重;可合并额外 Middleware |
configs/procurement_order.yaml |
同步订单 Agent 定义 | 订单工具、request_order_info、两层 HITL、订单字段与结果格式 |
configs/procurement_analyst.yaml |
异步分析 Agent 定义 | 查询/图表/搜索工具、采购 Skills、任务目录和报告规则 |
各级 __init__.py |
包标记 | 无运行逻辑 |
修改子 Agent 时优先改 YAML,而不是继续扩大 graphs/main_agent.py。但如果新增的是异步 Agent,还需要在 langgraph.json 注册 graph,并在异步 Middleware 中声明 graph ID 和 URL。
| 文件 | 暴露能力 | 主要职责 |
|---|---|---|
mcp_client.py |
load_mcp_tools() |
连接本地 ERP MCP 和第三方图表 MCP,按 analyst/order/chart 前缀分组 |
chart_generator.py |
generate_visualization |
把约 26 个 generate_* 图表工具合成一个 chart_type + chart_config 路由入口 |
web_search.py |
web_search(query) |
通过智谱搜狗 Web Search 返回最多 3 条外部信息 |
hitl_tools.py |
request_order_info |
触发 LangGraph interrupt,等待用户补充订单字段 |
assign_skill.py |
assign_skill |
校验技能、按 scope 复制到目标 Agent 目录,并写入用户 Store |
download_sandbox_file.py |
download_sandbox_file |
从当前用户沙箱下载文件到本机 src/download/,并防止文件名路径穿越 |
__init__.py |
工具包标记/轻量导出 | 无核心逻辑 |
supplier_、part_、inventory_→ analyst 查询工具。order_→ order 工具。- 第三方 MCP 中
generate_→ chart 工具。 - 图表 MCP 连接失败时只降级可视化,不阻止 ERP 核心工具启动。
chart_generator.py 不把 26 份大 Schema 同时暴露给模型,而是:
- 工具描述提供紧凑速查表。
- 完整参考放在
/skills/procurement/chart_params.md。 - 一个统一工具根据
chart_type路由到底层 MCP 工具。 - 类似 spreadsheet 的非可视化工具保留为独立工具。
这既降低工具 Schema token,也让 Agent 能按需读取完整参数。
| 文件 | 作用 | 关键点 |
|---|---|---|
server_main.py |
FastMCP 独立入口 | 注册四组工具,以 Streamable HTTP 监听 127.0.0.1:8000/mcp |
server_config.py |
Java ERP 与 MCP 地址配置 | 当前 Java base URL 为 http://127.0.0.1:8080/api |
http_base.py |
FastMCP lifespan | 创建一个共享 httpx.AsyncClient 连接池,关闭服务时统一释放 |
__init__.py |
包标记 | 无运行逻辑 |
| 文件 | MCP 工具 | Java REST API | 读/写 |
|---|---|---|---|
tools/suppliers_tools.py |
supplier_query |
GET /suppliers/search |
读 |
tools/parts_tools.py |
part_query |
GET /parts/page |
读 |
tools/parts_tools.py |
part_search |
GET /parts/search |
读 |
tools/parts_tools.py |
part_by_supplier |
GET /parts/supplier/{id} |
读 |
tools/inventory_tools.py |
inventory_warning |
GET /inventory/warning |
读 |
tools/order_tools.py |
order_search_details |
GET /orders/search-details |
读 |
tools/order_tools.py |
order_create |
POST /orders/create |
写 |
tools/order_tools.py |
order_update |
PUT /orders/update/{id} |
写 |
order_tools.py 还负责自动生成 PO + 日期 + 3 位随机数 的订单号、补默认下单时间、过滤 None,并递归把 Decimal/date 转成 JSON 可序列化值。
Skills 不等于普通 Python 工具。工具是固定可调用函数;Skill 是 Agent 按需读取的操作手册、脚本和数据资源。这样大段流程说明不会永久占用系统提示词。
| 文件 | 作用 |
|---|---|
main/skill-management/SKILL.md |
用户技能下载、创建、测试、分配、持久化和恢复的完整流程 |
main/skill-management/scripts/download_skill.py |
标准库实现的 ZIP 下载器;解析 slug、解压、校验 SKILL frontmatter、清理压缩包并输出 JSON |
| 文件 | 作用 |
|---|---|
procurement/procurement-analysis/SKILL.md |
需求拆解、ERP/外部数据收集、Python 分析、图表和报告的五步工作流 |
procurement/chart_params.md |
26 类可视化的 data 格式、特殊参数和通用参数速查 |
procurement/supplier-price-urls/SKILL.md |
指导 Agent 按供应商/零件查报价 URL |
procurement/supplier-price-urls/data/url_mapping.yaml |
供应商与物料到报价页面的静态映射数据 |
procurement/web-content-fetcher/SKILL.md |
通过 Jina/markdown.new/defuddle 等外部转换服务获取网页 Markdown 的说明 |
procurement/web-content-fetcher/fetch_content.py |
多服务 HTTP 获取、指定方法或 fallback 的 Python CLI |
procurement/web-content-fetcher/fetch.sh |
同能力的 Shell CLI |
procurement/web-content-fetcher/_meta.json |
技能来源、slug、版本和发布时间元数据 |
procurement/web-scraper/SKILL.md |
沙箱内直接抓网页并保存 Markdown 的说明,适合内网 URL |
procurement/web-scraper/scrape_page.py |
requests + BeautifulSoup + markdownify/手工 fallback 的完整 HTML→Markdown CLI |
procurement/web-scraper/_meta.json |
web-scraper 技能元数据 |
web-scraper 与 web-content-fetcher 的区别:前者从沙箱直接请求目标 URL,能访问沙箱网络可见的内网;后者依赖外部网页转 Markdown 服务,适合公开网页快速提取。
| 文件 | 作用 |
|---|---|
index.html |
Vite HTML 入口,提供 #app 挂载点 |
package.json |
前端元数据、dev/build/preview 脚本和依赖 |
package-lock.json |
npm 完整依赖锁,不手工修改 |
vite.config.js |
Vue 插件、3000 端口、/api → localhost:8090 代理和 dist 输出 |
src/main.js |
创建 Vue app、加载全局 CSS、挂载 App.vue |
src/styles/main.css |
全局重置、颜色、排版和页面基础样式 |
src/config/assets.js |
根据 Vite base URL 生成 logo/hero 图片地址 |
public/assets/whale-girl-logo.png |
侧边栏品牌图 |
public/assets/whale-girl-hero.png |
聊天空状态主视觉 |
| 文件 | 作用 | 关键点 |
|---|---|---|
src/api/client.js |
JWT fetch 基础层 | token 存 sessionStorage;401 清 token 并广播 auth-expired |
src/api/auth.js |
注册、登录、恢复登录、退出 | 注册/登录成功后保存 access token |
src/api/chat.js |
POST SSE 客户端 | 解析 token/tool_start/tool_args/tool_result/tool_end/interrupt/done/error;支持 AbortController |
src/api/history.js |
会话列表、消息、删除和预留标题更新 | 所有请求通过 authFetch |
src/api/tasks.js |
异步任务列表 | GET /api/tasks?limit= |
chat.js 使用工具栈而不是单一“当前工具”,因此能处理主 Agent 的 task 包住子 Agent 工具调用的嵌套顺序。
App.vue 持有全局页面状态:
currentUser、authChecking:认证状态。sessions、currentThreadId:会话导航。messages:按时间混合存放 user/assistant/tool。isStreaming、abortController:流式请求和停止。interruptData、isResuming:HITL 暂停与恢复。asyncTasks、tasksRefreshing、taskRefreshTimer:后台任务轮询。
挂载后先恢复 JWT,再加载会话和任务,并每 5 秒刷新任务。发送与恢复使用两套相似回调,把 SSE 事件增量更新到 messages。中断存在时隐藏普通输入框,显示 InterruptBanner。
| 文件 | 作用 | 输入/输出或重要行为 |
|---|---|---|
AuthScreen.vue |
登录/注册双模式页面 | 调用 auth API;成功后 emit authenticated |
Sidebar.vue |
品牌、会话搜索、会话选择/删除、用户与退出 | emit select/new/delete/logout;本地过滤会话标题 |
ChatArea.vue |
聊天空状态与消息滚动容器 | 根据 showToolCalls 过滤工具消息;深度监听并自动滚到底部 |
MessageItem.vue |
user/assistant/tool 三种消息渲染 | assistant/tool 文本交给 MarkdownRenderer;工具参数和结果可折叠;支持图片预览 |
MarkdownRenderer.vue |
Markdown、代码高亮和图片渲染 | 使用 markdown-it + highlight.js + v-html;当前原始 HTML 开启且未做 DOM 清洗,是已知安全待办 |
InputArea.vue |
文本输入、自动高度、发送/停止和工具开关 | Enter 发送,Shift+Enter 换行;流式时切换为停止按钮 |
InterruptBanner.vue |
订单字段补充和最终审批 UI | emit resume;补充格式 {supplement},审批格式 {decisions} |
AsyncTaskPanel.vue |
页面右侧可收缩异步任务抽屉 | 展开状态保存在 localStorage;展示 running/success/error/cancelled 等状态 |
ToolCallPanel.vue |
旧的独立工具调用详情面板 | 当前没有被 App.vue 或其他组件导入;工具信息已改由 MessageItem 内联显示 |
| 事件 | 后端产生位置 | 前端处理 | 用途 |
|---|---|---|---|
token |
chat.py AIMessage/Chunk |
chat.js onToken |
增量追加助手文本,并保留 source |
tool_start |
发现 tool call name | onToolStart |
创建 calling 状态的工具消息 |
tool_args |
tool call 参数 chunk | onToolArgs |
追加栈顶工具参数 |
tool_result |
ToolMessage | onToolResult |
填充文本、图片并出栈 |
tool_end |
工具结果之后 | onToolEnd |
兜底标记工具完成 |
interrupt |
values stream 中的 interrupts | onInterrupt |
显示数据补充或审批 UI |
done |
正常结束或中断保存后 | onDone |
结束流、更新 thread、刷新会话/任务 |
error |
stream 异常 | onError |
显示错误并恢复界面状态 |
消息 source 从 LangGraph namespace 提取。namespace 中有 tools: 段时视为子 Agent;否则为 main。
| 集合 | 写入者 | 保存内容 | 隔离键 |
|---|---|---|---|
users |
auth_service.py |
用户名、显示名、scrypt 密码哈希、状态 | _id/唯一 normalized username |
session_owners |
AgentLoader |
thread 所属用户和时间 | 唯一 thread_id + user_id 校验 |
checkpoints |
MongoDBSaver |
LangGraph 状态、interrupt 和消息 | thread_id |
checkpoint_writes 等 |
LangGraph checkpoint 实现 | pending writes/内部状态 | LangGraph 配置 |
session_display_messages |
AgentLoader |
前端混合展示消息,每条一个文档 | thread_id + user_id + index |
store_items |
MongoDBStore |
用户偏好与持久化技能 | namespace_path + key |
sandbox_registry |
backends/sandbox_manager.py |
用户到沙箱 ID 的绑定 | 唯一 user_id |
async_tasks |
async_task_store.py |
task/run/status/result/error | task_id + user_id |
默认路径,例如 /analysis、/data、/skills
→ 当前用户 OpenSandbox
/memories/
→ MongoDB StoreBackend
→ namespace 由 runtime.context.user_id 决定
/persisted-skills/
→ MongoDB StoreBackend
→ namespace = (users, user_id, skills)
这让 Agent 看见的是统一文件系统,但不同目录实际落在不同存储介质。
| Key | 存储类型 | 用途 |
|---|---|---|
erp_agent_access_token |
sessionStorage |
当前标签页 JWT,关闭标签页后清除 |
erp_async_tasks_collapsed |
localStorage |
记住异步任务抽屉是否收起 |
motorparts_db.sql 是 Java ERP 的业务数据,而不是 Agent 自身状态。八张表分别覆盖客户、库存、物流、订单明细、零部件、采购订单、供应商和 ERP 用户。
| 方法 | 路径 | 认证 | 作用 |
|---|---|---|---|
| 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 中断,返回 SSE |
| GET | /api/chat/{thread_id} |
是 | 当前 checkpoint 消息状态 |
| GET | /api/chat/{thread_id}/history |
是 | checkpoint 状态历史 |
| GET | /api/history |
是 | 当前用户会话列表 |
| GET | /api/history/{thread_id}/messages |
是 | 当前用户完整展示消息 |
| DELETE | /api/history/{thread_id} |
是 | 删除会话相关数据 |
| PATCH | /api/history/{thread_id} |
是 | 标题更新预留接口,当前不真正持久化 |
| GET | /api/tasks |
是 | 当前用户异步任务及刷新后的状态/结果 |
| GET | /health |
否 | FastAPI 健康检查 |
| 文件 | 作用 | 是否产生数据 |
|---|---|---|
scripts/run_benchmark.py |
检查 Web/Java 服务,压测只读库存接口,可选真实 SSE 并发样本 | 写 reports/*.json;--include-llm 会注册 qa_bench_* 用户 |
scripts/generate_report.py |
把 benchmark JSON 转成 Markdown 摘要 | 写同名 .md |
scripts/run_agent_smoke.py |
终端交互式调用 Agent、显示流和处理两类 interrupt | 手工调试入口,不由 pytest 收集 |
scripts/run_mcp_smoke.py |
MCP/Agent 客户端连接示例 | 手工连接辅助,不由 pytest 收集 |
| 文件 | 作用 | 注意事项 |
|---|---|---|
tests/conftest.py |
服务 URL、随机 QA 凭据、live LLM 开关 | 用户名前缀 qa_auto_ |
tests/test_async_sandbox_binding.py |
claim round-trip、防跨 task 重放、异步工具集完整性 | 单元测试 |
tests/test_mongodb_store_namespace.py |
namespace 完整身份和分隔符无歧义 | 单元测试 |
tests/test_sandbox_prebuilt_environment.py |
镜像快速检查和禁止隐式现场安装 | 单元测试 |
tests/test_user_skill_isolation.py |
用户技能 namespace、同名技能隔离和分页恢复 | 单元测试 |
tests/test_all_tools.py |
MCP 全工具和 Agent 业务链路测试;随机数据生成 | integration;含 ERP 写测试,必须谨慎 |
tests/test_auth_isolation.py |
注册、JWT /me、空历史、未授权 401 |
会创建 QA 用户,应清理 |
tests/test_mcp_integration.py |
检查 8 个 ERP MCP 工具并真实查询火花塞 | 只读,需要 MCP 与 Java ERP |
tests/test_sse_stream.py |
验证真实 token→done SSE 生命周期 | 默认跳过;需 RUN_LIVE_LLM_TESTS=1,会创建 QA 用户/会话 |
test_all_tools.py 属于 integration 测试,其中的写测试只有显式设置 RUN_ERP_WRITE_TESTS=1 才应执行。任何会注册账号或写数据库的测试,都应在 finally/fixture 中补充自动清理。
| 文件 | 作用 |
|---|---|
docs/CODEBASE_GUIDE.md |
当前文件:面向开发者的目录、调用链和复习手册 |
docs/agent-backend-stress-test-report.md |
后端功能、高压联调、修复记录、性能观察和剩余风险 |
docs/frontend-multi-user-api.md |
前端接入 JWT、多用户隔离、聊天/历史 API 的精简接口说明 |
reports/ 中每个时间点有一份原始 JSON 和一份 Markdown 摘要:
benchmark-20260821-141746.*:库存预警 10 样本,平均约 0.038 秒。benchmark-20260821-141814.*:库存预警 10 样本,平均约 0.016 秒。benchmark-20260821-141913.*:库存预警 10 样本,平均约 0.107 秒。
这些是历史证据,不是运行配置。旧报告标题仍可能使用项目旧称,不影响当前 generate_report.py 以后生成 procurepilot 标题。
| 需求 | 第一入口 | 继续追踪 |
|---|---|---|
| 修改主 Agent 路由规则 | agent/memory/prompts.py |
graphs/main_agent.py、memory/AGENTS.md |
| 新增同步子 Agent | subagents/configs/*.yaml |
subagents/loader.py、graphs/main_agent.py |
| 新增异步子 Agent | langgraph.json |
异步 graph 工厂、user_async_subagents.py |
| 新增 ERP MCP 工具 | mcp_server/tools/ |
server_main.py、mcp_client.py、子 Agent YAML |
| 修改订单字段/审批 | procurement_order.yaml |
order_tools.py、hitl_tools.py、InterruptBanner.vue |
| 修改 SSE 事件 | api_view/api/chat.py |
frontend/src/api/chat.js、App.vue |
| 修改会话历史展示 | agent_loader.py |
api/history.py、history.js、Sidebar.vue |
| 修改异步任务面板 | api/tasks.py |
tasks.js、App.vue、AsyncTaskPanel.vue |
| 修改用户登录 | auth_service.py |
api/auth.py、api/auth.js、AuthScreen.vue |
| 修改用户沙箱生命周期 | backends/sandbox_manager.py |
sandbox_setup.py、sandbox_proxy.py、sandbox_health.py |
| 修改沙箱命令执行 | backends/custom_opensandbox.py |
Docker 镜像与 OpenSandbox 配置 |
| 新增预置 Skill | src/skills/{scope}/ |
skills_sync.py、对应子 Agent YAML |
| 修改持久化技能 | assign_skill.py |
user_skills_restore.py、mongodb_store.py |
| 修改长期偏好 | context_injection.py |
memory_update.py、CompositeBackend /memories/ 路由 |
| 修改图表类型 | chart_generator.py |
skills/procurement/chart_params.md |
| 修改模型 | agent/core/config.py |
.env.example、core/env_utils.py |
| 修改服务端口 | 各服务配置 | start_web.py、README、Vite proxy、Docker Compose |
memory/prompts.py
→ graphs/main_agent.py
→ subagents/loader.py
→ configs/procurement_order.yaml
→ configs/procurement_analyst.yaml
→ middlewares/factories.py
graphs/main_agent.py 中的 ASYNC_ANALYST_INSTRUCTIONS
→ user_async_subagents.py
→ core/async_sandbox_claims.py
→ langgraph.json
→ graphs/async_analyst.py
→ async_task_store.py
→ api_view/api/tasks.py
→ frontend AsyncTaskPanel.vue
docker-compose.yml / opensandbox.toml
→ sandbox-image/Dockerfile
→ custom_opensandbox.py
→ sandbox_setup.py
→ sandbox_manager.py
→ sandbox_proxy.py
→ sandbox_health.py
→ sandbox_breaker.py
auth_service.py
→ AgentLoader.claim/assert_thread_owner
→ backends/sandbox_manager.py
→ config.user_skills_namespace
→ MongoDBStore namespace_path
→ async sandbox claim
api_view/api/chat.py
→ frontend/src/api/chat.js
→ frontend/src/App.vue
→ ChatArea.vue
→ MessageItem.vue
→ InterruptBanner.vue
以下内容可能出现在当前电脑,但不应当作为项目源码阅读或提交:
| 路径 | 来源 | 是否可删除/重建 |
|---|---|---|
.env |
本地真实密钥 | 不提交;删除前先确认密钥有备份 |
.venv/ |
Python 虚拟环境 | 可由 uv sync 或 pip 重建 |
frontend/node_modules/ |
npm 依赖 | 可由 npm install 重建 |
frontend/dist/ |
Vite 生产构建 | 可由 npm run build 重建 |
__pycache__/、.pytest_cache/、.ruff_cache/ |
Python/测试/静态检查缓存 | 可安全重建 |
*.egg-info/、build/、dist/ |
Python 构建产物 | 可由 uv build 重建 |
.langgraph_api/ |
LangGraph 开发运行状态 | 本地运行产物 |
src/download/ |
从用户沙箱下载到宿主机的报告/文件 | 可能含用户数据,不提交;删除前确认是否需要保留 |
*.log、temp/、.tmp-* |
运行日志和临时文件 | 通常可重建,排障时可能有价值 |
- Java ERP 源码不在本仓库;
src/mcp_server/是它的 MCP 适配层,不是 ERP 本身。 - Agent Protocol 主要承载异步采购分析;同步聊天和订单子 Agent 在 FastAPI 进程创建的主 Graph 中执行。
- 同步和异步 Agent 都可以操作 OpenSandbox,但异步 Agent 必须通过签名 claim 连接当前用户的同一个私有沙箱。
- 用户沙箱生命周期统一由
src/agent/backends/sandbox_manager.py管理,包括预热、重连、重建和 MongoDB 绑定。 ToolCallPanel.vue当前未接入页面;实际工具调用由MessageItem.vue内联渲染。session_display_messages与 checkpoint 故意分开:前者保证 UI 顺序与子 Agent 工具细节,后者保证 Graph 恢复和 HITL。/memories/与/persisted-skills/看起来像文件夹,实际由 CompositeBackend 路由到 MongoDB Store。src/download/是宿主机下载落点,不是沙箱内/analysis/tasks/{task_id}/。langgraph dev是开发运行时;生产异步执行需要独立部署和持久性方案。MarkdownRenderer.vue当前允许原始 HTML 并用v-html,尚未完成 DOMPurify/协议白名单修复,复习前端安全时应优先查看。- Docker 默认配置为本地开发模式,OpenSandbox 无鉴权且挂载 Docker Socket;公网部署必须收紧。
- 前端任务完成更新当前依赖 5 秒轮询,不是服务端主动推送。
| 术语 | 在本项目中的含义 |
|---|---|
| Graph Factory | 启动期预计算重组件,请求期按用户沙箱创建轻量 Graph |
| Agent Protocol | LangGraph 的 thread/run/graph HTTP 执行服务,本项目用于异步 analyst |
| MCP | Agent 工具协议;本地 FastMCP 把 Java ERP REST API 暴露成工具 |
| HITL | Human-in-the-Loop;字段补充和订单最终审批两类中断 |
| Checkpoint | LangGraph 可恢复执行状态,包含 interrupt 和消息状态 |
| Display Messages | 专门供前端重放的 user/assistant/tool 混合消息 |
| StoreBackend | 把 LangGraph Store 映射成 Agent 可见文件路径的后端 |
| CompositeBackend | 按路径把文件访问分流到沙箱或 Store 的虚拟文件系统 |
| SandboxBackendProxy | 可热替换底层沙箱、但保持 Graph 引用不变的稳定代理 |
| Skill | Agent 按需读取的操作手册、脚本和资源,不等同于固定函数工具 |
| Offloading | 大工具结果自动写文件,只在上下文保留路径和预览 |
| Summarization | 上下文接近上限时把旧消息压缩为摘要 |
| task_id | 异步任务的 LangGraph thread ID,也是任务目录和查询主键 |
如果很久以后只记得五句话,请记住:
AgentLoader是 Web 到用户 Agent/沙箱的入口。graphs/main_agent.py是整个主 Graph 的装配中心。backends/sandbox_manager.py + sandbox_proxy.py是用户隔离和故障恢复的核心。user_async_subagents.py + graphs/async_analyst.py + langgraph.json构成异步分析闭环。chat.py + frontend/api/chat.js + App.vue构成从 LangGraph 到浏览器的 SSE 状态机。