diff --git a/data/.config.example.toml b/data/config.example.toml similarity index 67% rename from data/.config.example.toml rename to data/config.example.toml index 2af0066e95f9517fd2ee1dbde4edad2b48a18bd1..a17ccd411bbd7fb0e7dfdedb0e48113f36c216ba 100644 --- a/data/.config.example.toml +++ b/data/config.example.toml @@ -3,19 +3,6 @@ mode = 'local' cookie = 'domain' data_dir = '/var/lib/euler_copilot' -[login] -provider = 'authhub' -admin_user = [ - "admin" -] - -[login.settings] -host = 'http://127.0.0.1:8000' -host_inner = 'http://127.0.0.1:11120' -login_api = 'http://127.0.0.1:8080/api/auth/login' -app_id = '' -app_secret = '' - [rag] rag_service = 'http://127.0.0.1:9988' diff --git a/design/services/activity.md b/design/services/activity.md index 431881995946a757b6c7449e8ec1fed144a6875a..ab26e0298f7a76d9ce1aa00d24d57163c0d8c44c 100644 --- a/design/services/activity.md +++ b/design/services/activity.md @@ -38,12 +38,27 @@ Activity 模块是 openEuler Intelligence 框架中的用户活动控制系统 #### 静态方法 -- `is_active(user_id)`: 先按用户滑动窗口统计,再按全局并发统计,达到任一阈值即返回 `True` -- `set_active(user_id)`: 在未超过全局并发上限时登记一个活动任务,内部使用 SQLAlchemy `merge` 以 userId 为键写入最新时间戳 -- `remove_active(user_id)`: 移除用户活动状态 +- `can_active(user_id)`: 判断系统是否可以接受新任务 + - 先检查用户滑动窗口限流:统计该用户在 `SLIDE_WINDOW_TIME` 秒内的请求数,若 >= `SLIDE_WINDOW_QUESTION_COUNT` 则返回 `False` + - 再检查全局并发限制:统计当前所有活跃任务数,若 >= `MAX_CONCURRENT_TASKS` 则返回 `False` + - 两项检查都通过则返回 `True` + +- `set_active(user_id)`: 登记一个活动任务 + - 先检查当前活跃任务数,若 >= `MAX_CONCURRENT_TASKS` 则抛出 `ActivityError` + - 使用 `session.add()` 添加新的 `SessionActivity` 记录,包含 userId 和当前时间戳 + - 每次调用都会新增一条记录(不是更新已有记录) + +- `is_active(user_id)`: 判断用户是否有活动记录 + - 统计该用户的活动记录数量,返回 count > 0 + +- `remove_active(user_id)`: 移除用户的所有活动记录 + - 删除该用户的所有 SessionActivity 记录 > **注意** -> 当前实现仅在 `is_active` 阶段执行滑动窗口校验;`set_active` 只进行一次全局并发计数后写入数据库。 +> +> - `can_active` 负责限流检查(用户级 + 系统级) +> - `set_active` 每次调用都新增记录,可能导致同一用户有多条活动记录 +> - `remove_active` 会删除用户的所有活动记录 ## 时序图 @@ -56,40 +71,40 @@ sequenceDiagram Note over Client, DB: 用户请求处理流程 Client->>Router: 发起请求 - Router->>Activity: is_active(user_id) + Router->>Activity: can_active(user_id) Note over Activity, DB: 滑动窗口限流检查 - Activity->>DB: SELECT COUNT(*) FROM framework_session_activity
WHERE userId=? AND timestamp >= ? + Activity->>DB: SELECT COUNT(*) FROM framework_session_activity
WHERE userId=? AND timestamp BETWEEN (now-15s) AND now DB-->>Activity: 返回用户窗口内请求数 - Activity->>Activity: 检查是否超过SLIDE_WINDOW_QUESTION_COUNT - + Activity->>Activity: 检查是否 >= SLIDE_WINDOW_QUESTION_COUNT + alt 用户请求数超限 - Activity-->>Router: 返回True (限流) + Activity-->>Router: 返回False (限流) Router-->>Client: 返回429错误 else 用户请求数正常 Note over Activity, DB: 全局并发检查 Activity->>DB: SELECT COUNT(*) FROM framework_session_activity DB-->>Activity: 返回当前活跃任务数 - Activity->>Activity: 检查是否超过MAX_CONCURRENT_TASKS - + Activity->>Activity: 检查是否 >= MAX_CONCURRENT_TASKS + alt 全局并发超限 - Activity-->>Router: 返回True (限流) + Activity-->>Router: 返回False (限流) Router-->>Client: 返回429错误 else 系统可处理 - Activity-->>Router: 返回False (允许) + Activity-->>Router: 返回True (允许) Router->>Activity: set_active(user_id) Note over Activity, DB: 设置活动状态 Activity->>DB: SELECT COUNT(*) FROM framework_session_activity DB-->>Activity: 返回当前活跃任务数 - Activity->>Activity: 检查是否超过MAX_CONCURRENT_TASKS - + Activity->>Activity: 检查是否 >= MAX_CONCURRENT_TASKS + alt 并发超限 Activity-->>Router: 抛出ActivityError Router-->>Client: 返回503错误 else 系统仍可处理 - Activity->>DB: MERGE INTO framework_session_activity
(userId, timestamp) - DB-->>Activity: 插入或更新成功 + Activity->>DB: INSERT INTO framework_session_activity
(userId, timestamp) + DB-->>Activity: 插入成功 Activity-->>Router: 设置成功 Router-->>Client: 处理请求 @@ -144,35 +159,37 @@ erDiagram ```mermaid flowchart TD - A[用户请求] --> B[Activity.is_active检查] - + A[用户请求] --> B[Activity.can_active检查] + B --> C{滑动窗口限流检查} - C -->|超过限制| D[返回限流状态] + C -->|超过限制| D[返回False] C -->|未超过| E{全局并发检查} - + E -->|超过限制| D - E -->|未超过| F[Activity.set_active] - - F --> G{并发检查} - G -->|检查失败| H[抛出ActivityError] - G -->|检查通过| I[插入/更新活动记录] - - I --> J[处理用户请求] - J --> K[请求完成] - K --> L[Activity.remove_active] - L --> M[删除活动记录] - M --> N[释放资源] + E -->|未超过| F[返回True] + + F --> G[Activity.set_active] - D --> O[返回429错误] - H --> P[返回503错误] - N --> Q[请求处理完成] + G --> H{并发检查} + H -->|检查失败| I[抛出ActivityError] + H -->|检查通过| J[插入活动记录] + + J --> K[处理用户请求] + K --> L[请求完成] + L --> M[Activity.remove_active] + M --> N[删除活动记录] + N --> O[释放资源] + + D --> P[返回429错误] + I --> Q[返回503错误] + O --> R[请求处理完成] style A fill:#e1f5fe - style Q fill:#c8e6c9 - style O fill:#ffcdd2 + style R fill:#c8e6c9 style P fill:#ffcdd2 + style Q fill:#ffcdd2 style D fill:#fff3e0 - style H fill:#fff3e0 + style I fill:#fff3e0 ``` ## 限流机制详解 @@ -195,9 +212,9 @@ flowchart LR subgraph "登记活跃任务" K[set_active调用] --> L[统计当前活跃任务数] - L --> M{超过上限?} - M -->|是| O[抛出异常] - M -->|否| N[插入/更新记录] + L --> M{>= 上限?} + M -->|是| O[抛出ActivityError] + M -->|否| N[插入新记录] end E --> F @@ -306,14 +323,15 @@ SLIDE_WINDOW_QUESTION_COUNT = 5 # 窗口内最大请求数 ## 使用示例 ```python -# 检查是否被限流 -if await Activity.is_active(user_id): - raise HTTPException(status_code=429, detail="请求过于频繁") +# 检查系统是否可以接受新任务 +if not await Activity.can_active(user_id): + raise HTTPException(status_code=429, detail="请求过于频繁或系统繁忙") # 设置活动状态 try: await Activity.set_active(user_id) # 处理业务逻辑 + ... finally: # 清理活动状态 await Activity.remove_active(user_id) diff --git a/design/services/session.md b/design/services/session.md deleted file mode 100644 index 717fa0a84d1d8a7f322b9ee7f84ac4b82eb81916..0000000000000000000000000000000000000000 --- a/design/services/session.md +++ /dev/null @@ -1,267 +0,0 @@ -# Session模块设计文档 - -## 概述 - -Session 模块是 openEuler Intelligence 框架中的会话管理系统,负责创建、删除和验证用户会话。该模块实现了基于数据库的会话存储机制,支持会话创建、会话删除、用户信息获取以及黑名单用户检查功能,确保系统安全性和用户身份验证的可靠性。 - -## 核心功能 - -- **会话创建**: 为用户创建新的浏览器会话 -- **会话删除**: 删除指定的会话记录 -- **用户信息获取**: 从会话中获取用户标识 -- **黑名单检查**: 验证用户是否在黑名单中 -- **会话查询**: 根据用户标识查询会话 - -## 数据模型 - -### Session实体 - -- **表名**: `framework_session` -- **主键**: `id` (String(255), 默认为随机生成的16字节十六进制字符串) -- **字段**: - - `userId`: 用户标识 (String(50), 外键关联framework_user.id) - - `ip`: IP地址 (String(255), 可为空) - - `pluginId`: 插件ID (String(255), 可为空) - - `token`: Token信息 (String(2000), 可为空) - - `validUntil`: 有效期 (DateTime, 时区感知) - - `sessionType`: 会话类型 (Enum(SessionType)) - -### SessionType枚举 - -- `ACCESS_TOKEN`: 访问令牌 -- `REFRESH_TOKEN`: 刷新令牌 -- `PLUGIN_TOKEN`: 插件令牌 -- `CODE`: 代码类型会话 - -## 配置常量 - -- `SESSION_TTL`: 会话有效期,单位为分钟 (默认: 30 \* 24 \* 60,即30天) - -## 服务层 - -### SessionManager类 - -#### 静态方法 - -- `create_session(user_id, ip)`: 创建浏览器会话 -- `delete_session(session_id)`: 删除浏览器会话 -- `get_user(session_id)`: 从会话中获取用户 -- `get_session_by_user(user_id)`: 根据用户标识获取会话 - -## 时序图 - -```mermaid -sequenceDiagram - participant Client as 客户端 - participant SessionMgr as SessionManager - participant BlacklistMgr as UserBlacklistManager - participant DB as 数据库 - - Note over Client, DB: 创建会话流程 - Client->>SessionMgr: create_session(user_id, ip) - SessionMgr->>SessionMgr: 验证参数 - alt 参数无效 - SessionMgr-->>Client: 抛出ValueError - else 参数有效 - SessionMgr->>DB: 创建Session对象 - Note over SessionMgr, DB: 设置会话有效期为当前时间+SESSION_TTL - SessionMgr->>DB: session.merge(data) - SessionMgr->>DB: session.commit() - DB-->>SessionMgr: 提交成功 - SessionMgr-->>Client: 返回session_id - end - - Note over Client, DB: 获取用户流程 - Client->>SessionMgr: get_user(session_id) - SessionMgr->>DB: 查询Session.userId - DB-->>SessionMgr: 返回user_id或None - - alt 用户不存在 - SessionMgr-->>Client: 返回None - else 用户存在 - SessionMgr->>BlacklistMgr: check_blacklisted_users(user_id) - BlacklistMgr->>DB: 查询用户黑名单状态 - DB-->>BlacklistMgr: 返回黑名单状态 - BlacklistMgr-->>SessionMgr: 返回是否在黑名单中 - - alt 用户在黑名单中 - SessionMgr->>SessionMgr: 记录错误日志 - SessionMgr->>SessionMgr: delete_session(session_id) - SessionMgr->>DB: 删除会话 - DB-->>SessionMgr: 删除成功 - SessionMgr-->>Client: 返回None - else 用户不在黑名单中 - SessionMgr-->>Client: 返回user_id - end - end - - Note over Client, DB: 删除会话流程 - Client->>SessionMgr: delete_session(session_id) - alt session_id为空 - SessionMgr-->>Client: 直接返回 - else session_id有效 - SessionMgr->>DB: 查询Session - DB-->>SessionMgr: 返回session_data或None - alt 会话存在 - SessionMgr->>DB: session.delete(session_data) - DB-->>SessionMgr: 删除成功 - end - SessionMgr->>DB: session.commit() - DB-->>SessionMgr: 提交成功 - SessionMgr-->>Client: 返回None - end - - Note over Client, DB: 根据用户查询会话流程 - Client->>SessionMgr: get_session_by_user(user_id) - SessionMgr->>DB: 查询Session.id - DB-->>SessionMgr: 返回session_id或None - SessionMgr-->>Client: 返回session_id或None -``` - -## ER图 - -```mermaid -erDiagram - User ||--o{ Session : "用户拥有会话" - User ||--o{ SessionActivity : "用户产生活动" - - User { - string userId PK "用户标识" - boolean isWhitelisted "是否白名单" - integer credit "信用分" - string personalToken "个人令牌" - } - - Session { - string id PK "会话ID" - string userId FK "用户标识" - string ip "IP地址" - string pluginId "插件ID" - string token "Token信息" - datetime validUntil "有效期" - enum sessionType "会话类型" - } - - SessionActivity { - BigInteger id PK - string userId FK "用户标识" - datetime timestamp "活动时间戳" - } -``` - -## 流程图 - -```mermaid -flowchart TD - subgraph "创建会话流程" - A1[客户端请求创建会话] --> B1{验证参数} - B1 -->|参数无效| C1[抛出ValueError] - B1 -->|参数有效| D1[创建Session对象] - D1 --> E1[设置会话有效期] - E1 --> F1[保存到数据库] - F1 --> G1[返回session_id] - end - - subgraph "获取用户流程" - A2[客户端请求获取用户] --> B2[查询会话] - B2 --> C2{会话存在?} - C2 -->|不存在| D2[返回None] - C2 -->|存在| E2[查询黑名单] - E2 --> F2{用户在黑名单?} - F2 -->|是| G2[记录错误日志] - G2 --> H2[删除会话] - H2 --> I2[返回None] - F2 -->|否| J2[返回user_id] - end - - subgraph "删除会话流程" - A3[客户端请求删除会话] --> B3{session_id为空?} - B3 -->|是| C3[直接返回] - B3 -->|否| D3[查询会话] - D3 --> E3{会话存在?} - E3 -->|是| F3[删除会话] - E3 -->|否| G3[提交事务] - F3 --> G3 - G3 --> H3[返回None] - end - - subgraph "根据用户查询会话流程" - A4[客户端请求查询会话] --> B4[查询数据库] - B4 --> C4[返回session_id或None] - end - - style A1 fill:#e1f5fe - style G1 fill:#c8e6c9 - style A2 fill:#e1f5fe - style D2 fill:#fff3e0 - style I2 fill:#fff3e0 - style J2 fill:#c8e6c9 - style A3 fill:#e1f5fe - style H3 fill:#c8e6c9 - style A4 fill:#e1f5fe - style C4 fill:#c8e6c9 -``` - -## 安全考虑 - -1. **会话有效期**: 会话设置了30天的默认有效期,防止长期未使用的会话被滥用 -2. **IP地址验证**: 创建会话时验证IP地址,防止无效请求 -3. **用户黑名单检查**: 获取用户信息时检查用户是否在黑名单中,增强系统安全性 -4. **会话自动清理**: 对于黑名单用户的会话自动删除,防止未授权访问 -5. **参数验证**: 对输入参数进行严格验证,防止无效数据 - -## 性能优化 - -1. **数据库索引**: 对userId和id字段建立索引,提高查询效率 -2. **异步操作**: 所有数据库操作使用异步方式,提高并发性能 -3. **连接池管理**: 使用数据库连接池管理连接,减少连接开销 -4. **最小化查询**: get_user方法只查询必要的userId字段,而非整个Session对象 - -## 与其他模块的交互 - -1. **UserBlacklistManager**: 用于检查用户是否在黑名单中 -2. **PostgreSQL数据库**: 用于存储和检索会话数据 -3. **认证系统**: 提供会话创建和验证功能 -4. **路由层**: 使用会话管理功能进行用户身份验证 - -## 异常处理 - -### ValueError异常 - -- **触发条件**: 当创建会话时提供的IP地址或用户标识为空 -- **错误信息**: "用户IP错误!" 或 "用户名错误!" -- **处理方式**: 向上层抛出异常,由调用方处理 - -## 配置说明 - -```toml -# 会话配置 -SESSION_TTL = 43200 # 会话有效期(分钟),默认30天 -``` - -## 使用示例 - -```python -# 创建会话 -session_id = await SessionManager.create_session(user_id="user123", ip="192.168.1.1") - -# 获取用户信息 -user_id = await SessionManager.get_user(session_id) -if user_id: - # 用户有效,处理业务逻辑 -else: - # 用户无效或在黑名单中 - -# 删除会话 -await SessionManager.delete_session(session_id) - -# 根据用户查询会话 -session_id = await SessionManager.get_session_by_user(user_id) -``` - -## 扩展性 - -1. **会话类型扩展**: SessionType枚举可以扩展支持更多会话类型 -2. **会话属性扩展**: Session模型可以添加更多字段以支持额外功能 -3. **验证机制扩展**: 可以增加更多的验证逻辑,如设备指纹验证 -4. **分布式会话**: 可以扩展支持分布式环境下的会话管理 diff --git "a/documents/user-guide/\345\274\200\345\217\221\346\214\207\345\215\227/EulerCopilot\346\217\222\344\273\266\345\274\200\345\217\221\346\214\207\345\215\227.md" "b/documents/user-guide/\345\274\200\345\217\221\346\214\207\345\215\227/EulerCopilot\346\217\222\344\273\266\345\274\200\345\217\221\346\214\207\345\215\227.md" index 4698438ce0ce3fe940f87e7219a303c162e6aac0..ae75486cc6fef44e792513972bc2ba95f6a56435 100644 --- "a/documents/user-guide/\345\274\200\345\217\221\346\214\207\345\215\227/EulerCopilot\346\217\222\344\273\266\345\274\200\345\217\221\346\214\207\345\215\227.md" +++ "b/documents/user-guide/\345\274\200\345\217\221\346\214\207\345\215\227/EulerCopilot\346\217\222\344\273\266\345\274\200\345\217\221\346\214\207\345\215\227.md" @@ -48,17 +48,16 @@ test_plugin # 插件文件夹,该文件夹的名称即为插件ID; ### 字段说明 - ID:插件的ID,用于在EulerCopilot内唯一标识该插件。 - - 要求:小写英文字母与符号的组合 + - 要求:小写英文字母与符号的组合 - name:插件的名字,用于提供给前端进行展示。 - - 要求:任意字符串,长度小于15个字。 + - 要求:任意字符串,长度小于15个字。 - description:插件的描述,用户提供给大模型进行自动插件选择。 - - 要求:精准、完整地描述插件的功能、输入与输出。 + - 要求:精准、完整地描述插件的功能、输入与输出。 - predefined_question:插件的预定义问题,用于在用户无输入时自动填充该问题。(建设中) - automatic_flow:是否将每个API自动拆分为Flow - auth:插件的鉴权信息 - - type:插件的鉴权类型。可以为“param”、“header”和“cookie”和“oidc”四种类型。 - - args:实际的鉴权字段(键值对)。 - + - type:插件的鉴权类型。可以为“param”、“header”和“cookie”三种类型。 + - args:实际的鉴权字段(键值对)。 ## openapi.yaml @@ -133,12 +132,14 @@ curl -X POST http://example.com:port/suffix/url \ > 由于YAML有诸多层级,因此此处使用如下方式描述YAML中特定的字段: > 有YAML文件如下 +> > ```yaml > a: > b1: > c: test1 > b2: ["test2"] >``` +> > 则:`a.b1.c`指值为`test1`的字段;`a.b2[]`指值为`["test2"]`的数组。 #### 全局字段 @@ -170,7 +171,6 @@ curl -X POST http://example.com:port/suffix/url \ JSON Schema的全部规范内容可参照[JSON Schema官方文档](https://json-schema.org/understanding-json-schema/reference)。 - ##### Schema格式样例 有如下的Schema YAML样例: @@ -257,7 +257,7 @@ YAML格式的Schema编写,可以参考[OpenAPI文档中的DataType章节](http - 正确工作流逻辑示例: -``` +```text 工作流功能:查询某一主机的所有CVE列表,并生成特定格式输出 步骤1:调用API接口,获取某一主机的全部CVE ID 步骤2:根据获得的CVE ID和给定的输出格式,生成自然语言结果 @@ -265,7 +265,7 @@ YAML格式的Schema编写,可以参考[OpenAPI文档中的DataType章节](http - 错误工作流逻辑示例:多个低耦合任务 -``` +```text 工作流功能:根据用户输入,到特定的数据库中查询数据。再根据用户输入,查询输入对应的任务metadata。结合数据库中的数据和任务metadata,生成任务报告。 ``` @@ -273,13 +273,12 @@ YAML格式的Schema编写,可以参考[OpenAPI文档中的DataType章节](http - 错误工作流逻辑示例:工作流耦合 -``` +```text 工作流功能:需要先调用flow_1获取测试数据才能使用该工作流。该工作流的作用是将flow_1返回值中的data字段提取出来并存储在数据库的test_data表中,... ``` 工作流间的先后关系应通过用户问题和自然语言上下文进行实现;不同工作流之间暂时无法进行结构化数据的传递。 - ### 基本格式 一个`flow.yaml`的基本格式如下: