From 387c4e6f7eee9eaa1204e488eb5735aa0b8dde51 Mon Sep 17 00:00:00 2001 From: zk Date: Thu, 2 Apr 2026 14:37:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E5=BC=80?= =?UTF-8?q?=E5=8F=91AI=E8=BE=85=E5=8A=A9=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .kiro/steering/code-with-standards.md | 31 +++++ .kiro/steering/代码开发风格文档.md | 170 ++++++++++++++++++++++++++ .kiro/steering/项目结构说明.md | 115 +++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 .kiro/steering/code-with-standards.md create mode 100644 .kiro/steering/代码开发风格文档.md create mode 100644 .kiro/steering/项目结构说明.md diff --git a/.kiro/steering/code-with-standards.md b/.kiro/steering/code-with-standards.md new file mode 100644 index 0000000..60d3cf3 --- /dev/null +++ b/.kiro/steering/code-with-standards.md @@ -0,0 +1,31 @@ +--- +inclusion: always +--- + +# 项目规范执行指引 + +## 方案讨论前 + +必读 `#[[file:.kiro/steering/项目结构说明.md]]`,全面了解: +- 项目分层结构:`config` → `core` → `ai` → `models` → `services` → `api` +- 所有 ORM 模型及其关联 +- 鉴权体系设计(JWT + Redis + 功能权限) +- 现有的公共能力(中间件、日志、异常处理、AI 模型枚举),避免重复造轮子 +- 与 Java 后端(back-end)的关系:共享数据库、Redis、JWT Secret + +方案讨论时: +- 优先给出简洁的方案思路(涉及哪些模块、新增内容放在哪、核心流程概要),不要一开始就铺开所有细节 +- 用户明确要求时,再给出详细的方案流程(表结构、接口清单、完整逻辑步骤等) +- 做好解耦,说明与现有模块的关系 + +## 开发方案输出前 / 写代码前 + +必读 `#[[file:.kiro/steering/代码开发风格文档.md]]`,严格遵守: +- 命名约定、类型注解规范 +- 分包规则(api/services/models/schemas 按功能模块组织) +- Service 类注释规范(主要功能、依赖服务、使用的表、方法逻辑流程) +- 接口规范、异常处理、Redis 使用、数据库设计风格 + +## 写完代码后 + +涉及新增文件、新增模块或目录结构变更时,必须同步更新 `#[[file:.kiro/steering/项目结构说明.md]]`,保持文档与实际代码一致。 diff --git a/.kiro/steering/代码开发风格文档.md b/.kiro/steering/代码开发风格文档.md new file mode 100644 index 0000000..185ede6 --- /dev/null +++ b/.kiro/steering/代码开发风格文档.md @@ -0,0 +1,170 @@ +--- +inclusion: manual +--- + +# 代码开发风格文档 + +本项目为 FastAPI + SQLAlchemy (asyncio) 的 Python 3.12 后端项目,应用主目录为 `app/`。 + +## 项目结构 + +- `app/config/` — 配置层:Pydantic Settings 统一配置 +- `app/core/` — 核心基础设施:数据库、Redis、鉴权、中间件、异常处理、日志、统一响应 +- `app/ai/` — AI 能力层:LLM 模型枚举与实例创建 +- `app/api/` — 路由层:REST API 接口定义 +- `app/models/` — ORM 模型层:SQLAlchemy 声明式映射 +- `app/services/` — 业务逻辑层:Service 类 +- `app/core/schemas/` — 公共 Schema:统一响应模型等 + +## 命名约定 + +### 文件命名 +- 全部小写,下划线分隔,如 `func_permission_service.py`、`user_func_usage_log.py` +- 路由文件以业务名命名,如 `health.py`、`resume.py` +- ORM 模型文件与表名对应(去掉 `bg_` 前缀),如 `func_permission.py` 对应 `bg_func_permission` + +### 类命名 +- Service 以 `Service` 结尾,如 `FuncPermissionService` +- ORM 模型用 PascalCase 业务名,无后缀,如 `FuncPermission`、`UserFuncUsageLog` +- Pydantic Schema 按用途命名:请求参数以 `Param` 结尾,响应以 `Dto` 结尾,如 `ResumeParam`、`ResumeDto` +- 枚举类以大写命名,如 `LLM` + +### 变量与函数命名 +- 函数和变量使用 snake_case,如 `check_and_deduct`、`user_id` +- 私有函数以单下划线开头,如 `_insert_usage_log` +- 常量使用全大写下划线,如 `_FRIENDLY_MESSAGES`、`_SKIP_PATHS` + +## 类型注解 + +- 所有函数参数和返回值必须有类型注解 +- ORM 模型字段使用 `Mapped[T]` + `mapped_column()` 声明 +- Pydantic 模型字段使用标准类型注解 + `Field()` +- 可选字段使用 `Optional[T]` 或 `T | None` +- 集合类型使用 `list[T]`、`dict[K, V]`(Python 3.12 内置泛型) + +## 注释规范 + +- 模块级注释使用文件顶部的 docstring,说明模块用途和使用示例 +- 类注释使用 docstring,说明对应的表名和用途 +- 方法注释使用 docstring,简洁描述功能 +- 复杂逻辑用行内注释 `#` 说明 + +### ORM 模型类注释 +- 类 docstring 说明对应的表名和用途 +- 特殊字段通过 `comment` 参数说明含义,如 `comment="状态 1=启用 0=禁用"` + +### Service 类注释 +- 模块级 docstring 说明该服务的主要功能、依赖服务、使用的表 +- 格式示例: + ```python + """功能权限 Service + + 校验用户功能权限并扣减库存,业务异常时回退。 + 逻辑与 Java 端 FuncPermissionService 完全一致。 + """ + ``` +- 每个方法用 docstring 简要说明逻辑流程,复杂方法可分步骤描述 + +## 分包规则 + +### API 路由(`app/api/`) +- 每个业务模块一个路由文件,如 `health.py`、`resume.py` +- 使用 `APIRouter(prefix="/xxx", tags=["xxx"])` 定义路由前缀和标签 +- 在 `app/main.py` 中注册路由 + +### Service(`app/services/`) +- 每个业务模块一个 Service 文件 +- Service 类通过构造函数接收 `AsyncSession`,如 `def __init__(self, session: AsyncSession)` +- 不使用全局 Service 实例,每次请求通过依赖注入创建 + +### ORM 模型(`app/models/`) +- 每个表一个模型文件 +- 所有模型继承 `app.core.database.Base` +- 表名通过 `__tablename__` 指定 + +### Pydantic Schema(`app/core/schemas/`) +- 公共 Schema 放在 `app/core/schemas/` 下,如 `responses.py` +- 业务相关的请求/响应 Schema 放在对应的 `app/api/` 或 `app/services/` 同级目录,或集中在 `app/core/schemas/{功能模块}/` 下 + +## 获取当前登录用户 + +- 通过 `RequestContext.user_id.get()` 获取当前登录用户 ID +- 或通过依赖注入 `Depends(require_login)` 获取并校验 +- 需要功能权限校验时使用 `Depends(func_permission("func_code"))` + +## 接口规范 + +- Router 只负责参数接收和调用 Service,不写业务逻辑 +- 白名单路径(无需鉴权)在 `settings.auth_whitelist` 中配置 +- POST 用 `@router.post()`,GET 用 `@router.get()` +- 复杂参数使用 Pydantic 模型 + `Body()`,简单参数使用 `Query()` 或 `Path()` +- 路由方法直接返回业务数据,由 `ResponseWrapMiddleware` 自动包装为 `StandardResponse` + +## 异常处理 + +- HTTP 异常使用 `raise HTTPException(status_code=xxx, detail="描述")` +- 简单断言直接使用 Python `assert` 或 `if not ... raise` +- 不要 catch 后吞掉异常,交由全局异常处理器(`exceptions.py`)统一处理 +- 全局异常处理器已注册:HTTP异常、验证异常、断言异常、未知异常 + +## Redis 使用规范 + +- 通过 `app.core.redis.redis_client` 或依赖注入 `Depends(get_redis)` 获取客户端 +- key 命名与 Java 端保持一致,如 `login:token:{userId}` +- 值统一 JSON 序列化(`json.dumps` / `json.loads`) +- 设置 TTL 时使用 `ex` 参数(秒) + +## 数据库设计风格 + +- 与 Java 端共享同一数据库,表结构由 Java 端管理 +- 表名以 `bg_` 前缀,下划线命名,如 `bg_func_permission` +- 主键 `id`,类型 `BigInteger` +- 时间字段使用 `DateTime` 类型,包含 `create_time` 和 `update_time` +- 逻辑删除字段 `is_delete`,类型 `BigInteger`,0=正常,非0=删除 +- 状态字段用 `Integer`,0/1 表示,通过 `comment` 说明含义 +- 查询使用 SQLAlchemy `select()` + `where()` 构建条件 +- 更新使用 `update()` + `where()` + `values()` +- 会话通过 `get_db()` 依赖注入获取,自动 commit/rollback/close + +## 异步规范 + +- 所有数据库操作、Redis 操作、HTTP 请求使用 `async/await` +- Service 方法统一使用 `async def` +- 路由处理函数统一使用 `async def` +- 避免在异步上下文中使用同步阻塞操作 + +## AI 调用规范 + +- 通过 `LLM` 枚举创建模型实例:`LLM.DEEPSEEK_V3.create(temperature=0)` +- kwargs 透传给 LangChain `ChatOpenAI`(temperature、max_tokens 等) +- AI 调用应做好异常捕获和容错,单次失败不应影响整体流程 +- 长耗时 AI 调用考虑异步执行 + +## 代码格式规范 + +### 紧凑风格 +- 避免过度换行,保持代码紧凑易读 +- 链式调用尽量写在一行,除非超过 120 字符 +- 方法参数列表较多时,可适当换行但保持紧凑 +- f-string 拼接优先写在一行 + +### 示例 + +**推荐(紧凑风格):** +```python +# 查询语句一行 +result = await session.execute(select(FuncPermission).where(FuncPermission.func_code == func_code, FuncPermission.status == 1)) + +# 链式操作一行 +perm = result.scalar_one_or_none() + +# f-string 拼接一行 +log.info(f"功能权限校验 userId:{user_id} funcCode:{func_code}") + +# 方法参数紧凑排列 +async def check_and_deduct(self, user_id: int, func_code: str) -> int: + +# 多条件 where 紧凑排列 +result = await self.session.execute(select(UserFuncPermissionStock).where( + UserFuncPermissionStock.user_id == user_id, UserFuncPermissionStock.func_code == func_code)) +``` diff --git a/.kiro/steering/项目结构说明.md b/.kiro/steering/项目结构说明.md new file mode 100644 index 0000000..2c96671 --- /dev/null +++ b/.kiro/steering/项目结构说明.md @@ -0,0 +1,115 @@ +--- +inclusion: manual +--- + +# OfferPie Python AI 项目结构说明 + +## 1️⃣ 项目整体层次 +``` +offerpie_python_ai/ +│ +├─ .env / .env.test / .env.prod # 环境变量配置(dev/test/prod) +├─ requirements.txt # Python 依赖清单 +│ +└─ app/ # 应用主目录 + ├─ main.py # FastAPI 应用入口(注册异常处理、中间件、CORS、路由) + ├─ banner.txt # 启动 Banner + │ + ├─ config/ # **配置层** + │ └─ settings.py # Pydantic Settings 统一配置(环境、数据库、Redis、LLM供应商、JWT、CORS、日志等) + │ + ├─ core/ # **核心基础设施层** + │ ├─ auth.py # 权限校验依赖(require_login、func_permission 装饰器) + │ ├─ context.py # 请求上下文变量(RequestContext:request_id、user_id) + │ ├─ database.py # SQLAlchemy 异步引擎 + 会话工厂(init_db、close_db、get_db) + │ ├─ redis.py # Redis 异步连接池(init_redis、close_redis、get_redis) + │ ├─ lifespan.py # FastAPI 生命周期管理(启动初始化 DB/Redis,关闭释放资源) + │ ├─ logger.py # Loguru 日志配置(控制台+文件,自动注入 request_id/user_id) + │ ├─ middleware.py # 中间件注册(RequestID、JWT鉴权、登录拦截、请求日志、响应统一包装) + │ ├─ exceptions.py # 全局异常处理器(HTTP异常、验证异常、断言异常、未知异常) + │ └─ schemas/ + │ └─ responses.py # 统一响应模型 StandardResponse(code/msg/data/timestamp/uuid) + │ + ├─ ai/ # **AI 能力层** + │ └─ models.py # LLM 模型枚举(LLM.DOUBAO_PRO_256K、DEEPSEEK_V3、GPT_4O 等),基于 LangChain ChatOpenAI + │ + ├─ api/ # **路由层**(REST API 接口) + │ └─ health.py # 健康检查接口 GET /health/ + │ + ├─ models/ # **ORM 模型层**(SQLAlchemy 声明式映射) + │ ├─ func_permission.py # 功能权限定义表(bg_func_permission) + │ ├─ user_func_permission_stock.py # 用户功能权限库存表(bg_user_func_permission_stock) + │ └─ user_func_usage_log.py # 用户功能使用记录表(bg_user_func_usage_log) + │ + └─ services/ # **业务逻辑层** + └─ func_permission_service.py # 功能权限服务(校验+扣减+回退,逻辑与Java端一致) +``` + +## 2️⃣ 各层模块职责 +| 层级 | 主要职责 | 关键类/文件 | +|------|----------|-------------| +| **config** | 统一配置管理,基于 Pydantic Settings,支持 .env 文件加载 | `Settings`(数据库、Redis、LLM供应商、JWT、CORS、日志等全部配置项) | +| **core** | 核心基础设施:数据库连接、Redis连接、鉴权、日志、中间件、异常处理、统一响应 | `database.py`、`redis.py`、`auth.py`、`middleware.py`、`exceptions.py`、`logger.py`、`StandardResponse` | +| **ai** | AI 模型管理,封装多供应商 LLM 实例创建,基于 LangChain ChatOpenAI | `LLM` 枚举(火山引擎:doubao/deepseek,心缘:gpt-4o/claude) | +| **api** | REST API 路由定义 | `health.py`(健康检查) | +| **models** | SQLAlchemy ORM 模型,与 Java 端共享同一数据库 | `FuncPermission`、`UserFuncPermissionStock`、`UserFuncUsageLog` | +| **services** | 业务逻辑实现 | `FuncPermissionService`(功能权限校验、扣减、回退) | + +## 3️⃣ 技术栈 +| 类别 | 技术选型 | 说明 | +|------|----------|------| +| **Web 框架** | FastAPI + Uvicorn + Gunicorn | 异步 ASGI 框架 | +| **ORM** | SQLAlchemy 2.0 (asyncio) + asyncmy | 异步 MySQL 驱动 | +| **缓存** | redis-py (asyncio) | 异步 Redis 客户端 | +| **AI/LLM** | LangChain + LangChain-OpenAI + LangGraph | AI 编排框架,兼容 OpenAI 协议的多供应商接入 | +| **配置** | Pydantic Settings + python-dotenv | 类型安全的环境变量管理 | +| **日志** | Loguru | 结构化日志,自动注入请求上下文 | +| **鉴权** | PyJWT | JWT 解析,与 Java 端共享同一 jwt_secret | +| **数据处理** | Pandas + NumPy | 数据分析与处理 | +| **HTTP** | httpx | 异步 HTTP 客户端 | + +## 4️⃣ 中间件执行链(由外到内) +| 顺序 | 中间件 | 职责 | +|------|--------|------| +| 1 | `RequestIDMiddleware` | 生成 ShortUUID 请求ID,写入响应头 X-Request-ID | +| 2 | `JwtAuthMiddleware` | 从 Cookie/Header 解析 JWT,校验 Redis 登录信息,续期,写入 RequestContext.user_id | +| 3 | `AuthRequiredMiddleware` | 非白名单路径必须有 user_id,否则返回 401 | +| 4 | `RequestLogMiddleware` | 记录请求方法、URL、参数、响应状态码和耗时 | +| 5 | `ResponseWrapMiddleware` | 将业务路由的 JSON 响应统一包装为 StandardResponse 格式 | + +## 5️⃣ 鉴权体系 +- 与 Java 端共享同一 JWT Secret 和 Redis 登录信息 +- Token 来源:优先 Cookie `Token`,其次 Header `Token` +- 白名单路径(`/health/**`、`/docs/**`、`/redoc/**`、`/openapi.json`)跳过鉴权 +- 功能权限校验通过 `func_permission(func_code)` 依赖注入实现,逻辑与 Java 端 `FuncPermissionAspect` 完全一致: + 1. 校验每日免费额度 + 2. 查付费库存(时间+次数维度) + 3. SQL 原子扣减 + 4. 业务异常自动回退 + +## 6️⃣ AI 模型配置 +| 供应商 | 模型 | 枚举值 | +|--------|------|--------| +| 火山引擎 | doubao-pro-256k | `LLM.DOUBAO_PRO_256K` | +| 火山引擎 | doubao-pro-32k | `LLM.DOUBAO_PRO_32K` | +| 火山引擎 | doubao-lite-128k | `LLM.DOUBAO_LITE_128K` | +| 火山引擎 | deepseek-v3-250324 | `LLM.DEEPSEEK_V3` | +| 火山引擎 | deepseek-r1-250528 | `LLM.DEEPSEEK_R1` | +| 心缘 | gpt-4o | `LLM.GPT_4O` | +| 心缘 | gpt-4o-mini | `LLM.GPT_4O_MINI` | +| 心缘 | claude-sonnet-4-20250514 | `LLM.CLAUDE_SONNET_4` | + +所有模型通过 `LLM.XXX.create(**kwargs)` 创建 LangChain `ChatOpenAI` 实例,kwargs 透传 temperature、max_tokens 等参数。 + +## 7️⃣ 与 Java 后端的关系 +- **共享数据库**:Python 端与 Java 端(back-end)连接同一 MySQL 数据库(offerpie),ORM 模型对应相同的表 +- **共享 Redis**:共享登录态(`login:token:{userId}`),JWT Secret 一致 +- **共享权限体系**:功能权限校验逻辑与 Java 端 `FuncPermissionAspect` 完全对齐 +- **职责分工**:Java 端负责业务 CRUD(用户、简历、岗位等),Python 端负责 AI 能力(LLM 调用、智能分析等) + +## 8️⃣ 构建与运行 +- **虚拟环境**:项目使用 `.venv` 目录管理 Python 虚拟环境 +- **依赖安装**:`pip install -r requirements.txt` +- **开发启动**:`python -m app.main`(默认 ENV=dev,端口由 settings.server_port 控制) +- **生产部署**:通过 Gunicorn + Uvicorn Worker 运行 +- **环境切换**:通过 `.env` / `.env.test` / `.env.prod` 文件控制环境变量