# Screen Agent > **前端仓库**:[jiawei/my-v0](https://git.qflink.xyz/jiawei/my-v0) 可视化大屏编辑器的后端服务,提供两部分能力: - **AI 编辑**:把自然语言需求转换为经过校验的结构化编辑动作,由前端应用到画布;支持上传数据文件,并用查询结果直接制图。 - **大屏管理**:大屏的保存、版本发布、回收站与线上访问。 ## 功能 - 自然语言新建大屏,增删、更换图表,修改组件属性、位置、尺寸与画布,支持对齐和分布。 - 上传 CSV / TSV / Excel / JSON / JSONL / Parquet,对数据问答、汇总,并将查询结果填入图表。 - 动作按物料字段定义校验,并在画布副本上整批模拟执行;失败原因回传 Agent 修正,仅交付通过的动作。 - 多轮对话;信息不足时暂停任务向用户澄清,回答后继续,也可取消。 - 通过 SSE 推送处理进度、问答文本增量与最终结果。 - 大屏保存(乐观锁)、发布快照与历史版本、分享链接、回收站、封面图、数据源服务端代理。 ## 架构 ```mermaid flowchart LR Client[大屏编辑器] --> API[FastAPI] API --> Graph[LangGraph 工作流] Graph --> Intent[意图判断] Intent -->|问答| QA[问答 Agent] Intent -->|其他| Screen[大屏 Agent] Screen --> MCP[MCP 物料查询] Screen --> Batch[动作校验与模拟] QA --> Data[DuckDB / Parquet] Screen --> Data Graph -->|SSE| Client API --> Mongo[(MongoDB)] ``` 外层 LangGraph 负责路由、状态检查点与澄清恢复,内层 LangChain Agent 通过工具循环完成任务。意图由 TypeSafe Jev 判断,仅在明确为问答且概率达到阈值时进入问答分支。 | 组件 | 技术 | |------|------| | Web / 模型 | FastAPI、Pydantic | | Agent 工作流 | LangGraph、LangChain(`langchain-openai`) | | 意图判断 | TypeSafe Jev | | 物料与字段查询 | MCP(`mcp_servers/`,由应用自动拉起,端口 8201) | | 存储 | MongoDB(物料、会话、检查点、文件元数据、大屏) | | 数据文件 | python-calamine、PyArrow(Parquet)、DuckDB | | 观测 | Loguru、Langfuse(可选) | ## 快速开始 **依赖**:Python ≥ 3.11、[uv](https://docs.astral.sh/uv/)、MongoDB、支持工具调用与结构化输出的 OpenAI 兼容聊天模型服务、TypeSafe API Key。 ```sh uv sync --locked cp .env.example .env # 填写下表中的配置 uv run python -m scripts.seed_materials # 导入物料目录,见下方说明 uv run uvicorn app.main:app --host 127.0.0.1 --port 8000 ``` 启动后访问 查看完整接口文档。 | 配置 | 说明 | |------|------| | `LLM_API_KEY` `LLM_MODEL` `LLM_BASE_URL` | 聊天模型。默认发送 `reasoning_effort=low`,服务端不支持时设 `LLM_REASONING_EFFORT=` | | `TYPESAFE_API_KEY` | 意图判断 | | `MONGODB_URI` `MONGODB_DB` | 物料目录与大屏存取必需;未配置时会话与检查点退回进程内存,大屏接口返回 503 | | `AUTH_ENABLED` `USER_CENTER_URL` | 鉴权。本地开发设 `AUTH_ENABLED=false`;开启后请求携带 `Authorization: Bearer `,服务调用用户中心 `GET /api/users/me` 校验 | | `LANGFUSE_TRACING_ENABLED` | 未部署 Langfuse 时设为 `false` | 全部配置及默认值见 [.env.example](.env.example) 与 [app/config.py](app/config.py)。 **物料初始化**:物料定义位于 [app/resources/materials](app/resources/materials),必须导入 MongoDB 后服务才能增改组件;导入会整体替换现有目录,之后需重启服务。导入脚本为 [scripts/seed_materials.py](scripts/seed_materials.py),可附带自定义物料目录作为参数。 ## 接口 所有接口以 `/api` 为前缀,JSON 响应统一为 `{code, data, msg}`。除标注外均需登录。 ### Agent | 接口 | 说明 | |------|------| | `POST /agent/run` | 提交需求与当前画布,返回 SSE | | `POST /agent/resume` | 回答澄清、选择选项或取消任务,返回 SSE | 请求示例: ```json { "prompt": "在画布顶部添加标题:销售数据概览", "screen": { "canvas": { "width": 1920, "height": 1080 }, "nodes": [] }, "context": { "conversation_id": "" } } ``` 每次 `run` 提交画布的完整快照;同一段对话复用 `conversation_id`,历史由服务端读取。 SSE 事件: | 事件 | 含义 | |------|------| | `progress` | 当前处理阶段 | | `answer_delta` | 问答文本增量,最终以 `final.data.answer` 为准 | | `final` | 本轮结果,`data.status` 见下 | | `error` | 流开始后的执行异常 | `final.data.status`:`completed`(有 `actions` 时由前端按序应用)、`waiting_for_input`(展示 `clarification`,用 `thread_id` 调用 `resume`)、`failed`(业务失败,不交付动作)、`cancelled`。流开始前的错误以 HTTP 状态码返回;未收到 `final` 或 `error` 即断开,应视为结果不完整。 ### 会话 | 接口 | 说明 | |------|------| | `POST /conversations` | 创建会话 | | `GET /conversations` | 分页列出当前用户的会话 | | `GET /conversations/{id}` | 读取会话历史 | | `PATCH /conversations/{id}` | 重命名 | | `DELETE /conversations/{id}` | 删除 | ### 数据文件 上传后后台解析(HTTP 202),轮询进度至 `ready` 后即可在同一会话中被 Agent 使用;已解析且未过期的文件自动带入后续对话。 | 接口 | 说明 | |------|------| | `GET /files/limits` | 上传限制与支持格式(无需登录) | | `POST /files` | `multipart/form-data` 上传,需带 `conversation_id` | | `GET /files?conversation_id=` | 会话下的文件 | | `GET /files/{id}` | 文件详情与表信息 | | `GET /files/{id}/progress` | 解析进度 | | `GET /files/{id}/tables/{table}/rows` | 分页、排序读取 | | `POST /files/{id}/tables/{table}/aggregate` | 分组汇总 | | `DELETE /files/{id}` | 删除 | ### 大屏管理 大屏仅所有者可访问,他人的大屏与不存在同样返回 404。保存与发布需携带 `revision`,与服务端不一致时返回 409。 | 接口 | 说明 | |------|------| | `POST /screens` | 创建 | | `GET /screens` | 列表:关键字、状态、排序、分页,`deleted=true` 查看回收站 | | `GET /screens/{id}` | 详情 | | `PUT /screens/{id}` | 保存(乐观锁) | | `PATCH /screens/{id}` | 重命名 | | `DELETE /screens/{id}` | 移入回收站,默认保留 30 天后自动清除 | | `POST /screens/{id}/restore` | 从回收站恢复 | | `DELETE /screens/trash` | 清空回收站 | | `POST /screens/{id}/publish` | 发布当前版本,首次发布生成 `share_id` | | `POST /screens/{id}/unpublish` | 下线 | | `GET /screens/{id}/publishes` | 发布历史 | | `POST /screens/{id}/publishes/{version}/restore` | 将历史版本恢复为草稿 | | `POST /screens/{id}/copy` | 复制 | | `PUT /screens/{id}/thumbnail` | 上传封面图(≤ 1 MB) | ### 公开与其他 | 接口 | 说明 | |------|------| | `GET /public/screens/{share_id}` | 线上版本(发布快照),匿名;数据源 `headers` 不下发 | | `GET /public/screens/{share_id}/datasources/{id}` | 线上取数,请求配置取自发布快照,匿名 | | `GET /public/thumbnails/{id}` | 封面图,匿名 | | `POST /datasource/fetch` | 编辑态数据源代理;仅允许公网 http(s) 地址,限 5 秒、2 MB | | `GET /materials` | 组件物料目录(无需登录) | ## 项目结构 ```text app/ ├── api/ HTTP 路由 ├── services/ 会话、大屏、物料、数据源代理与持久化装配 ├── processor/ LangGraph 工作流与节点 ├── agent/ 大屏 / 问答 Agent、工具、Skills 加载 ├── actions/ 动作执行、布局计算、整批模拟 ├── datafiles/ 数据文件解析、存储、查询与后台任务 ├── schemas/ 请求、画布、动作、会话、大屏模型 ├── resources/ 物料定义与字段规则 ├── clients/ LLM、Jev、MCP、用户中心客户端 ├── prompt/ 提示词 └── core/ common/ observability/ 认证、异常、日志、响应与 SSE、追踪 mcp_servers/ 应用管理的本地 MCP 服务(配置见 mcp_servers.json) skills/ 大屏设计、编辑、图表替换与数据制图规则 ``` 阅读主链路:[app/api/agent.py](app/api/agent.py) → [app/services/agent.py](app/services/agent.py) → [app/processor/graph.py](app/processor/graph.py) → [app/agent/screen_agent.py](app/agent/screen_agent.py) → [app/actions/batch.py](app/actions/batch.py)。动作协议定义在 [app/schemas/actions](app/schemas/actions)。 ## 部署注意 - **单实例**:任务与会话的并发控制、上传进度保存在进程内,请以单 worker 运行;同一会话同时只能执行一个任务。 - **本地存储**:数据文件与封面图写入磁盘(`DATA_FILE_DIR`、`THUMBNAIL_DIR`,默认在 `data/` 下),容器部署需挂载持久卷。 - **反向代理**:SSE 需关闭响应缓冲并放宽读取超时;上传大小限制需与 `DATA_FILE_MAX_MB` 一致。应用未配置 CORS,请通过同源代理转发 `/api`。 - **连接中断**:客户端断开会取消当前任务,不支持心跳、事件重放或断线续传。 - **日志**:写入 `logs/app.log`。 ## 开发 扩展组件:修改物料定义,重新导入后重启。调整 Agent 行为:修改 [skills](skills) 与 [app/prompt](app/prompt)。新增 MCP 服务:修改 [mcp_servers.json](mcp_servers.json),连接配置支持 `${环境变量}` 展开。 测试使用标准库 `unittest`,目录 `tests/` 不在版本控制内: ```sh uv run python -m unittest discover -s tests ```