Feat/0.2.0 #5
@@ -1,295 +1,198 @@
|
||||
# Screen Agent · my-v0-server
|
||||
# Screen Agent
|
||||
|
||||
面向可视化大屏编辑器的 AI 后端。用户通过自然语言创建大屏、调整组件和分析上传的数据,服务将需求转换为经过校验的结构化编辑动作,交给前端执行。
|
||||
可视化大屏编辑器的后端服务,提供两部分能力:
|
||||
|
||||
本仓库提供 API、Agent 工作流、组件物料和数据处理能力。接入时,前端负责提交当前画布快照、展示流式反馈,并应用返回的动作。
|
||||
- **AI 编辑**:把自然语言需求转换为经过校验的结构化编辑动作,由前端应用到画布;支持上传数据文件,并用查询结果直接制图。
|
||||
- **大屏管理**:大屏的保存、版本发布、回收站与线上访问。
|
||||
|
||||
[快速开始](#快速开始) · [使用指南](#使用指南) · [接口概览](#接口概览) · [架构设计](#架构设计) · [开发与测试](#开发与测试)
|
||||
## 功能
|
||||
|
||||
## 功能特性
|
||||
- 自然语言新建大屏,增删、更换图表,修改组件属性、位置、尺寸与画布,支持对齐和分布。
|
||||
- 上传 CSV / TSV / Excel / JSON / JSONL / Parquet,对数据问答、汇总,并将查询结果填入图表。
|
||||
- 动作按物料字段定义校验,并在画布副本上整批模拟执行;失败原因回传 Agent 修正,仅交付通过的动作。
|
||||
- 多轮对话;信息不足时暂停任务向用户澄清,回答后继续,也可取消。
|
||||
- 通过 SSE 推送处理进度、问答文本增量与最终结果。
|
||||
- 大屏保存(乐观锁)、发布快照与历史版本、分享链接、回收站、封面图、数据源服务端代理。
|
||||
|
||||
- **自然语言编辑大屏**:新建大屏,新增、删除或更换图表,修改组件属性、位置、尺寸与画布配置,支持对齐和分布等布局操作。
|
||||
- **数据驱动的问答与制图**:上传 CSV、TSV、Excel(XLSX / XLS / XLSB)、JSON、JSONL 或 Parquet,查询和汇总数据,用查询结果填充图表。
|
||||
- **动作校验与模拟执行**:按物料字段定义校验修改,并在画布副本上模拟每批动作;成功的批次累加在工作画布上,失败原因返回 Agent
|
||||
修正,通过的动作按顺序交付。
|
||||
- **多轮对话与澄清**:保存会话历史;需求需要补充时暂停任务,用户回答后继续,也可以取消等待中的任务。
|
||||
- **实时反馈**:通过 SSE 返回处理进度、问答文本增量和最终结果,区分业务失败与执行异常。
|
||||
- **组件能力扩展**:以 JSON 定义物料、以 Skills 描述任务做法,通过 MCP 提供组件目录与字段查询。
|
||||
## 架构
|
||||
|
||||
```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 或以上,版本要求见 [pyproject.toml](pyproject.toml) |
|
||||
| uv | 安装依赖并运行项目,仓库提供 `uv.lock` |
|
||||
| MongoDB | 完整大屏编辑所需的物料目录,以及会话、检查点和文件元数据存储 |
|
||||
| 聊天模型服务 | 通过 `ChatOpenAI` 接入;需要支持工具调用、结构化输出与流式响应 |
|
||||
| TypeSafe / Jev | 判断请求是否进入问答流程,需要独立的 API Key |
|
||||
|
||||
用户中心和 Langfuse 可在本地开发时关闭。默认物料 MCP 服务由应用自动启动,使用本机 `8201` 端口;API 默认使用 `8000` 端口。
|
||||
|
||||
> 不配置 MongoDB 时,会话和检查点可使用进程内存,但物料目录不会回退到本地 JSON,新增、更换组件等能力无法正常使用。首次运行请完成物料初始化。
|
||||
|
||||
### 1. 安装依赖
|
||||
|
||||
获取仓库后,在项目根目录运行:
|
||||
**依赖**: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
|
||||
```
|
||||
|
||||
### 2. 配置环境
|
||||
启动后访问 <http://127.0.0.1:8000/docs> 查看完整接口文档。
|
||||
|
||||
将 [.env.example](.env.example) 复制为 `.env`,已有配置无需覆盖。填写以下配置:
|
||||
| 配置 | 说明 |
|
||||
|------|------|
|
||||
| `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` |
|
||||
|
||||
| 配置 | 说明 |
|
||||
|--------------------------------------------|----------------------------------------------|
|
||||
| `LLM_API_KEY`、`LLM_MODEL`、`LLM_BASE_URL` | 聊天模型密钥、模型名称和 API 地址 |
|
||||
| `TYPESAFE_API_KEY` | Jev 意图判断服务密钥 |
|
||||
| `MONGODB_URI`、`MONGODB_DB` | MongoDB 连接地址和数据库名 |
|
||||
| `AUTH_ENABLED` | 本地调试可设为 `false`,所有请求共用开发用户 |
|
||||
| `LANGFUSE_TRACING_ENABLED` | 未配置 Langfuse 时设为 `false` |
|
||||
全部配置及默认值见 [.env.example](.env.example) 与 [app/config.py](app/config.py)。
|
||||
|
||||
客户端默认发送 `reasoning_effort=low`;模型服务不支持该参数时,设置 `LLM_REASONING_EFFORT=`。
|
||||
**物料初始化**:物料定义位于 [app/resources/materials](app/resources/materials),必须导入 MongoDB 后服务才能增改组件;导入会整体替换现有目录,之后需重启服务。导入脚本为 [scripts/seed_materials.py](scripts/seed_materials.py),可附带自定义物料目录作为参数。
|
||||
|
||||
正式接入用户中心时设置 `AUTH_ENABLED=true` 和 `USER_CENTER_URL`,请求携带 `Authorization: Bearer <token>`。后端通过用户中心的
|
||||
`GET /api/users/me` 获取当前用户。
|
||||
## 接口
|
||||
|
||||
### 3. 初始化物料目录
|
||||
所有接口以 `/api` 为前缀,JSON 响应统一为 `{code, data, msg}`。除标注外均需登录。
|
||||
|
||||
首次使用需将 `app/resources/materials` 中的物料定义导入 MongoDB。工作区包含 `scripts/seed_materials.py` 时,可运行:
|
||||
### Agent
|
||||
|
||||
```sh
|
||||
uv run python -m scripts.seed_materials
|
||||
```
|
||||
| 接口 | 说明 |
|
||||
|------|------|
|
||||
| `POST /agent/run` | 提交需求与当前画布,返回 SSE |
|
||||
| `POST /agent/resume` | 回答澄清、选择选项或取消任务,返回 SSE |
|
||||
|
||||
该脚本会整体替换目标数据库中的物料目录和共享字段分组,更新后需重启服务。当前 `scripts/` 未纳入版本控制,新克隆的工作区需另行取得初始化脚本。
|
||||
|
||||
### 4. 启动与验证
|
||||
|
||||
```sh
|
||||
uv run uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
|
||||
```
|
||||
|
||||
启动后访问:
|
||||
|
||||
- [Swagger UI](http://127.0.0.1:8000/docs):查看请求模型和调试普通接口。
|
||||
- [OpenAPI](http://127.0.0.1:8000/openapi.json):获取接口定义。
|
||||
- [物料目录](http://127.0.0.1:8000/api/materials):确认物料已载入,正常返回 `code: 0`。
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 创建会话并发起任务
|
||||
|
||||
调用 `POST /api/conversations` 创建会话,取得 `data.conversation_id`,再向 `POST /api/agent/run` 提交需求和当前画布:
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"prompt": "在画布顶部添加标题:销售数据概览",
|
||||
"screen": {
|
||||
"canvas": {
|
||||
"width": 1920,
|
||||
"height": 1080
|
||||
},
|
||||
"nodes": []
|
||||
},
|
||||
"context": {
|
||||
"conversation_id": "创建会话接口返回的 ID"
|
||||
}
|
||||
"screen": { "canvas": { "width": 1920, "height": 1080 }, "nodes": [] },
|
||||
"context": { "conversation_id": "<POST /conversations 返回的 ID>" }
|
||||
}
|
||||
```
|
||||
|
||||
开启鉴权后,创建会话和后续请求都需要携带 Bearer token。每次新任务都应提交 **当前画布的完整快照**;继续同一段对话时复用
|
||||
`conversation_id`,历史消息由服务端读取。
|
||||
每次 `run` 提交画布的完整快照;同一段对话复用 `conversation_id`,历史由服务端读取。
|
||||
|
||||
### 处理流式结果
|
||||
SSE 事件:
|
||||
|
||||
`/api/agent/run` 和 `/api/agent/resume` 均返回 `text/event-stream`。前端使用支持 POST 和响应流读取的客户端,例如 `fetch`。
|
||||
| 事件 | 含义 |
|
||||
|------|------|
|
||||
| `progress` | 当前处理阶段 |
|
||||
| `answer_delta` | 问答文本增量,最终以 `final.data.answer` 为准 |
|
||||
| `final` | 本轮结果,`data.status` 见下 |
|
||||
| `error` | 流开始后的执行异常 |
|
||||
|
||||
| 事件 | 客户端处理方式 |
|
||||
|----------------|------------------------------------------------------------------------|
|
||||
| `progress` | 展示当前处理阶段 |
|
||||
| `answer_delta` | 按顺序追加 `data.delta`;用于问答场景,最终以 `final.data.answer` 为准 |
|
||||
| `final` | 根据 `data.status` 展示结果、应用动作或发起澄清 |
|
||||
| `error` | 展示 `msg` 中的执行错误,结束本轮处理 |
|
||||
`final.data.status`:`completed`(有 `actions` 时由前端按序应用)、`waiting_for_input`(展示 `clarification`,用 `thread_id` 调用 `resume`)、`failed`(业务失败,不交付动作)、`cancelled`。流开始前的错误以 HTTP 状态码返回;未收到 `final` 或 `error` 即断开,应视为结果不完整。
|
||||
|
||||
每个事件的 `data:` 行统一为 `{code, data, msg}` JSON,`final.data.status` 的含义如下:
|
||||
### 会话
|
||||
|
||||
- `completed`:本轮完成;若有 `actions`,由前端按顺序应用。此状态不表示前端已经完成修改。
|
||||
- `waiting_for_input`:展示 `clarification`,保留 `thread_id` 等待用户回答。
|
||||
- `failed`:业务流程无法完成,`answer` 说明原因,不交付动作草稿。
|
||||
- `cancelled`:用户取消了等待补充的任务。
|
||||
| 接口 | 说明 |
|
||||
|------|------|
|
||||
| `POST /conversations` | 创建会话 |
|
||||
| `GET /conversations` | 分页列出当前用户的会话 |
|
||||
| `GET /conversations/{id}` | 读取会话历史 |
|
||||
| `PATCH /conversations/{id}` | 重命名 |
|
||||
| `DELETE /conversations/{id}` | 删除 |
|
||||
|
||||
流开始前的错误通过 HTTP 状态码返回;流开始后的异常通过 `error` 事件返回。客户端不能仅凭 HTTP 200 判断成功,未收到 `final` 或
|
||||
`error` 就断开应视为结果不完整。
|
||||
### 数据文件
|
||||
|
||||
### 回答澄清问题
|
||||
上传后后台解析(HTTP 202),轮询进度至 `ready` 后即可在同一会话中被 Agent 使用;已解析且未过期的文件自动带入后续对话。
|
||||
|
||||
当结果为 `waiting_for_input` 时,向 `POST /api/agent/resume` 提交:
|
||||
| 接口 | 说明 |
|
||||
|------|------|
|
||||
| `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}` | 删除 |
|
||||
|
||||
```json
|
||||
{
|
||||
"thread_id": "替换为等待补充的任务 UUID",
|
||||
"reply": {
|
||||
"answer": "使用月度销售额,放在画布左侧"
|
||||
}
|
||||
}
|
||||
```
|
||||
### 大屏管理
|
||||
|
||||
也可使用 `reply.option_id` 提交返回的选项,或用 `reply: {"cancel": true}` 取消暂停中的任务。恢复接口沿用任务所属会话。
|
||||
大屏仅所有者可访问,他人的大屏与不存在同样返回 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) |
|
||||
|
||||
1. 创建会话,将文件与 `conversation_id` 一起以 `multipart/form-data` 提交到 `POST /api/files`。
|
||||
2. 接口返回 HTTP 202 和 `data.file_id`,轮询 `GET /api/files/{file_id}/progress`。
|
||||
3. 等待 `status=ready` 后,在同一会话发起 Agent 请求,例如“按月份汇总销售额,生成柱状图”。解析失败时状态为 `failed`,原因在
|
||||
`error.msg` 中。
|
||||
4. Agent 查询文件数据,将结果转换为图表配置,再返回经过校验的编辑动作。
|
||||
### 公开与其他
|
||||
|
||||
会话中已解析且未过期的文件会自动提供给 Agent,无需每轮重新上传。
|
||||
|
||||
## 接口概览
|
||||
|
||||
所有业务接口统一使用 `/api` 前缀,普通 JSON 响应同样采用 `{code, data, msg}` 结构。除物料目录和上传限制外,下列接口默认需要登录。
|
||||
|
||||
| 方法与路径 | 用途 |
|
||||
|------------------------------------------------------|--------------------------------------|
|
||||
| `POST /api/conversations` | 创建会话 |
|
||||
| `GET /api/conversations` | 分页查询当前用户的会话 |
|
||||
| `GET /api/conversations/{conversation_id}` | 读取会话历史 |
|
||||
| `POST /api/agent/run` | 发起任务,返回 SSE |
|
||||
| `POST /api/agent/resume` | 恢复或取消暂停中的任务,返回 SSE |
|
||||
| `GET /api/materials` | 获取公开的组件物料目录 |
|
||||
| `GET /api/files/limits` | 获取当前上传限制与支持格式,无需认证 |
|
||||
| `POST /api/files` | 上传文件并后台解析 |
|
||||
| `GET /api/files?conversation_id=...` | 获取会话文件和进行中的上传 |
|
||||
| `GET /api/files/{file_id}` | 获取文件详情与表信息 |
|
||||
| `GET /api/files/{file_id}/progress` | 查询解析进度 |
|
||||
| `GET /api/files/{file_id}/tables/{table}/rows` | 分页读取并排序表数据 |
|
||||
| `POST /api/files/{file_id}/tables/{table}/aggregate` | 分组汇总表数据 |
|
||||
| `DELETE /api/files/{file_id}` | 删除文件 |
|
||||
|
||||
完整字段、约束和响应模型以运行中的 [Swagger UI](http://127.0.0.1:8000/docs)
|
||||
为准;动作协议定义见 [app/schemas/actions](app/schemas/actions)。
|
||||
|
||||
## 架构设计
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Client[大屏编辑器] --> API[FastAPI / AgentService]
|
||||
API --> Input[输入与会话上下文]
|
||||
Input --> Intent[Jev 意图判断]
|
||||
Intent -->|明确问答且达到阈值| QA[问答 Agent]
|
||||
Intent -->|其他请求| Screen[大屏 Agent]
|
||||
Screen --> Materials[MCP 物料与字段查询]
|
||||
Screen --> Batch[动作校验与整批模拟执行]
|
||||
Screen -->|需要补充| Wait[LangGraph 暂停]
|
||||
Wait -->|用户回答并恢复| Input
|
||||
QA --> Data[数据描述与 DuckDB 查询]
|
||||
Screen --> Data
|
||||
Data --> Files[会话文件 / Parquet]
|
||||
QA --> SSE[SSE 进度与结果]
|
||||
Screen --> SSE
|
||||
SSE --> Client
|
||||
```
|
||||
|
||||
外层 LangGraph 管理路由、任务状态与澄清恢复;内层 LangChain Agent 根据上下文调用工具。只有 Jev 选中问答且概率达到阈值时进入问答分支,其余请求交给大屏
|
||||
Agent。
|
||||
|
||||
大屏 Agent 通过 `get_nodes` 读取组件完整配置,通过 MCP 查询物料,通过 `apply_actions`
|
||||
提交修改。每批动作在工作画布(原始画布加上之前成功的修改)上模拟执行,读取和修改都基于它;字段和动作校验失败时这一批不生效,返回原因由
|
||||
Agent 修正。上传数据解析为 Parquet,查询结果可直接填入图表配置,避免模型逐行复写数据。
|
||||
|
||||
| 技术 | 职责 |
|
||||
|------------------------------------|------------------------------------------|
|
||||
| FastAPI / Pydantic | HTTP 接口、请求与响应模型、字段校验 |
|
||||
| LangGraph | 外层工作流、检查点、暂停与恢复 |
|
||||
| LangChain / langchain-openai | Agent 工具循环与聊天模型调用 |
|
||||
| TypeSafe / Jev | 意图判断 |
|
||||
| MCP | 组件物料和字段查询,接入额外工具服务 |
|
||||
| MongoDB | 物料目录、会话历史、图检查点、文件元数据 |
|
||||
| python-calamine / PyArrow / DuckDB | 表格读取、Parquet 存储、数据查询与汇总 |
|
||||
| Loguru / Langfuse | 应用日志与可选的调用追踪 |
|
||||
| 接口 | 说明 |
|
||||
|------|------|
|
||||
| `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/
|
||||
├── main.py # 应用入口与服务生命周期
|
||||
├── config.py # 环境变量与配置校验
|
||||
├── api/ # Agent、会话、物料与文件接口
|
||||
├── services/ # 任务调度、会话存储与持久化装配
|
||||
├── processor/ # LangGraph 工作流、节点、状态与历史裁剪
|
||||
├── agent/ # 大屏和问答 Agent、本地工具、Skills 加载
|
||||
├── actions/ # 动作执行、布局计算与整批模拟
|
||||
├── datafiles/ # 文件解析、存储、查询、概况与后台任务
|
||||
├── schemas/ # 请求、画布、动作、会话和数据文件模型
|
||||
├── resources/ # 物料定义、目录缓存与字段规则
|
||||
├── clients/ # LLM、Jev、MCP、用户中心客户端
|
||||
├── prompt/ # 领域约束、意图、问答与数据分析提示词
|
||||
├── core/ # 认证、异常处理和日志
|
||||
├── common/ # 统一响应与 SSE 编码
|
||||
└── observability/ # Langfuse 追踪
|
||||
mcp_servers/ # 应用管理的本地 MCP 服务
|
||||
skills/ # 大屏设计、编辑、图表替换与数据制图规则
|
||||
mcp_servers.json # MCP 服务连接配置
|
||||
.env.example # 环境变量示例
|
||||
pyproject.toml # Python 依赖与项目元数据
|
||||
uv.lock # 依赖锁文件
|
||||
├── 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)。
|
||||
|
||||
主要可调参数如下,完整配置见 [.env.example](.env.example) 和 [app/config.py](app/config.py)。
|
||||
## 部署注意
|
||||
|
||||
| 配置 | 默认值 | 用途 |
|
||||
|-----------------------------------------------------|------------------|-----------------------------------------------------------------------------|
|
||||
| `MAX_AGENT_STEPS` / `MAX_QA_STEPS` | `12` / `8` | 大屏和问答 Agent 的单次模型调用上限;大屏 Agent 没有给出结论时另加 1 次收尾 |
|
||||
| `INTENT_QA_MIN_PROBABILITY` | `0.5` | 问答分支的判定阈值 |
|
||||
| `CONVERSATION_HISTORY_TURNS` / `HISTORY_MAX_TOKENS` | `20` / `4096` | 历史读取轮数与带入模型的 token 预算 |
|
||||
| `MONGODB_CHECKPOINT_TTL` | `604800` | 检查点保留秒数,`0` 表示永久保留 |
|
||||
| `DATA_FILE_DIR` | `data/files` | 原始文件和解析结果的磁盘目录 |
|
||||
| `DATA_FILE_MAX_MB` / `DATA_FILE_TTL` | `500` / `604800` | 单文件大小上限与保留秒数 |
|
||||
| `DATA_FILE_INSIGHTS` | `true` | 上传后生成文件说明、列含义和图表建议,可关闭 |
|
||||
| `DATA_QUERY_TIMEOUT` / `DATA_EMBED_MAX_ROWS` | `10` / `1000` | 单次 SQL 查询超时秒数与每处查询写入组件的行数上限 |
|
||||
| `AUTH_ENABLED` / `AUTH_CACHE_TTL_SECONDS` | `true` / `30` | 用户中心鉴权与 token 校验缓存秒数 |
|
||||
| `MCP_TOOL_TIMEOUT` | `5` | 单次 MCP 工具调用超时秒数 |
|
||||
- **单实例**:任务与会话的并发控制、上传进度保存在进程内,请以单 worker 运行;同一会话同时只能执行一个任务。
|
||||
- **本地存储**:数据文件与封面图写入磁盘(`DATA_FILE_DIR`、`THUMBNAIL_DIR`,默认在 `data/` 下),容器部署需挂载持久卷。
|
||||
- **反向代理**:SSE 需关闭响应缓冲并放宽读取超时;上传大小限制需与 `DATA_FILE_MAX_MB` 一致。应用未配置 CORS,请通过同源代理转发 `/api`。
|
||||
- **连接中断**:客户端断开会取消当前任务,不支持心跳、事件重放或断线续传。
|
||||
- **日志**:写入 `logs/app.log`。
|
||||
|
||||
- **单 worker 运行**:任务与会话的并发保护、上传进度保存在进程内;即使配置 MongoDB,也不能据此直接扩展为多
|
||||
worker。同一会话同时只能执行一个任务。
|
||||
- **文件存储**:MongoDB 保存元数据,原始文件和 Parquet 位于 `DATA_FILE_DIR`。容器部署需保留该目录,并为反向代理配置匹配的上传大小限制。
|
||||
- **流式连接**:断开连接会取消当前执行,不会转为后台任务。当前没有 SSE 心跳、事件重放或断线续传;代理应关闭响应缓冲,并给模型调用留出足够的等待时间。
|
||||
- **前端接入**:保持 `/api` 前缀;当前应用未配置 CORS,中间开发代理或同源反向代理可将 `/api` 转发到后端。
|
||||
- **日志与追踪**:日志写入 `logs/app.log`。启用 Langfuse 时填写真实的公钥、私钥和服务地址;追踪故障不阻断主业务。
|
||||
## 开发
|
||||
|
||||
## 开发与测试
|
||||
扩展组件:修改物料定义,重新导入后重启。调整 Agent 行为:修改 [skills](skills) 与 [app/prompt](app/prompt)。新增 MCP 服务:修改 [mcp_servers.json](mcp_servers.json),连接配置支持 `${环境变量}` 展开。
|
||||
|
||||
阅读主链路可从 [app/main.py](app/main.py)
|
||||
开始,依次查看 [Agent 接口](app/api/agent.py)、[AgentService](app/services/agent.py)、[外层工作流](app/processor/graph.py)、[大屏 Agent](app/agent/screen_agent.py)
|
||||
和 [动作模拟](app/actions/batch.py)。
|
||||
|
||||
扩展组件时修改 [物料定义](app/resources/materials),导入数据库后重启服务;修改任务处理规则时查看 [skills](skills);新增 MCP
|
||||
服务时修改 [mcp_servers.json](mcp_servers.json),连接配置支持 `${环境变量名}` 展开。
|
||||
|
||||
当前 `.gitignore` 排除了 `tests/`、`docs/`、`scripts/` 等本地辅助目录,普通克隆不会包含这些内容。若工作区已有测试文件,在根目录使用标准库
|
||||
`unittest` 运行:
|
||||
测试使用标准库 `unittest`,目录 `tests/` 不在版本控制内:
|
||||
|
||||
```sh
|
||||
uv run python -m unittest discover -s tests -v
|
||||
uv run python -m unittest discover -s tests
|
||||
```
|
||||
|
||||
测试所需的 `openpyxl` 已列入开发依赖,`uv sync --locked` 默认安装。单元测试不能替代真实模型、Jev、MongoDB、用户中心和前端动作应用的联调验证。
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 现象 | 检查项 |
|
||||
|---------------------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| 会话或 Agent 接口返回 401 | 本地调试确认 `AUTH_ENABLED=false`;开启鉴权时携带有效 Bearer token |
|
||||
| 提示物料目录未加载,或 MCP 物料服务无法启动 | 检查 `MONGODB_URI`、物料初始化结果与 `8201` 端口,导入后重启服务 |
|
||||
| Agent 返回 422,提示缺少会话 | 先创建会话,并在 `context.conversation_id` 中传入返回的 ID |
|
||||
| 请求返回 409 | 同一会话或任务仍在运行,或尝试恢复未处于等待补充状态的任务 |
|
||||
| API 可访问,但 Agent 执行失败 | 查看流中的 `error`、`final.data.answer` 和 `logs/app.log`,核对模型、Jev 密钥与服务连通性 |
|
||||
| 上传返回 202,但文件暂时不可用 | 202 仅表示上传已接收,继续轮询解析进度,等待 `ready` |
|
||||
| 前端一直等不到流式反馈 | 检查是否持续读取响应流,以及代理是否缓冲 SSE 或提前超时 |
|
||||
|
||||
Reference in New Issue
Block a user