From 6c1440a20c73fc4c3e00840e926ad214e9068411 Mon Sep 17 00:00:00 2001 From: GuoQing Zhang Date: Mon, 25 May 2026 17:40:19 +0800 Subject: [PATCH] docs: consolidate AGENTS.md with progressive disclosure, symlink CLAUDE.md - Merge CLAUDE.md + AGENTS.md into a single AGENTS.md (~190 lines, P0 only) - CLAUDE.md and src/backend/CLAUDE.md are now symlinks to their AGENTS.md counterparts so all AI coding tools (Cursor, Copilot, etc.) read the same source - Move backend commands, module map, and subsystem internals to src/backend/AGENTS.md (auto-loaded by Claude Code only when editing backend files) - Frontend critical constraints remain inline in root AGENTS.md for non-Claude-Code tools - Drop v2.5 branch references and verbose historical context --- AGENTS.md | 678 +++++++++--------------------------------- CLAUDE.md | 271 +---------------- src/backend/AGENTS.md | 234 +++++++++++++++ src/backend/CLAUDE.md | 1 + 4 files changed, 371 insertions(+), 813 deletions(-) mode change 100644 => 120000 CLAUDE.md create mode 100644 src/backend/AGENTS.md create mode 120000 src/backend/CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index 912046ebb..a8e89f251 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,600 +1,192 @@ -# CLAUDE.md +# AGENTS.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +Guidance for AI agents and Claude Code. Loaded every session — only P0 rules live here. +Deeper backend reference (module map, subsystems): `src/backend/AGENTS.md` (auto-loaded when editing backend files). -## 项目概述 +--- -BiSheng (毕昇) v2.5.0-dev — 面向企业的开源 LLM 应用 DevOps 平台。支持工作流编排、知识库管理、多 Agent 协作(Linsight 灵思)、模型评测与微调、MCP 集成。 +## 1. Project Identity -**架构定位**:前后端分离 + 异步任务处理的分层架构。7 个运行时进程组 + 6 个基础设施服务,后端遵循 DDD(领域驱动设计)模式。 +**BiSheng (毕昇)** — Enterprise LLM application DevOps platform. Monorepo, three sub-projects: -**v2.5 核心改造**:权限体系从 RBAC 迁移到 ReBAC(OpenFGA)+ 多租户支持(逻辑隔离)。改造上下文见「v2.5 改造上下文」章节。 +| Path | Project | Stack | +|------|---------|-------| +| `src/backend/` | FastAPI + Celery Workers + Linsight Worker | Python 3.10+, uv, SQLModel, LangGraph | +| `src/frontend/platform/` | Admin / builder UI | Vite 5 + **Zustand** + react-query v3 + bs-ui | +| `src/frontend/client/` | End-user chat UI (`/workspace` base path) | Vite 6 + **Recoil** + react-query v5 + shadcn/ui | -## 部署架构 +--- -采用混合部署:主要服务本地源码运行,存储服务 Docker 容器化。 +## 2. Commands -``` -本地服务 (源码部署) Docker 存储层 -├── FastAPI 后端 (uvicorn) :7860 ├── Milvus 2.5 向量库 :19530 -├── MySQL 8.0 :3306 ├── Elasticsearch 8.12 :9200 -├── Redis 7.0 :6379 ├── MinIO 对象存储 :9000 -├── Celery Workers ├── OpenFGA 权限引擎 :8080 -├── Linsight Worker (可选) └── OnlyOffice :8701 -├── Gateway (Java, 商业版) :8180 -├── Platform 前端 Vite :3001 -└── Client 前端 Vite :4001 -``` +Backend commands (test, lint, start, Celery, Alembic) → `src/backend/CLAUDE.md`. -**Nginx 反向代理**: 8860 → 3001(Platform 前端) - -**两种 API 代理模式**(通过 `VITE_PROXY_TARGET` 环境变量切换): -- **开源模式**(默认):Vite `/api/` → Backend:7860(直连后端) -- **商业版模式**:Vite `/api/` → Gateway:8180 → Backend:7860(经 Gateway 代理) - -**关键原则**: 本地与 Docker 绝不运行同类服务,避免端口冲突。 - -**Docker 仅中间件 + 本机 bisheng / Gateway / 双前端**:一键脚本与端口对齐说明见 [`docker/local-dev/README.md`](docker/local-dev/README.md)。 - -## 开发命令 - -### 环境准备 ```bash -# Python 3.10.14 (必须) -conda create --name BiShengVENV python==3.10.14 -conda activate BiShengVENV - -# 后端依赖 (使用 uv,lockfile 为 uv.lock) -cd src/backend -uv sync --frozen --python /path/to/python -``` - -### 启动服务 -```bash -# 1a. 推荐:仅 Docker 中间件(本机跑 bisheng / 前端 / Gateway 时用) -# Windows: powershell -ExecutionPolicy Bypass -File docker/local-dev/start-middleware.ps1 -# Linux/macOS: bash docker/local-dev/start-middleware.sh - -# 1b. 或:全量 compose 后再手动停掉与本地冲突的容器 -cd docker && docker compose -p bisheng up -d -docker stop bisheng-backend bisheng-backend-worker bisheng-frontend - -# 2. 后端 API (端口 7860;config 须为相对 bisheng 包目录的文件名,例如 export config=config.yaml) -cd src/backend -.venv/bin/uvicorn bisheng.main:app --host 0.0.0.0 --port 7860 --workers 1 --no-access-log - -# 3. Celery Workers (各开一个终端) -.venv/bin/celery -A bisheng.worker.main worker -l info -c 20 -P threads -Q knowledge_celery -n knowledge@%h -.venv/bin/celery -A bisheng.worker.main worker -l info -c 100 -P threads -Q workflow_celery -n workflow@%h -.venv/bin/celery -A bisheng.worker.main beat -l info - -# 4. Linsight Worker (可选,灵思 Agent 框架) -.venv/bin/python bisheng/linsight/worker.py --worker_num 4 --max_concurrency 5 -``` - -### Gateway(商业版,可选) -```bash -# Gateway 源码在独立仓库: https://github.com/dataelement/bisheng-gateway -# 远程源码: /opt/bisheng-gateway/(114 服务器) - -# 构建 (Maven, Java 17) -cd /opt/bisheng-gateway -mvn clean package -DskipTests - -# 启动 (端口 8180,避免与 OpenFGA 8080 冲突;本地连 Docker 中间件用 local 配置) -java -jar target/gateway-0.0.1-SNAPSHOT.jar --spring.profiles.active=local --server.port=8180 - -# 组织同步到 bisheng:当前 bisheng 已无 /api/v2/group/sync;Gateway 通过 F014 HMAC 调 bisheng -# POST /api/v1/departments/sync。联调入口见 docker/local-dev/README.md §6(含一键脚本与冒烟命令)。 - -# 启用商业版功能需设置后端环境变量 -export BISHENG_PRO=true # 在启动后端前设置,开启 /api/v1/user/sso 端点 -``` - -### 前端开发 -```bash -# Platform 前端 (管理端,端口 3001) -cd src/frontend/platform -npm install -npm start -- --host 0.0.0.0 # 默认代理 /api/ 到 localhost:7860 - -# 使用 Gateway 代理模式启动(商业版功能) +# Frontend +cd src/frontend/platform && npm install && npm start -- --host 0.0.0.0 # :3001 +cd src/frontend/client && npm install && npm run dev # :4001 +# Commercial Gateway proxy mode: VITE_PROXY_TARGET=http://localhost:8180 npm start -- --host 0.0.0.0 -# Client 前端 (用户端,端口 4001,基础路径 /workspace) -cd src/frontend/client -npm install -npm run dev +# Middleware (Docker only) +bash docker/local-dev/start-middleware.sh # MySQL / Redis / Milvus / ES / MinIO / OpenFGA ``` -### 测试与代码风格 -```bash -cd src/backend -.venv/bin/pytest test/ # 全部测试 -.venv/bin/pytest test/test_xxx.py::test_fn # 单个用例 -.venv/bin/pytest test/ -k "keyword" # 按关键字 -.venv/bin/black . # 格式化 -.venv/bin/ruff check . --fix # lint 检查 +--- + +## 3. Backend Rules (P0) + +### 3.1 Layered Architecture (DDD) + +Call chain — never skip layers: +``` +Router → Endpoint → Service → Repository → DB ``` -## 代码导航 +- **Never** `import bisheng.database.models.*` in endpoints (arch-guard RULE-3 WARNING). +- **Never** write ORM queries in Service; **never** add new DAO entry points for new features. +- New module layout: `/{api/router.py, api/endpoints/, domain/services/, domain/models/, domain/schemas/, domain/repositories/}` +- Register the router in `bisheng/api/router.py`. -> 回答"代码在哪"。详细架构文档见 `docs/architecture/`。 +### 3.2 Dual-DB Compatibility (MySQL + DM8) ⚠️ -### 仓库结构 +Every new feature must work on both dialects. DM8 is not optional. -``` -bisheng/ -├── src/backend/bisheng/ # FastAPI 后端主应用 -├── src/backend/bisheng_langchain/ # LangChain 扩展包 (独立 Python 包) -├── src/frontend/platform/ # Platform 管理端前端 (React) -├── src/frontend/client/ # Client 用户端前端 (React) -├── docker/ # Docker Compose 部署 -└── docs/ # 架构文档 + PRD +| ✅ Use | ❌ Never use | +|--------|-------------| +| `dialect_helpers.JsonType` | `sqlalchemy.JSON`, `mysql.JSON` | +| `dialect_helpers.LargeText` | `LONGTEXT`, `MEDIUMTEXT` | +| `dialect_helpers.UPDATE_TIME_SERVER_DEFAULT` | `ON UPDATE CURRENT_TIMESTAMP` | +| `SQLAlchemy inspect()` | `information_schema`, `DATABASE()` | +| Explicit relational columns | `JSON_EXTRACT` / `JSON_CONTAINS` / `JSON_SEARCH` | -``` +macOS: DM8 driver (`dmPython`/`dmAsync`) is not installed (`sys_platform != 'darwin'`). Real DM8 validation runs on CI/Linux only. -### 后端入口与启动 +### 3.3 Multi-Tenancy — Auto-Injected, Never Manual -- **`main.py`** — FastAPI 应用创建,lifespan 管理(初始化基础设施 → 初始化默认数据 → yield → 逆序清理) -- **`api/router.py`** — 全局路由注册(v1: 29 个路由,v2: 6 个 RPC 路由) -- **`config.yaml`** — 主配置文件(本地开发用) +**Never write `WHERE tenant_id = X` manually.** SQLAlchemy events handle it automatically for 23+ tables. +`multi_tenant.enabled=false` behaves identically to single-tenant (default `tenant_id=1`). -中间件栈(请求入站顺序):`CORSMiddleware` → `CustomMiddleware`(请求日志 + X-Trace-ID) → `WebSocketLoggingMiddleware` +### 3.4 Permissions — Unified Entry Point -基础设施初始化顺序(`ApplicationContextManager`,`core/context/manager.py`): -``` -DatabaseManager → RedisManager → MinioManager → EsConnManager(业务) → EsConnManager(统计) → HttpClientManager → PromptManager → FGAClient(OpenFGA) -``` - -### 后端模块地图 - -**DDD 领域模块**(有自己的顶级目录 + `api/` + `domain/` 结构): - -| 模块 | 路径 | 职责 | -|------|------|------| -| knowledge | `knowledge/` | 知识库管理、RAG 文档处理管道 | -| workflow | `workflow/` | 工作流 DAG 执行引擎(LangGraph) | -| permission | `permission/` | ReBAC 权限引擎(OpenFGA 集成、权限检查、授权管理、数据迁移) | -| linsight | `linsight/` | Linsight Agent 自主任务框架,独立 Worker | -| llm | `llm/` | LLM 供应商管理、模型注册与配置 | -| chat_session | `chat_session/` | 聊天会话管理、消息持久化 | -| tool | `tool/` | 工具/插件管理 | -| channel | `channel/` | 多渠道通信、情报中心 | -| message | `message/` | 消息收件箱 | -| user | `user/` | 用户管理、认证(JWT)、RBAC 菜单权限 | -| finetune | `finetune/` | 模型微调流水线 | -| share_link | `share_link/` | 公开分享链接 | -| telemetry_search | `telemetry_search/` | 遥测数据检索 | -| workstation | `workstation/` | 工作台后端 | -| open_endpoints | `open_endpoints/` | v2 RPC 接口,面向外部系统集成 | -| mcp_manage | `mcp_manage/` | MCP 协议集成(SSE/STDIO/Streamable) | - -**非独立模块**(路由在 `api/v1/` 中,无独立顶级目录):assistant, evaluation, audit, group, tag, mark, flows, skillcenter, variable, report, invite_code - -**基础设施模块**: - -| 目录 | 职责 | -|------|------| -| `core/context/` | 应用生命周期上下文管理(BaseContextManager → ApplicationContextManager) | -| `core/config/settings.py` | Pydantic Settings 配置模型 | -| `core/database/` | SQLAlchemy 引擎工厂(同步 pymysql + 异步 aiomysql) | -| `core/cache/` | Redis 缓存(RedisManager) | -| `core/ai/` | AI 模型服务封装(llm/, embeddings/, asr/, tts/, rerank/) | -| `core/storage/minio/` | MinIO S3 对象存储 | -| `core/search/elasticsearch/` | Elasticsearch 集成(业务实例 + 统计实例) | -| `core/vectorstore/` | Milvus 向量库集成 | -| `core/openfga/` | OpenFGA SDK 封装(FGAClient 单例) | -| `core/prompts/` | 提示词模板管理 | -| `core/external/` | HTTP 客户端、情报中心客户端 | -| `common/errcode/` | 错误码定义(5 位编码 MMMEE) | -| `common/schemas/api.py` | 统一响应模型 UnifiedResponseModel | -| `common/dependencies/` | FastAPI 依赖注入(UserPayload) | -| `database/models/` | SQLModel ORM 模型,每个文件含 Schema + DAO | -| `worker/` | Celery 异步任务 | - -### API 路由 - -**v1** (`/api/v1`,29 个,面向前端):chat, knowledge, knowledge_space, qa, workflow, assistant, llm, user, group, tool, evaluation, finetune, server, linsight, session, channel, message, share_link, telemetry_search, flows, workstation, skillcenter, endpoints, variable, report, audit, tag, mark, invite_code - -**v2 RPC** (`/api/v2`,6 个,面向外部集成):knowledge_rpc, filelib_rpc, chat_rpc, assistant_rpc, workflow_rpc, llm_rpc。实现在 `open_endpoints/api/`。 - -### 数据模型与存储 - -核心 ORM 模型(`database/models/`): - -| 模型 | 说明 | -|------|------| -| Flow | 应用统一定义(FlowType: ASSISTANT=5, WORKFLOW=10, WORKSTATION=15, LINSIGHT=20, CHANNEL_ARTICLE=25, KNOWLEDGE_SPACE=30)| -| FlowVersion | 版本控制,`is_current` 标记当前版本 | -| Assistant / AssistantLink | 助手配置 + 关联表(工具/技能/知识库) | -| ChatMessage | 聊天消息(LONGTEXT),含 liked/solved/sensitive_status | -| MessageSession | 会话记录,关联应用与用户 | -| Role / RoleAccess | 角色定义 + 权限映射(AdminRole=1, DefaultRole=2) | -| Tenant / UserTenant | 租户主表 + 用户-租户多对多关联 | -| Department / UserDepartment | 部门树(物化路径)+ 用户-部门关联 | - -**6 种存储引擎**:MySQL(关系数据)、Redis(缓存/Broker/状态)、Milvus(稠密向量)、Elasticsearch(稀疏索引/遥测统计,双实例)、MinIO(文件对象)、OpenFGA(关系型权限) - -### 前端架构 - -| 维度 | Platform (管理端) | Client (用户端) | -|------|-------------------|-----------------| -| 路径 | `src/frontend/platform/` | `src/frontend/client/` | -| 端口 | 3001 | 4001 | -| 基础路径 | `/` | `/workspace` | -| 定位 | 管理员/构建者 | 终端用户对话 | - -**技术栈**:React 18 + TypeScript + Vite + Radix UI + Tailwind CSS + i18next(中/英/日)+ Axios - -**Platform 状态管理**:Zustand stores(`src/store/`)+ React Context(`src/contexts/`,11 个 Provider) - -**Platform API 层**:`src/controllers/request.ts`(Axios 封装,JWT 注入,统一拦截),API 模块在 `src/controllers/API/` - -**Vite 代理**:Platform `/api/` → `:7860`,`/bisheng` `/tmp-dir` → MinIO `:9000`;Client 路径去除 `/workspace` 前缀后转发 - -### 数据流 - -同步:浏览器 → Nginx :8860 → Vite → FastAPI :7860 → Service → Repository → 底层数据库查询。异步:FastAPI → Celery → Milvus/ES/MinIO。WebSocket 通过 ChatManager 回调流式输出。 - -### 双库兼容红线(MySQL + 达梦) - -- **默认双库**:后端新功能必须同时兼容 MySQL 与达梦(DM8),不能把 MySQL 当作唯一生产数据库。 -- **模型类型**:结构化字段统一优先使用 `bisheng.core.database.dialect_helpers.JsonType`;大文本统一优先使用 `LargeText`;`update_time` 统一使用 `UPDATE_TIME_SERVER_DEFAULT`。 -- **禁止 MySQL 专属写法**:新增模型、迁移、守卫逻辑中,不得直接引入仅 MySQL 可用的 `JSON`、`LONGTEXT`、`ON UPDATE CURRENT_TIMESTAMP`、`information_schema`、`DATABASE()` 等假设。 -- **查询约束**:除非同时提供达梦分支并验证通过,否则不要依赖 `JSON_EXTRACT`、`JSON_UNQUOTE`、`JSON_CONTAINS`、`JSON_SEARCH` 等 MySQL JSON SQL;凡是业务上需要检索/排序/过滤的字段,优先拆成显式列,不要只放在 JSON/CLOB 快照里。 -- **迁移约束**:表存在性、列存在性、索引存在性检查统一走 SQLAlchemy `inspect()` 或 `core/database` / alembic helper,不能直接查 MySQL 元数据表。 -- **Feature 约束**:凡是新增表、迁移、方言敏感查询的 feature,`spec.md` 和 `tasks.md` 都要显式写入 MySQL + 达梦兼容要求,并至少包含一个方言级验证任务。 - -## 开发约定 - -> 回答"写代码遵循什么规则"。 - -### 分层架构 - -标准 DDD 模块目录结构: -``` -module_name/ - api/ - router.py # FastAPI Router 注册 - endpoints/ # 按功能拆分的端点文件 - domain/ - services/ # 领域服务(核心业务逻辑) - models/ # 领域模型(ORM 实体) - schemas/ # Pydantic DTO - repositories/ # 仓储层(默认承接数据库访问) -``` - -**调用链路**:`Router → Endpoint → Service → Repository → 底层数据库查询` - -**仓储优先原则**: -- 新功能默认走 `api -> service -> repository -> database`,Service 不直接拼 ORM 查询,Endpoint 不直接访问 `database/models/`。 -- 现有 DAO 属于存量兼容层,后续逐步淘汰;除非是在原有存量代码里做最小改动修复,否则不要为新业务继续新增 DAO 风格数据库入口。 -- Repository 负责封装查询、持久化、分页、事务边界内的数据访问细节;Service 负责业务编排、权限、状态流转和领域规则。 - -**DAO 迁移说明**:保留历史 `get_xxx()` / `create_xxx()` / `update_xxx()`、`aget_xxx()` / `acreate_xxx()` 风格方法用于存量兼容,但新 feature 不应再以 DAO 作为首选数据访问层。 - -**新增业务模块**:① 在 `src/backend/bisheng/` 下创建模块目录(含 `api/` 和 `domain/`)→ ② 在模块 `api/router.py` 创建 APIRouter → ③ 在 `src/backend/bisheng/api/router.py` 注册路由 - -### API 规范 - -**认证注入**:`UserPayload = Depends(UserPayload.get_login_user)`,WebSocket 用 `UserPayload.get_login_user_from_ws` - -**统一响应**: ```python -UnifiedResponseModel: {status_code: int, status_message: str, data: T} -resp_200(data) # 成功 -resp_500(code, msg) # 业务错误 +from bisheng.permission.domain.services.permission_service import PermissionService +await PermissionService.check(...) # check access +await PermissionService.authorize(...) # write OpenFGA owner tuple on resource creation (required) ``` -**分页**:`PageData[T]`(推荐,字段 data + total)、`PageList[T]`(旧版兼容,字段 list + total) +**Never** query `role_access` directly for resource authorization (arch-guard RULE-8 VIOLATION). +Resource creation **must** call `PermissionService.authorize()`; failures go to the `failed_tuples` retry table. -**错误码**:5 位编码 `MMMEE`(模块 3 位 + 错误 2 位),定义在 `common/errcode/`。三种输出:`return_resp()`(HTTP)、`to_sse_event()`(SSE)、`websocket_close_message()`(WS)。模块编码:100=server, 101=finetune, 104=assistant, 105=flow, 106=user, 108=llm, 109=knowledge, 110=linsight, 120=workstation, 130=chat/channel, 140=message, 150=tool, 160=dataset, 170=telemetry, 180=knowledge_space +Five-level short-circuit: `super_admin` → tenant mismatch deny → tenant admin → ReBAC (OpenFGA) → RBAC menu. -### 认证与权限 +### 3.5 API Conventions -**JWT**:Token 存 Cookie(`access_token_cookie`),也支持 Header/WebSocket 提取。Payload:`{user_id, user_name, tenant_id}`。 +```python +from bisheng.common.dependencies.user_deps import UserPayload +user: UserPayload = Depends(UserPayload.get_login_user) # WebSocket: get_login_user_from_ws -**权限检查链路**(五级短路): -1. 系统管理员(`system:global` 的 `super_admin`)→ 全权放行 -2. 租户归属检查 → `tenant_id` 不匹配直接拒绝(安全底线) -3. 租户管理员(`tenant:{id}` 的 `admin`)→ 租户内全权放行 -4. ReBAC(OpenFGA)→ owner/manager/editor/viewer 四级资源角色 -5. RBAC 菜单权限 → `WEB_MENU` 控制前端导航可见性 - -**关键文件**:`permission/`(ReBAC 权限模块,统一权限检查入口 `PermissionService`)、`user/domain/services/auth.py`(LoginUser,内部委托 PermissionService)、`common/dependencies/user_deps.py`(UserPayload) - -### 多租户与数据隔离 - -- 所有业务表包含 `tenant_id` 字段,通过 SQLAlchemy event 自动注入查询过滤和写入填充,无需手动 WHERE -- 资源创建时同步写入 OpenFGA owner 元组(通过 `PermissionService.authorize`) -- 权限检查使用 `PermissionService.check()` 而非直接查询 `RoleAccess` -- Celery 任务发送时将 `tenant_id` 写入 headers,Worker 执行前恢复 `current_tenant_id` ContextVar -- 外部存储按租户隔离:MinIO 路径前缀、Milvus/ES collection/index 前缀、Redis key 前缀 - -### 扩展工作流节点 - -三步:① `workflow/common/node.py` 添加 NodeType 枚举 → ② `workflow/nodes//` 创建节点类继承 BaseNode 实现 `_run()` → ③ `workflow/nodes/node_manage.py` 注册到 NODE_CLASS_MAP - -### 前端开发规范 - -两个前端技术栈差异较大,**不可混用**。详细规则在 `.claude/rules/` 中按目录自动加载: - -| 维度 | Platform (`src/frontend/platform/`) | Client (`src/frontend/client/`) | -|------|-------------------------------------|--------------------------------| -| 状态管理 | Zustand + React Context | Recoil | -| 路径别名 | `@/` → `src/` | `~/` (或 `@/`) → `src/` | -| HTTP 层 | `@/controllers/request.ts` | `~/api/request.ts` | -| UI 组件库 | `@/components/bs-ui/` | `~/components/ui/` | -| i18n Hook | `useTranslation()` → `t()` | `useLocalize()` → `localize()` | -| i18n 文件 | `public/locales/{lang}/{ns}.json`(多 namespace) | `src/locales/{lang}/translation.json`(单文件) | -| Toast | `toast({title, variant, description})` | `showToast({message, severity})` | - -**规范文件**:`.claude/rules/platform-frontend.md` / `.claude/rules/client-frontend.md`(按 globs 自动生效) - -**前端 Skills**: -- `/i18n-localizer` — 提取硬编码中文为 i18n key,自动识别 Client/Platform 并使用对应约定 -- `/react-component-refactor` — 大组件拆分(hook 提取、子组件拆分、目录重组),两端通用 - -## 核心子系统 - -> 回答"核心引擎内部怎么运转"。 - -### 工作流引擎 (`workflow/`) - -基于 LangGraph 的 DAG 执行引擎。核心组件: -- `graph/graph_engine.py` — GraphEngine,将工作流 JSON 编译为 LangGraph 状态机 -- `graph/graph_state.py` — GraphState 变量池,节点间数据传递 -- `graph/workflow.py` — Workflow 包装类,管理超时和对话历史 -- `nodes/node_manage.py` — NodeFactory 工厂 + NODE_CLASS_MAP 注册表 -- `edges/edges.py` — EdgeManage 边管理 -- `callback/` — 回调系统(on_node_start, on_stream_msg, on_output_msg 等) - -**14 种节点类型**(每种在 `workflow/nodes/` 下有独立子目录):START, END, INPUT, OUTPUT, FAKE_OUTPUT, LLM, CODE, CONDITION, KNOWLEDGE_RETRIEVER, QA_RETRIEVER, RAG, TOOL, AGENT, REPORT - -**中断/恢复**:INPUT 节点和 OUTPUT(通过 FakeNode)触发 LangGraph `interrupt_before`,暂停等待用户输入。通过 Redis 存储状态,Celery 任务恢复执行。 - -**变量引用格式**:`{node_id}.{variable_key}` 或 `{node_id}.{variable_key}#{index}` - -**配置**:WorkflowConf(max_steps=50, timeout=720min) - -**Celery 执行**:`execute_workflow` / `continue_workflow` / `stop_workflow`,任务在 `worker/workflow/tasks.py` - -### 知识库/RAG 管道 (`knowledge/`) - -三阶段管道:**Load → Transform → Ingest** - -- **Load**:按文件类型选择加载器(PDF/DOCX/TXT/HTML/Excel/图片),PDF 支持 4 种引擎(ETL4LM/MineRU/PaddleOCR/本地) -- **Transform**:摘要提取 → 附件/图片处理 → 缩略图生成 → 文本分块(ElemCharacterTextSplitter,默认 chunk_size=1000) → 预览缓存 -- **Ingest**:同时写入 Milvus(稠密向量,语义检索)+ Elasticsearch(稀疏索引,BM25 关键词检索) - -**文件处理状态**:WAITING(5) → PROCESSING(1) → SUCCESS(2) / FAILED(3) / TIMEOUT(6) - -**异步处理**:所有文件处理通过 Celery `knowledge_celery` 队列执行 - -**核心管道类**:`knowledge/rag/pipeline/base.py`(NormalPipeline)、`knowledge/rag/knowledge_file_pipeline.py`(KnowledgeFilePipeline) - -### Linsight Agent 框架 (`linsight/`) - -独立 Worker 进程架构,通过 Redis 队列与 API 解耦。 - -**流程**:用户提交 → SOP 生成 → 任务拆解 → Agent 逐步执行(支持工具调用、用户交互、子任务生成) - -**事件驱动**:TaskStart, TaskEnd, ExecStep, NeedUserInput, GenerateSubTask - -**状态持久化**:Redis 缓存 + MySQL 双写,Redis 键 TTL 1 小时 - -**Worker 进程模型**:多个 ScheduleCenterProcess(multiprocessing),每个内部 asyncio.Semaphore 控制并发 - -**核心文件**:`linsight/worker.py`(Worker 入口)、`linsight/domain/task_exec.py`(LinsightWorkflowTask 任务执行器) - -**bisheng_langchain 运行时**:`src/backend/bisheng_langchain/linsight/`(LinsightAgent, TaskManage, Task/ReactTask) - -### MCP 管理 (`mcp_manage/`) - -Factory 模式创建三种 MCP 客户端(SSE/STDIO/Streamable)。`McpTool`(`mcp_manage/langchain/tool.py`)将 MCP 工具桥接为 LangChain StructuredTool,供 TOOL/AGENT 节点和 Linsight Agent 调用。 - -### Celery Workers (`worker/`) - -| 队列 | 并发 | 职责 | -|------|------|------| -| `knowledge_celery` | 20 线程 | 文档解析、Embedding、向量写入 | -| `workflow_celery` | 100 线程 | 工作流 DAG 执行 | -| `celery` (默认) | 100 线程 | 遥测统计 | - -Beat 定时任务:每日 00:30 同步遥测统计,05:30 同步情报中心文章。Worker 心跳:每 5 秒向 Redis 写入(`celery_worker_alive_queues`)。多租户下 Beat 遍历所有活跃租户逐个执行。 - -### 商业版 API 网关(`bisheng-gateway`,独立仓库) - -> 详细架构文档见 `docs/architecture/11-gateway.md`。 - -独立的 Java 项目(仓库 `dataelement/bisheng-gateway`),作为商业拓展套件部署在 bisheng 后端之前,提供 SSO/OAuth 登录、内容安全审查、流量控制、License 验证。 - -**技术栈**:Spring Boot 3.2.6 + Spring Cloud Gateway (Reactive/WebFlux) + MyBatis-Plus 3.5.6 + JustAuth (OAuth) + Sa-Token - -**请求流**: -``` -浏览器 → Nginx → Vite → Gateway:8180 ─┬→ 自己处理: /api/oauth2/*, /api/sensitive/*, /api/group/* - └→ 代理转发: /api/v1/**, /api/v2/** → Backend:7860 +from bisheng.common.schemas.api import resp_200, resp_500 +return resp_200(data) # success +return resp_500(code, msg) # business error ``` -**SSO 认证流程**:Gateway 处理 OAuth/SSO/LDAP 认证 → 获取用户信息 → 调 bisheng `POST /api/v1/user/sso` 自动注册/登录 → 设置 JWT Cookie → 重定向到首页。需要后端设置 `BISHENG_PRO=true` 环境变量。 +Error codes: 5-digit `MMMEE` (3-digit module + 2-digit error), defined in `common/errcode/`. +Module numbers: 100=server, 104=assistant, 105=flow, 106=user, 108=llm, 109=knowledge, 110=linsight, 120=workstation, 130=chat, 140=message, 150=tool, 180=knowledge_space. -**前端集成**:`src/frontend/platform/src/controllers/API/pro.ts` 调用 6 个 Gateway 自有 API(SSO URL、LDAP 登录、敏感词、用户组)。 +Pagination: `PageData[T]` (new code) with fields `data` + `total`; `PageList[T]` is legacy-compat only. -**数据库**:4 张独立表(`gt_` 前缀):`gt_user_group`、`gt_group_resource`、`gt_sensitive_words`、`gt_block_record`。 +--- -## v2.5 改造上下文 +## 4. Frontend Rules (P0) -> 理解遗留代码和迁移背景。目标架构的行为已在上方各章节中描述。 +The two React apps **must not be mixed**. Apply rules by directory: -### 权限体系:RBAC → ReBAC +| Dimension | Platform (`src/frontend/platform/`) | Client (`src/frontend/client/`) | +|-----------|-------------------------------------|--------------------------------| +| State | **Zustand** (`@/store/`) + Context for local UI | **Recoil** (`~/store/`) | +| Server state | react-query **v3** (`useQuery({ queryFn })`) | react-query **v5** | +| Path alias | `@/` → `src/` | `~/` (or `@/`) → `src/` | +| HTTP layer | `@/controllers/request.ts` | `~/api/request.ts` | +| UI library | `@/components/bs-ui/` (Radix-based) | `~/components/ui/` (shadcn) | +| Icons | `@/components/bs-icons/` | `lucide-react` | +| i18n hook | `useTranslation()` → `t()` | `useLocalize()` → `localize()` | +| i18n files | `public/locales/{lang}/{ns}.json` (multi-namespace) | `src/locales/{lang}/translation.json` (single file) | +| Toast | `toast({ title, variant: 'error'\|'success', description })` | `showToast({ message, severity: 'error'\|'success' })` | +| Confirm dialog | `bsConfirm(...)` (bs-ui) | — | +| Workflow editor | `@xyflow/react` (**not** `react-flow-renderer`), nodes in `src/CustomNodes/` | — | -**为什么改**:旧 RBAC 权限分散在 `role_access` + `group_resource` + `space_channel_member` 三套机制中,无部门概念、无文件夹级权限、无操作级细粒度。 +**Hard rules (both apps):** +- TypeScript only (`.ts` / `.tsx`); functional components only; no class components. +- Single file ≤ 600 lines. Extract sub-components or hooks when exceeded. +- `interface` for Props; `type` for internal types. +- `handleXxx` for internal handlers; `onXxx` for props. +- **Never** `import axios` directly — always use the wrapped request module above. +- **Never** introduce new UI libraries or state management libraries. +- All code comments in English. +- 403: handled automatically by response interceptors. Never add 403 branches in business code. -**新旧体系分工**: -``` -OpenFGA (ReBAC) role 表 (策略角色 RBAC,保留) -├── 谁能访问/编辑/管理什么资源 ├── 能看到哪些菜单 (WEB_MENU) -├── 部门/用户组/文件夹继承 ├── 各资源创建上限 (Quota) -└── super_admin 短路判定 └── 角色作用域(部门级) -``` +--- -**权限金字塔**:`owner ⊃ manager(can_manage) ⊃ editor(can_edit) ⊃ viewer(can_read)` +## 5. Architecture Guard (Auto-enforced) -**三种授权主体**:`user:X`、`department:X#member`、`user_group:X#member` +`scripts/arch-guard.sh` runs after every Write/Edit via PostToolUse hook: -**OpenFGA 资源类型**:system, tenant, department, user_group, knowledge_space, folder, knowledge_file, channel, workflow, assistant, tool, dashboard +| # | Rule | Severity | +|---|------|----------| +| 1 | `common/`, `core/` must not import `domain/`, `api/` | VIOLATION | +| 2 | `database/models/` must not import `domain/` | VIOLATION | +| 3 | Endpoints must not directly import `database/models/` | WARNING (migration period) | +| 4 | `domain/models/` must not import `domain/services/` | VIOLATION | +| 5 | API layer must not cross-import between modules | VIOLATION | +| 6 | Frontend store must not call HTTP directly (use `controllers/API/` or `api/`) | WARNING | +| 7 | No hardcoded secrets (password/secret/token literals) | WARNING | +| 8 | DAO/Model must not read `RoleAccessDao` for permission filtering | VIOLATION | -**关键设计决策**: -- 部门 admin 向下传递(`admin from parent`),member 不继承 -- 授权给"部门(含子部门)"时,业务层展开子部门树,为每个子部门写入元组 -- MySQL 与 OpenFGA 双写,失败记入 `failed_tuples` 补偿表 -- `LoginUser.access_check` 内部委托 `PermissionService.check` +**VIOLATION rules must be fixed immediately** — these are v2.5 refactor boundaries. -**废弃表**(迁移后):`role_access`(资源授权部分)、`group_resource`、`space_channel_member` → 迁至 OpenFGA。保留 `role_access` 中 WEB_MENU 类型。 +--- -### 多租户引入 - -**为什么**:面向大型集团企业(中粮、首钢),需数据隔离、独立管理、统一管控。 - -**核心概念**:租户 = 部门树根节点,创建租户时自动创建根部门。系统管理员跨租户,租户管理员管租户内。用户与租户多对多(`user_tenant`)。 - -**隔离方式**:逻辑隔离 — 共享数据库 + `tenant_id` 字段。23+ 张业务表添加 `tenant_id`。默认租户(tenant_id=1)兼容升级,新租户用新前缀。 - -**配置开关**:`multi_tenant.enabled`(默认 false,关闭时行为与单租户一致)。 - -### 文档索引 - -| 文档 | 路径 | -|------|------| -| 权限改造 PRD | `docs/PRD/2.5 权限管理体系改造 PRD/2.5 权限管理体系改造 PRD.md` | -| 多租户需求文档 | `docs/PRD/2.5 权限管理体系改造 PRD/2.5 多租户需求文档.md` | -| 多租户管理 PRD | `docs/PRD/2.5 权限管理体系改造 PRD/2.5 多租户管理 PRD.md` | -| ReBAC 技术方案 | `docs/PRD/2.5 权限管理体系改造 PRD/2.5 技术方案.md` | -| 技术方案 Review | `docs/PRD/2.5 权限管理体系改造 PRD/2.5 技术方案 Review.md` | -| v2.4 权限体系详解 | `docs/architecture/10-permission-rbac.md` | - -## 运维参考 - -### 核心配置 - -主配置文件: `src/backend/bisheng/config.yaml` - -配置加载优先级:`YAML 文件 → 环境变量(BS_*) → 数据库配置(initdb_config) → Redis 缓存(100s TTL)` - -主要配置分组: -- `database_url` — MySQL 连接(密码 Fernet 加密,key 在 settings.py 的 `secret_key`) -- `redis_url` / `celery_redis_url` — Redis 连接 -- `vector_stores.milvus` / `vector_stores.elasticsearch` — 向量库与搜索引擎 -- `object_storage.minio` — MinIO 对象存储 -- `openfga` — OpenFGA 连接(api_url, store_id, model_id) -- `multi_tenant` — 多租户开关(enabled, default_tenant_code, storage_isolation) -- `celery_task` — Celery 任务路由和定时任务 -- `workflow_conf` — 工作流参数(max_steps=50, timeout=720min) -- `linsight_conf` — Linsight 参数(max_steps=200, retry_num=3) -- `knowledge` — 知识库解析引擎配置(loader_provider: etl4lm/mineru/paddle_ocr) -- `cookie_conf` — JWT Cookie 配置(默认过期 86400s) - -支持 `!env ${VAR}` 语法从环境变量注入配置值。 - -### CI/CD - -- **协作分支**: `2.5.0-PM`(v2.5 开发主线) -- **Drone CI**: push 到 `2.5.0-PM` 自动触发构建 + 部署到测试服务器 + 飞书通知 -- **配置文件**: `.drone.yml`(两条流水线:`cicd` 用于 release,`feat_cicd` 用于开发分支) - -### 访问地址 - -| 服务 | 地址 | -|------|------| -| 主界面(本地) | http://localhost:3001 | -| API 文档 | http://localhost:7860/docs | -| 健康检查 | GET /health | - -### 已知事项 - -1. **默认管理员**: 首个注册用户为系统管理员(super_admin),多租户开启时需先创建租户 -2. **密码加密**: Fernet key 在 `core/config/settings.py` 中,用于加密 config.yaml 中的数据库/Redis 密码 -3. **uv 依赖管理**: 使用 uv(非 Poetry),lockfile 为 `uv.lock` -4. **前端开发模式**: `npm start` 运行 vite dev server,自动代理 API 到后端 -5. **MinIO 图片代理签名匹配**: Vite 的 `fileServiceTarget`(`vite.config.mts`)必须与后端 `config.yaml` 的 `object_storage.minio.sharepoint` 一致,否则签名校验失败导致图片 403 -6. **OpenFGA**: 必须部署 OpenFGA 服务(Docker),作为 ReBAC 权限引擎 - -## SDD 开发规范 - -> BiSheng 采用 SDD(Spec-Driven Development)方法论进行 Feature 级开发。 -> 完整指南:`docs/SDD-Guide.md`,项目适配:`features/README.md`。 - -### 工作流(9 步) +## 6. SDD Workflow (Required for non-trivial features) ``` -0. release-contract.md(版本开始时,一次性) -1. Spec Discovery → ★ 用户确认 -2. 编写 spec.md -3. /sdd-review spec → ★ 用户确认 -4. 编写 tasks.md -5. /sdd-review tasks(自动推进) -6. 创建 Feature 分支 feat/v2.5.0/{NNN}-{name},基于 2.5.0-PM -7. 逐任务执行 → /task-review → 打勾 -7.5. /e2e-test(强制) -8. /code-review --base 2.5.0-PM(自动) -9. 合并回 2.5.0-PM +0. release-contract.md (once per version) +1. Spec Discovery → ★ user confirms +2. spec.md → /sdd-review spec → ★ user confirms +3. tasks.md → /sdd-review tasks +4. branch: feat//{NNN}-{name} +5. implement task-by-task → /task-review → check off +6. /e2e-test (mandatory) +7. /code-review --base
+8. merge ``` -### 产物位置 +Artifacts: `features/v{X.Y.Z}/{NNN}-{name}/spec.md` and `tasks.md`. Templates: `features/_templates/`. +**★ pause points cannot be skipped.** Deviations must be recorded in `tasks.md §实际偏差记录`. -| 产物 | 路径 | -|------|------| -| 版本契约 | `features/v2.5.0/release-contract.md` | -| Feature 规格 | `features/v2.5.0/{NNN}-{name}/spec.md` | -| Feature 任务 | `features/v2.5.0/{NNN}-{name}/tasks.md` | -| 模板 | `features/_templates/` | +Tests: file new backend tests under `test//` (e.g., `test/approval/`), not in `test/` root. `asyncio_mode=auto`. -### 架构红线(L0 自动守卫) +--- -以下规则由 `scripts/arch-guard.sh` 在每次 Write/Edit 后自动检查(通过 `.claude/settings.json` PostToolUse hook): +## 7. Common Pitfalls -| # | 规则 | 严重度 | 说明 | -|---|------|--------|------| -| 1 | common/core 不导入 domain/api | VIOLATION | 基础设施层不反向依赖领域层 | -| 2 | database/models 不导入 domain | VIOLATION | 纯 ORM 层不知道领域逻辑 | -| 3 | Endpoint 不直接导入 database/models | WARNING | 迁移期降级,应通过 Domain 层访问 | -| 4 | domain.models 不导入 domain.services | VIOLATION | 模型层不反向依赖服务层 | -| 5 | API 层不跨模块互相导入 | VIOLATION | 各模块 API 独立 | -| 6 | 前端 store 不直接调 HTTP | WARNING | 应通过 controllers/API 或 api/ 封装 | -| 7 | 硬编码敏感信息检测 | WARNING | password/secret/token 赋值检测 | +| Pitfall | Reality | +|---------|---------| +| `/api/v1/env` version field | Hardcoded `2.4.0` in source — unreliable. Use route probing instead. | +| MinIO image 403 | Vite `fileServiceTarget` must exactly match `config.yaml` `object_storage.minio.sharepoint`. | +| Passwords in config.yaml | Fernet-encrypted. Never write plaintext passwords into the YAML. | +| First registered user | Becomes `super_admin` automatically. In multi-tenant mode, create the tenant first. | +| `BISHENG_PRO=true` | Must be set **before** starting the backend, or `/api/v1/user/sso` endpoint won't exist. | +| DB config changes | 100s Redis TTL — wait or flush Redis after changing DB-stored config. | +| Celery Beat + multi-tenant | Beat iterates all active tenants; adding a task multiplies load by N tenants. | +| API proxy modes | Default: Vite → `:7860`. Commercial: set `VITE_PROXY_TARGET=http://localhost:8180`. | -### 测试要求(务实版) +--- -| 层 | 要求 | 当前现状 | -|----|------|---------| -| 后端 Service | Test-First:先测试再实现 | 需先搭建 conftest(F000) | -| 后端 API | 集成测试覆盖 happy path + error path | 需搭建 TestClient fixture | -| 前端 Platform | 手动验证(待搭建 Vitest 后转自动化) | 无测试框架 | -| 前端 Client | 手动验证(有 Jest 配置但无用例) | 有 Jest 但空 | -| E2E | API 端到端测试 + 手动验证清单 | 无浏览器 E2E 框架 | +## 8. Reference -- **测试目录约束**:新增后端测试按模块归档到 `src/backend/test//` 下,例如 `test/approval/`、`test/knowledge/`、`test/workflow/`;不要继续把模块测试统一堆到 `src/backend/test/` 根目录。 -- **例外**:只有跨模块公共夹具、全局集成冒烟、或历史存量测试迁移未完成时,才允许保留在根目录。 - -### 审查命令 - -| 命令 | 时机 | 说明 | -|------|------|------| -| `/sdd-review spec` | spec 编写后 | 14 项需求+架构检查 | -| `/sdd-review tasks` | tasks 编写后 | 21 项拆解质量检查 | -| `/task-review ` | 每个任务完成后 | L1 约定合规(6 项) | -| `/code-review --base 2.5.0-PM` | Feature 全部完成后 | L2 多维度审查(6 维度) | -| `/e2e-test ` | 全部任务完成后 | 生成并运行 E2E 测试 | - -### 命名速查 - -| 对象 | 约定 | -|------|------| -| DAO 方法(同步) | `get_xxx()` / `create_xxx()` / `update_xxx()` / `delete_xxx()` | -| DAO 方法(异步) | `aget_xxx()` / `acreate_xxx()` / `aupdate_xxx()` / `adelete_xxx()` | -| 错误码 | 5 位 MMMEE,类名 `{Module}{Error}Error`,继承 `BaseErrorCode` | -| API 响应 | `resp_200(data)` / `resp_500(code, msg)` / `UnifiedResponseModel[T]` | -| Feature 分支 | `feat/v2.5.0/{NNN}-{name}`,基于 `2.5.0-PM` | -| Feature 目录 | `features/v2.5.0/{NNN}-{kebab-case-name}/` | +- **Backend module map, subsystem internals** → `src/backend/CLAUDE.md` +- **Architecture docs** → `docs/architecture/` (`10-permission-rbac.md`, `11-gateway.md`) +- **SDD guide** → `docs/SDD-Guide.md` +- **v2.5 permission/multi-tenant PRD** → `docs/PRD/` +- **Skills**: `/sdd-review`, `/task-review`, `/code-review`, `/e2e-test`, `/i18n-localizer`, `/react-component-refactor` diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 07e442217..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,270 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -> 写给后续 Claude 实例:本文只放「不读会写错的事」。代码地图、模块清单、节点枚举值等可 grep 出来的内容不在这里——需要更深的全景请查 `AGENTS.md`。 - ---- - -## 1. 项目身份 - -**BiSheng (毕昇)** — 企业级开源 LLM 应用 DevOps 平台。Monorepo,三大子工程: - -| 路径 | 工程 | 技术栈 | -|------|------|--------| -| `src/backend/` | FastAPI 后端 + Celery Workers + Linsight Worker | Python 3.10+, uv, SQLModel, LangGraph | -| `src/frontend/platform/` | 管理/构建端(admin & builder) | Vite 5 + **Zustand** + react-query v3 + bs-ui | -| `src/frontend/client/` | 终端用户对话端(`/workspace` 基路径) | Vite 6 + **Recoil** + react-query v5 + shadcn/ui | - - ---- - -## 2. 常用命令 - -### 后端(cwd: `src/backend/`,所有命令前 `cd src/backend`) - -```bash -# 依赖(uv,lockfile = uv.lock) -.venv/bin/python -V # 必须是 3.10.x -uv sync --frozen --python .venv/bin/python - -# 测试 -.venv/bin/pytest test/ # 全部 -.venv/bin/pytest test//test_xxx.py::test_fn # 单用例 -.venv/bin/pytest test/ -k "keyword" # 关键字过滤 -.venv/bin/pytest test/ -m "not e2e" # 排除 e2e -# 测试目录约束:新增测试按模块归档到 test// (test/approval/、test/knowledge/…), -# 不要再往 test/ 根目录堆。asyncio_mode=auto,async 测试函数不需要 @pytest.mark.asyncio。 - -# 格式化 / Lint(与 PostToolUse hook 一致) -.venv/bin/ruff format -.venv/bin/ruff check --fix - -# 启动 API(端口 7860;config 必须是相对 bisheng 包目录的文件名) -export config=config.yaml -.venv/bin/uvicorn bisheng.main:app --host 0.0.0.0 --port 7860 --workers 1 --no-access-log - -# Celery(不同队列各开一个终端) -.venv/bin/celery -A bisheng.worker.main worker -l info -c 20 -P threads -Q knowledge_celery -n knowledge@%h -.venv/bin/celery -A bisheng.worker.main worker -l info -c 100 -P threads -Q workflow_celery -n workflow@%h -.venv/bin/celery -A bisheng.worker.main beat -l info - -# 数据库迁移(Alembic,alembic.ini 在 src/backend/) -.venv/bin/alembic upgrade head -.venv/bin/alembic revision --autogenerate -m "msg" # 注意:autogen 只在 MySQL 反映准,达梦兼容需手工 review -``` - -### 前端 - -```bash -# Platform(管理端,端口 3001) -cd src/frontend/platform && npm install && npm start -- --host 0.0.0.0 -# 商业版 Gateway 代理模式: -VITE_PROXY_TARGET=http://localhost:8180 npm start -- --host 0.0.0.0 - -# Client(终端用户,端口 4001) -cd src/frontend/client && npm install && npm run dev -``` - -### 一键中间件(Docker,仅基础设施,bisheng/前端跑本机) - -```bash -bash docker/local-dev/start-middleware.sh # MySQL/Redis/Milvus/ES/MinIO/OpenFGA -``` - ---- - -## 3. 后端写代码必读 - -### 3.1 分层架构(DDD) - -``` -api/router.py → api/endpoints/ → domain/services/ → domain/repositories/ → 数据库 - ↑ - domain/models/ + domain/schemas/ -``` - -**仓储优先**:新功能默认 `api → service → repository → database`。 -- Service 不直接拼 ORM 查询。 -- Endpoint **不直接** `import bisheng.database.models.*`(arch-guard RULE-3 会告警,迁移期 WARNING)。 -- 现有 DAO(`database/models/.py` 里的 `get_xxx()` / `aget_xxx()`)是存量兼容层,**不要为新业务扩展 DAO 入口**——除非是在原有代码里做最小修复。 - -**新建领域模块**:① 在 `src/backend/bisheng/` 下建 `/{api,domain}/` → ② `/api/router.py` 创建 APIRouter → ③ 在 `bisheng/api/router.py` 注册。 - -### 3.2 双库兼容红线(MySQL + 达梦 DM8)⚠️ - -**所有新功能必须同时跑通两种方言**,达梦不是可选项。 - -| 场景 | 用这个 | 不要用 | -|------|--------|--------| -| JSON 字段 | `bisheng.core.database.dialect_helpers.JsonType` | `sqlalchemy.JSON`、`mysql.JSON` | -| 大文本 | `dialect_helpers.LargeText` | `LONGTEXT`、`MEDIUMTEXT` | -| 更新时间 | `dialect_helpers.UPDATE_TIME_SERVER_DEFAULT` | 手写 `ON UPDATE CURRENT_TIMESTAMP` | -| 表/列/索引存在性检查 | SQLAlchemy `inspect()` 或 `core/database` helper | `information_schema`、`DATABASE()` | -| JSON 内容查询 | 拆成显式关系列 | `JSON_EXTRACT`/`JSON_UNQUOTE`/`JSON_CONTAINS`/`JSON_SEARCH` | - -**新增 spec/tasks 必须显式声明双库兼容**,且至少一个方言级验证任务。 - -注:开发机若为 macOS,达梦驱动 (`dmPython`/`dmAsync`) 不会安装(pyproject.toml `sys_platform != 'darwin'` marker)——本地无法跑达梦真实验证,CI/Linux 上才能跑。 - -### 3.3 多租户:tenant_id 自动注入 - -23+ 张业务表带 `tenant_id`。**不要手动 WHERE tenant_id = X**——SQLAlchemy event 已经做了: -- 读:查询自动注入过滤 -- 写:插入自动填充当前 `current_tenant_id` ContextVar -- Celery:发送时 header 写 tenant_id,Worker 执行前恢复 ContextVar -- 存储:MinIO 路径前缀 / Milvus collection 前缀 / ES index 前缀 / Redis key 前缀都按租户隔离 - -`multi_tenant.enabled=false` 时行为等同单租户(默认 `tenant_id=1`),代码无须分支判断。 - -### 3.4 权限:五级短路 + ReBAC(OpenFGA) - -权限检查链路(任一级命中就短路): - -1. `system:global` 的 `super_admin` → 全权 -2. 资源 `tenant_id` 不匹配当前用户租户 → 拒绝(安全底线) -3. `tenant:{id}` 的 `admin` → 租户内全权 -4. **ReBAC**:OpenFGA owner ⊃ manager(`can_manage`) ⊃ editor(`can_edit`) ⊃ viewer(`can_read`) -5. RBAC:`WEB_MENU` 仅控制前端导航可见性 - -**不要直接查 `role_access` 做资源授权**——arch-guard RULE-8 会拦。统一入口: - -```python -from bisheng.permission.domain.services.permission_service import PermissionService -await PermissionService.check(...) # 权限校验 -await PermissionService.authorize(...) # 创建资源时写 owner 元组 -``` - -资源创建时**必须同步写 OpenFGA owner 元组**(通过 `PermissionService.authorize`)。失败会进 `failed_tuples` 补偿表。 - -### 3.5 API 约定 - -```python -# 认证注入 -from bisheng.common.dependencies.user_deps import UserPayload -user: UserPayload = Depends(UserPayload.get_login_user) -# WebSocket 用 UserPayload.get_login_user_from_ws - -# 统一响应 -from bisheng.common.schemas.api import resp_200, resp_500, UnifiedResponseModel -return resp_200(data) -return resp_500(code, msg) - -# 分页:新代码用 PageData[T](data + total);PageList[T](list + total)是旧版兼容 -``` - -**错误码**:5 位 `MMMEE`(模块 3 位 + 错误 2 位),定义在 `common/errcode/`。模块号速查:100=server, 101=finetune, 104=assistant, 105=flow, 106=user, 108=llm, 109=knowledge, 110=linsight, 120=workstation, 130=chat/channel, 140=message, 150=tool, 160=dataset, 170=telemetry, 180=knowledge_space。三种输出:`return_resp()`(HTTP)/ `to_sse_event()`(SSE)/ `websocket_close_message()`(WS)。 - -### 3.6 JWT / Cookie - -Token 在 Cookie 名 `access_token_cookie`,也支持 Header / WS query。Payload `{user_id, user_name, tenant_id}`。Cookie 默认过期 86400s(`cookie_conf`)。 - ---- - -## 4. 前端开发速查 - -两个 React 工程**约定不能混用**,按目录自动适配(`.claude/rules/{platform,client}-frontend.md` 通过 globs 自动加载)。 - -| 维度 | Platform (`src/frontend/platform/`) | Client (`src/frontend/client/`) | -|------|-------------------------------------|--------------------------------| -| 状态管理 | **Zustand** (`@/store/`) + Context(UI 局部) | **Recoil** (`~/store/`) | -| 服务端状态 | react-query **v3**(`useQuery({ queryFn })`) | react-query **v5** | -| 路径别名 | `@/` → `src/` | `~/`(或 `@/`)→ `src/` | -| HTTP 封装 | `@/controllers/request.ts` | `~/api/request.ts` | -| UI 库 | `@/components/bs-ui/` | `~/components/ui/`(shadcn) | -| 图标 | `@/components/bs-icons/` | `lucide-react` | -| i18n hook | `useTranslation()` → `t()` | `useLocalize()` → `localize()` | -| i18n 文件 | `public/locales/{lang}/{ns}.json`(多 namespace) | `src/locales/{lang}/translation.json`(单文件) | -| Toast | `toast({ title, variant: 'error' \| 'success', description })` | `showToast({ message, severity: 'error' \| 'success' })` | -| Confirm | `bsConfirm(...)`(bs-ui) | — | -| 工作流编辑器 | `@xyflow/react`(**不是** `react-flow-renderer`),节点在 `src/CustomNodes/` | — | - -**通用硬规则**:TypeScript only / 函数组件 only / 单文件 ≤ 600 行 / `interface` for Props、`type` for 内部 / `handleXxx` 内部、`onXxx` props / 注释英文 / 禁止直接 `import axios` / **不要新引入 UI 库或状态库**。 - -**403**:两端响应拦截器都自动处理(重定向),业务代码不要再写 403 分支。 - ---- - -## 5. 架构红线(自动守卫) - -`scripts/arch-guard.sh` 在每次 Write/Edit 之后由 PostToolUse hook 同步执行。8 条规则,违反立刻在 stderr 提示: - -| # | 规则 | 严重度 | -|---|------|--------| -| 1 | `common/`、`core/` 不导入 `domain/`、`api/` | VIOLATION | -| 2 | `database/models/` 不导入 `domain/` | VIOLATION | -| 3 | Endpoint 不直接导入 `database/models/` | WARNING(迁移期) | -| 4 | `domain/models/` 不导入 `domain/services/` | VIOLATION | -| 5 | API 层不跨模块互相导入 | VIOLATION | -| 6 | 前端 store 不直接调 HTTP(应走 `controllers/API/` 或 `api/`) | WARNING | -| 7 | 硬编码敏感信息(password/secret/token) | WARNING | -| 8 | DAO/Model 不直读 `RoleAccessDao` 做权限过滤 | VIOLATION | - -**违反 VIOLATION 必须修**——这是 v2.5 重构留下的边界,不能再退化。 - ---- - -## 6. SDD(Spec-Driven Development)工作流 - -非琐碎 feature **走 SDD**。完整指南:`docs/SDD-Guide.md`,BiSheng 适配:`features/README.md`。 - -``` -0. release-contract.md(每版本一次) -1. Spec Discovery → ★ 用户确认 -2. spec.md -3. /sdd-review spec → ★ 用户确认 -4. tasks.md -5. /sdd-review tasks(自动) -6. 拉 feature 分支 feat//{NNN}-{name} -7. 逐任务实现 → /task-review → 打勾 -7.5. /e2e-test (强制) -8. /code-review --base <主线分支>(自动) -9. 合并回主线 -``` - -产物布局:`features/v{X.Y.Z}/{NNN}-{kebab-name}/{spec.md,tasks.md}`,模板在 `features/_templates/`。 - -**两个 ★ 暂停点不能跳过**。实现偏差必须记录到 `tasks.md` §实际偏差记录。 - ---- - -## 7. 高频踩坑清单 - -| 坑 | 真相 | -|----|------| -| `/api/v1/env` 的 `version` 字段 | **源码硬编码 `2.4.0`,不可靠**。判断后端代码版本走路由探测,不要依赖此字段。 | -| MinIO 图片 403 | Vite 的 `fileServiceTarget`(`vite.config.mts`)必须与后端 `config.yaml` 的 `object_storage.minio.sharepoint` **完全一致**,否则签名校验失败。 | -| `config.yaml` 中数据库/Redis 密码 | Fernet 加密,key 在 `core/config/settings.py` 的 `secret_key`。明文密码不能直接写入 YAML。 | -| 首次注册用户 | 自动成为系统管理员(`super_admin`)。多租户开启时必须先创建租户再注册用户。 | -| `BISHENG_PRO=true` | 启动后端**之前**设置,否则 `/api/v1/user/sso` 端点不开。 | -| 配置加载优先级 | `YAML → 环境变量(BS_*) → DB(initdb_config) → Redis 缓存(100s TTL)`。改了 DB 配置后等 100s 或清 Redis 才生效。 | -| Celery Beat 多租户 | Beat 会遍历所有活跃租户逐个执行定时任务,加任务时考虑 N 倍放大。 | -| API 代理两种模式 | 默认 Vite `/api/` → 7860;商业版 `VITE_PROXY_TARGET=http://localhost:8180` 经 Gateway。开发本地默认走第一种。 | - ---- - -## 8. 项目级 Skills - -`.claude/skills/`: - -| 名称 | 用途 | 触发 | -|------|------|------| -| `i18n-localizer` | 提取硬编码中文 → i18n key,三套 locale 同步 | `/i18n-localizer` / "国际化这个模块" | -| `react-component-refactor` | 大组件拆分(hook 提取、子组件、目录重组) | `/react-component-refactor` / "重构这个组件" | -| `sdd-review` | spec/tasks 文档审查 | `/sdd-review spec` 或 `tasks` | -| `task-review` | L1 任务级合规检查 | `/task-review ` | -| `code-review` | L2 多维度代码审查 | `/code-review --base <主线>` | -| `e2e-test` | 生成 + 运行 API E2E 测试 + 手动验证清单 | `/e2e-test ` | - ---- - -## 9. 更深的全景 - -- `AGENTS.md` — 完整 600 行架构详解(部署架构、模块地图、子系统内部、Gateway 商业版、v2.5 迁移背景) -- `docs/architecture/` — 架构文档(含 `11-gateway.md`、`10-permission-rbac.md`) -- `docs/SDD-Guide.md` — SDD 方法论 -- `docs/PRD/` — 产品 PRD(v2.5 权限改造、多租户管理、技术方案 Review) -- `docker/local-dev/README.md` — 本地一键开发环境 -- `src/backend/README.md` — 后端 README - -需要更细的数据流、节点类型、配置项分组——读这些。 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 000000000..47dc3e3d8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/src/backend/AGENTS.md b/src/backend/AGENTS.md new file mode 100644 index 000000000..28a4c3023 --- /dev/null +++ b/src/backend/AGENTS.md @@ -0,0 +1,234 @@ +# Backend Reference + +Auto-loaded when Claude reads files in `src/backend/`. Complements root `AGENTS.md`. +P0 rules (DDD, dual-DB, permissions, API conventions) live in `AGENTS.md`. + +--- + +## Commands (cwd: `src/backend/`) + +```bash +# Dependencies (uv, lockfile = uv.lock, Python must be 3.10.x) +uv sync --frozen --python .venv/bin/python + +# Tests +.venv/bin/pytest test/ # all +.venv/bin/pytest test//test_xxx.py::test_fn # single test +.venv/bin/pytest test/ -k "keyword" # filter by keyword +.venv/bin/pytest test/ -m "not e2e" # exclude e2e +# New tests go under test// (e.g. test/approval/), not test/ root +# asyncio_mode=auto — no @pytest.mark.asyncio needed on async functions + +# Format / Lint (matches PostToolUse hook) +.venv/bin/ruff format +.venv/bin/ruff check --fix + +# Start API (port 7860; config must be a filename relative to the bisheng package dir) +export config=config.yaml +.venv/bin/uvicorn bisheng.main:app --host 0.0.0.0 --port 7860 --workers 1 --no-access-log + +# Celery (one terminal per queue) +.venv/bin/celery -A bisheng.worker.main worker -l info -c 20 -P threads -Q knowledge_celery -n knowledge@%h +.venv/bin/celery -A bisheng.worker.main worker -l info -c 100 -P threads -Q workflow_celery -n workflow@%h +.venv/bin/celery -A bisheng.worker.main beat -l info + +# Linsight Worker (optional) +.venv/bin/python bisheng/linsight/worker.py --worker_num 4 --max_concurrency 5 + +# DB migration (alembic.ini in src/backend/) +.venv/bin/alembic upgrade head +.venv/bin/alembic revision --autogenerate -m "msg" # autogen only reflects MySQL accurately; review DM8 compatibility manually +``` + +--- + +## Module Map + +### DDD Domain Modules (own top-level dir + `api/` + `domain/`) + +| Module | Path | Responsibility | +|--------|------|----------------| +| knowledge | `knowledge/` | Knowledge base management, RAG document pipeline | +| workflow | `workflow/` | Workflow DAG execution engine (LangGraph) | +| permission | `permission/` | ReBAC engine (OpenFGA integration, permission check, authorization, migration) | +| linsight | `linsight/` | Linsight autonomous agent framework, independent Worker | +| llm | `llm/` | LLM provider management, model registration | +| chat_session | `chat_session/` | Chat session management, message persistence | +| tool | `tool/` | Tool / plugin management | +| channel | `channel/` | Multi-channel communication, intelligence center | +| message | `message/` | Message inbox | +| user | `user/` | User management, auth (JWT), RBAC menu permissions | +| finetune | `finetune/` | Model fine-tuning pipeline | +| share_link | `share_link/` | Public share links | +| telemetry_search | `telemetry_search/` | Telemetry data retrieval | +| workstation | `workstation/` | Workstation backend | +| open_endpoints | `open_endpoints/` | v2 RPC interfaces for external system integration | +| mcp_manage | `mcp_manage/` | MCP protocol integration (SSE / STDIO / Streamable) | + +**Non-standalone modules** (routes under `api/v1/`, no own top-level dir): +assistant, evaluation, audit, group, tag, mark, flows, skillcenter, variable, report, invite_code + +### Infrastructure Modules + +| Directory | Responsibility | +|-----------|----------------| +| `core/context/` | App lifecycle context management (`ApplicationContextManager`) | +| `core/config/settings.py` | Pydantic Settings config model | +| `core/database/` | SQLAlchemy engine factory (sync pymysql + async aiomysql) | +| `core/cache/` | Redis cache (RedisManager) | +| `core/ai/` | AI model service wrappers (llm, embeddings, asr, tts, rerank) | +| `core/storage/minio/` | MinIO S3 object storage | +| `core/search/elasticsearch/` | Elasticsearch (business instance + stats instance) | +| `core/vectorstore/` | Milvus vector store | +| `core/openfga/` | OpenFGA SDK wrapper (FGAClient singleton) | +| `common/errcode/` | Error code definitions (5-digit MMMEE) | +| `common/schemas/api.py` | Unified response model `UnifiedResponseModel` | +| `common/dependencies/` | FastAPI dependency injection (`UserPayload`) | +| `database/models/` | SQLModel ORM models; each file contains Schema + DAO | +| `worker/` | Celery async tasks | + +--- + +## API Routes + +**v1** (`/api/v1`, 29 routes, frontend-facing): +chat, knowledge, knowledge_space, qa, workflow, assistant, llm, user, group, tool, evaluation, finetune, server, linsight, session, channel, message, share_link, telemetry_search, flows, workstation, skillcenter, endpoints, variable, report, audit, tag, mark, invite_code + +**v2 RPC** (`/api/v2`, 6 routes, external integration): +knowledge_rpc, filelib_rpc, chat_rpc, assistant_rpc, workflow_rpc, llm_rpc +(implemented in `open_endpoints/api/`) + +--- + +## Core Data Models (`database/models/`) + +| Model | Notes | +|-------|-------| +| Flow | Unified app definition. FlowType: ASSISTANT=5, WORKFLOW=10, WORKSTATION=15, LINSIGHT=20, CHANNEL_ARTICLE=25, KNOWLEDGE_SPACE=30 | +| FlowVersion | Version control; `is_current` marks the active version | +| Assistant / AssistantLink | Assistant config + join table (tools / skills / knowledge bases) | +| ChatMessage | Chat messages; fields: liked, solved, sensitive_status | +| MessageSession | Session records linking app and user | +| Role / RoleAccess | Role definition + permission mapping (AdminRole=1, DefaultRole=2) | +| Tenant / UserTenant | Tenant master table + user-tenant many-to-many | +| Department / UserDepartment | Department tree (materialized path) + user-department join | + +**6 storage engines**: MySQL (relational), Redis (cache/broker/state), Milvus (dense vectors), Elasticsearch (sparse index + telemetry stats, dual instances), MinIO (file objects), OpenFGA (relational permissions) + +--- + +## App Entry Points + +- **`main.py`** — FastAPI app creation, lifespan management +- **`api/router.py`** — Global route registration +- **`config.yaml`** — Main config file (local dev) + +Infrastructure init order (`core/context/manager.py`): +``` +DatabaseManager → RedisManager → MinioManager → EsConnManager(business) +→ EsConnManager(stats) → HttpClientManager → PromptManager → FGAClient(OpenFGA) +``` + +Middleware stack (inbound order): `CORSMiddleware` → `CustomMiddleware` (request log + X-Trace-ID) → `WebSocketLoggingMiddleware` + +--- + +## Workflow Engine (`workflow/`) + +LangGraph-based DAG execution engine. + +| File | Role | +|------|------| +| `graph/graph_engine.py` | GraphEngine — compiles workflow JSON into LangGraph state machine | +| `graph/graph_state.py` | GraphState variable pool for inter-node data passing | +| `graph/workflow.py` | Workflow wrapper managing timeout and conversation history | +| `nodes/node_manage.py` | NodeFactory + NODE_CLASS_MAP registry | +| `callback/` | Callback system (on_node_start, on_stream_msg, on_output_msg, …) | + +**14 node types** (each in its own `workflow/nodes//`): +START, END, INPUT, OUTPUT, FAKE_OUTPUT, LLM, CODE, CONDITION, KNOWLEDGE_RETRIEVER, QA_RETRIEVER, RAG, TOOL, AGENT, REPORT + +**Add a new node type** (3 steps): +1. Add `NodeType` enum entry in `workflow/common/node.py` +2. Create node class under `workflow/nodes//`, inherit `BaseNode`, implement `_run()` +3. Register in `workflow/nodes/node_manage.py` → `NODE_CLASS_MAP` + +**Interrupt / resume**: INPUT node and OUTPUT (via FakeNode) trigger LangGraph `interrupt_before`. State stored in Redis; Celery task resumes execution. + +**Variable reference format**: `{node_id}.{variable_key}` or `{node_id}.{variable_key}#{index}` + +**Config**: WorkflowConf (max_steps=50, timeout=720 min) + +**Celery tasks**: `execute_workflow` / `continue_workflow` / `stop_workflow` in `worker/workflow/tasks.py` + +--- + +## Knowledge / RAG Pipeline (`knowledge/`) + +Three-phase pipeline: **Load → Transform → Ingest** + +- **Load**: file-type-specific loaders (PDF / DOCX / TXT / HTML / Excel / images); PDF supports 4 engines (ETL4LM / MineRU / PaddleOCR / local) +- **Transform**: summary extraction → attachment/image handling → thumbnail generation → text chunking (ElemCharacterTextSplitter, default chunk_size=1000) → preview cache +- **Ingest**: simultaneous write to Milvus (dense vectors, semantic search) + Elasticsearch (sparse BM25 index) + +**File processing states**: WAITING(5) → PROCESSING(1) → SUCCESS(2) / FAILED(3) / TIMEOUT(6) + +**Async processing**: all file processing via Celery `knowledge_celery` queue + +**Core classes**: `knowledge/rag/pipeline/base.py` (NormalPipeline), `knowledge/rag/knowledge_file_pipeline.py` (KnowledgeFilePipeline) + +--- + +## Linsight Agent Framework (`linsight/`) + +Independent Worker process, decoupled from API via Redis queue. + +**Flow**: user submits → SOP generation → task decomposition → Agent executes step-by-step (tool calls, user interaction, sub-task generation) + +**Events**: TaskStart, TaskEnd, ExecStep, NeedUserInput, GenerateSubTask + +**State persistence**: Redis cache + MySQL dual-write; Redis key TTL 1 hour + +**Worker model**: multiple `ScheduleCenterProcess` (multiprocessing), each with `asyncio.Semaphore` concurrency control + +**Key files**: +- `linsight/worker.py` — Worker entry point +- `linsight/domain/task_exec.py` — `LinsightWorkflowTask` executor +- `src/backend/bisheng_langchain/linsight/` — LinsightAgent, TaskManage, Task/ReactTask runtime + +--- + +## Celery Workers (`worker/`) + +| Queue | Concurrency | Responsibility | +|-------|-------------|----------------| +| `knowledge_celery` | 20 threads | Document parsing, embedding, vector writes | +| `workflow_celery` | 100 threads | Workflow DAG execution | +| `celery` (default) | 100 threads | Telemetry stats | + +Beat tasks: telemetry sync at 00:30, intelligence center articles at 05:30 daily. +Worker heartbeat: writes to Redis (`celery_worker_alive_queues`) every 5 seconds. +Multi-tenant: Beat iterates all active tenants per task — adding a task multiplies by N tenants. + +--- + +## Configuration Reference (`config.yaml`) + +Load priority: `YAML file → env vars (BS_*) → DB config (initdb_config) → Redis cache (100s TTL)` + +Supports `!env ${VAR}` syntax for env var injection. + +Key config groups: + +| Group | Notes | +|-------|-------| +| `database_url` | MySQL connection. Password is Fernet-encrypted (key in `core/config/settings.py` `secret_key`) | +| `redis_url` / `celery_redis_url` | Redis connections | +| `vector_stores.milvus` | Milvus connection | +| `vector_stores.elasticsearch` | ES connection (business + stats instances) | +| `object_storage.minio` | MinIO. `sharepoint` must match Vite `fileServiceTarget` exactly | +| `openfga` | OpenFGA: api_url, store_id, model_id | +| `multi_tenant` | enabled (default false), default_tenant_code, storage_isolation | +| `workflow_conf` | max_steps=50, timeout=720 min | +| `linsight_conf` | max_steps=200, retry_num=3 | +| `cookie_conf` | JWT cookie expiry (default 86400s) | diff --git a/src/backend/CLAUDE.md b/src/backend/CLAUDE.md new file mode 120000 index 000000000..47dc3e3d8 --- /dev/null +++ b/src/backend/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file