Files
my-v0-server/README.md
T
2026-10-12 01:14:06 -07:00

201 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```
启动后访问 <http://127.0.0.1:8000/docs> 查看完整接口文档。
| 配置 | 说明 |
|------|------|
| `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 <token>`,服务调用用户中心 `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": "<POST /conversations 返回的 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
```