基本实现通用自动化(含图表、代码、ppt等生成)
This commit is contained in:
1 parent
1111d208c4
commit
b422e96b2c
197 files changed
+13923
-8081
No files matched your search
@@ -421,9 +421,190 @@ curl -o /dev/null -s -w "%{http_code}\n" http://localhost:8901/health
|
||||
curl -o /dev/null -s -w "%{http_code}\n" http://localhost:8902/health
|
||||
curl -o /dev/null -s -w "%{http_code}\n" http://localhost:8903/health
|
||||
|
||||
|
||||
## 当前对话与执行流程总览
|
||||
|
||||
### 一、多轮对话整体流程
|
||||
|
||||
```
|
||||
┌─ Web UI ──────────────────────────────────────────────────────────────────────┐
|
||||
│ app.js → send.js │
|
||||
│ POST /api/chat/start → POST /api/chat/complete │
|
||||
│ 同时轮询 /api/tool-calls/{sid}/live (1.2s) 展示"思考中..."+工具调用实时面板 │
|
||||
└────────────────────────────────────┬────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─ server.py ────────────────────────────────────────────────────────────────────┐
|
||||
│ /api/chat/complete → agent_runtime.execute_agent(chat_history, session_id) │
|
||||
└────────────────────────────────────┬────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─ runtime.py:execute_agent() ───────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ ① 从 SQLite message_store 加载历史消息 │
|
||||
│ ② 从 session_meta 读取上轮 turn_tool_context(工具名/参/文字结果) │
|
||||
│ ③ 拼装 messages = [SystemMessage + SQLite历史 + synthetic(工具上下文) + │
|
||||
│ HumanMessage(用户输入)] │
|
||||
│ ④ start_live_turn() 开启前端实时推送 │
|
||||
│ │
|
||||
│ ⑤ graph.invoke(messages) ────────────────▶ 见"图内 ReAct 循环" │
|
||||
│ │
|
||||
│ ⑥ _finalize_turn(): │
|
||||
│ ├ save_turn() → tool_calling/{sid}/turn_{id}.json (工具调用轨迹) │
|
||||
│ ├ _save_turn_tool_context() → session_meta.turn_tool_context (跨对话记忆) │
|
||||
│ └ _persist_messages_from_pending_turn() → SQLite (仅user+最终AI, 不含工具) │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 二、图内 ReAct 循环(`build_agent_graph` — `graph.py`)
|
||||
|
||||
```
|
||||
START
|
||||
│
|
||||
▼
|
||||
┌─────────────┐ 有 tool_calls ┌───────────┐ ┌─────────────────────┐
|
||||
│ agent │───────────────────────▶│ tools │───▶│ process_tool_artifact│
|
||||
│ (call_model)│◀───────────────────────│ (ToolNode) │ │ (截图 → synthetic │
|
||||
└─────────────┘ 无 tool_calls └───────────┘ │ HumanMessage) │
|
||||
│ ▲ └──────────┬──────────┘
|
||||
│ [END] │ │
|
||||
▼ └────────────────────────┘
|
||||
END
|
||||
```
|
||||
|
||||
**`agent` 节点内部(`call_model` — nodes.py):**
|
||||
|
||||
```
|
||||
call_model(state)
|
||||
├── _filter_short_term_memory() ← 裁剪超过 trajectory_rounds 的合成截图
|
||||
├── _build_reflection_prompt() ← 注入反思引导文本
|
||||
├── model_with_tools.invoke() ← LLM 调用
|
||||
│
|
||||
├── _compress_messages_in_loop() ← ★ 每步后检查压缩 ★
|
||||
│ │
|
||||
│ ├ 读 response.usage_metadata.total_tokens
|
||||
│ ├ > MINI_COMPRESS_RATE (50%窗口) → 轻量压缩:保留本轮首个 agent 动作
|
||||
│ ├ > HARD_COMPRESS_RATE (75%窗口) → 全量压缩:只保留当前 user 消息
|
||||
│ └ state["messages"] 就地替换为 [SystemMessage(摘要) + 保留部分]
|
||||
│
|
||||
├── 提取 thinking (content) → 前端 think 面板
|
||||
└── return {"messages": [response]} ← add_messages 追加到 state
|
||||
```
|
||||
|
||||
**`should_continue` 路由(routing.py):**
|
||||
|
||||
```
|
||||
最后一条 AIMessage 是否含 tool_calls?
|
||||
├ YES → 检查策略
|
||||
│ ├ confirm 级 → END(等待人工确认)
|
||||
│ ├ 循环检测触发 → END
|
||||
│ └ 正常 → "tools"
|
||||
└ NO → END
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 三、多 Agent 模式(`multi_agent_graph.py`)
|
||||
|
||||
```
|
||||
START
|
||||
│
|
||||
▼
|
||||
┌──────────────┐ main完成 ┌─────────────────────┐
|
||||
│ supervisor │─────────────────────▶│ parallel_sub_agents │
|
||||
└──────────────┘ └──────────┬──────────┘
|
||||
▲ │ 并行完成
|
||||
│ ▼
|
||||
└─────────────────────── ┌──────────────┐
|
||||
│ supervisor │
|
||||
子Agent结果注入 └──────┬───────┘
|
||||
回 main 的 messages │ 有 agent_call → 循环
|
||||
▼
|
||||
┌──────────────┐ 无 agent_call
|
||||
│ supervisor │──────────────────▶ END
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
**主 Agent 节点**(`make_main_agent_node`):单步执行 — model invoke → 工具分类 → 工具执行(单轮)→ 返回 supervisor。由 `_main_continues` 标志 + supervisor 控制循环。
|
||||
|
||||
**子 Agent 执行**(`_execute_single_sub_agent`):隔离的 [SystemMessage + task_description] → 子 Agent 的 ReAct 图(共用 `nodes.py` 的 `call_model`,自动受益于压缩)→ 返回 `tag_message` 注入主 Agent。
|
||||
|
||||
---
|
||||
|
||||
### 四、压缩机制对比
|
||||
|
||||
| | 旧(已移除) | 新 |
|
||||
|---|---|---|
|
||||
| **触发位置** | `execute_agent` 中,`graph.invoke()` 之前 | `call_model` 中,每次 LLM 调用之后 |
|
||||
| **token 来源** | SQLite `session_meta.last_total_tokens` | 模型 response `usage_metadata.total_tokens` |
|
||||
| **压缩范围** | 只压缩 SQLite 中的简化历史(user+AI) | 压缩图状态中完整消息(含工具调用/结果) |
|
||||
| **持久化** | 写 SQLite `last_total_tokens` + `compressed_content` | 就地替换 `state["messages"]`,不写库 |
|
||||
| **单 Agent** | 图外 pre-invoke 一次 | 图内每步 LLM 调用后检查 |
|
||||
| **子 Agent** | 无 | 共用 `nodes.py` 的 `call_model`,自动覆盖 |
|
||||
|
||||
Agent/
|
||||
├── config/
|
||||
│ └── env_config.json # WORKSPACE_DIR 配置
|
||||
│
|
||||
├── history/ # [需挂载]
|
||||
│ ├── multi_inputs/{session_id}/
|
||||
│ │ ├── ui_messages.json # LangChain 聊天历史
|
||||
│ │ ├── session_meta.json # 会话元数据 + 工具调用记忆
|
||||
│ │ └── *.png # 用户上传的附件
|
||||
│ └── tool_calling/{session_id}/
|
||||
│ ├── turn_{turn_id}.json # 每轮工具调用完整记录
|
||||
│ └── {turn_id}/
|
||||
│ ├── _artifact_*.png # 工具产生的截图
|
||||
│ └── _file_* # 工具产生的其他文件
|
||||
│
|
||||
└── workspace/ # [需挂载]
|
||||
├── ppt_qingdao/ # Agent 产出的 PPT 子目录
|
||||
├── trasformer/ # 另一个业务子目录
|
||||
├── *.pptx # 散落的 PPT 文件
|
||||
└── generate_charts.py # Agent 自动生成的脚本
|
||||
关键发现:
|
||||
两个目录的路径都是通过 __file__ 动态推导的,没有硬编码绝对路径 → 只要目录结构一致,挂载到容器内同名位置即可
|
||||
terminal_execute 是唯一在代码中直接调用 get_workspace_dir() 的工具(作为默认工作目录)
|
||||
doc_tool、send_file 依赖 LLM 通过 system_prompt 中注入的 workspace 路径来传参
|
||||
16 个模块引用了 history 目录,核心入口是 tool_call_recorder.py 和 agent_utils.py
|
||||
二、工具分类:谁进沙箱、谁留宿主机
|
||||
进 Docker 沙箱 原因 留宿主机 原因
|
||||
terminal_execute 必须隔离,执行任意命令 gui 需要桌面截图+键鼠模拟
|
||||
web_search 纯 HTTP API 调用 browser_control 需要宿主机浏览器+快捷键
|
||||
agent_call 纯进程内调用 software_control Win32 API + 注册表 + os.startfile
|
||||
skill_router 只读 skills/ + LLM doc 用户可传任意宿主机路径
|
||||
human_interaction 零外部依赖 send_file 同上
|
||||
todo_list 纯内存操作 directory_listing 同上
|
||||
date_query 纯 datetime.now() email SMTP 附件来自宿主机任意路径
|
||||
rag ChromaDB + 嵌入API(限制路径后)
|
||||
如果将 doc/send_file/directory_listing/email 的路径参数强制限定在 workspace 内,则它们也可以迁入沙箱。那样最终只有 3 个 GUI 工具必须在宿主机。
|
||||
三、Docker 沙箱方案设计
|
||||
terminal_execute 的改造方式:
|
||||
沙箱内部预装 Python + myenv venv + 常用工具(git, node 等),每次命令在隔离容器中执行,产物自然落入挂载的 workspace/ 目录。
|
||||
|
||||
# app打包(使用pyinstaller和npm)
|
||||
|
||||
## 先用 PyInstaller 把 FastAPI 后端打成独立 exe
|
||||
cd Agent
|
||||
pip install pyinstaller
|
||||
pyinstaller --onefile --name fastapi-backend --add-data "src;src" src/web/server.py
|
||||
```
|
||||
cd Agent\electron
|
||||
## 打包 Electron 应用
|
||||
```
|
||||
# 第一步:安装 Electron + electron-builder(仅首次)
|
||||
npm install
|
||||
|
||||
# 第二步:打包生成 .exe
|
||||
npx electron-builder --win
|
||||
```
|
||||
生成的 .exe 在 Agent\electron\dist\ 目录下。
|
||||
|
||||
|
||||
# 测试用例
|
||||
(email、sendfile)
|
||||
今天和昨天有什么邮件
|
||||
发封邮件给19553226590@163.com,内容就是我桌面的图片"C:\Users\86166\Desktop\风景\8.png"
|
||||
发封邮件给19553226590@163.com,内容就是我桌面的图片"C:\Users\86166\Desktop\8.png"
|
||||
|
||||
(websearch、terminal、sendfile)
|
||||
查一下济南和青岛近10年的GDP并画个图表
|
||||
|
||||
Reference in new issue
Block a user