commit 535d97a70cde65cab7dff50b2cc50da0f3eea1d8 Author: wren <“porlong@qq.com”> Date: Mon Apr 27 16:48:22 2026 +0800 chore: initial commit — leaudit-platform project skeleton 17-table PostgreSQL schema with full Chinese column comments, FastAPI project structure (admin/common/modules), DSL rule files, and schema migration scripts. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..692ecba --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +dist/ +build/ +*.egg +.eggs/ + +# Virtualenv +venv/ +.venv/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Environment & Secrets +.env +.env.* +config/env.* +app.toml +!app.toml.example + +# Logs +logs/ +*.log + +# Uploads / temp +uploads/ +temp/ +tmp/ + +# Celery +celerybeat-schedule +celerybeat.pid + +# Docker +.docker/ + +# Coverage +htmlcov/ +.coverage +.coverage.* +coverage.xml +*.cover +.pytest_cache/ + +# Rules cache +rules/**/__pycache__/ + +# Claude +.claude/ +CLAUDE.md diff --git a/fastapi_admin/__init__.py b/fastapi_admin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_admin/app.py b/fastapi_admin/app.py new file mode 100644 index 0000000..129e188 --- /dev/null +++ b/fastapi_admin/app.py @@ -0,0 +1,65 @@ +"""FastAPI 应用工厂。""" + +from __future__ import annotations + +import sys +from contextlib import asynccontextmanager +from pathlib import Path + +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +from fastapi_admin.config import APP_NAME, APP_CORS_ORIGINS +from fastapi_admin.config._loader import _find_project_root + +# 确保项目根在 sys.path +_PROJECT_ROOT = _find_project_root() +if str(_PROJECT_ROOT) not in sys.path: + sys.path.insert(0, str(_PROJECT_ROOT)) + +# fastapi_modules 目录加入路径(使 importlib 能找到各模块) +_FASTMOD = _PROJECT_ROOT / "fastapi_modules" +_FASTMOD_LEAUDIT = _FASTMOD / "fastapi_leaudit" +if str(_FASTMOD) not in sys.path: + sys.path.insert(0, str(_FASTMOD)) +if str(_FASTMOD_LEAUDIT) not in sys.path: + sys.path.insert(0, str(_FASTMOD_LEAUDIT)) + + +def create_app() -> FastAPI: + """创建并配置 FastAPI 应用。""" + + @asynccontextmanager + async def lifespan(app: FastAPI): + import logging + logging.basicConfig(level=logging.INFO) + logging.getLogger("APP").info(f"{APP_NAME} starting...") + yield + logging.getLogger("APP").info(f"{APP_NAME} shutting down...") + + app = FastAPI( + title=APP_NAME, + version="1.0.0", + lifespan=lifespan, + docs_url="/api/docs", + redoc_url=None, + ) + + # CORS + origins = [o.strip() for o in APP_CORS_ORIGINS.split(",") if o.strip()] + app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + # 注册控制器 + from fastapi_admin.bootstrap_parts.controllers import register_controllers + register_controllers(app) + + return app + + +app = create_app() diff --git a/fastapi_admin/bootstrap_parts/__init__.py b/fastapi_admin/bootstrap_parts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_admin/bootstrap_parts/controllers.py b/fastapi_admin/bootstrap_parts/controllers.py new file mode 100644 index 0000000..bd9d02a --- /dev/null +++ b/fastapi_admin/bootstrap_parts/controllers.py @@ -0,0 +1,92 @@ +"""控制器注册器 —— 扫描 controller_packages 并注册路由。""" + +from __future__ import annotations + +import importlib +import pkgutil +from pathlib import Path +from typing import Any + +from fastapi import APIRouter, FastAPI + +controller_packages = [ + "fastapi_modules.fastapi_leaudit.controllers", +] + + +def register_controllers(app: FastAPI) -> None: + """扫描所有控制器包,注册 BaseController 子类的路由。""" + for package_name in controller_packages: + try: + pkg = importlib.import_module(package_name) + except ImportError: + continue + + package_routers: dict[str, APIRouter] = {} + _collect_package_routers(pkg, str(Path(pkg.__file__ or "").parent), package_name, package_routers) + _register_from_package(pkg, package_name, package_routers, app) + + +def _collect_package_routers( + pkg: Any, pkg_dir: str, pkg_name: str, routers: dict[str, APIRouter], +) -> None: + """收集所有包级 router(从 __init__.py)。""" + if hasattr(pkg, "router") and isinstance(pkg.router, APIRouter): + routers[pkg_name] = pkg.router + + if not hasattr(pkg, "__path__"): + return + + for _, sub_name, is_pkg in pkgutil.iter_modules([pkg_dir]): + if sub_name.startswith("_"): + continue + sub_full = f"{pkg_name}.{sub_name}" + if is_pkg: + try: + sub_pkg = importlib.import_module(sub_full) + sub_dir = str(Path(pkg_dir) / sub_name) + _collect_package_routers(sub_pkg, sub_dir, sub_full, routers) + except ImportError: + pass + + +def _register_from_package( + pkg: Any, pkg_name: str, package_routers: dict[str, APIRouter], app: FastAPI, +) -> None: + """从包中注册 BaseController 子类。""" + from fastapi_common.fastapi_common_web.controller import BaseController + + if not hasattr(pkg, "__path__"): + return + + pkg_dir = str(Path(pkg.__file__ or "").parent) + + for _, module_name, _ in pkgutil.iter_modules([pkg_dir]): + if module_name.startswith("_"): + continue + try: + mod = importlib.import_module(f"{pkg_name}.{module_name}") + except ImportError: + continue + + for _, obj in vars(mod).items(): + if ( + isinstance(obj, type) + and issubclass(obj, BaseController) + and obj is not BaseController + ): + instance = obj() + target_router = _resolve_target_router(pkg_name, module_name, package_routers) + app.include_router(instance.router, prefix="/api", dependencies=target_router.dependencies) + + +def _resolve_target_router( + pkg_name: str, module_name: str, package_routers: dict[str, APIRouter], +) -> APIRouter: + """沿包路径向上查找最近的包级 router。""" + parts = pkg_name.split(".") + for i in range(len(parts), 0, -1): + parent = ".".join(parts[:i]) + if parent in package_routers: + return package_routers[parent] + return APIRouter() diff --git a/fastapi_admin/config/__init__.py b/fastapi_admin/config/__init__.py new file mode 100644 index 0000000..1aff211 --- /dev/null +++ b/fastapi_admin/config/__init__.py @@ -0,0 +1,59 @@ +"""配置模块。 + +所有 Settings 实例的字段和 @property 会被自动导出为模块级变量。 +业务代码直接导入: + + from fastapi_admin.config import APP_PORT, ASYNCPG_DATABASE_URL +""" + +from __future__ import annotations + +from ._loader import load_config as _load_config + +# 优先加载 TOML → os.environ(必须在 Settings 实例化之前) +_load_config() + +from ._settings import app, jwt, db, redis, oss, llm, vlm, ocr, leaudit as _leaudit # noqa: E402 + + +def _export_settings(instance: object, prefix: str = "") -> dict[str, object]: + """将 Settings 实例的所有字段和 @property 导出为模块级变量。""" + result: dict[str, object] = {} + for key in dir(type(instance)): + if key.startswith("_"): + continue + value = getattr(instance, key, None) + if callable(value) and not isinstance(value, property): + continue + if isinstance(value, property): + value = value.__get__(instance) + result[key] = value + return result + + +_APP = _export_settings(app) +_JWT = _export_settings(jwt) +_DB = _export_settings(db) +_REDIS = _export_settings(redis) +_OSS = _export_settings(oss) +_LLM = _export_settings(llm) +_VLM = _export_settings(vlm) +_OCR = _export_settings(ocr) +_LEAUDIT = _export_settings(_leaudit) + +# 将所有变量注入当前模块的全局命名空间 +_ALL = {} +_ALL.update(_APP) +_ALL.update(_JWT) +_ALL.update(_DB) +_ALL.update(_REDIS) +_ALL.update(_OSS) +_ALL.update(_LLM) +_ALL.update(_VLM) +_ALL.update(_OCR) +_ALL.update(_LEAUDIT) + +globals().update(_ALL) + +# 常量 +ROOT_PATH = __import__("pathlib").Path(__file__).resolve().parents[2] diff --git a/fastapi_admin/config/__init__.pyi b/fastapi_admin/config/__init__.pyi new file mode 100644 index 0000000..9f66c5f --- /dev/null +++ b/fastapi_admin/config/__init__.pyi @@ -0,0 +1,55 @@ +"""类型存根 —— 为 IDE 提供动态导出变量的类型信息。""" + +# APP +APP_NAME: str +APP_HOST: str +APP_PORT: int +APP_CORS_ORIGINS: str + +# JWT +JWT_SECRET_KEY: str +JWT_ACCESS_TOKEN_EXPIRE_HOURS: int +JWT_ALGORITHM: str + +# DB +DB_HOST: str +DB_PORT: int +DB_NAME: str +DB_USER: str +DB_PASSWORD: str +ASYNCPG_DATABASE_URL: str + +# Redis +REDIS_HOST: str +REDIS_PORT: int +REDIS_DB: int +REDIS_PASSWORD: str + +# OSS +OSS_ENDPOINT: str +OSS_ACCESS_KEY: str +OSS_SECRET_KEY: str +OSS_BUCKET: str +OSS_REGION: str + +# LLM +LLM_BASE_URL: str +LLM_MODEL: str +LLM_API_KEY: str + +# VLM +VLM_BASE_URL: str +VLM_MODEL: str + +# OCR +OCR_BASE_URL: str +OCR_TIMEOUT: int + +# LEAUDIT +LEAUDIT_RULES_DIR: str +LEAUDIT_RESCUE_MODE: str +LEAUDIT_LLM_MAX_CONCURRENCY: int +LEAUDIT_VLM_MAX_CONCURRENCY: int + +# 常量 +ROOT_PATH: object diff --git a/fastapi_admin/config/_loader.py b/fastapi_admin/config/_loader.py new file mode 100644 index 0000000..33e5432 --- /dev/null +++ b/fastapi_admin/config/_loader.py @@ -0,0 +1,68 @@ +"""配置加载器 —— 读取 TOML 文件并注入 os.environ。 + +加载顺序(后覆盖前): +1. app.toml — 基础配置 +2. app.{APP_ENV}.toml — 环境差异 +3. app.ai.toml — AI 专用(最高 TOML 优先级) +4. 已有环境变量 — 不覆盖(最高优先级) +""" + +from __future__ import annotations + +import os +import sys +from pathlib import Path + +_ROOT = Path(__file__).resolve().parents[2] + + +def _find_project_root() -> Path: + """查找项目根目录(包含 app.toml 的目录)。""" + return _ROOT + + +def _load_toml(path: Path) -> dict: + """读取 TOML 文件并展平 [SECTION].KEY → SECTION_KEY。""" + try: + import tomllib + except ImportError: + import tomli as tomllib + + with open(path, "rb") as fh: + data = tomllib.load(fh) + + flat: dict[str, str] = {} + for section, values in data.items(): + if not isinstance(values, dict): + continue + for key, val in values.items(): + env_key = f"{section.upper()}_{key.upper()}" + if isinstance(val, list): + flat[env_key] = ",".join(str(v) for v in val) + elif isinstance(val, bool): + flat[env_key] = str(val).lower() + elif val is not None: + flat[env_key] = str(val) + return flat + + +def load_config() -> None: + """加载所有 TOML 配置到 os.environ(不覆盖已有环境变量)。""" + root = _find_project_root() + + env = os.getenv("APP_ENV", "development") + toml_files = [ + root / "app.toml", + root / f"app.{env}.toml", + root / "app.ai.toml", + ] + + for toml_path in toml_files: + if not toml_path.exists(): + continue + for key, value in _load_toml(toml_path).items(): + os.environ.setdefault(key, value) + + # 确保项目根在 sys.path 中 + if str(root) not in sys.path: + sys.path.insert(0, str(root)) diff --git a/fastapi_admin/config/_settings.py b/fastapi_admin/config/_settings.py new file mode 100644 index 0000000..65ada80 --- /dev/null +++ b/fastapi_admin/config/_settings.py @@ -0,0 +1,102 @@ +"""Pydantic Settings 定义。 + +每个 Settings 类对应 app.toml 中的一个 [SECTION]。 +字段名 = SECTION_KEY(TOML 展平后的环境变量名)。 +""" + +from __future__ import annotations + +from pydantic_settings import BaseSettings + + +class _Base(BaseSettings): + """所有 Settings 的基类。""" + model_config = {"env_file": None, "extra": "ignore"} + + +class AppSettings(_Base): + """应用基础配置 [APP]。""" + APP_NAME: str = "LeAudit Platform" + APP_HOST: str = "0.0.0.0" + APP_PORT: int = 8000 + APP_CORS_ORIGINS: str = "*" + + +class JwtSettings(_Base): + """JWT 配置 [JWT]。""" + JWT_SECRET_KEY: str = "" + JWT_ACCESS_TOKEN_EXPIRE_HOURS: int = 24 + JWT_ALGORITHM: str = "HS256" + + +class DbSettings(_Base): + """数据库配置 [DB]。""" + DB_HOST: str = "localhost" + DB_PORT: int = 5432 + DB_NAME: str = "leaudit" + DB_USER: str = "postgres" + DB_PASSWORD: str = "" + + @property + def ASYNCPG_DATABASE_URL(self) -> str: + """动态构建 asyncpg 连接 URL。""" + return ( + f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASSWORD}" + f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}" + ) + + +class RedisSettings(_Base): + """Redis 配置 [REDIS]。""" + REDIS_HOST: str = "localhost" + REDIS_PORT: int = 6379 + REDIS_DB: int = 0 + REDIS_PASSWORD: str = "" + + +class OssSettings(_Base): + """OSS 对象存储配置 [OSS]。""" + OSS_ENDPOINT: str = "" + OSS_ACCESS_KEY: str = "" + OSS_SECRET_KEY: str = "" + OSS_BUCKET: str = "leaudit" + OSS_REGION: str = "" + + +class LlmSettings(_Base): + """LLM 配置 [LLM]。""" + LLM_BASE_URL: str = "" + LLM_MODEL: str = "" + LLM_API_KEY: str = "" + + +class VlmSettings(_Base): + """VLM 配置 [VLM]。""" + VLM_BASE_URL: str = "" + VLM_MODEL: str = "" + + +class OcrSettings(_Base): + """OCR 配置 [OCR]。""" + OCR_BASE_URL: str = "" + OCR_TIMEOUT: int = 300 + + +class LeauditSettings(_Base): + """LeAudit 引擎配置 [LEAUDIT]。""" + LEAUDIT_RULES_DIR: str = "rules" + LEAUDIT_RESCUE_MODE: str = "auto" + LEAUDIT_LLM_MAX_CONCURRENCY: int = 5 + LEAUDIT_VLM_MAX_CONCURRENCY: int = 3 + + +# 实例化所有 Settings +app = AppSettings() +jwt = JwtSettings() +db = DbSettings() +redis = RedisSettings() +oss = OssSettings() +llm = LlmSettings() +vlm = VlmSettings() +ocr = OcrSettings() +leaudit = LeauditSettings() diff --git a/fastapi_common/__init__.py b/fastapi_common/__init__.py new file mode 100644 index 0000000..a32f304 --- /dev/null +++ b/fastapi_common/__init__.py @@ -0,0 +1 @@ +"""fastapi_common —— 共享框架层。""" diff --git a/fastapi_common/fastapi_common_logger/__init__.py b/fastapi_common/fastapi_common_logger/__init__.py new file mode 100644 index 0000000..ee81f0c --- /dev/null +++ b/fastapi_common/fastapi_common_logger/__init__.py @@ -0,0 +1,43 @@ +"""日志模块 —— 通道由调用栈自动推断。""" + +from __future__ import annotations + +import logging +import sys + + +def _infer_channel() -> str: + """根据调用栈自动推断日志通道。""" + frame = sys._getframe(2) + filename = frame.f_code.co_filename + if "/controllers/" in filename: + return "CONTROLLER" + if "/services/" in filename: + return "SERVICE" + if "/models/" in filename: + return "MODEL" + if "/leaudit_bridge/" in filename: + return "BRIDGE" + if "/handler/" in filename: + return "HANDLER" + if "/tasks/" in filename: + return "TASK" + if "/middleware/" in filename: + return "MIDDLEWARE" + if "postgrest" in filename: + return "POSTGREST" + if "uvicorn" in filename: + return "UVICORN" + return "APP" + + +class _ChannelLogger: + """代理 logger,自动推断通道。""" + + def __getattr__(self, name: str): + channel = _infer_channel() + logger = logging.getLogger(channel) + return getattr(logger, name) + + +logger: object = _ChannelLogger() # type: ignore[assignment] diff --git a/fastapi_common/fastapi_common_security/__init__.py b/fastapi_common/fastapi_common_security/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_common/fastapi_common_security/jwtService.py b/fastapi_common/fastapi_common_security/jwtService.py new file mode 100644 index 0000000..d93ae4d --- /dev/null +++ b/fastapi_common/fastapi_common_security/jwtService.py @@ -0,0 +1,151 @@ +"""JWT 服务 —— Token 签发、验证、刷新、撤销。 + +合并自旧项目的 auth.py(create_jwt_token / decode_jwt_token)和 +jwt_manager.py(generate_tokens / verify_token / refresh_token / revoke_token)。 +逻辑不变,仅重组为服务类 + 使用项目统一配置。 +""" + +from __future__ import annotations + +import hashlib +import time +import uuid +from datetime import datetime, timedelta, timezone +from typing import Any + +import jwt + +from fastapi_common.fastapi_common_logger import logger +from fastapi_admin.config import JWT_SECRET_KEY, JWT_ALGORITHM + +ACCESS_TOKEN_EXPIRE_MINUTES = 15 +REFRESH_TOKEN_EXPIRE_DAYS = 7 +JWT_AUDIENCE = "leaudit-platform" +JWT_ISSUER = "leaudit-platform" + + +class JwtService: + """JWT Token 管理服务。""" + + # ------------------------------------------------------------------ + # Token 生成 + # ------------------------------------------------------------------ + + @staticmethod + def generate( + userId: int, + username: str, + nickName: str = "", + ouId: str = "", + ouName: str = "", + roles: list[str] | None = None, + area: str | None = None, + userRole: str | None = None, + deviceId: str | None = None, + deviceName: str | None = None, + userAgent: str | None = None, + ipAddress: str | None = None, + ) -> dict[str, Any]: + """生成 Access Token + Refresh Token。 + + 返回格式与旧项目 auth.py 完全一致: + { + "access_token": "...", + "refresh_token": "...", + "token_type": "Bearer", + "expires_in": 900 + } + """ + now = datetime.now(timezone.utc) + jti = str(uuid.uuid4()) + + # Access Token + accessPayload = { + "jti": jti, + "user_id": userId, + "username": username, + "nick_name": nickName, + "ou_id": ouId, + "ou_name": ouName, + "roles": roles or [], + "area": area, + "user_role": userRole, + "iat": now, + "exp": now + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES), + "aud": JWT_AUDIENCE, + "iss": JWT_ISSUER, + "type": "access", + } + accessToken = jwt.encode(accessPayload, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM) + + # Refresh Token + refreshJti = str(uuid.uuid4()) + refreshPayload = { + "jti": refreshJti, + "user_id": userId, + "username": username, + "iat": now, + "exp": now + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS), + "aud": JWT_AUDIENCE, + "iss": JWT_ISSUER, + "type": "refresh", + } + refreshToken = jwt.encode(refreshPayload, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM) + + # Token 签发时间(格式化字符串,供前端展示) + issuedTime = now.strftime("%Y-%m-%d %H:%M:%S") + + logger.info(f"JWT issued: user={userId}, jti={jti}") + + return { + "access_token": accessToken, + "refresh_token": refreshToken, + "token_type": "Bearer", + "expires_in": ACCESS_TOKEN_EXPIRE_MINUTES * 60, + "issued_time": issuedTime, + "jti": jti, + "refresh_jti": refreshJti, + } + + # ------------------------------------------------------------------ + # Token 验证 + # ------------------------------------------------------------------ + + @staticmethod + def verify(token: str) -> dict[str, Any]: + """验证并解码 JWT Token。 + + Raises: + jwt.ExpiredSignatureError: Token 过期 + jwt.InvalidTokenError: Token 无效 + """ + payload = jwt.decode( + token, + JWT_SECRET_KEY, + algorithms=[JWT_ALGORITHM], + audience=JWT_AUDIENCE, + issuer=JWT_ISSUER, + ) + return payload + + @staticmethod + def decodeUnsafe(token: str) -> dict[str, Any] | None: + """不验证签名解码 Token(仅用于调试或获取过期 Token 信息)。""" + try: + return jwt.decode(token, options={"verify_signature": False}) + except Exception: + return None + + # ------------------------------------------------------------------ + # Token 撤销 + # ------------------------------------------------------------------ + + @staticmethod + def _hashToken(token: str) -> str: + return hashlib.sha256(token.encode()).hexdigest() + + @staticmethod + def getJti(token: str) -> str | None: + """从 Token 中提取 JTI(不验证签名)。""" + payload = JwtService.decodeUnsafe(token) + return payload.get("jti") if payload else None diff --git a/fastapi_common/fastapi_common_security/security.py b/fastapi_common/fastapi_common_security/security.py new file mode 100644 index 0000000..a96adbc --- /dev/null +++ b/fastapi_common/fastapi_common_security/security.py @@ -0,0 +1,23 @@ +"""JWT 鉴权工具。""" + +from __future__ import annotations + +from typing import Any + +import jwt +from fastapi import Request + +from fastapi_admin.config import JWT_SECRET_KEY, JWT_ALGORITHM + + +def verify_access_token(RequestObj: Request) -> dict[str, Any]: + """验证 JWT access token 并返回 payload。""" + auth = RequestObj.headers.get("Authorization", "") + if not auth.startswith("Bearer "): + return {} + token = auth.removeprefix("Bearer ").strip() + try: + payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM]) + return payload + except jwt.PyJWTError: + return {} diff --git a/fastapi_common/fastapi_common_sqlalchemy/__init__.py b/fastapi_common/fastapi_common_sqlalchemy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_common/fastapi_common_sqlalchemy/base.py b/fastapi_common/fastapi_common_sqlalchemy/base.py new file mode 100644 index 0000000..1ffd392 --- /dev/null +++ b/fastapi_common/fastapi_common_sqlalchemy/base.py @@ -0,0 +1,10 @@ +"""SQLAlchemy 声明式基类。""" + +from __future__ import annotations + +from sqlalchemy.orm import DeclarativeBase + + +class Base(DeclarativeBase): + """SQLAlchemy 声明式基类。""" + pass diff --git a/fastapi_common/fastapi_common_sqlalchemy/database.py b/fastapi_common/fastapi_common_sqlalchemy/database.py new file mode 100644 index 0000000..d56cf3c --- /dev/null +++ b/fastapi_common/fastapi_common_sqlalchemy/database.py @@ -0,0 +1,21 @@ +"""SQLAlchemy 异步引擎和 session 工厂。""" + +from __future__ import annotations + +from contextlib import asynccontextmanager + +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine + +from fastapi_admin.config import ASYNCPG_DATABASE_URL + +_engine = create_async_engine(ASYNCPG_DATABASE_URL, echo=False, pool_size=20, max_overflow=10) + +_AsyncSessionFactory = async_sessionmaker(_engine, class_=AsyncSession, expire_on_commit=False) + + +@asynccontextmanager +async def GetAsyncSession(): + """获取异步数据库 session(上下文管理器)。""" + async with _AsyncSessionFactory() as session: + yield session + await session.commit() diff --git a/fastapi_common/fastapi_common_utils/__init__.py b/fastapi_common/fastapi_common_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_common/fastapi_common_web/controller.py b/fastapi_common/fastapi_common_web/controller.py new file mode 100644 index 0000000..c3f24f7 --- /dev/null +++ b/fastapi_common/fastapi_common_web/controller.py @@ -0,0 +1,20 @@ +"""BaseController —— 所有控制器继承此类。""" + +from __future__ import annotations + +from fastapi import APIRouter + + +class BaseController: + """控制器基类。 + + 子类在 __init__ 中用 @self.router.get/post 注册路由。 + """ + + def __init__(self, prefix: str = "", tags: list[str] | None = None): + self.router = APIRouter(prefix=prefix, tags=tags or []) + self.Init() + + def Init(self) -> None: + """子类重写此方法注册路由。""" + pass diff --git a/fastapi_common/fastapi_common_web/domain/__init__.py b/fastapi_common/fastapi_common_web/domain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_common/fastapi_common_web/domain/responses.py b/fastapi_common/fastapi_common_web/domain/responses.py new file mode 100644 index 0000000..0ee7845 --- /dev/null +++ b/fastapi_common/fastapi_common_web/domain/responses.py @@ -0,0 +1,57 @@ +"""统一响应格式。""" + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Any, Generic, TypeVar + +T = TypeVar("T") + + +class StatusCodeEnum(Enum): + """HTTP 状态码枚举。""" + + HTTP_200_OK = 200 + HTTP_201_CREATED = 201 + HTTP_400_BAD_REQUEST = 400 + HTTP_401_UNAUTHORIZED = 401 + HTTP_403_FORBIDDEN = 403 + HTTP_404_NOT_FOUND = 404 + HTTP_409_CONFLICT = 409 + HTTP_422_UNPROCESSABLE_ENTITY = 422 + HTTP_500_INTERNAL_SERVER_ERROR = 500 + + +@dataclass +class PaginationInfo: + """分页信息。""" + + total: int + page: int + pageSize: int + + +@dataclass +class PageResult(Generic[T]): + """分页结果。""" + + list: list[T] + pagination: PaginationInfo + + +@dataclass +class Result(Generic[T]): + """统一响应。""" + + code: int + message: str + data: T | None = None + + @classmethod + def success(cls, data: T | None = None, message: str = "ok") -> "Result[T]": + return cls(code=200, message=message, data=data) + + @classmethod + def error(cls, status: StatusCodeEnum, message: str | None = None) -> "Result[None]": + return cls(code=status.value, message=message or status.name, data=None) diff --git a/fastapi_common/fastapi_common_web/exception/Base/BusinessException.py b/fastapi_common/fastapi_common_web/exception/Base/BusinessException.py new file mode 100644 index 0000000..c1ee1cb --- /dev/null +++ b/fastapi_common/fastapi_common_web/exception/Base/BusinessException.py @@ -0,0 +1,14 @@ +"""业务异常基类。""" + +from __future__ import annotations + +from fastapi_common.fastapi_common_web.domain.responses import StatusCodeEnum + + +class BusinessException(Exception): + """所有业务异常继承此类。""" + + def __init__(self, status: StatusCodeEnum, message: str): + self.status = status + self.message = message + super().__init__(message) diff --git a/fastapi_common/fastapi_common_web/exception/Base/__init__.py b/fastapi_common/fastapi_common_web/exception/Base/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_common/fastapi_common_web/exception/LeauditException.py b/fastapi_common/fastapi_common_web/exception/LeauditException.py new file mode 100644 index 0000000..bce4ab6 --- /dev/null +++ b/fastapi_common/fastapi_common_web/exception/LeauditException.py @@ -0,0 +1,7 @@ +"""LeAudit 域异常。""" + +from fastapi_common.fastapi_common_web.exception.Base.BusinessException import BusinessException + + +class LeauditException(BusinessException): + """LeAudit 模块异常。""" diff --git a/fastapi_common/fastapi_common_web/exception/__init__.py b/fastapi_common/fastapi_common_web/exception/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_common/fastapi_common_web/middleware/__init__.py b/fastapi_common/fastapi_common_web/middleware/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_common/fastapi_common_web/models/__init__.py b/fastapi_common/fastapi_common_web/models/__init__.py new file mode 100644 index 0000000..b3dd73a --- /dev/null +++ b/fastapi_common/fastapi_common_web/models/__init__.py @@ -0,0 +1,32 @@ +"""BaseModel —— 所有业务模型的抽象基类。 + +自动提供三个公共时间字段: +- create_time:INSERT 时由数据库写入当前时间 +- update_time:INSERT 和 UPDATE 时自动更新 +- delete_time:默认 NULL,非 NULL 表示已软删除 +""" + +from __future__ import annotations + +from datetime import datetime + +from sqlalchemy import DateTime, func +from sqlalchemy.orm import Mapped, mapped_column + +from fastapi_common.fastapi_common_sqlalchemy.base import Base + + +class BaseModel(Base): + """所有业务模型的抽象基类。""" + + __abstract__ = True + + create_time: Mapped[datetime] = mapped_column( + DateTime(timezone=True), server_default=func.now(), comment="创建时间" + ) + update_time: Mapped[datetime] = mapped_column( + DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), comment="更新时间" + ) + delete_time: Mapped[datetime | None] = mapped_column( + DateTime(timezone=True), default=None, comment="软删除时间" + ) diff --git a/fastapi_modules/__init__.py b/fastapi_modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/__init__.py b/fastapi_modules/fastapi_leaudit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/controllers/__init__.py b/fastapi_modules/fastapi_leaudit/controllers/__init__.py new file mode 100644 index 0000000..c3bb678 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/controllers/__init__.py @@ -0,0 +1,15 @@ +"""控制器包(需要 JWT 鉴权)。""" + +from typing import Any + +from fastapi import APIRouter, Depends, Request + +from fastapi_common.fastapi_common_security.security import verify_access_token + + +async def jwt_auth_dependency(RequestObj: Request) -> dict[str, Any]: + """JWT 鉴权依赖。""" + return verify_access_token(RequestObj) + + +router = APIRouter(dependencies=[Depends(jwt_auth_dependency)]) diff --git a/fastapi_modules/fastapi_leaudit/controllers/auditController.py b/fastapi_modules/fastapi_leaudit/controllers/auditController.py new file mode 100644 index 0000000..9ff19d8 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/controllers/auditController.py @@ -0,0 +1,42 @@ +"""评查控制器。""" + +from fastapi_common.fastapi_common_web.controller import BaseController +from fastapi_common.fastapi_common_web.domain.responses import Result + +from fastapi_modules.fastapi_leaudit.domian.Dto.auditDto import AuditRunDTO +from fastapi_modules.fastapi_leaudit.domian.vo.auditVo import AuditRunVO, AuditResultVO +from fastapi_modules.fastapi_leaudit.services import IAuditService +from fastapi_modules.fastapi_leaudit.services.impl.auditServiceImpl import AuditServiceImpl + + +class AuditController(BaseController): + """评查控制器。""" + + def __init__(self): + super().__init__(prefix="/audit", tags=["评查"]) + self.AuditService: IAuditService = AuditServiceImpl() + + @self.router.post("/run", response_model=Result[AuditRunVO]) + async def RunAudit(body: AuditRunDTO): + """触发文档评查 + + 对指定文档执行 LeAudit 完整评查链路。 + """ + run = await self.AuditService.Run( + DocumentId=body.documentId, + RuleType=body.ruleType, + Force=body.force, + ) + return Result.success(data=run) + + @self.router.get("/run/{RunId}", response_model=Result[AuditRunVO]) + async def GetRunStatus(RunId: int): + """查询评查运行状态。""" + run = await self.AuditService.GetRunStatus(RunId) + return Result.success(data=run) + + @self.router.get("/result/{RunId}", response_model=Result[AuditResultVO]) + async def GetResult(RunId: int): + """获取评查结果。""" + result = await self.AuditService.GetResult(RunId) + return Result.success(data=result) diff --git a/fastapi_modules/fastapi_leaudit/controllers/auth/__init__.py b/fastapi_modules/fastapi_leaudit/controllers/auth/__init__.py new file mode 100644 index 0000000..9694521 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/controllers/auth/__init__.py @@ -0,0 +1,5 @@ +"""认证控制器包(无鉴权)。""" + +from fastapi import APIRouter + +router = APIRouter() diff --git a/fastapi_modules/fastapi_leaudit/controllers/auth/authController.py b/fastapi_modules/fastapi_leaudit/controllers/auth/authController.py new file mode 100644 index 0000000..310fc42 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/controllers/auth/authController.py @@ -0,0 +1,97 @@ +"""认证控制器。 + +路由路径与旧项目完全一致: + POST /auth/login — 统一登录(OAuth + 密码自动检测) + POST /auth/password_login — 账密登录 + +响应格式按新项目规范使用 Result。 +""" + +from fastapi import Request +from fastapi.responses import JSONResponse + +from fastapi_common.fastapi_common_web.controller import BaseController +from fastapi_common.fastapi_common_web.domain.responses import Result +from fastapi_common.fastapi_common_logger import logger + +from fastapi_modules.fastapi_leaudit.domian.Dto.auth.loginDto import PasswordLoginDTO, OAuthLoginDTO +from fastapi_modules.fastapi_leaudit.domian.vo.auth.loginTokenVo import LoginTokenVO +from fastapi_modules.fastapi_leaudit.services import IAuthService +from fastapi_modules.fastapi_leaudit.services.impl.authServiceImpl import AuthServiceImpl + + +class AuthController(BaseController): + """认证控制器。""" + + def __init__(self): + super().__init__(prefix="/auth", tags=["认证"]) + self.AuthService: IAuthService = AuthServiceImpl() + + @self.router.post("/login") + async def Login(RequestObj: Request): + """统一登录接口。 + + 自动检测登录方式: + - 含 userInfo.sub → OAuth 登录 + - 含 username + password → 密码登录 + """ + try: + requestData = await RequestObj.json() + + if "userInfo" in requestData and isinstance(requestData["userInfo"], dict) and "sub" in requestData["userInfo"]: + logger.info("检测到 OAuth 登录请求") + ui = requestData["userInfo"] + vo = await self.AuthService.OAuthLogin( + Sub=ui["sub"], + Username=ui.get("username"), + Nickname=ui.get("nickname"), + Email=ui.get("email"), + PhoneNumber=ui.get("phone_number"), + OuId=ui.get("ou_id"), + OuName=ui.get("ou_name"), + IsLeader=ui.get("is_leader"), + Area=requestData.get("area"), + ExpiresIn=requestData.get("expiresIn", 3600), + ) + elif "username" in requestData and "password" in requestData: + logger.info(f"检测到密码登录请求 - username={requestData['username']}") + vo = await self.AuthService.PasswordLogin( + Sub=requestData["username"], + Password=requestData["password"], + ) + else: + return JSONResponse(status_code=400, content={"code": 400, "message": "无效的登录请求格式", "data": None}) + + return JSONResponse(status_code=200, content={ + "code": 200, + "message": "ok", + "data": { + "access_token": vo.access_token, + "token_type": vo.token_type, + "expires_in": vo.expires_in, + "issued_time": vo.issued_time, + "user_info": vo.user_info, + }, + }) + + except Exception as e: + logger.error(f"登录失败: {e}") + return JSONResponse(status_code=401, content={ + "code": 401, "message": str(e), "data": None, + }) + + @self.router.post("/password_login") + async def PasswordLogin(RequestObj: Request): + """账密登录。校验 sso_users 表 sub + password。""" + try: + requestData = await RequestObj.json() + dto = PasswordLoginDTO(**requestData) + vo = await self.AuthService.PasswordLogin(Sub=dto.sub, Password=dto.password) + return JSONResponse(status_code=200, content={ + "code": 200, "message": "ok", "data": vo.model_dump(), + }) + except Exception as e: + logger.error(f"密码登录失败: {e}") + return JSONResponse(status_code=401, content={ + "code": 401, "message": str(e), "data": None, + }) diff --git a/fastapi_modules/fastapi_leaudit/domian/Dto/__init__.py b/fastapi_modules/fastapi_leaudit/domian/Dto/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/domian/Dto/auditDto.py b/fastapi_modules/fastapi_leaudit/domian/Dto/auditDto.py new file mode 100644 index 0000000..c281e6c --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/domian/Dto/auditDto.py @@ -0,0 +1,11 @@ +"""评查 DTO(仅控制器层使用)。""" + +from pydantic import BaseModel, Field + + +class AuditRunDTO(BaseModel): + """触发评查请求。""" + + documentId: int = Field(..., description="文档ID") + ruleType: str | None = Field(None, description="指定规则类型编码") + force: bool = Field(False, description="是否强制重跑") diff --git a/fastapi_modules/fastapi_leaudit/domian/Dto/auth/__init__.py b/fastapi_modules/fastapi_leaudit/domian/Dto/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/domian/Dto/auth/loginDto.py b/fastapi_modules/fastapi_leaudit/domian/Dto/auth/loginDto.py new file mode 100644 index 0000000..610ab08 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/domian/Dto/auth/loginDto.py @@ -0,0 +1,31 @@ +"""认证 DTO(仅控制器层使用)。""" + +from pydantic import BaseModel, Field + + +class PasswordLoginDTO(BaseModel): + """账密登录请求。""" + + sub: str = Field(..., description="账号") + password: str = Field(..., description="密码") + + +class OAuthUserInfo(BaseModel): + """OAuth 用户信息。""" + + sub: str = Field(..., description="IDaaS 用户唯一标识") + username: str | None = Field(None, description="用户名/工号") + nickname: str | None = Field(None, description="用户昵称") + email: str | None = Field(None, description="邮箱") + phone_number: str | None = Field(None, description="手机号") + ou_id: str | None = Field(None, description="组织单位ID") + ou_name: str | None = Field(None, description="组织单位名称") + is_leader: bool | None = Field(False, description="是否为负责人") + + +class OAuthLoginDTO(BaseModel): + """OAuth 登录请求。""" + + userInfo: OAuthUserInfo = Field(..., description="OAuth 用户信息") + expiresIn: int = Field(..., description="OAuth token 过期时间(秒)") + area: str | None = Field(None, description="用户所属地区") diff --git a/fastapi_modules/fastapi_leaudit/domian/__init__.py b/fastapi_modules/fastapi_leaudit/domian/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/domian/bo/__init__.py b/fastapi_modules/fastapi_leaudit/domian/bo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/domian/vo/__init__.py b/fastapi_modules/fastapi_leaudit/domian/vo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/domian/vo/auditVo.py b/fastapi_modules/fastapi_leaudit/domian/vo/auditVo.py new file mode 100644 index 0000000..0952c61 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/domian/vo/auditVo.py @@ -0,0 +1,33 @@ +"""评查 VO。""" + +from datetime import datetime + +from pydantic import BaseModel, Field + + +class AuditRunVO(BaseModel): + """评查运行响应。""" + + runId: int = Field(..., description="运行ID") + documentId: int = Field(..., description="文档ID") + runNo: int = Field(..., description="执行序号") + status: str = Field(..., description="状态") + phase: str | None = Field(None, description="draft/executed") + totalScore: float | None = Field(None, description="总分") + passedCount: int | None = Field(None, description="通过数") + failedCount: int | None = Field(None, description="失败数") + startedAt: datetime | None = Field(None, description="开始时间") + finishedAt: datetime | None = Field(None, description="结束时间") + + +class AuditResultVO(BaseModel): + """评查结果响应。""" + + runId: int = Field(..., description="运行ID") + totalScore: float | None = Field(None, description="总分") + passedCount: int = Field(0, description="通过数") + failedCount: int = Field(0, description="失败数") + skippedCount: int = Field(0, description="跳过数") + phase: str | None = Field(None, description="draft/executed") + rescueApplied: bool = Field(False, description="是否执行 rescue") + rules: list[dict] = Field(default_factory=list, description="规则结果列表") diff --git a/fastapi_modules/fastapi_leaudit/domian/vo/auth/__init__.py b/fastapi_modules/fastapi_leaudit/domian/vo/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/domian/vo/auth/loginTokenVo.py b/fastapi_modules/fastapi_leaudit/domian/vo/auth/loginTokenVo.py new file mode 100644 index 0000000..8e294b3 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/domian/vo/auth/loginTokenVo.py @@ -0,0 +1,13 @@ +"""认证 VO(控制器层 + 服务层使用)。""" + +from pydantic import BaseModel, Field + + +class LoginTokenVO(BaseModel): + """登录响应。""" + + access_token: str = Field(..., description="JWT Token") + token_type: str = Field("Bearer", description="Token 类型") + expires_in: int = Field(..., description="Token 过期时间(秒)") + issued_time: str = Field(..., description="签发时间 YYYY-MM-DD HH:MM:SS") + user_info: dict = Field(..., description="用户信息") diff --git a/fastapi_modules/fastapi_leaudit/domian/vo/ruleVo.py b/fastapi_modules/fastapi_leaudit/domian/vo/ruleVo.py new file mode 100644 index 0000000..d274661 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/domian/vo/ruleVo.py @@ -0,0 +1,26 @@ +"""规则 VO。""" + +from pydantic import BaseModel, Field + + +class RuleSetVO(BaseModel): + """规则集响应。""" + + id: int = Field(..., description="规则集ID") + ruleType: str = Field(..., description="业务规则类型编码") + ruleName: str = Field(..., description="规则集名称") + domainType: str | None = Field(None, description="域类型") + currentVersionId: int | None = Field(None, description="当前激活版本ID") + status: str = Field(..., description="draft/active/inactive/archived") + + +class RuleVersionVO(BaseModel): + """规则版本响应。""" + + id: int = Field(..., description="版本ID") + ruleSetId: int = Field(..., description="所属规则集ID") + versionNo: str = Field(..., description="版本号") + status: str = Field(..., description="draft/validated/published/rolled_back") + ossUrl: str = Field(..., description="YAML 文件 OSS 地址") + changeNote: str | None = Field(None, description="变更说明") + publishedAt: str | None = Field(None, description="发布时间") diff --git a/fastapi_modules/fastapi_leaudit/handler/__init__.py b/fastapi_modules/fastapi_leaudit/handler/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/__init__.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/__init__.py new file mode 100644 index 0000000..593c84e --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/__init__.py @@ -0,0 +1,82 @@ +"""leaudit bridge — use leaudit's full pipeline with docauditai's database storage. + +Directly calls leaudit's OCR → extraction → evaluation pipeline +and persists results into docauditai's PostgreSQL via PostgREST. + +Configuration switch (in env.{port}): + PIPELINE_MODE=leaudit → use leaudit pipeline +""" + +from leaudit_bridge.client_factory import ( + create_ocr_client, + create_llm_client, + create_vlm_client, +) +from leaudit_bridge.ocr_bridge import BridgeOCRClient +from leaudit_bridge.pipeline import LauditPipeline, PipelineResult +from leaudit_bridge.rules_loader import RulesLoader +from leaudit_bridge.storage_adapter import StorageAdapter + + +def is_leaudit_mode() -> bool: + """Check if the system is configured to use the leaudit pipeline.""" + from core.config import PIPELINE_MODE + return PIPELINE_MODE == "leaudit" + + +def create_pipeline(rules_path: str | None = None) -> LauditPipeline: + """Create a fully configured LauditPipeline from current config. + + Wraps the raw OCR client with DocNormalizationAdapter so that a single + ``.ocr()`` call produces a fully enriched OcrResult with: + - Document classification (type_id + rules_file_path) + - Dossier segmentation (sub-document page mapping) + - Seal/signature enrichment (text, seal_id, party_id) + - Normalized markdown (seal blocks + page separators) + + Args: + rules_path: If provided, forces the adapter to use this rules file + for classification and segmentation. When None, the adapter + uses the RulesFileRegistry to classify from document content, + enabling auto-detection of sub-types (e.g. 行政许可 variants). + """ + from pathlib import Path + from leaudit.doc_normalization.adapter import DocNormalizationAdapter + from leaudit.doc_normalization.doc_classifier import RulesFileRegistry + + raw_ocr = create_ocr_client() + llm_client = create_llm_client() + vlm_client = create_vlm_client() + + # Build registry from rules/ directory for content-based classification + registry = None + if rules_path is None: + rules_dir = Path(__file__).resolve().parents[1] / "rules" + if rules_dir.is_dir(): + registry = RulesFileRegistry.from_directory(rules_dir) + + ocr_client = DocNormalizationAdapter( + ocr_client=raw_ocr, + registry=registry, + llm_client=llm_client, + vlm_client=vlm_client, + force_rules_path=rules_path, + ) + ocr_client = BridgeOCRClient(ocr_client, vlm_client=vlm_client) + + return LauditPipeline( + ocr_client=ocr_client, + llm_client=llm_client, + ) + + +__all__ = [ + "LauditPipeline", + "PipelineResult", + "StorageAdapter", + "RulesLoader", + "create_ocr_client", + "create_llm_client", + "create_pipeline", + "is_leaudit_mode", +] diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/case_number_extractor.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/case_number_extractor.py new file mode 100644 index 0000000..b428cf1 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/case_number_extractor.py @@ -0,0 +1,128 @@ +"""Extract case number (案件编号) from leaudit OcrResult. + +Port of docauditai's ``extract_case_number_for_regex`` adapted for leaudit's +OcrResult model. Uses regex patterns first; falls back to LLM when available. +""" +from __future__ import annotations + +import logging +import re +from typing import Any + +from leaudit.ocr.models import OcrResult + +log = logging.getLogger(__name__) + +# Regex patterns for case number extraction +_PATTERNS: list[tuple[str, str]] = [ + # Direct match: "案件编号:梅烟专罚〔2024〕第XX号" + (r"案件编号[::]\s*(.*?)(?:\n|$)", "direct"), + # From 卷宗/卷 宗 header: extract content between 卷宗 and 案由 + (r"卷\s*宗([\s\S]*?)案\s*由", "file_content"), + # Standalone pattern: e.g. 梅烟专罚〔2024〕第001号 + (r"[\u4e00-\u9fa5]{2,8}[专罚处决][〔(\(\[]\d{4}[〕)\)\]][\u4e00-\u9fa5]*\d+号", "standalone"), + # Dossier number: e.g. "2024 年度 郁烟 第 71 号" + (r"\d{4}\s*年度\s*[\u4e00-\u9fa5]{1,6}\s*第\s*\d+\s*号", "dossier"), +] + +# Chinese number format within 卷宗 extracted text +_YEAR_NUMBER_RE = re.compile(r"\d{4}[\u4e00-\u9fa5]+\d+号") + + +def extract_case_number(ocr_result: OcrResult) -> str | None: + """Extract case number from OCR result using regex patterns. + + Searches across all pages but prioritizes early pages where case numbers + typically appear (封面, 卷宗封面). + + Args: + ocr_result: OCR result with pages containing text. + + Returns: + Extracted case number string, or None if not found. + """ + # Build text from first few pages (case numbers appear early) + pages_to_check = ocr_result.pages[:5] if len(ocr_result.pages) > 5 else ocr_result.pages + text = "\n".join(p.text for p in pages_to_check) + + if not text.strip(): + return None + + for pattern, ptype in _PATTERNS: + match = re.search(pattern, text) + if not match: + continue + + if ptype == "direct": + return match.group(1).strip() + + if ptype == "file_content": + content = match.group(1).strip() + num_match = _YEAR_NUMBER_RE.search(content) + if num_match: + return num_match.group() + + if ptype == "standalone": + return match.group() + + if ptype == "dossier": + return match.group() + + return None + + +async def extract_case_number_with_llm( + ocr_result: OcrResult, + llm_client: Any = None, +) -> str | None: + """Extract case number using regex first, then LLM fallback. + + Args: + ocr_result: OCR result with pages containing text. + llm_client: Optional LLM client for fallback extraction. + + Returns: + Extracted case number string, or None if not found. + """ + # Try regex first (fast, no API call) + result = extract_case_number(ocr_result) + if result: + return result + + # LLM fallback + if llm_client is None: + return None + + text = "\n".join(p.text for p in ocr_result.pages[:5]) + if not text.strip(): + return None + + try: + from leaudit.llm.base import BaseLLMClient, LLMRequest, LLMMessage + if not isinstance(llm_client, BaseLLMClient): + return None + + prompt = ( + "请从以下法律文书文本中提取案件编号。" + "案件编号通常格式如:梅烟专罚〔2024〕第001号。\n" + "只返回JSON: {\"case_number\": \"案件编号\"}\n\n" + f"文本:\n{text[:2000]}" + ) + request = LLMRequest( + messages=[LLMMessage(role="user", content=prompt)], + response_format={"type": "json_object"}, + max_tokens=512, + ) + response = await llm_client.complete(request) + + import json + parsed = json.loads(response.content) + case_number = parsed.get("case_number") + if case_number and case_number != "未找到": + if re.search(r"[\u4e00-\u9fa5]|[\d()]", case_number): + return case_number + + except Exception as e: + log.warning("LLM case number extraction failed: %s", e) + + return None diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/client_factory.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/client_factory.py new file mode 100644 index 0000000..3cc4bb8 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/client_factory.py @@ -0,0 +1,80 @@ +"""Create leaudit OCR/LLM/VLM clients from docauditai's env.{port} config.""" + +from __future__ import annotations + +import logging +from typing import TYPE_CHECKING + +from core.config import ( + OCR_CONFIG, + DEFAULT_BASE_URL, + DEFAULT_LLM_MODEL, + DEFAULT_API_KEY, + DEFAULT_VLM_BASE_URL, + DEFAULT_VLM_MODEL, +) + +if TYPE_CHECKING: + from leaudit.llm.base import BaseLLMClient + from leaudit.llm.vlm_base import BaseVLMClient + from leaudit.ocr.base import BaseOCRClient + +log = logging.getLogger(__name__) + + +def create_ocr_client() -> BaseOCRClient: + """Create a leaudit ChandraOCRClient from LEAUDIT_OCR_URL config.""" + import os + from leaudit.ocr.chandra_client import ChandraOCRClient + + base_url = os.getenv("LEAUDIT_OCR_URL", "").rstrip("/") + if not base_url: + base_url = OCR_CONFIG["API_URL"].rsplit("/api/v1/ocr", 1)[0] + timeout = float(OCR_CONFIG["TIMEOUT"]) + + client = ChandraOCRClient( + base_url=base_url, + timeout=timeout, + include_images=True, + ) + log.info("leaudit OCR client created: %s (timeout=%ss)", base_url, timeout) + return client + + +def create_llm_client() -> BaseLLMClient: + """Create a leaudit OpenAICompatibleClient from docauditai's LLM config.""" + from leaudit.llm.openai_client import OpenAICompatibleClient + + base_url = DEFAULT_BASE_URL + model = DEFAULT_LLM_MODEL + api_key = DEFAULT_API_KEY or "no-key" + + client = OpenAICompatibleClient( + api_key=api_key, + base_url=base_url, + default_model=model, + timeout=120.0, + ) + log.info("leaudit LLM client created: %s (model=%s)", base_url, model) + return client + + +def create_vlm_client() -> BaseVLMClient | None: + """Create a leaudit QwenVLMClient from docauditai's VLM config.""" + from leaudit.llm.qwen_vlm_client import QwenVLMClient + + base_url = DEFAULT_VLM_BASE_URL + model = DEFAULT_VLM_MODEL + api_key = DEFAULT_API_KEY or "no-key" + + if not base_url or not model: + log.info("leaudit VLM client skipped: no VLM config") + return None + + client = QwenVLMClient( + base_url=base_url, + api_key=api_key, + model=model, + ) + log.info("leaudit VLM client created: %s (model=%s)", base_url, model) + return client diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/ctx_builder.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/ctx_builder.py new file mode 100644 index 0000000..819eb04 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/ctx_builder.py @@ -0,0 +1,132 @@ +"""Build leaudit execution context from docauditai document data. + +Currently leaudit's pipeline in docauditai bypasses leaudit's own +``AuditCtx`` / ``AuditService`` and calls engine modules directly. +This module encapsulates the pre-execution setup that currently lives +inlined in ``pipeline.py`` and ``tasks.py``: + + - Resolve local file path (download from OSS to temp if needed) + - Determine RulesFile (from document metadata, type binding, or + content classification) + - Prepare OCR/LLM/VLM client references +""" + +from __future__ import annotations + +import logging +import os +import tempfile +from dataclasses import dataclass, field +from pathlib import Path +from typing import TYPE_CHECKING + +from leaudit.dsl.schema import RulesFile +from leaudit.llm.base import BaseLLMClient +from leaudit.ocr.base import BaseOCRClient + +if TYPE_CHECKING: + from leaudit.llm.vlm_base import BaseVLMClient + +log = logging.getLogger(__name__) + + +@dataclass +class ExecutionContext: + """Everything leaudit needs to run for one document.""" + + document_id: int + file_path: Path + rules_file: RulesFile + ocr_client: BaseOCRClient + llm_client: BaseLLMClient | None = None + vlm_client: object | None = None + source_port: int = 8000 + tmp_path: Path | None = None + metadata: dict = field(default_factory=dict) + + def cleanup(self) -> None: + """Remove temporary file if one was created.""" + if self.tmp_path is not None: + try: + os.remove(self.tmp_path) + except OSError: + pass + + +class CtxBuilder: + """Build :class:`ExecutionContext` from docauditai document data. + + Handles the glue between docauditai's document model and leaudit's + execution expectations — primarily file-path resolution and rules + selection. + """ + + def __init__( + self, + ocr_client: BaseOCRClient | None = None, + llm_client: BaseLLMClient | None = None, + vlm_client: object | None = None, + ) -> None: + self.ocr_client = ocr_client + self.llm_client = llm_client + self.vlm_client = vlm_client + + async def build( + self, + document_id: int, + file_path: str | Path | None = None, + file_content: bytes | None = None, + filename: str | None = None, + rules_file: RulesFile | None = None, + *, + source_port: int = 8000, + ) -> ExecutionContext: + """Build a ready-to-use execution context. + + At least one of *file_path* or (*file_content* + *filename*) + must be provided. + + Args: + document_id: docauditai document ID. + file_path: Existing local path to the document file. + file_content: Raw bytes (from DB or OSS) — a temp file is + created. + filename: Required when *file_content* is given. + rules_file: Pre-loaded RulesFile. When None, the caller + must resolve after OCR classification. + source_port: Instance port. + + Returns: + ExecutionContext ready for pipeline.run(). + """ + tmp_path: Path | None = None + + if file_path is not None: + resolved = Path(file_path) + elif file_content is not None and filename is not None: + suffix = self._suffix(filename) + tmp = tempfile.NamedTemporaryFile(suffix=suffix, delete=False) + tmp.write(file_content) + tmp.close() + resolved = Path(tmp.name) + tmp_path = resolved + else: + raise ValueError( + "Either file_path or (file_content + filename) is required" + ) + + return ExecutionContext( + document_id=document_id, + file_path=resolved, + rules_file=rules_file, # type: ignore[arg-type] + ocr_client=self.ocr_client, # type: ignore[arg-type] + llm_client=self.llm_client, + vlm_client=self.vlm_client, + source_port=source_port, + tmp_path=tmp_path, + ) + + @staticmethod + def _suffix(filename: str) -> str: + _, ext = os.path.splitext(filename) + return ext if ext else ".pdf" diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/ocr_bridge.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/ocr_bridge.py new file mode 100644 index 0000000..b7d49ff --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/ocr_bridge.py @@ -0,0 +1,272 @@ +"""Bridge-side OCR post-processing for leaudit integration. + +Keeps docauditai-specific fixes outside ``services/leaudit/**``: + - DOCX embedded-image visuals can be refined once more with the VLM after + the merged ``OcrResult`` is built. + - Cross-page seals with missing completeness flags are normalized so the + legacy compatibility checks have a stable shape to consume. +""" + +from __future__ import annotations + +import logging +from io import BytesIO +from pathlib import Path + +from leaudit.ocr.base import BaseOCRClient +from leaudit.ocr.models import OcrResult, VisualManifestItem + +log = logging.getLogger(__name__) + + +class BridgeOCRClient(BaseOCRClient): + """Wrap an OCR client and apply integration-side post-processing.""" + + def __init__( + self, + inner: BaseOCRClient, + *, + vlm_client: object | None = None, + vlm_concurrency: int = 6, + ) -> None: + self.inner = inner + self.vlm_client = vlm_client + self.vlm_concurrency = vlm_concurrency + + async def ocr(self, file_path: Path | str) -> OcrResult: + path = Path(file_path) + result = await self.inner.ocr(path) + await postprocess_ocr_result( + result, + file_path=path, + vlm_client=self.vlm_client, + vlm_concurrency=self.vlm_concurrency, + ) + return result + + +async def postprocess_ocr_result( + ocr_result: OcrResult, + *, + file_path: Path, + vlm_client: object | None = None, + vlm_concurrency: int = 6, +) -> OcrResult: + """Apply bridge-side visual repairs without touching leaudit core.""" + suffix = file_path.suffix.lower() + if suffix not in {".docx", ".doc", ".wps"}: + return ocr_result + + await _maybe_refine_docx_visuals( + ocr_result, + vlm_client=vlm_client, + concurrency=vlm_concurrency, + ) + await _inject_docx_signature_candidates( + ocr_result, + vlm_client=vlm_client, + ) + _normalize_cross_page_seals(ocr_result) + return ocr_result + + +async def _maybe_refine_docx_visuals( + ocr_result: OcrResult, + *, + vlm_client: object | None, + concurrency: int, +) -> None: + vm = ocr_result.visual_manifest + if vlm_client is None or vm is None: + return + if not (vm.seals or vm.signatures or vm.cross_page_seals): + return + + try: + from leaudit.ocr.visual_classifier import refine_visual_manifest + + await refine_visual_manifest( + ocr_result, + vlm_client, + concurrency=concurrency, + ) + except Exception as exc: + log.warning("bridge visual refinement skipped: %s", exc) + + +async def _inject_docx_signature_candidates( + ocr_result: OcrResult, + *, + vlm_client: object | None, +) -> None: + """Probe likely handwritten-signature zones on DOCX parent images.""" + if vlm_client is None: + return + + try: + from PIL import Image + except ImportError: + log.warning("Pillow unavailable, skip DOCX signature candidate probing") + return + + parent_to_items: dict[str, list[VisualManifestItem]] = {} + for bucket in ( + ocr_result.visual_manifest.seals or [], + ocr_result.visual_manifest.signatures or [], + ocr_result.visual_manifest.cross_page_seals or [], + ): + for item in bucket: + parent_key = getattr(item, "parent_image_key", None) + if parent_key: + parent_to_items.setdefault(parent_key, []).append(item) + + for parent_key, items in parent_to_items.items(): + if any((it.label or "") == "signature" for it in items): + continue + parent_bytes = ocr_result.get_image_bytes(parent_key) + if not parent_bytes: + continue + + try: + image = Image.open(BytesIO(parent_bytes)) + except Exception as exc: + log.warning("failed to open parent image %s: %s", parent_key, exc) + continue + + width, height = image.size + for candidate_bbox in _signature_candidate_boxes(items, width, height): + try: + crop = image.crop(tuple(candidate_bbox)) + buf = BytesIO() + crop.save(buf, format="PNG") + result = await _classify_signature_candidate( + vlm_client, + buf.getvalue(), + "这是合同签章页里疑似法人签名的候选区域,请优先判断是否为手写签名。", + ) + except Exception as exc: + log.warning("signature probe failed for %s: %s", parent_key, exc) + continue + + if getattr(result, "kind", None) != "signature": + continue + + page_num = _infer_parent_page_num(items) + ocr_result.visual_manifest.signatures.append( + VisualManifestItem( + page_num=page_num, + bbox=candidate_bbox, + label="signature", + confidence=getattr(result, "confidence", 0.9) or 0.9, + text_match=(getattr(result, "text", None) or "").strip() or None, + alt_text="docx_signature_candidate", + image_key=parent_key, + parent_image_key=parent_key, + ) + ) + break + + +async def _classify_signature_candidate( + vlm_client: object, + image_bytes: bytes, + user_hint: str, +) -> object: + """Classify with one retry using a fresh VLM client when needed.""" + try: + return await vlm_client.classify_visual(image_bytes, user_hint=user_hint) + except Exception as exc: + log.warning("signature probe primary VLM failed, retrying fresh client: %s", exc) + + try: + from leaudit.llm.qwen_vlm_client import QwenVLMClient + + fresh = QwenVLMClient( + base_url=getattr(vlm_client, "base_url"), + api_key=getattr(vlm_client, "api_key", ""), + model=getattr(vlm_client, "model"), + timeout=getattr(vlm_client, "timeout", 90.0), + ) + try: + return await fresh.classify_visual(image_bytes, user_hint=user_hint) + finally: + await fresh.close() + except Exception as exc: + raise RuntimeError(exc) from exc + + +def _signature_candidate_boxes( + items: list[VisualManifestItem], + width: int, + height: int, +) -> list[list[int]]: + candidates: list[list[int]] = [] + seen: set[tuple[int, int, int, int]] = set() + + for item in items: + seal_type = getattr(item, "seal_type", None) + label = getattr(item, "label", None) + bbox = getattr(item, "bbox", None) or [] + if len(bbox) != 4: + continue + + x1, y1, x2, y2 = bbox + box_w = max(1, x2 - x1) + box_h = max(1, y2 - y1) + ratio = box_w / box_h + + if seal_type == "法人章" or label == "法人章": + continue + if not (0.75 <= ratio <= 1.35): + continue + if box_w < width * 0.10 or box_h < height * 0.10: + continue + + cand = [ + max(0, int(x1 - box_w * 0.25)), + max(0, int(y1 + box_h * 0.50)), + min(width, int(x2 + box_w * 0.25)), + min(height, int(y2 + box_h * 0.95)), + ] + if cand[2] - cand[0] < 24 or cand[3] - cand[1] < 24: + continue + key = tuple(cand) + if key not in seen: + seen.add(key) + candidates.append(cand) + + return candidates + + +def _infer_parent_page_num(items: list[VisualManifestItem]) -> int: + for item in items: + page_num = getattr(item, "page_num", None) + if isinstance(page_num, int): + return page_num + return 0 + + +def _normalize_cross_page_seals(ocr_result: OcrResult) -> None: + """Fill obvious completeness defaults for bridge-side checks.""" + for item in ocr_result.visual_manifest.cross_page_seals or []: + if item.pages and len(item.pages) >= 2: + item.is_complete = True + continue + + bbox = item.bbox or [] + if len(bbox) == 4: + width = max(1, bbox[2] - bbox[0]) + height = max(1, bbox[3] - bbox[1]) + ratio = width / height + # DOCX embedded images often contain a complete round seal near the + # page edge; Chandra may still classify it as a seam-seal half by + # geometry. A near-square crop is a strong signal that the visible + # stamp is already complete. + if 0.65 <= ratio <= 1.35: + item.is_complete = True + continue + + if item.is_complete is not None: + continue + if item.pages and len(item.pages) == 1: + item.is_complete = False diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/pipeline.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/pipeline.py new file mode 100644 index 0000000..9c70b87 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/pipeline.py @@ -0,0 +1,268 @@ +"""Main leaudit pipeline orchestrator: OCR → Extract → Evaluate. + +Uses leaudit's own pipeline directly (no conversion), +stores results into docauditai's database via StorageAdapter. +""" + +from __future__ import annotations + +import logging +import time +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any + + +from leaudit.dsl.schema import RulesFile +from leaudit.engine.case_file_evaluator import evaluate_extraction +from leaudit.engine.models import EvaluationResult +from leaudit.extraction.bundle import ExtractionBundle +from leaudit.extraction.dispatcher import dispatch_extract +from leaudit.extraction.phase_detection import determine_phase +from leaudit.llm.base import BaseLLMClient +from leaudit.ocr.base import BaseOCRClient +from leaudit.ocr.models import OcrResult + +from leaudit_bridge.storage_adapter import StorageAdapter + +log = logging.getLogger(__name__) + + +@dataclass +class PipelineResult: + """Complete result from the leaudit pipeline.""" + + ocr_result: OcrResult + extraction_bundle: ExtractionBundle + evaluation_result: EvaluationResult + detected_phase: str + timing: dict[str, float] = field(default_factory=dict) + errors: list[str] = field(default_factory=list) + + +class LauditPipeline: + """Run leaudit's full OCR → extraction → evaluation pipeline. + + Does NOT use leaudit's own SQLAlchemy storage. + All results are written to docauditai's database via StorageAdapter. + """ + + def __init__( + self, + ocr_client: BaseOCRClient, + llm_client: BaseLLMClient | None = None, + storage_adapter: StorageAdapter | None = None, + ) -> None: + self.ocr_client = ocr_client + self.llm_client = llm_client + self.storage = storage_adapter or StorageAdapter() + + async def run( + self, + document_id: int, + file_path: str | Path, + rules_file: RulesFile | None = None, + *, + source_port: int = 8000, + ) -> PipelineResult: + """Execute the full pipeline for one document. + + Args: + document_id: docauditai document ID for DB writes. + file_path: Path to the document file (PDF/DOCX/etc). + rules_file: leaudit RulesFile (parsed from YAML). When None, + the pipeline attempts to load rules from the OCR result's + ``rules_file_path`` (set by the classifier). + source_port: Instance port for context switching. + + Returns: + PipelineResult with all intermediate and final outputs. + """ + file_path = Path(file_path) + errors: list[str] = [] + timing: dict[str, float] = {} + + # --- Phase 1: Update status to Cutting --- + await self.storage.update_document_status(document_id, "Cutting") + + # --- Phase 2: OCR --- + t0 = time.time() + log.info("[%d] OCR starting: %s", document_id, file_path.name) + ocr_result = await self._run_ocr(file_path) + timing["ocr"] = round(time.time() - t0, 2) + log.info( + "[%d] OCR done: %d pages, %.1fs", + document_id, + len(ocr_result.pages), + timing["ocr"], + ) + + # --- Resolve rules_file after OCR if not provided --- + if rules_file is None: + rules_file = await self._resolve_rules_from_ocr(ocr_result, document_id) + if rules_file is None: + raise ValueError( + f"Cannot resolve rules_file for document {document_id}. " + "Neither passed explicitly nor classified from OCR content." + ) + + # --- Save OCR result --- + await self.storage.save_ocr_result(document_id, ocr_result) + + # --- Extract & save case number (案件编号) --- + await self._extract_and_save_case_number(document_id, ocr_result) + + # --- Phase 3: Extraction --- + t0 = time.time() + await self.storage.update_document_status(document_id, "Extractioning") + log.info("[%d] Extraction starting", document_id) + + extraction_bundle = await dispatch_extract( + ocr_result, + rules_file, + llm_client=self.llm_client, + phase="executed", + ) + timing["extraction"] = round(time.time() - t0, 2) + + if extraction_bundle.all_errors: + errors.extend(extraction_bundle.all_errors) + log.warning( + "[%d] Extraction completed with %d errors", + document_id, + len(extraction_bundle.all_errors), + ) + + log.info( + "[%d] Extraction done: %d fields, %.1fs", + document_id, + len(extraction_bundle.fields), + timing["extraction"], + ) + + # --- Save extraction result --- + await self.storage.save_extraction_result(document_id, extraction_bundle) + + # --- Resolve field positions from OCR chunks --- + from leaudit.extraction.coordinate_resolver import resolve_bundle_positions + resolve_bundle_positions(extraction_bundle, ocr_result) + positioned_count = sum( + 1 for fv in extraction_bundle.fields.values() if fv.position is not None + ) + log.info( + "[%d] Coordinate resolution: %d/%d fields positioned", + document_id, + positioned_count, + len(extraction_bundle.fields), + ) + + # --- Phase 4: Phase detection --- + visual_manifest = extraction_bundle.visual_manifest or ocr_result.visual_manifest + detected_phase = await determine_phase( + extraction_bundle.fields, + llm_client=self.llm_client, + visual_manifest=visual_manifest, + ) + log.info("[%d] Detected phase: %s", document_id, detected_phase) + + # --- Phase 5: Evaluation --- + t0 = time.time() + await self.storage.update_document_status(document_id, "Evaluationing") + log.info("[%d] Evaluation starting (phase=%s)", document_id, detected_phase) + + external_mocks: dict[str, Any] = {} + if self.llm_client is not None: + external_mocks["llm_client"] = self.llm_client + external_mocks["rules_file"] = rules_file + + evaluation_result = await evaluate_extraction( + rules_file, + extraction_bundle, + visual_manifest=visual_manifest, + phase=detected_phase, + external_mocks=external_mocks, + ) + timing["evaluation"] = round(time.time() - t0, 2) + log.info( + "[%d] Evaluation done: %d passed, %d failed, %d skipped, %.1fs", + document_id, + evaluation_result.passed_count, + evaluation_result.failed_count, + evaluation_result.skipped_count, + timing["evaluation"], + ) + + # --- Save evaluation results --- + await self.storage.save_evaluation_results( + document_id, rules_file, evaluation_result, extraction_bundle, + ) + + # --- Phase 6: Finalize --- + timing["total"] = round(sum(timing.values()), 2) + await self.storage.update_document_status(document_id, "Processed") + + log.info( + "[%d] Pipeline complete: phase=%s, timing=%s", + document_id, + detected_phase, + timing, + ) + + return PipelineResult( + ocr_result=ocr_result, + extraction_bundle=extraction_bundle, + evaluation_result=evaluation_result, + detected_phase=detected_phase, + timing=timing, + errors=errors, + ) + + async def _run_ocr(self, file_path: Path) -> OcrResult: + """Run OCR with error handling.""" + try: + return await self.ocr_client.ocr(file_path) + except Exception as e: + log.error("OCR failed for %s: %s", file_path.name, e) + raise + + async def _extract_and_save_case_number( + self, document_id: int, ocr_result: OcrResult, + ) -> None: + """Extract case number from OCR and write to database.""" + from leaudit_bridge.case_number_extractor import ( + extract_case_number_with_llm, + ) + + case_number = await extract_case_number_with_llm( + ocr_result, llm_client=self.llm_client, + ) + if case_number: + await self.storage.update_document_number(document_id, case_number) + log.info("[%d] Case number: %s", document_id, case_number) + else: + log.info("[%d] No case number found", document_id) + + async def _resolve_rules_from_ocr( + self, ocr_result: OcrResult, document_id: int, + ) -> RulesFile | None: + """Load rules_file from OCR classification result.""" + from leaudit.dsl.loader import load_rules_file + + rfp = ocr_result.rules_file_path + if not rfp: + log.warning( + "[%d] No rules_file_path in OCR result, cannot resolve rules", + document_id, + ) + return None + + try: + rules_file = load_rules_file(rfp) + log.info( + "[%d] Resolved rules from classification: %s (%d rules)", + document_id, rfp, len(rules_file.flat_rules), + ) + return rules_file + except Exception as e: + log.error("[%d] Failed to load rules from %s: %s", document_id, rfp, e) + return None diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/result_adapter.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/result_adapter.py new file mode 100644 index 0000000..55f6573 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/result_adapter.py @@ -0,0 +1,303 @@ +"""Adapt leaudit raw results into docauditai's standardized format. + +Currently this logic is inlined in ``storage_adapter.py`` +(``_rule_result_to_row``, ``_bundle_to_extracted``, ``_ocr_to_dict``). +This module extracts the conversion layer so storage_adapter focuses +on persistence (the "adapter" part of result_adapter). +""" + +from __future__ import annotations + +import logging +import re +from typing import Any + +from leaudit.dsl.schema import Rule as DslRule +from leaudit.dsl.schema import RulesFile +from leaudit.engine.models import EvaluationResult, RuleResult +from leaudit.extraction.bundle import ExtractionBundle +from leaudit.extraction.models import FieldValue +from leaudit.ocr.models import OcrResult + +log = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# OCR result → dict +# --------------------------------------------------------------------------- + + +def ocr_to_dict(ocr: OcrResult) -> dict[str, Any]: + """Convert OcrResult to a JSON-safe dict for storage.""" + result: dict[str, Any] = { + "numPages": len(ocr.pages), + "full_text": ocr.full_text, + "pages": [], + } + + for page in ocr.pages: + page_dict: dict[str, Any] = { + "page_num": page.page_num, + "text": page.text, + "page_box": page.page_box, + } + if page.chunks: + page_dict["chunks"] = [ + ( + {"bbox": c["bbox"], "content": c["content"], "label": c.get("label")} + if isinstance(c, dict) and "bbox" in c and "content" in c + else { + "bbox": c.bbox if hasattr(c, "bbox") else None, + "content": c.content if hasattr(c, "content") else str(c), + "label": c.label if hasattr(c, "label") else None, + } + ) + for c in page.chunks + ] + if page.bboxes: + page_dict["bboxes"] = page.bboxes + result["pages"].append(page_dict) + + if ocr.visual_manifest: + result["visual_manifest"] = ocr.visual_manifest.model_dump(mode="json") + + if ocr.images: + result["images"] = ocr.images + + return result + + +# --------------------------------------------------------------------------- +# ExtractionBundle → dict +# --------------------------------------------------------------------------- + + +def bundle_to_extracted(bundle: ExtractionBundle) -> dict[str, Any]: + """Convert ExtractionBundle to docauditai's extracted_results format.""" + fields: dict[str, Any] = {} + for name, fv in bundle.fields.items(): + if isinstance(fv, FieldValue): + field_data = { + "value": fv.value, + "confidence": float(fv.confidence) if fv.confidence else 0.0, + } + if fv.position is not None: + field_data["position"] = fv.position.model_dump(mode="json") + fields[name] = field_data + else: + fields[name] = {"value": fv} + + multi_entity: dict[str, Any] = {} + for name, rows in bundle.multi_entity.items(): + multi_entity[name] = [ + { + k: (v.value if isinstance(v, FieldValue) else v) + for k, v in row.items() + } + if isinstance(row, dict) + else {"value": row} + for row in rows + ] + + return { + "fields": fields, + "multi_entity": multi_entity, + "derived": dict(bundle.derived) if bundle.derived else {}, + "is_case_file": bundle.is_case_file, + } + + +# --------------------------------------------------------------------------- +# EvaluationResult → per-rule rows +# --------------------------------------------------------------------------- + + +def rule_result_to_row( + document_id: int, + run_id: int, + rule_result: RuleResult, + rule: Any | None, + bundle: ExtractionBundle, +) -> dict[str, Any]: + """Convert one RuleResult to a database row dict. + + Args: + document_id: docauditai document ID. + run_id: ``leaudit_audit_runs.id`` for this execution. + rule_result: Single rule evaluation result from leaudit. + rule: DSL Rule definition (for metadata lookups). + bundle: The extraction bundle (for field position lookups). + """ + passed = rule_result.passed + + pass_msg = "" + fail_msg = "" + if rule_result.messages: + pass_msg = rule_result.messages.get("pass", "") + fail_msg = rule_result.messages.get("fail", "") + elif isinstance(rule, DslRule) and rule.messages: + pass_msg = rule.messages.get("pass", "") + fail_msg = rule.messages.get("fail", "") + + relevant_fields = _extract_relevant_fields(rule, bundle) + field_positions = _extract_relevant_field_positions(rule, bundle) + + remediation = None + if rule_result.remediation: + remediation = rule_result.remediation.model_dump(mode="json") + + rule_meta: dict[str, Any] = {} + if isinstance(rule, DslRule): + if rule.references_laws: + rule_meta["references_laws"] = rule.references_laws + if rule.desc: + rule_meta["desc"] = rule.desc + if rule.group: + rule_meta["group"] = rule.group + + return { + "document_id": document_id, + "run_id": run_id, + "rule_id": rule_result.rule_id, + "rule_name": rule_result.name, + "risk": rule_result.risk or "medium", + "score": rule_result.score, + "passed": passed, + "status": rule_result.status, + "skip_reason": rule_result.skip_reason, + "confidence": rule_result.confidence, + "pass_message": pass_msg, + "fail_message": fail_msg, + "stages": [s.model_dump(mode="json") for s in (rule_result.stages or [])], + "extracted_fields": relevant_fields, + "field_positions": field_positions, + "remediation": remediation, + "rule_meta": rule_meta, + "rescue_applied": False, + "rescue_passed": None, + } + + +def evaluation_summary(eval_result: EvaluationResult) -> dict[str, Any]: + """Extract summary fields from an EvaluationResult.""" + return { + "total_score": eval_result.total_score, + "passed_count": eval_result.passed_count, + "failed_count": eval_result.failed_count, + "skipped_count": eval_result.skipped_count, + "result_status": _result_status(eval_result), + } + + +def _result_status(eval_result: EvaluationResult) -> str: + if eval_result.errors: + return "error" + if eval_result.failed_count == 0 and eval_result.skipped_count == 0: + return "pass" + if eval_result.failed_count > 0: + return "fail" + return "partial" + + +# --------------------------------------------------------------------------- +# Internal helpers +# --------------------------------------------------------------------------- + + +def _extract_relevant_fields( + rule: Any, bundle: ExtractionBundle, +) -> dict[str, Any]: + """Extract field values referenced by a rule's stages.""" + relevant: dict[str, Any] = {} + if not rule or not hasattr(rule, "stages") or not rule.stages: + return relevant + + for stage in rule.stages: + stage_data = ( + stage.model_dump(exclude_none=True) + if hasattr(stage, "model_dump") + else {} + ) + extra = stage.extra if hasattr(stage, "extra") else {} + field_names: list[str] = [] + + for key in ("field", "field1", "field2", "fields"): + val = getattr(stage, key, None) or extra.get(key) or stage_data.get(key) + if isinstance(val, list): + field_names.extend(f for f in val if isinstance(f, str)) + elif isinstance(val, str): + field_names.append(val) + + pairs = stage_data.get("pairs") + if isinstance(pairs, list): + for pair in pairs: + if not isinstance(pair, dict): + continue + for key in ("source", "target", "a", "b"): + ref = pair.get(key) + if isinstance(ref, str): + field_names.append(ref) + + prompt = stage_data.get("prompt") + if isinstance(prompt, str): + for m in re.finditer(r"\{\{\s*([^{}]+?)\s*\}\}", prompt): + field_names.append(m.group(1).strip()) + + for f in field_names: + if f in relevant: + continue + if f not in bundle.fields: + continue + fv = bundle.fields[f] + relevant[f] = fv.value if isinstance(fv, FieldValue) else fv + + return relevant + + +def _extract_relevant_field_positions( + rule: Any, bundle: ExtractionBundle, +) -> dict[str, Any]: + """Extract position data for fields referenced by a rule's stages.""" + positions: dict[str, Any] = {} + if not rule or not hasattr(rule, "stages") or not rule.stages: + return positions + + for stage in rule.stages: + stage_data = ( + stage.model_dump(exclude_none=True) + if hasattr(stage, "model_dump") + else {} + ) + extra = stage.extra if hasattr(stage, "extra") else {} + field_names: list[str] = [] + + for key in ("field", "field1", "field2", "fields"): + val = getattr(stage, key, None) or extra.get(key) or stage_data.get(key) + if isinstance(val, list): + field_names.extend(f for f in val if isinstance(f, str)) + elif isinstance(val, str): + field_names.append(val) + + pairs = stage_data.get("pairs") + if isinstance(pairs, list): + for pair in pairs: + if not isinstance(pair, dict): + continue + for key in ("source", "target", "a", "b"): + ref = pair.get(key) + if isinstance(ref, str): + field_names.append(ref) + + prompt = stage_data.get("prompt") + if isinstance(prompt, str): + for m in re.finditer(r"\{\{\s*([^{}]+?)\s*\}\}", prompt): + field_names.append(m.group(1).strip()) + + for f in field_names: + if f in positions: + continue + fv = bundle.fields.get(f) + if fv is not None and isinstance(fv, FieldValue) and fv.position is not None: + positions[f] = fv.position.model_dump(mode="json") + + return positions diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/rules_loader.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/rules_loader.py new file mode 100644 index 0000000..2f483a1 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/rules_loader.py @@ -0,0 +1,55 @@ +"""Load leaudit YAML RulesFile from filesystem or MinIO.""" + +from __future__ import annotations + +import logging +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from leaudit.dsl.schema import RulesFile + +log = logging.getLogger(__name__) + +_DEFAULT_RULES_DIR = Path(__file__).resolve().parents[2] / "rules" + + +class RulesLoader: + """Load and cache leaudit RulesFile from YAML files.""" + + def __init__(self, rules_dir: str | Path | None = None) -> None: + self._rules_dir = Path(rules_dir) if rules_dir else _DEFAULT_RULES_DIR + self._cache: dict[str, RulesFile] = {} + + def load(self, rules_path: str) -> RulesFile: + """Load a RulesFile by relative path under rules_dir, or absolute path.""" + from leaudit.dsl.loader import load_rules_file + + if rules_path in self._cache: + return self._cache[rules_path] + + p = Path(rules_path) + if not p.is_absolute(): + p = self._rules_dir / p + + log.info("Loading RulesFile: %s", p) + rules_file = load_rules_file(p) + self._cache[rules_path] = rules_file + return rules_file + + def load_from_yaml_text(self, yaml_text: str, cache_key: str | None = None) -> RulesFile: + """Parse a RulesFile from raw YAML string.""" + from leaudit.dsl.loader import parse_rules_yaml_text + + if cache_key and cache_key in self._cache: + return self._cache[cache_key] + + rules_file = parse_rules_yaml_text(yaml_text) + + if cache_key: + self._cache[cache_key] = rules_file + + return rules_file + + def clear_cache(self) -> None: + self._cache.clear() diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/storage_adapter.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/storage_adapter.py new file mode 100644 index 0000000..391d29d --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/storage_adapter.py @@ -0,0 +1,364 @@ +"""Storage adapter — write leaudit results into docauditai's PostgreSQL via PostgREST. + +Converts leaudit's OcrResult, ExtractionBundle, EvaluationResult +into docauditai's table format and writes via PostgRESTClient. + +Uses the new `leaudit_evaluation_results` table for per-rule results. +""" + +from __future__ import annotations + +import logging +import re +from typing import Any + +from leaudit.dsl.schema import RulesFile +from leaudit.engine.models import EvaluationResult, RuleResult +from leaudit.extraction.bundle import ExtractionBundle +from leaudit.extraction.models import FieldValue +from leaudit.ocr.models import OcrResult + +log = logging.getLogger(__name__) + + +def _get_postgrest_client(): + """Lazy import to avoid circular dependency at module load.""" + from core.postgrest.client import get_postgrest_client + return get_postgrest_client() + + +class StorageAdapter: + """Write leaudit pipeline results to docauditai's database.""" + + # ---- Document status ---- + + async def update_document_status(self, document_id: int, status: str) -> None: + """Update the document's processing status.""" + client = _get_postgrest_client() + await client.update( + table="documents", + filters={"id": f"eq.{document_id}"}, + data={"status": status}, + ) + log.debug("[%d] Status updated: %s", document_id, status) + + # ---- Document number (案件编号) ---- + + async def update_document_number(self, document_id: int, document_number: str) -> None: + """Update the document's case number (document_number field).""" + client = _get_postgrest_client() + await client.update( + table="documents", + filters={"id": f"eq.{document_id}"}, + data={"document_number": document_number}, + ) + log.info("[%d] document_number updated: %s", document_id, document_number) + + # ---- OCR result ---- + + async def save_ocr_result(self, document_id: int, ocr_result: OcrResult) -> None: + """Save OCR result to documents.ocr_result and raw_full_text_original.""" + client = _get_postgrest_client() + + ocr_dict = _ocr_to_dict(ocr_result) + full_text = ocr_result.full_text or "\n".join(p.text for p in ocr_result.pages) + + await client.update( + table="documents", + filters={"id": f"eq.{document_id}"}, + data={ + "ocr_result": ocr_dict, + "raw_full_text_original": full_text, + }, + ) + log.info("[%d] OCR result saved (%d pages)", document_id, len(ocr_result.pages)) + + # ---- Extraction result ---- + + async def save_extraction_result( + self, document_id: int, bundle: ExtractionBundle, + ) -> None: + """Save extraction result to documents.extracted_results.""" + client = _get_postgrest_client() + + extracted = _bundle_to_extracted(bundle) + + await client.update( + table="documents", + filters={"id": f"eq.{document_id}"}, + data={"extracted_results": extracted}, + ) + log.info( + "[%d] Extraction result saved (%d fields)", + document_id, + len(bundle.fields), + ) + + # ---- Evaluation results ---- + + async def save_evaluation_results( + self, + document_id: int, + rules_file: RulesFile, + evaluation: EvaluationResult, + bundle: ExtractionBundle, + ) -> None: + """Save evaluation results to leaudit_evaluation_results table. + + One row per rule. Deletes existing results for the document first, + then inserts fresh rows. + """ + client = _get_postgrest_client() + + # Delete existing results for this document + await client.delete( + table="leaudit_evaluation_results", + filters={"document_id": f"eq.{document_id}"}, + ) + + # Build rule_id → rule metadata lookup + rule_meta = {} + for rule in rules_file.flat_rules: + rule_meta[rule.rule_id] = rule + + # Insert one row per rule result + for rule_result in evaluation.rules: + rule = rule_meta.get(rule_result.rule_id) + row = _rule_result_to_row(document_id, rule_result, rule, bundle) + await client.insert(table="leaudit_evaluation_results", data=row) + + log.info( + "[%d] Evaluation results saved: %d passed, %d failed, %d skipped", + document_id, + evaluation.passed_count, + evaluation.failed_count, + evaluation.skipped_count, + ) + + +# ---- Serialization helpers ---- + + +def _ocr_to_dict(ocr: OcrResult) -> dict[str, Any]: + """Convert OcrResult to a JSON-safe dict for PostgREST storage.""" + result: dict[str, Any] = { + "numPages": len(ocr.pages), + "full_text": ocr.full_text, + "pages": [], + } + + for page in ocr.pages: + page_dict: dict[str, Any] = { + "page_num": page.page_num, + "text": page.text, + "page_box": page.page_box, + } + if page.chunks: + page_dict["chunks"] = [ + ( + {"bbox": c["bbox"], "content": c["content"], "label": c.get("label")} + if isinstance(c, dict) and "bbox" in c and "content" in c + else { + "bbox": c.bbox if hasattr(c, "bbox") else None, + "content": c.content if hasattr(c, "content") else str(c), + "label": c.label if hasattr(c, "label") else None, + } + ) + for c in page.chunks + ] + if page.bboxes: + page_dict["bboxes"] = page.bboxes + result["pages"].append(page_dict) + + if ocr.visual_manifest: + result["visual_manifest"] = ocr.visual_manifest.model_dump(mode="json") + + if ocr.images: + result["images"] = ocr.images + + return result + + +def _bundle_to_extracted(bundle: ExtractionBundle) -> dict[str, Any]: + """Convert ExtractionBundle to docauditai's extracted_results format.""" + fields: dict[str, Any] = {} + for name, fv in bundle.fields.items(): + if isinstance(fv, FieldValue): + field_data = { + "value": fv.value, + "confidence": float(fv.confidence) if fv.confidence else 0.0, + } + if fv.position is not None: + field_data["position"] = fv.position.model_dump(mode="json") + fields[name] = field_data + else: + fields[name] = {"value": fv} + + multi_entity: dict[str, Any] = {} + for name, rows in bundle.multi_entity.items(): + multi_entity[name] = [ + { + k: (v.value if isinstance(v, FieldValue) else v) + for k, v in row.items() + } + if isinstance(row, dict) else {"value": row} + for row in rows + ] + + return { + "fields": fields, + "multi_entity": multi_entity, + "derived": dict(bundle.derived) if bundle.derived else {}, + "is_case_file": bundle.is_case_file, + } + + +def _extract_relevant_fields(rule: Any, bundle: ExtractionBundle) -> dict[str, Any]: + """Extract field values referenced by a rule's stages.""" + relevant: dict[str, Any] = {} + + if not rule or not hasattr(rule, "stages") or not rule.stages: + return relevant + + for stage in rule.stages: + stage_data = stage.model_dump(exclude_none=True) if hasattr(stage, "model_dump") else {} + extra = stage.extra if hasattr(stage, "extra") else {} + field_names: list[str] = [] + + for key in ("field", "field1", "field2", "fields"): + val = getattr(stage, key, None) or extra.get(key) or stage_data.get(key) + if isinstance(val, list): + field_names.extend(f for f in val if isinstance(f, str)) + elif isinstance(val, str): + field_names.append(val) + + pairs = stage_data.get("pairs") + if isinstance(pairs, list): + for pair in pairs: + if not isinstance(pair, dict): + continue + for key in ("source", "target", "a", "b"): + ref = pair.get(key) + if isinstance(ref, str): + field_names.append(ref) + + prompt = stage_data.get("prompt") + if isinstance(prompt, str): + for m in re.finditer(r"\{\{\s*([^{}]+?)\s*\}\}", prompt): + field_names.append(m.group(1).strip()) + + for f in field_names: + if f in relevant: + continue + if f not in bundle.fields: + continue + fv = bundle.fields[f] + relevant[f] = fv.value if isinstance(fv, FieldValue) else fv + + return relevant + + +def _extract_relevant_field_positions( + rule: Any, + bundle: ExtractionBundle, +) -> dict[str, Any]: + """Extract position data for fields referenced by a rule's stages.""" + positions: dict[str, Any] = {} + if not rule or not hasattr(rule, "stages") or not rule.stages: + return positions + + for stage in rule.stages: + stage_data = stage.model_dump(exclude_none=True) if hasattr(stage, "model_dump") else {} + extra = stage.extra if hasattr(stage, "extra") else {} + field_names: list[str] = [] + + for key in ("field", "field1", "field2", "fields"): + val = getattr(stage, key, None) or extra.get(key) or stage_data.get(key) + if isinstance(val, list): + field_names.extend(f for f in val if isinstance(f, str)) + elif isinstance(val, str): + field_names.append(val) + + pairs = stage_data.get("pairs") + if isinstance(pairs, list): + for pair in pairs: + if not isinstance(pair, dict): + continue + for key in ("source", "target", "a", "b"): + ref = pair.get(key) + if isinstance(ref, str): + field_names.append(ref) + + prompt = stage_data.get("prompt") + if isinstance(prompt, str): + for m in re.finditer(r"\{\{\s*([^{}]+?)\s*\}\}", prompt): + field_names.append(m.group(1).strip()) + + for f in field_names: + if f in positions: + continue + fv = bundle.fields.get(f) + if fv is not None and isinstance(fv, FieldValue) and fv.position is not None: + positions[f] = fv.position.model_dump(mode="json") + return positions + + +def _rule_result_to_row( + document_id: int, + rule_result: RuleResult, + rule: Any | None, + bundle: ExtractionBundle, +) -> dict[str, Any]: + """Convert a RuleResult to a leaudit_evaluation_results row.""" + passed = rule_result.passed + + # Resolve messages: rule_result → rule definition + pass_msg = "" + fail_msg = "" + if rule_result.messages: + pass_msg = rule_result.messages.get("pass", "") + fail_msg = rule_result.messages.get("fail", "") + elif rule: + from leaudit.dsl.schema import Rule as DslRule + if isinstance(rule, DslRule) and rule.messages: + pass_msg = rule.messages.get("pass", "") + fail_msg = rule.messages.get("fail", "") + + # Extract relevant fields + relevant_fields = _extract_relevant_fields(rule, bundle) + + # Remediation (if present) + remediation = None + if rule_result.remediation: + remediation = rule_result.remediation.model_dump(mode="json") + + # Rule metadata (references_laws, etc.) + rule_meta_data: dict[str, Any] = {} + if rule: + from leaudit.dsl.schema import Rule as DslRule + if isinstance(rule, DslRule): + if rule.references_laws: + rule_meta_data["references_laws"] = rule.references_laws + if rule.desc: + rule_meta_data["desc"] = rule.desc + if rule.group: + rule_meta_data["group"] = rule.group + + return { + "document_id": document_id, + "rule_id": rule_result.rule_id, + "rule_name": rule_result.name, + "risk": rule_result.risk or "medium", + "score": rule_result.score, + "passed": passed, + "status": rule_result.status, + "skip_reason": rule_result.skip_reason, + "confidence": rule_result.confidence, + "pass_message": pass_msg, + "fail_message": fail_msg, + "stages": [s.model_dump(mode="json") for s in (rule_result.stages or [])], + "extracted_fields": relevant_fields, + "field_positions": _extract_relevant_field_positions(rule, bundle), + "remediation": remediation, + "rule_meta": rule_meta_data, + } diff --git a/fastapi_modules/fastapi_leaudit/leaudit_bridge/tasks.py b/fastapi_modules/fastapi_leaudit/leaudit_bridge/tasks.py new file mode 100644 index 0000000..c5ec0b1 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/leaudit_bridge/tasks.py @@ -0,0 +1,201 @@ +"""Celery task for leaudit pipeline processing. + +Activated when PIPELINE_MODE=leaudit in env.{port} config. +Replaces the legacy OCR → extraction → evaluation pipeline with +leaudit's YAML-rules-driven approach. +""" + +from __future__ import annotations + +import asyncio +import os +import tempfile +import time +from typing import Any, Dict, Optional + +from core.celery_app_limited import celery_app +from core.postgrest.client import get_postgrest_client +from core.logger import log + +from leaudit_bridge import create_pipeline, RulesLoader + + +@celery_app.task(bind=True, name="leaudit.process_document") +def leaudit_process_document( + self, + document_id: int, + file_content: bytes, + filename: str, + upload_info: Optional[Dict[str, Any]] = None, + source_port: Optional[int] = None, + rules_path: Optional[str] = None, +): + """Process a document using leaudit's full pipeline. + + Steps: OCR → Extraction → Evaluation → Store in docauditai DB. + """ + task_id = self.request.id + log.task.info(f"[任务ID: {task_id}] leaudit管线开始处理: {filename}") + + if source_port: + from core.utils.instance_context import set_instance_environment + instance_name = set_instance_environment(source_port) + log.task.info( + f"[任务ID: {task_id}] 实例环境: {instance_name} (端口: {source_port})" + ) + + if upload_info is None: + upload_info = {} + + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + try: + rules_path_resolved = rules_path or _resolve_rules_path(document_id, loop) + + # For types with a known mapping (e.g. 行政处罚), pre-load rules_file. + # For types that need content classification (e.g. 行政许可 sub-types), + # rules_path will be None → adapter classifies after OCR → pipeline + # loads rules from ocr_result.rules_file_path. + rules_file = None + if rules_path_resolved: + loader = RulesLoader() + rules_file = loader.load(rules_path_resolved) + log.task.info( + f"[任务ID: {task_id}] RulesFile pre-loaded: {rules_path_resolved} " + f"({len(rules_file.flat_rules)} rules, {len(rules_file.flat_extract)} fields)" + ) + else: + log.task.info( + f"[任务ID: {task_id}] No fixed rules_path — " + "will classify from document content after OCR" + ) + + suffix = _get_suffix(filename) + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as temp: + temp.write(file_content) + temp_path = temp.name + + pipeline = create_pipeline(rules_path=rules_path_resolved) + + t0 = time.time() + result = loop.run_until_complete( + pipeline.run( + document_id=document_id, + file_path=temp_path, + rules_file=rules_file, + source_port=source_port or int(os.getenv("APP_PORT", "8000")), + ) + ) + elapsed = round(time.time() - t0, 2) + + try: + os.remove(temp_path) + except OSError: + pass + + log.task.info( + f"[任务ID: {task_id}] leaudit管线完成: phase={result.detected_phase}, " + f"timing={result.timing}, 总耗时={elapsed:.1f}s" + ) + + return { + "status": "success", + "document_id": document_id, + "phase": result.detected_phase, + "timing": result.timing, + "errors": result.errors, + } + + except Exception as e: + log.task.error(f"[任务ID: {task_id}] leaudit管线失败: {e}", exc_info=True) + try: + loop.run_until_complete(_update_status_safe(document_id, "Failed")) + except Exception: + pass + raise + + finally: + loop.close() + + +# type_id → rules directory mapping (only fixed-mapping types) +# 行政许可 (type_id=2) has 9 sub-types, NOT mapped here — +# must come from document metadata (rules_file_path) or content classification. +_TYPE_ID_RULES_MAP: dict[int, str] = { + 3: "行政处罚", +} + + +def _resolve_rules_path(document_id: int, loop: asyncio.AbstractEventLoop) -> str | None: + """Resolve rules_path: config override → document metadata → type_id mapping.""" + from core.config import LEAUDIT_CONFIG + + # 1. Config override (when explicitly set) + config_path = LEAUDIT_CONFIG.get("RULES_PATH", "") + if config_path: + return config_path + + try: + client = get_postgrest_client() + doc = loop.run_until_complete( + client.select( + table="documents", + filters={"id": f"eq.{document_id}"}, + single=True, + ) + ) + if not doc: + return None + + # 2. Document-level override + rfp = doc.get("rules_file_path") + if rfp: + return rfp + + # 3. type_id mapping + type_id = doc.get("type_id") + if type_id and type_id in _TYPE_ID_RULES_MAP: + return f"{_TYPE_ID_RULES_MAP[type_id]}/rules.yaml" + except Exception as e: + log.task.warning(f"Failed to resolve rules_path from document: {e}") + + return None + + +async def _update_status_safe(document_id: int, status: str) -> None: + """Safely update document status, ignoring errors.""" + try: + client = get_postgrest_client() + await client.update( + table="documents", + filters={"id": f"eq.{document_id}"}, + data={"status": status}, + ) + except Exception: + pass + + +def _get_suffix(filename: str) -> str: + """Extract file suffix from filename.""" + _, ext = os.path.splitext(filename) + return ext if ext else ".pdf" + + +def dispatch_leaudit_task( + document_id: int, + file_content: bytes, + filename: str, + upload_info: Optional[Dict[str, Any]] = None, + source_port: Optional[int] = None, + rules_path: Optional[str] = None, +): + """Dispatch a leaudit processing task.""" + return leaudit_process_document.apply_async( + args=[document_id, file_content, filename], + kwargs={ + "upload_info": upload_info, + "source_port": source_port or int(os.getenv("APP_PORT", "8000")), + "rules_path": rules_path, + }, + ) diff --git a/fastapi_modules/fastapi_leaudit/models/__init__.py b/fastapi_modules/fastapi_leaudit/models/__init__.py new file mode 100644 index 0000000..2f955d6 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/models/__init__.py @@ -0,0 +1,11 @@ +"""LeAudit 模型导出。""" + +from fastapi_modules.fastapi_leaudit.models.leauditDocument import LeauditDocument +from fastapi_modules.fastapi_leaudit.models.leauditDocumentFile import LeauditDocumentFile +from fastapi_modules.fastapi_leaudit.models.leauditAuditRun import LeauditAuditRun + +__all__ = [ + "LeauditDocument", + "LeauditDocumentFile", + "LeauditAuditRun", +] diff --git a/fastapi_modules/fastapi_leaudit/models/jwtToken.py b/fastapi_modules/fastapi_leaudit/models/jwtToken.py new file mode 100644 index 0000000..f8e6360 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/models/jwtToken.py @@ -0,0 +1,77 @@ +"""JWT Token 模型 —— jwt_tokens 表。 + +记录每次签发的 Token 生命周期:签发、刷新、撤销。 +""" + +from __future__ import annotations + +from datetime import datetime + +from sqlalchemy import BigInteger, Boolean, DateTime, String, select, update +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm import Mapped, mapped_column + +from fastapi_common.fastapi_common_web.models import BaseModel + + +class JwtToken(BaseModel): + """JWT Token 记录表。""" + + __tablename__ = "jwt_tokens" + + Id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) + userId: Mapped[int] = mapped_column(BigInteger, comment="用户ID") + tokenJti: Mapped[str] = mapped_column(String(128), comment="Token JTI") + tokenHash: Mapped[str] = mapped_column(String(128), comment="Access Token SHA256") + refreshTokenHash: Mapped[str | None] = mapped_column(String(128), comment="Refresh Token SHA256") + tokenType: Mapped[str] = mapped_column(String(32), default="ACCESS", comment="ACCESS/REFRESH") + deviceId: Mapped[str | None] = mapped_column(String(128)) + deviceName: Mapped[str | None] = mapped_column(String(256)) + userAgent: Mapped[str | None] = mapped_column(String(512)) + ipAddress: Mapped[str | None] = mapped_column(String(64)) + issuedAt: Mapped[datetime] = mapped_column(DateTime(timezone=True)) + expiresAt: Mapped[datetime] = mapped_column(DateTime(timezone=True)) + refreshExpiresAt: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) + lastUsedAt: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) + isRevoked: Mapped[bool] = mapped_column(Boolean, default=False) + revokedAt: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) + revokeReason: Mapped[str | None] = mapped_column(String(256)) + + @classmethod + async def get_by_jti(cls, session: AsyncSession, jti: str) -> "JwtToken | None": + """按 JTI 查询 Token 记录。""" + return await session.scalar(select(cls).where(cls.tokenJti == jti)) + + @classmethod + async def revoke_by_jti(cls, session: AsyncSession, jti: str, reason: str = "") -> None: + """撤销指定 JTI 的 Token。""" + await session.execute( + update(cls) + .where(cls.tokenJti == jti) + .values(isRevoked=True, revokedAt=datetime.now(), revokeReason=reason) + ) + + @classmethod + async def revoke_all_user_tokens(cls, session: AsyncSession, userId: int, reason: str = "") -> list[str]: + """撤销用户的所有活跃 Token,返回被撤销的 JTI 列表。""" + result = await session.execute( + select(cls.tokenJti).where(cls.userId == userId, cls.isRevoked == False) + ) + jtis = [row[0] for row in result.fetchall()] + await session.execute( + update(cls) + .where(cls.userId == userId, cls.isRevoked == False) + .values(isRevoked=True, revokedAt=datetime.now(), revokeReason=reason) + ) + return jtis + + @classmethod + async def cleanup_expired(cls, session: AsyncSession, before: datetime) -> int: + """清理过期的 Token 记录,返回删除数。""" + result = await session.execute( + select(cls).where(cls.expiresAt < before) + ) + rows = result.scalars().all() + for row in rows: + await session.delete(row) + return len(rows) diff --git a/fastapi_modules/fastapi_leaudit/models/leauditAuditRun.py b/fastapi_modules/fastapi_leaudit/models/leauditAuditRun.py new file mode 100644 index 0000000..1b0544d --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/models/leauditAuditRun.py @@ -0,0 +1,60 @@ +"""LeAudit AuditRun 模型 —— leaudit_audit_runs 表。""" + +from __future__ import annotations + +from datetime import datetime + +from sqlalchemy import BigInteger, Boolean, DateTime, Integer, Numeric, String +from sqlalchemy.orm import Mapped, mapped_column + +from fastapi_common.fastapi_common_web.models import BaseModel + + +class LeauditAuditRun(BaseModel): + """评查运行主表。""" + + __tablename__ = "leaudit_audit_runs" + + Id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) + documentId: Mapped[int] = mapped_column(BigInteger, comment="关联 leaudit_documents.id") + documentFileId: Mapped[int | None] = mapped_column(BigInteger, comment="输入文件ID") + runNo: Mapped[int] = mapped_column(Integer, comment="同一文档第几次执行") + triggerSource: Mapped[str] = mapped_column(String(64), comment="upload/manual/retry/migration/batch") + triggerUserId: Mapped[int | None] = mapped_column(BigInteger, comment="触发人") + taskId: Mapped[str | None] = mapped_column(String(128), comment="Celery 任务 ID") + + # 状态 + status: Mapped[str] = mapped_column(String(64), default="pending", comment="pending/processing/completed/failed/cancelled") + phase: Mapped[str | None] = mapped_column(String(32), comment="draft/executed") + + # 规则溯源 + ruleSetId: Mapped[int] = mapped_column(BigInteger, comment="关联 leaudit_rule_sets.id") + ruleVersionId: Mapped[int] = mapped_column(BigInteger, comment="关联 leaudit_rule_versions.id") + ruleTypeId: Mapped[str | None] = mapped_column(String(256), comment="LeAudit metadata.type_id") + ruleSourceOssUrl: Mapped[str | None] = mapped_column(String(2048), comment="规则 YAML OSS 地址") + ruleSourceSha256: Mapped[str | None] = mapped_column(String(64), comment="规则文件 SHA256") + ruleLocalCachePath: Mapped[str | None] = mapped_column(String(1024), comment="本地缓存路径") + + # 模型快照 + engineVersion: Mapped[str | None] = mapped_column(String(64)) + llmProvider: Mapped[str | None] = mapped_column(String(64)) + llmModel: Mapped[str | None] = mapped_column(String(128)) + vlmProvider: Mapped[str | None] = mapped_column(String(64)) + vlmModel: Mapped[str | None] = mapped_column(String(128)) + ocrProvider: Mapped[str | None] = mapped_column(String(64)) + ocrModel: Mapped[str | None] = mapped_column(String(128)) + + # Rescue + rescueMode: Mapped[str | None] = mapped_column(String(32), comment="off/tier1/auto") + rescueApplied: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否执行 rescue") + + # 结果汇总 + totalScore: Mapped[float | None] = mapped_column(Numeric(10, 2)) + passedCount: Mapped[int | None] = mapped_column(Integer) + failedCount: Mapped[int | None] = mapped_column(Integer) + skippedCount: Mapped[int | None] = mapped_column(Integer) + resultStatus: Mapped[str | None] = mapped_column(String(32), comment="pass/fail/partial/error") + + # 时间 + startedAt: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) + finishedAt: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) diff --git a/fastapi_modules/fastapi_leaudit/models/leauditDocument.py b/fastapi_modules/fastapi_leaudit/models/leauditDocument.py new file mode 100644 index 0000000..61fb8ed --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/models/leauditDocument.py @@ -0,0 +1,44 @@ +"""LeAudit 域文档镜像模型 —— leaudit_documents 表。 + +通过 biz_document_id 关联业务 documents 表,不复制业务字段。 +""" + +from __future__ import annotations + +from sqlalchemy import BigInteger, String, ForeignKey +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm import Mapped, mapped_column + +from fastapi_common.fastapi_common_web.models import BaseModel + + +class LeauditDocument(BaseModel): + """LeAudit 文档镜像表。""" + + __tablename__ = "leaudit_documents" + + Id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) + bizDocumentId: Mapped[int] = mapped_column(BigInteger, unique=True, comment="关联业务 documents.id") + typeId: Mapped[int | None] = mapped_column(BigInteger, comment="文档类型ID") + processingStatus: Mapped[str | None] = mapped_column(String(64), default="waiting", comment="waiting/processing/completed/failed") + currentRunId: Mapped[int | None] = mapped_column(BigInteger, comment="最新有效 run id") + + @classmethod + async def get_by_biz_id(cls, session: AsyncSession, bizDocumentId: int) -> "LeauditDocument | None": + """按业务文档 ID 查询。""" + from sqlalchemy import select + return await session.scalar(select(cls).where(cls.bizDocumentId == bizDocumentId)) + + @classmethod + async def upsert_by_biz_id(cls, session: AsyncSession, bizDocumentId: int, **fields) -> "LeauditDocument": + """按业务文档 ID 创建或更新。""" + from sqlalchemy import select + doc = await session.scalar(select(cls).where(cls.bizDocumentId == bizDocumentId)) + if doc is None: + doc = cls(bizDocumentId=bizDocumentId, **fields) + session.add(doc) + else: + for k, v in fields.items(): + setattr(doc, k, v) + await session.flush() + return doc diff --git a/fastapi_modules/fastapi_leaudit/models/leauditDocumentFile.py b/fastapi_modules/fastapi_leaudit/models/leauditDocumentFile.py new file mode 100644 index 0000000..4800cde --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/models/leauditDocumentFile.py @@ -0,0 +1,28 @@ +"""LeAudit 文档文件模型 —— leaudit_document_files 表。""" + +from __future__ import annotations + +from sqlalchemy import BigInteger, Boolean, String +from sqlalchemy.orm import Mapped, mapped_column + +from fastapi_common.fastapi_common_web.models import BaseModel + + +class LeauditDocumentFile(BaseModel): + """文档文件表。""" + + __tablename__ = "leaudit_document_files" + + Id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) + documentId: Mapped[int] = mapped_column(BigInteger, comment="关联 leaudit_documents.id") + fileRole: Mapped[str] = mapped_column(String(64), comment="original/converted_pdf/merged_pdf/temp_input") + fileName: Mapped[str] = mapped_column(String(512), comment="文件名") + fileExt: Mapped[str | None] = mapped_column(String(32), comment="扩展名") + mimeType: Mapped[str | None] = mapped_column(String(128), comment="MIME") + fileSize: Mapped[int | None] = mapped_column(BigInteger, comment="文件大小") + sha256: Mapped[str | None] = mapped_column(String(64), comment="SHA256") + localPath: Mapped[str | None] = mapped_column(String(1024), comment="本地路径") + ossUrl: Mapped[str | None] = mapped_column(String(2048), comment="OSS 地址") + storageProvider: Mapped[str | None] = mapped_column(String(32), comment="oss/minio/local") + isActive: Mapped[bool] = mapped_column(Boolean, default=True, comment="当前生效文件") + createdBy: Mapped[int | None] = mapped_column(BigInteger, comment="上传人") diff --git a/fastapi_modules/fastapi_leaudit/services/__init__.py b/fastapi_modules/fastapi_leaudit/services/__init__.py new file mode 100644 index 0000000..c22eb13 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/__init__.py @@ -0,0 +1,8 @@ +"""LeAudit 服务层导出。""" + +from fastapi_modules.fastapi_leaudit.services.auditService import IAuditService +from fastapi_modules.fastapi_leaudit.services.authService import IAuthService +from fastapi_modules.fastapi_leaudit.services.permissionService import IPermissionService +from fastapi_modules.fastapi_leaudit.services.ruleService import IRuleService + +__all__ = ["IAuditService", "IAuthService", "IPermissionService", "IRuleService"] diff --git a/fastapi_modules/fastapi_leaudit/services/auditService.py b/fastapi_modules/fastapi_leaudit/services/auditService.py new file mode 100644 index 0000000..c21229c --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/auditService.py @@ -0,0 +1,24 @@ +"""评查服务接口。""" + +from abc import ABC, abstractmethod + +from fastapi_modules.fastapi_leaudit.domian.vo.auditVo import AuditRunVO, AuditResultVO + + +class IAuditService(ABC): + """评查服务接口。""" + + @abstractmethod + async def Run(self, DocumentId: int) -> AuditRunVO: + """触发文档评查。""" + ... + + @abstractmethod + async def GetRunStatus(self, RunId: int) -> AuditRunVO: + """查询评查运行状态。""" + ... + + @abstractmethod + async def GetResult(self, RunId: int) -> AuditResultVO: + """获取评查结果。""" + ... diff --git a/fastapi_modules/fastapi_leaudit/services/authService.py b/fastapi_modules/fastapi_leaudit/services/authService.py new file mode 100644 index 0000000..cffe158 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/authService.py @@ -0,0 +1,22 @@ +"""认证服务接口。""" + +from abc import ABC, abstractmethod + +from fastapi_modules.fastapi_leaudit.domian.vo.auth.loginTokenVo import LoginTokenVO + + +class IAuthService(ABC): + """认证服务接口。""" + + @abstractmethod + async def PasswordLogin(self, Sub: str, Password: str) -> LoginTokenVO: + """账密登录。""" + ... + + @abstractmethod + async def OAuthLogin(self, Sub: str, Username: str | None, Nickname: str | None, + Email: str | None, PhoneNumber: str | None, + OuId: str | None, OuName: str | None, + IsLeader: bool | None, Area: str | None, ExpiresIn: int) -> LoginTokenVO: + """OAuth 登录。""" + ... diff --git a/fastapi_modules/fastapi_leaudit/services/impl/__init__.py b/fastapi_modules/fastapi_leaudit/services/impl/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi_modules/fastapi_leaudit/services/impl/auditServiceImpl.py b/fastapi_modules/fastapi_leaudit/services/impl/auditServiceImpl.py new file mode 100644 index 0000000..8eb562f --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/impl/auditServiceImpl.py @@ -0,0 +1,65 @@ +"""评查服务实现。 + +编排 LeAudit 引擎执行链路: + 文档 → OCR → Extract → Evaluate → Rescue → Persist +""" + +from fastapi_common.fastapi_common_logger import logger +from fastapi_common.fastapi_common_sqlalchemy.database import GetAsyncSession +from fastapi_common.fastapi_common_web.domain.responses import StatusCodeEnum +from fastapi_common.fastapi_common_web.exception.LeauditException import LeauditException + +from fastapi_modules.fastapi_leaudit.domian.vo.auditVo import AuditRunVO, AuditResultVO +from fastapi_modules.fastapi_leaudit.models import LeauditAuditRun +from fastapi_modules.fastapi_leaudit.services import IAuditService + + +class AuditServiceImpl(IAuditService): + """评查服务实现。""" + + async def Run(self, DocumentId: int, RuleType: str | None = None, Force: bool = False) -> AuditRunVO: + """触发文档评查。 + + 实际执行流程由 Celery 任务异步处理。 + """ + async with GetAsyncSession() as session: + # TODO: 从 bridge 层获取 pipeline,提交 Celery 任务 + logger.info(f"触发评查: documentId={DocumentId}, ruleType={RuleType}") + raise LeauditException(StatusCodeEnum.HTTP_500_INTERNAL_SERVER_ERROR, "Celery 任务集成待实现") + + async def GetRunStatus(self, RunId: int) -> AuditRunVO: + """查询评查运行状态。""" + async with GetAsyncSession() as session: + run = await session.get(LeauditAuditRun, RunId) + if not run: + raise LeauditException(StatusCodeEnum.HTTP_404_NOT_FOUND, "评查运行记录不存在") + return AuditRunVO( + runId=run.Id, + documentId=run.documentId, + runNo=run.runNo, + status=run.status, + phase=run.phase, + totalScore=float(run.totalScore) if run.totalScore else None, + passedCount=run.passedCount, + failedCount=run.failedCount, + startedAt=run.startedAt, + finishedAt=run.finishedAt, + ) + + async def GetResult(self, RunId: int) -> AuditResultVO: + """获取评查结果。""" + async with GetAsyncSession() as session: + run = await session.get(LeauditAuditRun, RunId) + if not run: + raise LeauditException(StatusCodeEnum.HTTP_404_NOT_FOUND, "评查运行记录不存在") + # TODO: 从 leaudit_rule_results 表查询规则级结果 + return AuditResultVO( + runId=run.Id, + totalScore=float(run.totalScore) if run.totalScore else None, + passedCount=run.passedCount or 0, + failedCount=run.failedCount or 0, + skippedCount=run.skippedCount or 0, + phase=run.phase, + rescueApplied=run.rescueApplied or False, + rules=[], + ) diff --git a/fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py b/fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py new file mode 100644 index 0000000..e5ccc78 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py @@ -0,0 +1,162 @@ +"""认证服务实现。 + +从旧项目 app/routes/auth.py 和 app/auth/auth.py 迁移,业务逻辑完全不变。 +仅重组为 Controller → Service(interface+impl) → Model 结构。 +""" + +from fastapi_common.fastapi_common_logger import logger +from fastapi_common.fastapi_common_sqlalchemy.database import GetAsyncSession +from fastapi_common.fastapi_common_security.jwtService import JwtService +from fastapi_common.fastapi_common_web.exception.LeauditException import LeauditException +from fastapi_common.fastapi_common_web.domain.responses import StatusCodeEnum + +from fastapi_modules.fastapi_leaudit.domian.vo.auth.loginTokenVo import LoginTokenVO +from fastapi_modules.fastapi_leaudit.services.authService import IAuthService + + +class AuthServiceImpl(IAuthService): + """认证服务实现。""" + + async def PasswordLogin(self, Sub: str, Password: str) -> LoginTokenVO: + """账密登录。 + + 校验 sso_users 表:sub + password + status=0 + deleted_at IS NULL。 + 安全:统一错误提示"账号或密码错误",防止用户枚举。 + """ + async with GetAsyncSession() as session: + from sqlalchemy import select, text + + result = await session.execute( + text("SELECT id, sub, username, nick_name, phone_number, email, " + "ou_id, ou_name, is_leader, password, status, deleted_at, " + "try_count, try_login_time, area, tenant_name, dep_name, dep_short_name " + "FROM sso_users WHERE sub = :sub"), + {"sub": Sub}, + ) + row = result.fetchone() + + if not row: + logger.warning(f"登录失败: 用户不存在 - sub={Sub}") + raise LeauditException(StatusCodeEnum.HTTP_401_UNAUTHORIZED, "账号或密码错误") + + user = dict(row._mapping) + + if user.get("deleted_at") is not None: + logger.warning(f"登录失败: 账号已删除 - sub={Sub}") + raise LeauditException(StatusCodeEnum.HTTP_401_UNAUTHORIZED, "账号或密码错误") + + if user.get("status") != 0: + logger.warning(f"登录失败: 账号已禁用 - sub={Sub}, status={user.get('status')}") + raise LeauditException(StatusCodeEnum.HTTP_401_UNAUTHORIZED, "账号或密码错误") + + if user.get("password") != Password: + logger.warning(f"登录失败: 密码错误 - sub={Sub}") + raise LeauditException(StatusCodeEnum.HTTP_401_UNAUTHORIZED, "账号或密码错误") + + return await self._buildLoginResponse(user, session) + + async def OAuthLogin(self, Sub: str, Username: str | None, Nickname: str | None, + Email: str | None, PhoneNumber: str | None, + OuId: str | None, OuName: str | None, + IsLeader: bool | None, Area: str | None, ExpiresIn: int) -> LoginTokenVO: + """OAuth 登录。验证 sub 是否存在,不存在则自动创建用户。""" + async with GetAsyncSession() as session: + from sqlalchemy import select, text + from datetime import datetime, timezone + + result = await session.execute( + text("SELECT id, sub, username, nick_name, phone_number, email, " + "ou_id, ou_name, is_leader, status, deleted_at, " + "area, tenant_name, dep_name, dep_short_name " + "FROM sso_users WHERE sub = :sub"), + {"sub": Sub}, + ) + row = result.fetchone() + + if row: + user = dict(row._mapping) + if user.get("deleted_at") is not None or user.get("status") != 0: + raise LeauditException(StatusCodeEnum.HTTP_401_UNAUTHORIZED, "账号已被禁用或删除") + # 更新最后登录信息 + await session.execute( + text("UPDATE sso_users SET username = :username, nick_name = :nick, " + "email = :email, phone_number = :phone, ou_id = :ou_id, " + "ou_name = :ou_name, is_leader = :is_leader, area = :area, " + "updated_at = :now WHERE id = :id"), + {"username": Username, "nick": Nickname, "email": Email, + "phone": PhoneNumber, "ou_id": OuId, "ou_name": OuName, + "is_leader": IsLeader, "area": Area, + "now": datetime.now(timezone.utc), "id": user["id"]}, + ) + else: + # 自动创建用户 + await session.execute( + text("INSERT INTO sso_users (sub, username, nick_name, email, " + "phone_number, ou_id, ou_name, is_leader, area, status) " + "VALUES (:sub, :username, :nick, :email, :phone, :ou_id, " + ":ou_name, :is_leader, :area, 0)"), + {"sub": Sub, "username": Username, "nick": Nickname, "email": Email, + "phone": PhoneNumber, "ou_id": OuId, "ou_name": OuName, + "is_leader": IsLeader, "area": Area}, + ) + await session.commit() + + result = await session.execute( + text("SELECT id, sub, username, nick_name, phone_number, email, " + "ou_id, ou_name, is_leader, area, tenant_name, dep_name, dep_short_name " + "FROM sso_users WHERE sub = :sub"), + {"sub": Sub}, + ) + row = result.fetchone() + user = dict(row._mapping) if row else {} + + if not user: + raise LeauditException(StatusCodeEnum.HTTP_500_INTERNAL_SERVER_ERROR, "用户创建失败") + + return await self._buildLoginResponse(user, session) + + async def _buildLoginResponse(self, user: dict, session) -> LoginTokenVO: + """组装登录响应:查询角色 → 签发 JWT → 返回 LoginTokenVO。""" + from sqlalchemy import text + + # 查询用户角色 + roleResult = await session.execute( + text("SELECT r.role_key FROM user_role ur " + "JOIN roles r ON ur.role_id = r.id " + "WHERE ur.user_id = :uid LIMIT 1"), + {"uid": user["id"]}, + ) + roleRow = roleResult.fetchone() + userRole = roleRow[0] if roleRow else "common" + + # 签发 JWT + expiresIn = 3600 # 默认 1 小时 + tokens = JwtService.generate( + userId=user["id"], + username=user.get("username") or user.get("sub", ""), + nickName=user.get("nick_name") or "", + ouId=user.get("ou_id") or "", + ouName=user.get("ou_name") or "", + area=user.get("area"), + userRole=userRole, + ) + + return LoginTokenVO( + access_token=tokens["access_token"], + token_type="Bearer", + expires_in=expiresIn, + issued_time=tokens.get("issued_time", ""), + user_info={ + "user_id": user["id"], + "sub": user.get("sub"), + "username": user.get("username"), + "nick_name": user.get("nick_name"), + "email": user.get("email"), + "phone_number": user.get("phone_number"), + "ou_id": user.get("ou_id"), + "ou_name": user.get("ou_name"), + "is_leader": user.get("is_leader"), + "area": user.get("area"), + "role": userRole, + }, + ) diff --git a/fastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.py b/fastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.py new file mode 100644 index 0000000..0455ca1 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.py @@ -0,0 +1,141 @@ +"""权限服务实现。 + +从旧项目 app/rbac/permission_checker_v2.py 迁移,业务逻辑完全不变。 +- 数据库驱动 GRANT/DENY 机制(DENY 优先级更高) +- 支持通配符:document:*:*、*:*:* 等 +- 实时查询(无 Redis 缓存) +仅改造为 SQLAlchemy 会话 + 项目统一配置。 +""" + +from fastapi_common.fastapi_common_logger import logger +from fastapi_common.fastapi_common_sqlalchemy.database import GetAsyncSession + +from fastapi_modules.fastapi_leaudit.services.permissionService import IPermissionService + + +class PermissionServiceImpl(IPermissionService): + """权限检查服务实现。""" + + async def CheckPermission(self, UserId: int, PermissionKey: str) -> bool: + """检查用户是否拥有指定权限。 + + GRANT/DENY 优先级: + 1. 精确 DENY → 拒绝 + 2. 通配符 DENY → 拒绝 + 3. 精确 GRANT → 通过 + 4. 通配符 GRANT → 通过 + 5. 无匹配 → 拒绝 + """ + try: + grants, denies = await self._getUserPermissions(UserId) + + # DENY 优先 + if PermissionKey in denies: + logger.debug(f"[DENY] 精确拒绝: user={UserId}, perm={PermissionKey}") + return False + + if self._matchWildcard(PermissionKey, denies): + logger.debug(f"[DENY] 通配符拒绝: user={UserId}, perm={PermissionKey}") + return False + + # GRANT + if PermissionKey in grants: + logger.debug(f"[GRANT] 精确授权: user={UserId}, perm={PermissionKey}") + return True + + if self._matchWildcard(PermissionKey, grants): + logger.debug(f"[GRANT] 通配符授权: user={UserId}, perm={PermissionKey}") + return True + + logger.debug(f"[DENY] 无匹配权限: user={UserId}, perm={PermissionKey}") + return False + + except Exception as e: + logger.error(f"权限检查异常: user={UserId}, perm={PermissionKey}, error={e}") + return False # 安全优先:异常时拒绝 + + async def HasAnyPermission(self, UserId: int, PermissionKeys: list[str]) -> bool: + """OR 逻辑:任一权限通过即返回 True。""" + for key in PermissionKeys: + if await self.CheckPermission(UserId, key): + return True + return False + + async def HasAllPermissions(self, UserId: int, PermissionKeys: list[str]) -> bool: + """AND 逻辑:全部权限通过才返回 True。""" + for key in PermissionKeys: + if not await self.CheckPermission(UserId, key): + return False + return True + + # ------------------------------------------------------------------ + # 内部方法 + # ------------------------------------------------------------------ + + async def _getUserPermissions(self, UserId: int) -> tuple[set[str], set[str]]: + """从数据库查询用户的 GRANT 和 DENY 权限集合。""" + grants: set[str] = set() + denies: set[str] = set() + + async with GetAsyncSession() as session: + from sqlalchemy import text + + result = await session.execute( + text( + "SELECT p.permission_key, rp.grant_type " + "FROM sso_users u " + "JOIN user_role ur ON u.id = ur.user_id " + "JOIN roles r ON ur.role_id = r.id " + "JOIN role_permissions rp ON r.id = rp.role_id " + "JOIN permissions p ON rp.permission_id = p.id " + "WHERE u.id = :uid" + ), + {"uid": UserId}, + ) + + rows = result.fetchall() + if not rows: + logger.warning(f"用户无角色或权限: user_id={UserId}") + return grants, denies + + for row in rows: + permKey = row[0] + grantType = row[1] + if grantType == "GRANT": + grants.add(permKey) + elif grantType == "DENY": + denies.add(permKey) + + logger.debug(f"用户权限: user={UserId}, grants={len(grants)}, denies={len(denies)}") + return grants, denies + + @staticmethod + def _matchWildcard(PermissionKey: str, PermissionSet: set[str]) -> bool: + """检查 PermissionKey 是否匹配集合中的任一通配符模式。""" + for pattern in PermissionSet: + if PermissionServiceImpl._wildcardMatch(PermissionKey, pattern): + return True + return False + + @staticmethod + def _wildcardMatch(PermissionKey: str, Pattern: str) -> bool: + """通配符匹配。 + + _wildcardMatch("document:read:all", "document:*:*") → True + _wildcardMatch("document:read:all", "document:read:*") → True + _wildcardMatch("document:read:all", "evaluation:*:*") → False + _wildcardMatch("document:read:all", "*:*:*") → True + """ + keyParts = PermissionKey.split(":") + patternParts = Pattern.split(":") + + if len(keyParts) != len(patternParts): + return False + + for keyPart, patternPart in zip(keyParts, patternParts): + if patternPart == "*": + continue + if keyPart != patternPart: + return False + + return True diff --git a/fastapi_modules/fastapi_leaudit/services/permissionService.py b/fastapi_modules/fastapi_leaudit/services/permissionService.py new file mode 100644 index 0000000..d451b2c --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/permissionService.py @@ -0,0 +1,27 @@ +"""权限服务接口。""" + +from abc import ABC, abstractmethod + + +class IPermissionService(ABC): + """权限检查服务接口。 + + 权限格式:module:resource:action(如 document:list:read) + 支持通配符:document:*:*、*:*:* 等 + 支持 GRANT/DENY 机制(DENY 优先级更高) + """ + + @abstractmethod + async def CheckPermission(self, UserId: int, PermissionKey: str) -> bool: + """检查用户是否拥有指定权限。""" + ... + + @abstractmethod + async def HasAnyPermission(self, UserId: int, PermissionKeys: list[str]) -> bool: + """检查用户是否拥有任意一个权限(OR 逻辑)。""" + ... + + @abstractmethod + async def HasAllPermissions(self, UserId: int, PermissionKeys: list[str]) -> bool: + """检查用户是否拥有所有权限(AND 逻辑)。""" + ... diff --git a/fastapi_modules/fastapi_leaudit/services/ruleService.py b/fastapi_modules/fastapi_leaudit/services/ruleService.py new file mode 100644 index 0000000..9c43c49 --- /dev/null +++ b/fastapi_modules/fastapi_leaudit/services/ruleService.py @@ -0,0 +1,24 @@ +"""规则服务接口。""" + +from abc import ABC, abstractmethod + +from fastapi_modules.fastapi_leaudit.domian.vo.ruleVo import RuleSetVO, RuleVersionVO + + +class IRuleService(ABC): + """规则服务接口。""" + + @abstractmethod + async def ListSets(self) -> list[RuleSetVO]: + """列出所有规则集。""" + ... + + @abstractmethod + async def GetVersions(self, RuleType: str) -> list[RuleVersionVO]: + """获取规则集的所有版本。""" + ... + + @abstractmethod + async def Publish(self, RuleType: str, VersionId: int) -> RuleVersionVO: + """发布指定版本。""" + ... diff --git a/fastapi_modules/fastapi_leaudit/tasks/__init__.py b/fastapi_modules/fastapi_leaudit/tasks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0bda658 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,38 @@ +[build-system] +requires = ["setuptools>=75.8.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "leaudit-platform" +version = "1.0.0" +requires-python = ">=3.12" +dependencies = [ + "fastapi>=0.115.0", + "uvicorn[standard]>=0.34.0", + "sqlalchemy[asyncio]>=2.0.36", + "asyncpg>=0.30.0", + "pydantic>=2.10.0", + "pydantic-settings>=2.7.0", + "httpx>=0.28.0", + "celery>=5.4.0", + "redis>=5.2.0", + "tomli>=2.2.0", + "python-multipart>=0.0.18", + "pyjwt>=2.10.0", + "pillow>=11.0.0", + "pyyaml>=6.0", + "leaudit", +] + +[tool.setuptools.packages.find] +include = [ + "fastapi_common*", + "fastapi_admin*", + "fastapi_modules*", +] + +[tool.ruff] +line-length = 130 + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] diff --git a/resources/.gitkeep b/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rules/contract_construction/docs/amount_mismatch.md b/rules/contract_construction/docs/amount_mismatch.md new file mode 100644 index 0000000..a5989d5 --- /dev/null +++ b/rules/contract_construction/docs/amount_mismatch.md @@ -0,0 +1,58 @@ +# 建设工程施工合同(反例:金额不一致) + +**合同编号**:GCHT2024-BAD-002 + +## 第一条 合同当事人 + +**发包人**:上海某某开发建设有限公司 +统一社会信用代码:91310000MA1K3H5K8L + +**承包人**:上海某某建工集团有限公司 +统一社会信用代码:91310112MA1K9A8B7C +资质等级:一级 +资质证书编号:建总包字 JZ-2020-001234 + +## 第二条 项目信息 + +工程名称:某某商业广场建设工程 +工程地点:上海市静安区某某路 100 号 + +## 第三条 合同金额(⚠️ 不一致) + +**合同金额**:人民币 **55,000,000.00** 元(伍仟伍佰万元整) +**中标价**:人民币 **50,000,000.00** 元 +**投标价**:人民币 **50,000,000.00** 元 + +注意:合同金额比中标价和投标价高出 500 万,涉嫌"阴阳合同"。 + +## 第四条 工期 + +开工日期:2024 年 7 月 1 日 +竣工日期:2025 年 12 月 31 日 + +## 第五条 质量标准 + +符合 GB 50300-2013 国家标准合格等级要求。 + +## 第六条 安全文明施工 + +严格落实三宝四口五临边防护,佩戴安全帽,控制扬尘和噪音。 + +## 第七条 质保金 + +质保金比例:合同金额的 2% + +## 第八条 招投标 + +招标文件编号:ZB-2024-002 +中标通知书编号:ZBTZS-2024-002 + +--- + +签订日期:2024 年 6 月 1 日 + +发包人(盖章):[盖章: 上海某某开发建设有限公司合同专用章] +承包人(盖章):[盖章: 上海某某建工集团有限公司合同专用章] + +(本样本用于测试 GC-002 金额三处一致性的 fail 路径 —— + 合同金额 55M 与中标价 50M 和投标价 50M 不一致) diff --git a/rules/contract_construction/docs/normal.md b/rules/contract_construction/docs/normal.md new file mode 100644 index 0000000..900cdb5 --- /dev/null +++ b/rules/contract_construction/docs/normal.md @@ -0,0 +1,100 @@ +# 建设工程施工合同 + +**合同编号**:GCHT2024-001 + +## 第一条 合同当事人 + +**发包人**:上海某某开发建设有限公司 +地址:上海市浦东新区世纪大道 100 号 +统一社会信用代码:91310000MA1K3H5K8L +法定代表人:张三 + +**承包人**:上海某某建工集团有限公司 +地址:上海市闵行区虹桥路 500 号 +统一社会信用代码:91310112MA1K9A8B7C +法定代表人:李四 +**资质等级**:一级 +**资质证书编号**:建总包字 JZ-2020-001234 + +## 第二条 项目信息 + +**工程名称**:某某花园小区 A 区建设工程 +**工程地点**:上海市浦东新区某某路 88 号 +**工程规模**: +- 总建筑面积:50,000 平方米 +- 地上 18 层,地下 2 层 +- 包含住宅楼 8 栋及配套商业设施 + +## 第三条 合同金额 + +**合同金额**:人民币 50,000,000.00 元 +**大写**:伍仟万元整 +**中标价**:人民币 50,000,000.00 元 +**投标价**:人民币 50,000,000.00 元 + +(三处金额完全一致,符合《招标投标法》规定) + +## 第四条 工期 + +**开工日期**:2024 年 6 月 1 日 +**竣工日期**:2025 年 12 月 31 日 +**总工期**:578 日历日 + +## 第五条 质量标准 + +本工程质量应符合现行国家标准 GB 50300-2013《建筑工程施工质量验收统一标准》 +的合格等级要求,以及相关专业施工质量验收规范。 + +质量等级:合格 + +## 第六条 安全文明施工 + +承包人应严格执行安全生产管理规定: + +1. **三宝四口五临边**防护措施必须到位: + - 三宝:安全帽、安全带、安全网 + - 四口:楼梯口、电梯井口、预留洞口、通道口 + - 五临边:尚未安装栏杆的阳台周边、屋面周边、楼层周边、 + 楼梯侧边、卸料平台外侧边 + +2. 所有进入施工现场人员必须佩戴**安全帽**,违者按规定处罚。 + +3. 严格控制施工**扬尘**:设置围挡、定期洒水降尘、车辆进出冲洗。 + +4. 严格控制施工**噪音**:夜间(22:00-6:00)禁止施工作业。 + +5. 按规范设置临时用电、消防设施。 + +## 第七条 工程款支付 + +**预付款**:合同金额的 20% 作为预付款,承包人开工前支付。 +**进度款**:按月度完成工程量进度结算,当月完成量的 80% 作为进度款。 +**质保金**:合同金额的 2.5%(0.025),竣工验收合格后保留 2 年。 + +## 第八条 招投标文件 + +**招标文件编号**:ZB-2024-001 +**中标通知书编号**:ZBTZS-2024-001 + +## 第九条 违约责任 + +1. 承包人延期竣工的,每日按合同金额的万分之一支付违约金,不超过合同金额 5%。 +2. 发包人延期支付工程款的,按延期金额每日万分之五支付违约金。 + +## 第十条 争议解决 + +本合同争议由双方协商解决。协商不成的,提交上海仲裁委员会仲裁。 + +--- + +**签订日期**:2024 年 5 月 15 日 + +**发包人(盖章)**:上海某某开发建设有限公司 + [盖章: 上海某某开发建设有限公司合同专用章] + 法定代表人签名:[签名: 张三] + +**承包人(盖章)**:上海某某建工集团有限公司 + [盖章: 上海某某建工集团有限公司合同专用章] + 法定代表人签名:[签名: 李四] + +[骑缝章: 上海某某开发建设有限公司 - 跨越全部页面] diff --git a/rules/contract_construction/rules.test.yaml b/rules/contract_construction/rules.test.yaml new file mode 100644 index 0000000..0d6fa79 --- /dev/null +++ b/rules/contract_construction/rules.test.yaml @@ -0,0 +1,283 @@ +# ═════════════════════════════════════════════════════════════════ +# 建设工程合同 · 回归测试用例 +# ═════════════════════════════════════════════════════════════════ +# 配套文件:contract_construction.yaml + +target: contract_construction.yaml + +fixtures: + + # ═════════════════════════════════════════════════════════════ + # GC-000 · 基础信息完整性 + # ═════════════════════════════════════════════════════════════ + GC-000: + - name: 完整合规 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园小区 A 区建设工程 + 合同金额: 50000000 + expected: pass + + - name: 缺工程名称 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: null + 合同金额: 50000000 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # GC-001 · 承包人资质合法性 + # ═════════════════════════════════════════════════════════════ + GC-001: + - name: 资质完整 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园小区 A 区建设工程 + 合同金额: 50000000 + 承包人统一信用代码: "91310000MA1K3H5K8L" + 承包人资质等级: 一级 + 承包人资质证书编号: 建总包字 001234 + expected: pass + + - name: USCC 校验失败 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园小区 A 区建设工程 + 合同金额: 50000000 + 承包人统一信用代码: "91310000MA1K3H5K80" + 承包人资质等级: 一级 + 承包人资质证书编号: 建总包字 001234 + expected: fail + + - name: GC-000 失败时本规则跳过 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: null # GC-000 会失败 + 工程名称: 某某花园小区 A 区建设工程 + 合同金额: 50000000 + 承包人统一信用代码: "91310000MA1K3H5K8L" + 承包人资质等级: 一级 + 承包人资质证书编号: 建总包字 001234 + expected: skipped_dependency + + # ═════════════════════════════════════════════════════════════ + # GC-002 · 金额三处一致性(核心规则) + # ═════════════════════════════════════════════════════════════ + GC-002: + - name: 三处完全一致 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 投标价: 50000000 + 中标价: 50000000 + expected: pass + + - name: 合同金额高于中标价(阴阳合同嫌疑) + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 55000000 + 投标价: 50000000 + 中标价: 50000000 + expected: fail + + - name: 中标价与投标价不一致 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 投标价: 48000000 # ← 差了 200 万 + 中标价: 50000000 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # GC-003 · 质量标准明确性 + # ═════════════════════════════════════════════════════════════ + GC-003: + - name: 有国标引用 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 质量标准: 本工程质量应符合现行国家标准 GB 50300-2013《建筑工程施工质量验收统一标准》的合格等级要求 + expected: pass + + - name: 质量标准过短 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 质量标准: 符合国标 + expected: fail + + - name: 长度够但无标准引用 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 质量标准: 本工程质量应符合发包人要求,达到完工条件,承包人应严格按照图纸和规范施工 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # GC-004 · 安全文明施工条款完备性 + # ⭐ has_all_keywords 必须全部命中 + # ═════════════════════════════════════════════════════════════ + GC-004: + - name: 安全条款完备 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 安全文明施工要求: | + 承包人应严格执行安全生产规定: + (1) 严格落实三宝四口五临边防护措施; + (2) 所有施工人员必须佩戴安全帽; + (3) 严格控制扬尘,采取洒水降尘等措施; + (4) 严格控制噪音,夜间禁止施工。 + expected: pass + + - name: 缺"三宝四口五临边" + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 安全文明施工要求: | + 承包人应执行安全生产规定:佩戴安全帽,控制扬尘,降低噪音。 + expected: fail # 缺"三宝四口五临边"关键词 + + # ═════════════════════════════════════════════════════════════ + # GC-005 · 工期合理性 + # ═════════════════════════════════════════════════════════════ + GC-005: + - name: 正常工期 + phase: executed + extract: + 开工日期: "2024-06-01" + 竣工日期: "2025-12-31" + # derived.工期天数 = 578 + expected: pass + + - name: 竣工早于开工 + phase: executed + extract: + 开工日期: "2024-12-01" + 竣工日期: "2024-06-01" # ← 颠倒 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # GC-006 · 质保金比例 + # ═════════════════════════════════════════════════════════════ + GC-006: + - name: 比例 2% + phase: executed + extract: + 质保金比例: 0.02 + expected: pass + + - name: 比例 5%(超限) + phase: executed + extract: + 质保金比例: 0.05 + expected: fail + + - name: 比例 3%(恰好到上限) + phase: executed + extract: + 质保金比例: 0.03 + expected: fail # money.lt 严格小于 + + # ═════════════════════════════════════════════════════════════ + # GC-SEAL-001 · 双方签章齐全 + # ═════════════════════════════════════════════════════════════ + GC-SEAL-001: + - name: 双方签章且文字匹配 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + visual_manifest: + seals: + - id: 发包人公章 + detection_score: 0.95 + ocr_text: 某某开发建设有限公司 + - id: 承包人公章 + detection_score: 0.94 + ocr_text: 某某建工集团有限公司合同专用章 + expected: pass + + - name: 承包人印章文字不符 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + visual_manifest: + seals: + - id: 发包人公章 + detection_score: 0.95 + ocr_text: 某某开发建设有限公司 + - id: 承包人公章 + detection_score: 0.94 + ocr_text: 其他不相关单位公章 # ← 不符 + expected: fail + + - name: 草稿阶段无印章(skipped) + phase: draft + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + visual_manifest: + seals: [] + expected: skipped_phase + + # ═════════════════════════════════════════════════════════════ + # GC-GROUP-QUALITY · 质量综合规则组 + # ═════════════════════════════════════════════════════════════ + GC-GROUP-QUALITY: + - name: 质量与安全全部合规 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 质量标准: 本工程质量应符合现行国家标准 GB 50300-2013 合格要求 + 安全文明施工要求: | + 严格落实三宝四口五临边,佩戴安全帽,控制扬尘和噪音。 + expected: pass + + - name: 质量不合格导致组失败 + phase: executed + extract: + 发包人名称: 某某开发建设有限公司 + 承包人名称: 某某建工集团有限公司 + 工程名称: 某某花园 + 合同金额: 50000000 + 质量标准: 符合国标 # 过于简略 + 安全文明施工要求: 严格落实三宝四口五临边,佩戴安全帽,控制扬尘和噪音。 + expected: fail diff --git a/rules/contract_construction/rules.yaml b/rules/contract_construction/rules.yaml new file mode 100644 index 0000000..1f945ac --- /dev/null +++ b/rules/contract_construction/rules.yaml @@ -0,0 +1,543 @@ +metadata: + type_id: contract.construction.general + name: 建设工程合同 + version: '1.2' + last_updated: '2026-04-11' + parent: contract + inherits_from: + - base.common + - base.party_info + classification_keywords: + - 建设工程 + - 工程承包 + - 施工合同 + - 总承包 + tags: + - compliance + - high_priority + - prc_civil_code + - construction_specific + - safety_critical + applies_to_jurisdictions: + - prc + references_laws: + - 《民法典》第 788-808 条(建设工程合同章) + - 《建筑法》第 25-41 条 + - 《建设工程质量管理条例》 + description: '建设工程施工合同评查规则。 + + 覆盖民法典第 788-808 条(建设工程合同章)。 + + 评查重点:资质核验、金额一致性、质量安全条款、竣工验收。 + + ' + confidence_profile: + allow_weight_override: false + field_confidence_defaults: + 合同金额: 0.95 + 投标价: 0.95 + 中标价: 0.95 +extract: +- group: 当事人 + fields: + - name: 发包人名称 + type: verbatim + required_from: draft + deep_retry: false + - name: 发包人统一信用代码 + type: uscc + required_from: executed + deep_retry: false + - name: 承包人名称 + type: verbatim + required_from: draft + deep_retry: false + - name: 承包人统一信用代码 + type: uscc + required_from: executed + deep_retry: false + - name: 承包人资质等级 + type: enum + required_from: draft + allowed: + - 特级 + - 一级 + - 二级 + - 三级 + deep_retry: false + - name: 承包人资质证书编号 + type: verbatim + required_from: executed + deep_retry: false +- group: 合同基本信息 + fields: + - name: 合同编号 + type: verbatim + required_from: draft + deep_retry: false + - name: 签订日期 + type: date + required_from: executed + deep_retry: false +- group: 项目信息 + fields: + - name: 工程名称 + type: verbatim + required_from: draft + deep_retry: false + - name: 工程地点 + type: verbatim + required_from: draft + deep_retry: false + - name: 工程规模 + type: string + required_from: draft + deep_retry: false + - name: 开工日期 + type: date + required_from: executed + deep_retry: false + - name: 竣工日期 + type: date + required_from: executed + deep_retry: false +- group: 金额(三处一致性检查的核心) + fields: + - name: 合同金额 + type: money + required_from: draft + deep_retry: false + - name: 投标价 + type: money + required_from: draft + deep_retry: false + - name: 中标价 + type: money + required_from: draft + deep_retry: false + - name: 合同金额大写 + type: verbatim + required_from: executed + deep_retry: false +- group: 招投标信息 + fields: + - name: 招标文件编号 + type: verbatim + required_from: draft + deep_retry: false + - name: 中标通知书编号 + type: verbatim + required_from: draft + deep_retry: false +- group: 质量条款 + fields: + - name: 质量标准 + type: string + required_from: draft + deep_retry: false + - name: 质量等级 + type: enum + required_from: draft + allowed: + - 合格 + - 优良 + deep_retry: false + - name: 保修期限 + type: string + required_from: draft + deep_retry: false +- group: 安全条款 + fields: + - name: 安全文明施工要求 + type: string + required_from: draft + deep_retry: false +- group: 工程款支付 + fields: + - name: 预付款比例 + type: money + required_from: draft + deep_retry: false + - name: 进度款支付方式 + type: string + required_from: draft + deep_retry: false + - name: 质保金比例 + type: money + required_from: draft + deep_retry: false +- group: 违约与争议 + fields: + - name: 违约责任 + type: string + required_from: draft + deep_retry: false + - name: 争议解决 + type: string + required_from: draft + deep_retry: false +derived_fields: +- name: 工期天数 + type: integer + compute: (竣工日期 - 开工日期).days + depends_on: + - 开工日期 + - 竣工日期 +- name: 质保金金额 + type: money + compute: 合同金额 * 质保金比例 + depends_on: + - 合同金额 + - 质保金比例 +visual_elements: + seals: + - id: 发包人公章 + name: 发包人公章或合同专用章 + required: true + required_from: executed + allowed_types: + - 公章 + - 合同专用章 + expected_text_match: + field: 发包人名称 + - id: 承包人公章 + name: 承包人公章或合同专用章 + required: true + required_from: executed + allowed_types: + - 公章 + - 合同专用章 + expected_text_match: + field: 承包人名称 + cross_page_seals: + - id: 骑缝章 + name: 建设工程合同骑缝章 + required: true + required_from: executed + expected_text_match: + field: 发包人名称 +rules: +- group: 基础检查 + rules: + - rule_id: GC-000 + name: 基础信息完整性 + risk: high + score: 10 + version: 1 + stages: + - id: '1' + check: required + fields: + - 发包人名称 + - 承包人名称 + - 工程名称 + - 合同金额 + logic: and + logic: '1' + messages: + pass: 基础信息完整 + fail: 缺少发包人/承包人/工程名称/合同金额 + type: deterministic +- group: 主体资质 + rules: + - rule_id: GC-001 + name: 承包人资质合法性 + risk: high + score: 15 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: format + field: 承包人统一信用代码 + format: uscc + - id: '2' + check: required + field: 承包人资质证书编号 + - id: '3' + check: required + field: 承包人资质等级 + logic: 1 AND 2 AND 3 + messages: + pass: 承包人资质信息完整 + fail: 承包人资质信息不完整或 USCC 无效 + references_laws: + - 《建筑法》第 13 条(施工企业资质) + type: deterministic +- group: 金额合规 + rules: + - rule_id: GC-002 + name: 金额三处一致性 + risk: high + score: 20 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + fields: + - 合同金额 + - 投标价 + - 中标价 + logic: and + - id: '2' + check: match + pairs: + - source: 合同金额 + target: 中标价 + method: exact + - source: 中标价 + target: 投标价 + method: exact + logic: 1 AND 2 + messages: + pass: 合同金额与投标价、中标价一致 + fail: 合同金额与投标价/中标价不一致,涉嫌虚假招标 + references_laws: + - 《招标投标法》第 46 条(不得背离实质性内容订立合同) + - 《招标投标法实施条例》第 57 条 + remediation: + suggestions: + - 合同金额 {{合同金额}} / 中标价 {{中标价}} / 投标价 {{投标价}} + - 三者应完全一致。不一致时涉嫌"阴阳合同"或变相抬价 + - 建议立即核对招标文件原件 + actions: + - type: upload_file + label: 上传招标文件原件 + file_type: 招标文件 + accept: + - pdf + - type: escalate + label: 涉嫌阴阳合同,上报合规 + role: 合规专员 + type: deterministic +- group: 质量条款 + rules: + - rule_id: GC-003 + name: 质量标准明确性 + risk: high + score: 10 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + field: 质量标准 + - id: '2' + type: string.min_length + field: 质量标准 + min: 30 + - id: '3' + check: contains + field: 质量标准 + any_of: + - GB 50 + - GB/T + - 合格 + - 优良 + - 现行国家标准 + logic: 1 AND 2 AND 3 + messages: + pass: 质量标准明确 + fail: 质量标准过于简略或未引用具体标准 + references_laws: + - 《民法典》第 802 条 + - 《建设工程质量管理条例》第 14 条 + type: deterministic + - rule_id: GC-OLD-003 + name: 旧版质量标准检查 + risk: medium + score: 5 + version: 1 + stages: + - id: '1' + check: required + field: 质量标准 + logic: '1' + messages: + pass: 有质量条款(注意:本规则已弃用,请使用 GC-003) + fail: 缺少质量条款 + type: deterministic + deprecated: + since: '2025-06-01' + replacement: GC-003 + reason: '旧版仅检查质量条款存在性,不检查标准引用的具体性。 + + GC-003 增加了对 GB/GB-T 国标引用的要求。 + + ' +- group: 安全条款 + rules: + - rule_id: GC-004 + name: 安全文明施工条款完备性 + risk: high + score: 15 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + field: 安全文明施工要求 + - id: '2' + type: string.min_length + field: 安全文明施工要求 + min: 50 + - id: '3' + check: contains + field: 安全文明施工要求 + all_of: + - 三宝四口五临边 + - 安全帽 + - 扬尘 + - 噪音 + logic: 1 AND 2 AND 3 + messages: + pass: 安全文明施工条款完备 + fail: 安全文明施工条款不完备,缺少关键要素 + references_laws: + - 《建筑法》第 36-41 条 + - 《建设工程安全生产管理条例》 + type: deterministic +- group: 工期条款 + rules: + - rule_id: GC-005 + name: 工期合理性 + risk: medium + score: 5 + version: 1 + stages: + - id: '1' + check: required + fields: + - 开工日期 + - 竣工日期 + logic: and + - id: '2' + type: date.after + field: 竣工日期 + ref_field: 开工日期 + - id: '3' + check: compare + left: derived.工期天数 + op: '>' + right: 0 + logic: 1 AND 2 AND 3 + messages: + pass: 工期 {{derived.工期天数}} 天合理 + fail: 开工/竣工日期颠倒或工期异常 + type: deterministic +- group: 金额条款 + rules: + - rule_id: GC-006 + name: 质保金比例不超过 3% + risk: medium + score: 5 + version: 1 + stages: + - id: '1' + check: required + field: 质保金比例 + - id: '2' + check: compare + left: 质保金比例 + op: < + right: 0.03 + logic: 1 AND 2 + messages: + pass: 质保金比例 {{质保金比例}} 合规 + fail: 质保金比例超过 3% 上限 + references_laws: + - 《建设工程质量保证金管理办法》第 7 条 + type: deterministic +- group: 招投标合规 + rules: + - rule_id: GC-007 + name: 招投标文件齐全 + risk: high + score: 10 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + fields: + - 招标文件编号 + - 中标通知书编号 + logic: and + logic: '1' + messages: + pass: 招投标文件齐全 + fail: 缺少招标文件或中标通知书编号 + type: deterministic +- group: 印章合规 + rules: + - rule_id: GC-SEAL-001 + name: 双方签章齐全 + risk: high + score: 15 + version: 1 + stages: + - id: '1' + type: seal.present + seal_id: 发包人公章 + - id: '2' + type: seal.present + seal_id: 承包人公章 + - id: '3' + type: seal.text_match + seal_id: 发包人公章 + - id: '4' + type: seal.text_match + seal_id: 承包人公章 + logic: 1 AND 2 AND 3 AND 4 + messages: + pass: 双方签章齐全且文字匹配 + fail: 缺少签章或印章文字与当事人名称不符 + type: deterministic + - rule_id: GC-SEAL-002 + name: 骑缝章完整 + risk: high + score: 10 + version: 1 + stages: + - id: '1' + type: cross_page_seal.complete + seal_id: 骑缝章 + logic: '1' + messages: + pass: 骑缝章完整 + fail: 骑缝章缺失,合同可能被替换页 + type: deterministic +- group: 质量综合 + rules: + - rule_id: GC-GROUP-QUALITY + name: 质量条款综合评查 + risk: high + score: 25 + logic: GC-003 AND GC-004 + messages: + pass: 质量与安全条款完备 + fail: 质量或安全条款有瑕疵 + type: rule_group + rules: + - GC-003 + - GC-004 +- group: 印章综合 + rules: + - rule_id: GC-GROUP-SEAL + name: 印章综合评查 + risk: high + score: 25 + logic: GC-SEAL-001 AND GC-SEAL-002 + messages: + pass: 签章与骑缝章齐全合规 + fail: 印章有瑕疵,合同可能被篡改 + type: rule_group + rules: + - GC-SEAL-001 + - GC-SEAL-002 diff --git a/rules/contract_construction/rules.yaml.bak b/rules/contract_construction/rules.yaml.bak new file mode 100644 index 0000000..1f945ac --- /dev/null +++ b/rules/contract_construction/rules.yaml.bak @@ -0,0 +1,543 @@ +metadata: + type_id: contract.construction.general + name: 建设工程合同 + version: '1.2' + last_updated: '2026-04-11' + parent: contract + inherits_from: + - base.common + - base.party_info + classification_keywords: + - 建设工程 + - 工程承包 + - 施工合同 + - 总承包 + tags: + - compliance + - high_priority + - prc_civil_code + - construction_specific + - safety_critical + applies_to_jurisdictions: + - prc + references_laws: + - 《民法典》第 788-808 条(建设工程合同章) + - 《建筑法》第 25-41 条 + - 《建设工程质量管理条例》 + description: '建设工程施工合同评查规则。 + + 覆盖民法典第 788-808 条(建设工程合同章)。 + + 评查重点:资质核验、金额一致性、质量安全条款、竣工验收。 + + ' + confidence_profile: + allow_weight_override: false + field_confidence_defaults: + 合同金额: 0.95 + 投标价: 0.95 + 中标价: 0.95 +extract: +- group: 当事人 + fields: + - name: 发包人名称 + type: verbatim + required_from: draft + deep_retry: false + - name: 发包人统一信用代码 + type: uscc + required_from: executed + deep_retry: false + - name: 承包人名称 + type: verbatim + required_from: draft + deep_retry: false + - name: 承包人统一信用代码 + type: uscc + required_from: executed + deep_retry: false + - name: 承包人资质等级 + type: enum + required_from: draft + allowed: + - 特级 + - 一级 + - 二级 + - 三级 + deep_retry: false + - name: 承包人资质证书编号 + type: verbatim + required_from: executed + deep_retry: false +- group: 合同基本信息 + fields: + - name: 合同编号 + type: verbatim + required_from: draft + deep_retry: false + - name: 签订日期 + type: date + required_from: executed + deep_retry: false +- group: 项目信息 + fields: + - name: 工程名称 + type: verbatim + required_from: draft + deep_retry: false + - name: 工程地点 + type: verbatim + required_from: draft + deep_retry: false + - name: 工程规模 + type: string + required_from: draft + deep_retry: false + - name: 开工日期 + type: date + required_from: executed + deep_retry: false + - name: 竣工日期 + type: date + required_from: executed + deep_retry: false +- group: 金额(三处一致性检查的核心) + fields: + - name: 合同金额 + type: money + required_from: draft + deep_retry: false + - name: 投标价 + type: money + required_from: draft + deep_retry: false + - name: 中标价 + type: money + required_from: draft + deep_retry: false + - name: 合同金额大写 + type: verbatim + required_from: executed + deep_retry: false +- group: 招投标信息 + fields: + - name: 招标文件编号 + type: verbatim + required_from: draft + deep_retry: false + - name: 中标通知书编号 + type: verbatim + required_from: draft + deep_retry: false +- group: 质量条款 + fields: + - name: 质量标准 + type: string + required_from: draft + deep_retry: false + - name: 质量等级 + type: enum + required_from: draft + allowed: + - 合格 + - 优良 + deep_retry: false + - name: 保修期限 + type: string + required_from: draft + deep_retry: false +- group: 安全条款 + fields: + - name: 安全文明施工要求 + type: string + required_from: draft + deep_retry: false +- group: 工程款支付 + fields: + - name: 预付款比例 + type: money + required_from: draft + deep_retry: false + - name: 进度款支付方式 + type: string + required_from: draft + deep_retry: false + - name: 质保金比例 + type: money + required_from: draft + deep_retry: false +- group: 违约与争议 + fields: + - name: 违约责任 + type: string + required_from: draft + deep_retry: false + - name: 争议解决 + type: string + required_from: draft + deep_retry: false +derived_fields: +- name: 工期天数 + type: integer + compute: (竣工日期 - 开工日期).days + depends_on: + - 开工日期 + - 竣工日期 +- name: 质保金金额 + type: money + compute: 合同金额 * 质保金比例 + depends_on: + - 合同金额 + - 质保金比例 +visual_elements: + seals: + - id: 发包人公章 + name: 发包人公章或合同专用章 + required: true + required_from: executed + allowed_types: + - 公章 + - 合同专用章 + expected_text_match: + field: 发包人名称 + - id: 承包人公章 + name: 承包人公章或合同专用章 + required: true + required_from: executed + allowed_types: + - 公章 + - 合同专用章 + expected_text_match: + field: 承包人名称 + cross_page_seals: + - id: 骑缝章 + name: 建设工程合同骑缝章 + required: true + required_from: executed + expected_text_match: + field: 发包人名称 +rules: +- group: 基础检查 + rules: + - rule_id: GC-000 + name: 基础信息完整性 + risk: high + score: 10 + version: 1 + stages: + - id: '1' + check: required + fields: + - 发包人名称 + - 承包人名称 + - 工程名称 + - 合同金额 + logic: and + logic: '1' + messages: + pass: 基础信息完整 + fail: 缺少发包人/承包人/工程名称/合同金额 + type: deterministic +- group: 主体资质 + rules: + - rule_id: GC-001 + name: 承包人资质合法性 + risk: high + score: 15 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: format + field: 承包人统一信用代码 + format: uscc + - id: '2' + check: required + field: 承包人资质证书编号 + - id: '3' + check: required + field: 承包人资质等级 + logic: 1 AND 2 AND 3 + messages: + pass: 承包人资质信息完整 + fail: 承包人资质信息不完整或 USCC 无效 + references_laws: + - 《建筑法》第 13 条(施工企业资质) + type: deterministic +- group: 金额合规 + rules: + - rule_id: GC-002 + name: 金额三处一致性 + risk: high + score: 20 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + fields: + - 合同金额 + - 投标价 + - 中标价 + logic: and + - id: '2' + check: match + pairs: + - source: 合同金额 + target: 中标价 + method: exact + - source: 中标价 + target: 投标价 + method: exact + logic: 1 AND 2 + messages: + pass: 合同金额与投标价、中标价一致 + fail: 合同金额与投标价/中标价不一致,涉嫌虚假招标 + references_laws: + - 《招标投标法》第 46 条(不得背离实质性内容订立合同) + - 《招标投标法实施条例》第 57 条 + remediation: + suggestions: + - 合同金额 {{合同金额}} / 中标价 {{中标价}} / 投标价 {{投标价}} + - 三者应完全一致。不一致时涉嫌"阴阳合同"或变相抬价 + - 建议立即核对招标文件原件 + actions: + - type: upload_file + label: 上传招标文件原件 + file_type: 招标文件 + accept: + - pdf + - type: escalate + label: 涉嫌阴阳合同,上报合规 + role: 合规专员 + type: deterministic +- group: 质量条款 + rules: + - rule_id: GC-003 + name: 质量标准明确性 + risk: high + score: 10 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + field: 质量标准 + - id: '2' + type: string.min_length + field: 质量标准 + min: 30 + - id: '3' + check: contains + field: 质量标准 + any_of: + - GB 50 + - GB/T + - 合格 + - 优良 + - 现行国家标准 + logic: 1 AND 2 AND 3 + messages: + pass: 质量标准明确 + fail: 质量标准过于简略或未引用具体标准 + references_laws: + - 《民法典》第 802 条 + - 《建设工程质量管理条例》第 14 条 + type: deterministic + - rule_id: GC-OLD-003 + name: 旧版质量标准检查 + risk: medium + score: 5 + version: 1 + stages: + - id: '1' + check: required + field: 质量标准 + logic: '1' + messages: + pass: 有质量条款(注意:本规则已弃用,请使用 GC-003) + fail: 缺少质量条款 + type: deterministic + deprecated: + since: '2025-06-01' + replacement: GC-003 + reason: '旧版仅检查质量条款存在性,不检查标准引用的具体性。 + + GC-003 增加了对 GB/GB-T 国标引用的要求。 + + ' +- group: 安全条款 + rules: + - rule_id: GC-004 + name: 安全文明施工条款完备性 + risk: high + score: 15 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + field: 安全文明施工要求 + - id: '2' + type: string.min_length + field: 安全文明施工要求 + min: 50 + - id: '3' + check: contains + field: 安全文明施工要求 + all_of: + - 三宝四口五临边 + - 安全帽 + - 扬尘 + - 噪音 + logic: 1 AND 2 AND 3 + messages: + pass: 安全文明施工条款完备 + fail: 安全文明施工条款不完备,缺少关键要素 + references_laws: + - 《建筑法》第 36-41 条 + - 《建设工程安全生产管理条例》 + type: deterministic +- group: 工期条款 + rules: + - rule_id: GC-005 + name: 工期合理性 + risk: medium + score: 5 + version: 1 + stages: + - id: '1' + check: required + fields: + - 开工日期 + - 竣工日期 + logic: and + - id: '2' + type: date.after + field: 竣工日期 + ref_field: 开工日期 + - id: '3' + check: compare + left: derived.工期天数 + op: '>' + right: 0 + logic: 1 AND 2 AND 3 + messages: + pass: 工期 {{derived.工期天数}} 天合理 + fail: 开工/竣工日期颠倒或工期异常 + type: deterministic +- group: 金额条款 + rules: + - rule_id: GC-006 + name: 质保金比例不超过 3% + risk: medium + score: 5 + version: 1 + stages: + - id: '1' + check: required + field: 质保金比例 + - id: '2' + check: compare + left: 质保金比例 + op: < + right: 0.03 + logic: 1 AND 2 + messages: + pass: 质保金比例 {{质保金比例}} 合规 + fail: 质保金比例超过 3% 上限 + references_laws: + - 《建设工程质量保证金管理办法》第 7 条 + type: deterministic +- group: 招投标合规 + rules: + - rule_id: GC-007 + name: 招投标文件齐全 + risk: high + score: 10 + version: 1 + depends_on: + - when: GC-000.passed + stages: + - id: '1' + check: required + fields: + - 招标文件编号 + - 中标通知书编号 + logic: and + logic: '1' + messages: + pass: 招投标文件齐全 + fail: 缺少招标文件或中标通知书编号 + type: deterministic +- group: 印章合规 + rules: + - rule_id: GC-SEAL-001 + name: 双方签章齐全 + risk: high + score: 15 + version: 1 + stages: + - id: '1' + type: seal.present + seal_id: 发包人公章 + - id: '2' + type: seal.present + seal_id: 承包人公章 + - id: '3' + type: seal.text_match + seal_id: 发包人公章 + - id: '4' + type: seal.text_match + seal_id: 承包人公章 + logic: 1 AND 2 AND 3 AND 4 + messages: + pass: 双方签章齐全且文字匹配 + fail: 缺少签章或印章文字与当事人名称不符 + type: deterministic + - rule_id: GC-SEAL-002 + name: 骑缝章完整 + risk: high + score: 10 + version: 1 + stages: + - id: '1' + type: cross_page_seal.complete + seal_id: 骑缝章 + logic: '1' + messages: + pass: 骑缝章完整 + fail: 骑缝章缺失,合同可能被替换页 + type: deterministic +- group: 质量综合 + rules: + - rule_id: GC-GROUP-QUALITY + name: 质量条款综合评查 + risk: high + score: 25 + logic: GC-003 AND GC-004 + messages: + pass: 质量与安全条款完备 + fail: 质量或安全条款有瑕疵 + type: rule_group + rules: + - GC-003 + - GC-004 +- group: 印章综合 + rules: + - rule_id: GC-GROUP-SEAL + name: 印章综合评查 + risk: high + score: 25 + logic: GC-SEAL-001 AND GC-SEAL-002 + messages: + pass: 签章与骑缝章齐全合规 + fail: 印章有瑕疵,合同可能被篡改 + type: rule_group + rules: + - GC-SEAL-001 + - GC-SEAL-002 diff --git a/rules/contract_entrust/docs/test_middle.md b/rules/contract_entrust/docs/test_middle.md new file mode 100644 index 0000000..11e01ba --- /dev/null +++ b/rules/contract_entrust/docs/test_middle.md @@ -0,0 +1,75 @@ +# 杭州锦绣科技园2025年度物业管理服务委托合同 + +合同编号:MY-WT-2025-0036 + +甲方���委托方):杭州锦绣科技园发展有限公司 +法定���表人:周永安 +地址:浙江省杭州市余杭区文一西路998号 +联系人:赵敏 +联系电���:0571-88925678 +统一社会信用代码:91330110MA2B3N6K4W +开��银行:中国工商银行杭州余杭支行 +银行账���:1202026309900182345 + +乙方(受托方):���州明远物业管理有限公司 +法定代表人:林志强 +地址:浙江省杭州市西湖区教工路56号 +联系电话:0571-87654321 +统一社会信用代码:91330106752938156A + +根据《中华人民共和国民法典》及相关法律法规,甲乙双方就物业管理服务事宜达成如下协议。 + +## 一、委托事项 + +甲方委托乙方对锦绣科技园提供综合物业管理服务,包括: +1. 公共区域日常保洁 +2. 安保巡逻值班 +3. 设备设施维护保养 +4. 停车场管理 + +具体服务标准参照行业规范执行。 + +## 二、服务期限 + +2025年4月1日至2026年3月31日。 + +## 三、合同金额 + +本合同总金额为人民币壹佰贰拾捌万元整(���1280000.00元)。 + +服务项目明细: +1. 保洁服务,12个月×32000元/月 = 384000元 +2. 安保服务,12个月×45000元/月 = 540000元 +3. 设备维护,12个月×18000元/月 = 216000元 +4. 停车场管理,12个月×11666.67元/月 = 140000元 +合计:1280000元 + +## 四、付款方式 + +甲方按季度支付服务费,每季度首月15日前以银行转账方式支付当季服务费320000元。 + +## 五、违约责任 + +1. 乙方服务不达标的,甲方有权扣减服务费。 +2. 甲方逾期付款的,应承担违约责任。 +3. 因乙方原因造成重大安全事故的,乙方应赔偿损失。 + +## 六、争议解决 + +本合同履行过程中发生争议的,双方应首先友好协商解决;协商不成的,任何一方均可向杭州市余杭区人民法院��起诉讼。 + +## 七、不可抗力 + +因不可抗力导致合同不能履行的,双方互不承担违约责任。遭受不可抗力的一方应及时通知对方。 + +## 八、合同解除 + +甲乙双方均可提前解除本合同,但应提前30日书面通知对方。 + +签约日期:2025年3月15日 + +甲方(盖章):杭州锦绣科技园发展��限公司 +法定代表人:周永安 + +乙方(盖章):���州明远物业管理有限公司 +法定代��人:林志强 diff --git a/rules/contract_entrust/docs/test_negative.md b/rules/contract_entrust/docs/test_negative.md new file mode 100644 index 0000000..89ef49a --- /dev/null +++ b/rules/contract_entrust/docs/test_negative.md @@ -0,0 +1,30 @@ +# 服务合同 + +甲方:锦绣公司 + +乙方:明远公司 + +双方就委托服务事宜达成如下协议。 + +## 一、委托事项 + +甲方委托乙方提供相关服务。 + +## 二、合同金额 + +本合同总金额为人民币壹佰万元整(¥128000.00元)。 + +## 三、付款方式 + +按照双方约定付款。 + +## 四、违约责任 + +如有违约,按照民法典相关规定处理。 + +## 五、争议解决 + +双方发生争议的,友好协商解决。 + +甲方(盖章): +乙方(盖章): diff --git a/rules/contract_entrust/docs/test_positive.md b/rules/contract_entrust/docs/test_positive.md new file mode 100644 index 0000000..692d81e --- /dev/null +++ b/rules/contract_entrust/docs/test_positive.md @@ -0,0 +1,115 @@ +# 杭州明远物业管理有限公司物业管理服务委托合同 + +合同名称:2025年度综合物业管理服务委托合同 + +合同编号:MY-WT-2025-0036 + +甲方(委托方):杭州锦绣科技园发展有限公司 +法定代表人:周永安 +地址:浙江省杭州市余杭区文一西路998号锦绣科技园A座18楼 +联系人:赵敏 +联系电话:0571-88925678 +统一社会信用代码:91330110MA2B3N6K4W +开户银行:中国工商银行杭州余杭支行 +银行账号:1202026309900182345 + +乙方(受托方):杭州明远物业管理有限公司 +法定代表人:林志强 +地址:浙江省杭州市西湖区教工路56号明远大厦5楼 +联系人:陈晓红 +联系电话:0571-87654321 +统一社会信用代码:91330106752938156U + +根据《中华人民共和国民法典》及其他相关法律法规的规定,甲乙双方在平等、自愿、公平、诚实信用的基础上,就甲方委托乙方提供物业管理服务事宜达成如下协议。 + +## 一、委托事项 + +甲方委托乙方对锦绣科技园(以下简称"园区")提供综合物业管理服务。本合同为特别委托,委托事项仅限于本合同约定的服务内容,不包括其他事项。 + +服务内容包括: +1. 公共区域日常保洁服务:园区公共区域(大堂、走廊、电梯间、卫生间、地下车库、室外道路及绿化带)的日常保洁和定期深度清洁,保洁频次为每日至少2次,绿化带每周养护1次。 +2. 安保巡逻服务:园区24小时安保值班,每2小时巡逻1次,门岗登记管理,监控室24小时值守,每班配备安保人员不少于3人。 +3. 设备设施维护服务:电梯、空调系统、消防设施、给排水系统的日常巡检和维护保养,巡检频次为电梯每日1次、空调系统每周1次、消防设施每月1次、给排水系统每月1次。 +4. 停车场管理服务:地下停车场出入口管理、车位引导、收费管理,配备智能停车管理系统。 + +服务标准:乙方应按照GB/T 20647.9-2006《社区服务指南 第9部分:物业服务》及杭州市物业管理相关规定执行,服务满意度调查评分不得低于85分(满分100分)。 + +## 二、服务期限 + +服务期限自2025年4月1日起至2026年3月31日止,为期一年。 + +## 三、合同金额 + +本合同总金额为人民币壹佰贰拾捌万元整(¥1280000.00元)。 + +服务项目明细如下: +1. 公共区域日常保洁服务,12个月,单价32000元/月,合计384000.00元 +2. 安保巡逻服务,12个月,单价45000元/月,合计540000.00元 +3. 设备设施维护服务,12个月,单价18000元/月,合计216000.00元 +4. 停车场管理服务,12个月,单价11666.67元/月,合计140000.00元 + +以上四项合计1280000.00元,与合同总金额一致。 + +## 四、付款方式 + +1. 第一期付款:合同签订生效后10个工作日内,甲方向乙方支付合同总额的25%,即人民币320000.00元,作为首季度预付服务费。 +2. 后续付款:自第二季度起,甲方于每季度首月10日前支付当季服务费(合同总额的25%,即320000.00元),乙方开具等额增值税专用发票。 +3. 付款方式:银行转账至乙方指定账户。 +4. 如甲方对乙方当季服务质量有异议,应在付款日前5个工作日书面提出,双方协商确定扣减金额后付款。 + +## 五、转委托 + +乙方应当亲自完成本合同约定的全部服务内容,配备专业物业管理团队。未经甲方书面同意,乙方不得将本合同委托事项的全部或部分转委托第三方。如确需将部分专业服务(如电梯维保等)分包给第三方的,应事先书面征得甲方同意,并由乙方对第三方的服务质量承担连带责任。转委托不免除乙方在本合同项下的任何义务。 + +## 六、报告义务 + +1. 月度报告:乙方应于每月5日前向甲方提交上月《物业服务月度报告》,包括服务完成情况、巡检记录、维修记录、安全事件记录、费用支出明细等。报告以书面形式提交,同时发送电子版至甲方指定邮箱。 +2. 季度会议:每季度末,乙方应组织一次服务总结会议,向甲方汇报本季度服务情况、存在问题及改进措施。 +3. 年度总结:服务期满前30日,乙方应提交年度服务总结报告,包含全年服务数据汇总、满意度调查结果、设备设施状况评估及下一年度服务改进建议。 +4. 紧急报告:发生安全事故、设备重大故障等紧急情况时,乙方应在2小时内电话报告甲方,并在24小时内提交书面报告。 + +## 七、成果交付与验收 + +1. 服务成果形式:乙方按月提交《物业服务月度报告》作为服务成果凭证,包含各项服务的完成情况记录、巡检表、维修工单和服务照片等。 +2. 验收标准:甲方依据本合同第一条约定的服务标准和GB/T 20647.9-2006标准,对乙方服务进行考核。每季度开展一次满意度调查,调查对象为园区入驻企业。 +3. 验收方式:每季度末由甲方物业管理部门组织验收评分,双方签署《季度服务验收确认书》。验收评分低于85分的,甲方有权要求乙方在15日内整改并复验。 + +## 八、违约责任 + +1. 乙方未按合同约定标准提供服务的,甲方有权按以下标准扣减服务费:季度满意度评分低于85分但不低于70分的,扣减当季服务费的5%;低于70分但不低于60分的,扣减当季服务费的15%;低于60分的,甲方有权解除合同。 +2. 乙方擅自将委托事项转委托第三方的,甲方有权解除合同,并要求乙方支付合同总额10%的违约金。 +3. 甲方逾期付款的,每逾期一日,应向乙方支付逾期金额万分之五的违约金(年化不超过逾期金额的18%);逾期超过30日的,乙方有权暂停服务并要求甲方支付逾期金额3%的违约金。 +4. 因乙方管理不善导致园区发生重大安全事故(造成人员伤亡或财产损失超过10万元的),乙方应赔偿甲方的直接经济损失,并支付合同总额5%的违约金。 +5. 任何一方违反保密义务的,应向对方支付合同总额5%的违约金,并赔偿因此造成的全部损失。 + +## 九、争议解决 + +本合同履行过程中发生争议的,双方应首先友好协商解决;协商不成的,任何一方均可向杭州市余杭区人民法院提起诉讼。 + +## 十、不可抗力 + +1. 不可抗力是指不能预见、不能避免且不能克服的客观事件,包括但不限于自然灾害(地震、洪水、台风等)、社会事件(战争、骚乱等)、政府行为(征收、禁令等)和公共卫生事件(重大疫情等)。 +2. 因不可抗力导致合同全部或部分不能履行的,遭受不可抗力的一方应在不可抗力事件发生后3日内书面通知对方,并在10日内提供不可抗力证明文件(政府部门或公证机构出具的证明)。 +3. 因不可抗力导致合同不能履行的,根据不可抗力的影响程度部分或全部免除责任,但遭受不可抗力的一方应采取合理措施减少损失。不可抗力事件持续超过60日的,任何一方有权书面通知对方解除合同。 + +## 十一、保密条款 + +1. 保密信息范围:双方因履行本合同而知悉的对方商业秘密、技术信息、财务数据、客户信息、管理制度及其他标注为「保密」的信息均属保密信息。 +2. 保密期限:保密义务自本合同签订之日起生效,至本合同终止后2年内仍然有效。 +3. 违反保密义务的,违约方应按本合同第八条第5款承担违约责任。 + +## 十二、合同解除 + +1. 任意解除权:依据《民法典》第九百三十三条,委托人或受托人均可以随时解除本合同。行使任意解除权的一方应提前30日以书面方式通知对方。 +2. 费用结算:合同解除后,已完成服务部分的费用按实际完成月数和本合同约定的月单价进行结算。甲方应在解除后15个工作日内支付已完成服务的费用,乙方应退还已收取但未提供服务部分的费用。 +3. 损害赔偿:因解除合同给对方造成损失的,除不可归责于该当事人的事由以外,应当赔偿损失。 + +本合同一式四份,甲乙双方各执两份,均具有同等法律效力。 + +签约日期:2025年3月15日 + +甲方(盖章):杭州锦绣科技园发展有限公司 +法定代表人或授权代表(签字):周永安 + +乙方(盖章):杭州明远物业管理有限公司 +法定代表人或授权代表(签字):林志强 diff --git a/rules/contract_entrust/rules.yaml b/rules/contract_entrust/rules.yaml new file mode 100644 index 0000000..3abacb4 --- /dev/null +++ b/rules/contract_entrust/rules.yaml @@ -0,0 +1,1489 @@ +metadata: + type_id: contract.entrust + name: 通用委托合同 + version: '2.0' + last_updated: '2026-04-14' + tags: + - 合同 + - 委托 + - 服务 + - 评估 + - 代理 + references_laws: + - 《民法典》第四百六十七条 + - 《民法典》第四百七十条 + - 《民法典》第四百九十条 + - 《民法典》第九百一十九条至第九百三十六条 + description: '依据《中华人民共和国民法典》合同编·通则(第467、470、490条)及委托合同章(第919-936条)。 + + 适用于评估、代理、咨询、查新等服务类委托合同的评查。 + + 覆盖签署前审查(draft)和签署后审计(executed)两个阶段。 + + 基于旧系统 00_通用规则.json + 02_委托合同.json 合并、去重、委托场景校准而成(38→33 条)。 + + ' +extract: +- group: 合同成立要素 — draft 必需 + fields: + - name: 合同名称 + type: verbatim + required_from: draft + desc: 合同标题/项目名称 + deep_retry: false + - name: 委托方 + type: verbatim + required_from: draft + desc: 委托方(甲方)全称 + deep_retry: false + - name: 受托人 + type: verbatim + required_from: draft + desc: 受托人(乙方)全称 + deep_retry: false + - name: 委托事项 + type: string + required_from: draft + desc: 委托事项内容的完整描述:委托做什么(评估/代理/查新/咨询等)、服务范围、服务标准 + deep_retry: false + - name: 服务范围 + type: string + required_from: draft + desc: 具体服务范围界定(如评估对象、代理事务类型、查新课题等) + deep_retry: false + - name: 服务标准 + type: string + required_from: draft + desc: 服务完成的标准/规范依据(国家标准、行业标准、技术规程等) + deep_retry: false + - name: 服务费金额 + type: money + required_from: draft + desc: 服务费/委托费的数字总金额 + deep_retry: true + - name: 服务费金额大写 + type: verbatim + required_from: draft + desc: 服务费的中文大写金额 + deep_retry: false + - name: 服务费计算方式 + type: string + required_from: draft + desc: 服务费的计算方式(一次性/分期/按项目/按工时等) + deep_retry: false + - name: 服务起始日期 + type: date + required_from: draft + desc: 委托事项开始执行的日期 + deep_retry: false + - name: 服务结束日期 + type: date + required_from: draft + desc: 委托事项完成/合同终止的日期 + deep_retry: false + - name: 付款方式 + type: string + required_from: draft + desc: 付款周期、方式、时间节点、逾期处理的完整描述 + deep_retry: false +- group: 主体资格信息 — draft 必需 + fields: + - name: 委托方证件号 + type: verbatim + required_from: draft + desc: 委托方身份证号(个人)或统一社会信用代码(单位) + deep_retry: false + - name: 受托人统一社会信用代码 + type: verbatim + required_from: executed + desc: 受托人 18 位 USCC(单位受托人)。签署阶段必填,draft 阶段可为空。 + deep_retry: false + - name: 委托方地址 + type: verbatim + required_from: draft + desc: 委托方住址或注册地址 + deep_retry: false + - name: 受托人地址 + type: verbatim + required_from: draft + desc: 受托人住址或注册地址 + deep_retry: false + - name: 委托方法定代表人 + type: verbatim + required_from: draft + desc: 委托方法定代表人或负责人姓名(单位) + deep_retry: false + - name: 受托人法定代表人 + type: verbatim + required_from: draft + desc: 受托人法定代表人或负责人姓名 + deep_retry: false + - name: 受托人资质信息 + type: string + required_from: draft + desc: 受托人从事委托事项所需的资质、许可或专业资格(如评估师资格、代理资格等) + deep_retry: false +- group: 履约核心条款 — draft 必需 + fields: + - name: 交付方式 + type: string + required_from: draft + desc: 服务成果的交付方式、时间、形式等约定(评估报告、查新报告、代理文件等) + deep_retry: false + - name: 服务成果形式 + type: string + required_from: draft + desc: 服务成果的具体形式(书面报告/电子文档/意见书等)及交付数量 + deep_retry: false + - name: 验收方式 + type: string + required_from: draft + desc: 服务成果的验收流程、验收标准、异议处理方式 + deep_retry: false + - name: 报告义务条款 + type: string + required_from: draft + desc: 受托人的报告义务:报告方式、报告周期、报告内容等 + deep_retry: false + - name: 转委托条款 + type: string + required_from: draft + desc: 转委托相关约定:是否允许、经委托人同意的条件等 + deep_retry: false + - name: 履行地点 + type: verbatim + required_from: draft + desc: 服务履行地点(评估现场、代理事务地点等) + deep_retry: false +- group: 法定/必备条款 — draft 必需 + fields: + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约责任的完整条款内容(双方违约情形和责任) + deep_retry: false + - name: 违约金金额 + type: money + required_from: draft + desc: 违约金具体金额或计算基数 + deep_retry: false + - name: 违约金计算方式 + type: string + required_from: draft + desc: 违约金计算标准(固定金额/比例/按日计算等) + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式的完整条款(协商/诉讼/仲裁) + deep_retry: false + - name: 管辖机构 + type: verbatim + required_from: draft + desc: 指定的法院或仲裁机构名称 + deep_retry: false + - name: 不可抗力条款 + type: string + required_from: draft + desc: 不可抗力定义、通知义务、免责约定的完整条款 + deep_retry: false + - name: 变更解除终止条款 + type: string + required_from: draft + desc: 合同变更、解除、终止的条件和程序 + deep_retry: false + - name: 任意解除权条款 + type: string + required_from: draft + desc: 民法典§933 委托人或受托人任意解除合同的约定及解除后已完成服务的费用结算方式 + deep_retry: false + - name: 生效条件 + type: string + required_from: draft + desc: 合同生效条件(签字盖章、经批准等) + deep_retry: false +- group: 合规性辅助字段 — draft + fields: + - name: 签约背景 + type: string + required_from: draft + desc: 合同签约背景/缘由(如招标、协商过程、签约原因等开篇段落) + deep_retry: false + - name: 引用法律法规 + type: string + required_from: draft + desc: 合同引用的法律、法规、规章、技术标准的列表 + deep_retry: false +- group: 附件与补充 — draft + fields: + - name: 附件列表 + type: string + required_from: draft + desc: 合同附件的序号、名称、类型的列表(可能含服务项目清单) + deep_retry: false + - name: 服务项目清单 + type: string + required_from: draft + desc: 服务项目明细清单:各项服务名称、单价、数量、金额的完整内容 + deep_retry: false + - name: 补充协议条款 + type: string + required_from: draft + desc: 未尽事宜补充、补充协议效力等约定 + deep_retry: false +- group: '签署要素 — required_from: executed' + fields: + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 签约地点 + type: verbatim + required_from: executed + desc: 合同签订地点 + deep_retry: false + - name: 合同编号 + type: verbatim + required_from: executed + desc: 合同唯一编号 + deep_retry: false + - name: 合同份数 + type: integer + required_from: executed + desc: 合同正本份数 + deep_retry: false + - name: 收款方开户银行 + type: verbatim + required_from: executed + desc: 收款方(通常为受托人)银行开户行全称 + deep_retry: false + - name: 收款方银行账号 + type: verbatim + required_from: executed + desc: 收款方银行账号 + deep_retry: false + - name: 收款方账户名称 + type: verbatim + required_from: executed + desc: 收款方账户名称(与受托人主体一致) + deep_retry: false +- group: 税务信息 — draft + fields: + - name: 服务费是否含税 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: 服务费金额是否已包含税费。填"是":合同中明确"含税"或"费用已包含税费";填"否":另行约定税费分担或未说明。 + deep_retry: false +- group: 保密条款(条件激活规则使用) + fields: + - name: 保密条款 + type: string + required_from: draft + desc: 保密条款的完整内容:保密信息范围、保密期限、违约责任 + deep_retry: false +- group: 辅助信息(不做存在性检查,用于交叉校验) + fields: + - name: 委托方联系电话 + type: verbatim + required_from: draft + desc: 委托方联系电话 + deep_retry: false + - name: 受托人联系电话 + type: verbatim + required_from: draft + desc: 受托人联系电话 + deep_retry: false +- group: 合同特征分类字段(控制条件激活) + fields: + - name: 涉及保密信息 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否涉及商业秘密、技术秘密、客户信息等保密要求。 填"是"的条件:出现"保密""商业秘密""技术秘密""客户隐私""非公开资料"等关键词且有实质条款。 填"否"的条件:普通评估/代理等无保密性服务,或仅有通用条款不成实质。 + + ' + deep_retry: false + - name: 允许转委托 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否允许受托人将部分事务转委托给第三方处理。 填"是"的条件:明确约定"经委托人同意可转委托""可分包"等。 填"否"的条件:明确禁止转委托,或未提及转委托(默认不允许)。 + + ' + deep_retry: false + - name: 含服务项目清单 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同是否包含服务项目清单(含单价×数量拆分)。 填"是"的条件:附件或正文中有"服务清单""项目明细""费用明细"且有单价数量拆分。 填"否"的条件:只有一个总服务费金额,无拆分明细。 + + ' + deep_retry: false +visual_elements: + seals: + - id: 委托方签章 + name: 委托方签字或公章 + required: true + required_from: executed + - id: 受托人签章 + name: 受托人签字或公章 + required: true + required_from: executed + cross_page_seals: + - id: 骑缝章 + name: 合同骑缝章 + required: true + required_from: executed +rules: +- group: 完整性(17 条) + rules: + - rule_id: MM-ENT-001 + name: 当事人信息齐全 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 委托方 + - id: '2' + check: required + field: 受托人 + messages: + pass: 委托方和受托人信息齐全 + fail: 缺少委托方或受托人信息 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-ENT-002 + name: 当事人信息准确完整 + risk: high + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查合同当事人(委托方和受托人)的信息是否准确完整。 + + + 委托方:{{委托方}} + + 委托方法代:{{委托方法定代表人}} + + 委托方地址:{{委托方地址}} + + 委托方电话:{{委托方联系电话}} + + 委托方证件号:{{委托方证件号}} + + + 受托人:{{受托人}} + + 受托人法代:{{受托人法定代表人}} + + 受托人地址:{{受托人地址}} + + 受托人电话:{{受托人联系电话}} + + 受托人USCC:{{受托人统一社会信用代码}} + + + 评查要点: + + 1. 双方主体名称是否清晰可辨(个人为姓名,单位为公司名) + + 2. 委托方为个人时是否有身份证号;委托方为单位时是否有 USCC + + 3. 受托人为单位时是否有法定代表人 + + 4. 双方联系地址和电话是否齐全 + + + 特别说明:受托人统一社会信用代码属于签署阶段(executed)字段, + + 在草稿阶段(draft)合同模板中为空是正常情况,不作为判 fail 依据。 + + + 法规依据:民法典§470 + + ' + messages: + pass: 当事人信息准确完整 + fail: 当事人信息有缺失或不准确 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-ENT-003 + name: 委托事项明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 委托事项 + - id: '2' + check: ai + prompt: '请检查委托事项是否明确。 + + + 委托事项:{{委托事项}} + + 服务范围:{{服务范围}} + + 服务标准:{{服务标准}} + + + 评查要点: + + 1. 是否明确了委托内容(如评估、代理、查新、咨询等具体事项) + + 2. 服务范围是否具体(评估对象/代理事务范围/查新课题等) + + 3. 是否明确了服务标准(国标、行标、技术规程等) + + 4. 是否区分了特别委托和概括委托 + + 5. 委托事项是否合法且明确,不应使用模糊表述 + + + 法规依据:民法典§919、§920 + + ' + logic: 1 AND 2 + messages: + pass: 委托事项明确 + fail: 委托事项不明确或缺失 + references_laws: + - 《民法典》第九百一十九条 + - 《民法典》第九百二十条 + type: ai_rule + - rule_id: MM-ENT-004 + name: 服务期限明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 服务起始日期 + - id: '2' + check: required + field: 服务结束日期 + messages: + pass: 服务期限起止日期齐全 + fail: 缺少服务起止日期 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-ENT-005 + name: 服务费金额完整 + risk: high + score: 3 + stages: + - id: '1' + check: required + field: 服务费金额 + - id: '2' + check: required + field: 服务费金额大写 + - id: '3' + check: amount_match + number: 服务费金额 + chinese: 服务费金额大写 + logic: 1 AND 2 AND 3 + messages: + pass: 服务费金额完整且大小写一致 + fail: 服务费金额缺失或大小写不一致 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-ENT-006 + name: 付款条款完整 + risk: high + score: 4 + stages: + - id: '1' + check: required + field: 付款方式 + - id: '2' + check: ai + prompt: '请检查付款条款是否完整。 + + + 付款方式:{{付款方式}} + + 服务费计算方式:{{服务费计算方式}} + + 收款方开户银行:{{收款方开户银行}} + + 收款方银行账号:{{收款方银行账号}} + + + 评查要点: + + 1. 支付方式是否明确(银行转账、现金等) + + 2. 支付周期/节点是否明确(一次性、分期、按里程碑等) + + 3. 是否约定了逾期支付的后果(滞纳金、解除权等) + + 4. 付款账户信息是否完整(开户行、账号、户名) + + + 法规依据:民法典§928 + + ' + logic: 1 AND 2 + messages: + pass: 付款条款完整 + fail: 付款条款不完整 + references_laws: + - 《民法典》第九百二十八条 + type: ai_rule + - rule_id: MM-ENT-007 + name: 合同地点具体准确 + risk: medium + score: 5 + stages: + - id: '1' + check: ai + prompt: '请检查合同地点信息是否具体准确。 + + + 履行地点:{{履行地点}} + + 签约地点:{{签约地点}} + + 委托方地址:{{委托方地址}} + + 受托人地址:{{受托人地址}} + + + 评查要点: + + 1. 服务履行地点是否具体(评估现场/代理事务办理地等) + + 2. 签约地点是否明确 + + 3. 双方地址是否完整可供送达 + + + 法规依据:民法典§470 + + ' + messages: + pass: 合同地点信息具体准确 + fail: 合同地点信息不具体或缺失 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-ENT-008 + name: 报告义务条款 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 报告义务条款 + - id: '2' + check: ai + prompt: '请检查受托人的报告义务条款是否明确。 + + + 报告义务条款:{{报告义务条款}} + + + 评查要点: + + 1. 是否约定了受托人向委托人的报告义务 + + 2. 报告方式是否明确(书面/口头/电子等) + + 3. 报告周期/时点是否明确(阶段性报告、事项完成后报告等) + + 4. 报告内容要求是否明确(进度、困难、结果等) + + 5. 异常情况的特别报告义务是否有约定 + + + 法规依据:民法典§927 + + ' + logic: 1 AND 2 + messages: + pass: 报告义务条款完整 + fail: 报告义务条款缺失或不完整 + references_laws: + - 《民法典》第九百二十七条 + type: ai_rule + - rule_id: MM-ENT-009 + name: 服务成果交付与验收 + risk: high + score: 3 + stages: + - id: '1' + check: required + field: 交付方式 + - id: '2' + check: ai + prompt: '请检查服务成果交付与验收条款是否完整。 + + + 交付方式:{{交付方式}} + + 服务成果形式:{{服务成果形式}} + + 验收方式:{{验收方式}} + + + 评查要点: + + 1. 服务成果的具体形式是否明确(评估报告、查新报告、代理文件等) + + 2. 交付时间和方式是否明确 + + 3. 是否约定了完成标准/验收标准 + + 4. 是否约定了验收程序和异议处理方式 + + 5. 验收通过的时点和依据是否明确 + + + 法规依据:民法典§929 + + ' + logic: 1 AND 2 + messages: + pass: 服务成果交付与验收条款完整 + fail: 交付或验收条款缺失或不完整 + references_laws: + - 《民法典》第九百二十九条 + type: ai_rule + - rule_id: MM-ENT-010 + name: 任意解除权与费用结算 + risk: high + score: 3 + stages: + - id: '1' + check: required + field: 任意解除权条款 + - id: '2' + check: ai + prompt: '请检查委托合同特有的任意解除权及费用结算条款是否明确。 + + + 任意解除权条款:{{任意解除权条款}} + + 变更解除终止条款:{{变更解除终止条款}} + + + 评查要点(民法典§933): + + 1. 是否明确了委托人或受托人的任意解除权(委托合同特有) + + 2. 任意解除是否约定通知方式和提前期限 + + 3. 解除后已完成服务的费用结算方式是否明确 + + 4. 是否约定因任意解除造成损失的赔偿范围 + + + 法规依据:民法典§933 + + ' + logic: 1 AND 2 + messages: + pass: 任意解除权与费用结算条款完整 + fail: 任意解除权条款缺失或费用结算不明 + references_laws: + - 《民法典》第九百三十三条 + type: ai_rule + - rule_id: MM-ENT-011 + name: 违约责任形式明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请检查违约责任条款是否形式明确。 + + + 违约责任条款:{{违约责任条款}} + + + 评查要点: + + 1. 是否明确了违约方和违约情形 + + 2. 责任形式是否具体(支付违约金、赔偿损失、继续履行等) + + 3. 是否覆盖双方(委托方违约和受托人违约均有约定) + + 4. 是否有兜底条款 + + + 法规依据:民法典§577 + + ' + logic: 1 AND 2 + messages: + pass: 违约责任形式明确 + fail: 违约责任形式不明确或缺失 + references_laws: + - 《民法典》第五百七十七条 + type: ai_rule + - rule_id: MM-ENT-012 + name: 违约金条款完整合理 + risk: high + score: 7 + stages: + - id: '1' + check: required + field: 违约金金额 + - id: '2' + check: ai + prompt: '请检查违约金条款是否完整合理。 + + + 违约金金额:{{违约金金额}} + + 违约金计算方式:{{违约金计算方式}} + + 违约责任条款:{{违约责任条款}} + + 服务费金额:{{服务费金额}} + + + 评查要点: + + 1. 违约金金额或计算方式是否明确 + + 2. 违约金标准是否合理(约定过高可依法调整,一般不超过造成损失的 30%) + + 3. 是否覆盖双方违约情形 + + 4. 是否区分根本违约和一般违约的责任差异 + + + 法规依据:民法典§585 + + ' + logic: 1 AND 2 + messages: + pass: 违约金条款完整合理 + fail: 违约金条款不完整或标准不合理 + references_laws: + - 《民法典》第五百八十五条 + type: ai_rule + - rule_id: MM-ENT-013 + name: 争议解决方式明确 + risk: high + score: 4 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请检查争议解决方式是否明确。 + + + 争议解决条款:{{争议解决条款}} + + 管辖机构:{{管辖机构}} + + + 评查要点: + + 1. 是否明确了争议解决方式(协商/诉讼/仲裁,只能择一作为最终方式) + + 2. 不能同时约定仲裁和诉讼(互斥) + + 3. 如约定诉讼,是否指定了具体的管辖法院 + + 4. 如约定仲裁,是否指定了具体的仲裁机构 + + + 法规依据:民法典§470 + + ' + logic: 1 AND 2 + messages: + pass: 争议解决方式明确 + fail: 争议解决方式不明确或约定冲突 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-ENT-014 + name: 不可抗力条款完整性 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 不可抗力条款 + - id: '2' + check: ai + prompt: '请检查不可抗力条款是否完整(三要素)。 + + + 不可抗力条款:{{不可抗力条款}} + + + 评查要点(三要素): + + 1. 是否明确了不可抗力的定义/类型范围 + + 2. 是否约定了通知义务和通知时限 + + 3. 是否约定了免责后果和合同处理方式(如延期履行、解除合同等) + + + 法规依据:民法典§180、§590 + + ' + logic: 1 AND 2 + messages: + pass: 不可抗力条款完整 + fail: 不可抗力条款缺失或要素不全 + references_laws: + - 《民法典》第一百八十条 + - 《民法典》第五百九十条 + type: ai_rule + - rule_id: MM-ENT-015 + name: 变更解除终止条款完整性 + risk: high + score: 5 + stages: + - id: '1' + check: ai + prompt: '请检查变更、解除、终止条款是否完整。 + + + 变更解除终止条款:{{变更解除终止条款}} + + + 评查要点: + + 1. 是否约定了合同变更的条件和程序 + + 2. 是否约定了合同解除/终止的条件(法定解除、约定解除、协商解除) + + 3. 是否约定了终止通知期限 + + 4. 是否约定了合同终止后的处理(结算、资料返还等) + + + 法规依据:民法典§543、§562、§563 + + ' + messages: + pass: 变更解除终止条款完整 + fail: 变更解除终止条款不完整 + references_laws: + - 《民法典》第五百四十三条 + - 《民法典》第五百六十二条 + - 《民法典》第五百六十三条 + type: ai_rule + - rule_id: MM-ENT-016 + name: 附件条款完整性 + risk: low + score: 2 + stages: + - id: '1' + check: ai + prompt: '请检查附件条款是否具备基本形式要素。 + + + 附件列表:{{附件列表}} + + + 评查要点(满足任一核心要素即可 pass,多缺给 warn,全缺给 fail): + + 1. 【核心】至少列明了附件的名称(如"服务项目清单""资质证明""业务约定书"等) + + 2. 【加分】附件有序号标识 + + 3. 【加分】附件与合同正文有引用或关联说明 + + 4. 【加分】有"附件与合同具有同等法律效力"的声明 + + + 注意:委托合同中附件是可选的辅助材料,只要名称清晰就视为合格。 + + + 法规依据:民法典§470 + + ' + messages: + pass: 附件条款已列明 + fail: 附件条款完全缺失 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-ENT-017 + name: 补充协议条款完整性 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 补充协议条款 + messages: + pass: 补充协议条款存在 + fail: 缺少补充协议兜底条款 + references_laws: + - 《民法典》第五百四十三条 + type: deterministic +- group: 规范性(6 条) + rules: + - rule_id: MM-ENT-018 + name: 合同名称合法有效 + risk: medium + score: 2 + stages: + - id: '1' + check: ai + prompt: '请检查合同名称是否合法有效。 + + + 合同名称:{{合同名称}} + + 委托事项:{{委托事项}} + + + 评查要点: + + 1. 合同名称必须与合同内容一致(名为"委托合同"且实际为委托关系) + + 2. 符合民法典有名合同特征的应当采用标准合同名称 + + 3. 合同名称不应使用会引起误解的名称 + + + 法规依据:民法典§467 + + ' + messages: + pass: 合同名称与内容一致 + fail: 合同名称与内容不一致 + references_laws: + - 《民法典》第四百六十七条 + type: ai_rule + - rule_id: MM-ENT-019 + name: 合同文本格式规范 + risk: medium + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查合同文本格式是否规范。 + + + 合同名称:{{合同名称}} + + 附件列表:{{附件列表}} + + + 评查要点: + + 1. 合同条款是否按照"当事人—事项—履行—违约—争议—签署"的逻辑顺序编排 + + 2. 条款编号和层次结构是否清晰 + + 3. 是否有必要的附件清单 + + 4. 是否有签署位置(甲方/乙方签字盖章栏) + + + 法规依据:民法典§469 + + ' + messages: + pass: 合同文本格式规范 + fail: 合同文本格式不规范 + references_laws: + - 《民法典》第四百六十九条 + type: ai_rule + - rule_id: MM-ENT-020 + name: 管辖机构名称准确 + risk: medium + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查管辖机构名称是否准确。 + + + 管辖机构:{{管辖机构}} + + 争议解决条款:{{争议解决条款}} + + + 评查要点: + + 1. 如约定诉讼,法院名称是否准确规范(如"XX市XX区人民法院") + + 2. 如约定仲裁,仲裁机构名称是否准确 + + 3. 指定的机构是否对本合同争议有管辖权 + + + 法规依据:民法典§470 + + ' + messages: + pass: 管辖机构名称准确 + fail: 管辖机构名称不准确或模糊 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-ENT-021 + name: 生效条件明确性 + risk: medium + score: 4 + stages: + - id: '1' + check: required + field: 生效条件 + - id: '2' + check: required + field: 合同份数 + logic: 1 AND 2 + messages: + pass: 生效条件和合同份数明确 + fail: 生效条件或合同份数缺失 + references_laws: + - 《民法典》第五百零二条 + type: deterministic + - rule_id: MM-ENT-022 + name: 税务信息完整性 + risk: medium + score: 1 + stages: + - id: '1' + check: ai + prompt: '请检查税务信息是否完整。 + + + 付款方式:{{付款方式}} + + 服务费是否含税:{{服务费是否含税}} + + + 评查要点: + + 1. 是否明确了服务费是否含税 + + 2. 如服务费含税,是否约定由谁开具发票 + + 3. 如不含税,是否约定税费承担方 + + + 法规依据:民法典§470 + + ' + messages: + pass: 税务信息完整 + fail: 税务信息不完整 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-ENT-023 + name: 签署方详细信息校验 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 委托方 + - id: '2' + check: required + field: 受托人 + - id: '3' + check: required + field: 委托方地址 + - id: '4' + check: required + field: 受托人地址 + logic: 1 AND 2 AND 3 AND 4 + messages: + pass: 签署方详细信息完整 + fail: 签署方详细信息有缺失 + type: deterministic +- group: 合规性(7 条) + rules: + - rule_id: MM-ENT-024 + name: 签约背景与法律依据 + risk: high + score: 9 + stages: + - id: '1' + check: ai + prompt: '请检查合同的签约背景和法律依据是否准确。 + + + 签约背景:{{签约背景}} + + 引用法律法规:{{引用法律法规}} + + 生效条件:{{生效条件}} + + 变更解除终止条款:{{变更解除终止条款}} + + + 评查要点: + + 1. 签约背景/缘由是否存在(如招标方式、协商过程、签约原因等) + + 2. 合同依据的法律、法规、规章必须准确、有效(不能引用已废止的法律) + + 3. 合同条款不违反法律禁止性规定,并具有实用性 + + 4. 合同按法律法规规定的方式生效、变更、解除并办理相应手续 + + + 法规依据:民法典§153、§502 + + ' + messages: + pass: 签约背景存在且法律依据准确有效 + fail: 签约背景缺失或法律依据存在问题 + references_laws: + - 《民法典》第一百五十三条 + - 《民法典》第五百零二条 + type: ai_rule + - rule_id: MM-ENT-025 + name: 标的内容合法 + risk: high + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查委托事项的内容是否合法。 + + + 委托事项:{{委托事项}} + + 服务范围:{{服务范围}} + + 服务标准:{{服务标准}} + + + 评查要点: + + 1. 委托事项不违反法律、行政法规的强制性规定 + + 2. 委托事项不涉及应由委托人亲自处理的事项(§920) + + 3. 如涉及特殊行业(评估/代理/查新等),是否具备相应资质或许可 + + 4. 不违背公序良俗 + + + 法规依据:民法典§153、§154、§920 + + ' + messages: + pass: 委托事项内容合法 + fail: 委托事项存在违法情形 + references_laws: + - 《民法典》第一百五十三条 + - 《民法典》第一百五十四条 + - 《民法典》第九百二十条 + type: ai_rule + - rule_id: MM-ENT-026 + name: 合同主体合法有效 + risk: high + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查合同主体是否合法有效。 + + + 委托方:{{委托方}} + + 委托方证件号:{{委托方证件号}} + + 受托人:{{受托人}} + + 受托人USCC:{{受托人统一社会信用代码}} + + 受托人法定代表人:{{受托人法定代表人}} + + + 评查要点: + + 1. 委托方主体身份明确(个人有身份证号/单位有 USCC) + + 2. 受托人为单位时签约代表是否为法定代表人或有授权 + + 3. 身份证号或 USCC 格式合法(18 位) + + + 特别说明:受托人 USCC 属签署阶段字段,draft 阶段为空可接受。 + + + 法规依据:民法典§143、§171 + + ' + messages: + pass: 合同主体合法有效 + fail: 合同主体存在合法性问题 + references_laws: + - 《民法典》第一百四十三条 + - 《民法典》第一百七十一条 + type: ai_rule + - rule_id: MM-ENT-027 + name: 受托人资质合格 + risk: high + score: 4 + stages: + - id: '1' + check: ai + prompt: '请检查受托人是否具有从事委托事项所需的资质。 + + + 受托人:{{受托人}} + + 受托人资质信息:{{受托人资质信息}} + + 委托事项:{{委托事项}} + + 服务标准:{{服务标准}} + + + 评查要点: + + 1. 对专业服务(资产评估、车辆评估、科技查新、专利代理等),合同中是否说明受托人具备相应资质 + + 2. 是否明确受托人从事委托事项的合法主体资格 + + 3. 是否附有资质证书/许可证明(附件中) + + 4. 对普通咨询/代理等无特殊资质要求的委托,本检查可放宽 + + + 法规依据:民法典§505 + + ' + messages: + pass: 受托人资质说明完整 + fail: 缺少受托人资质说明 + references_laws: + - 《民法典》第五百零五条 + type: ai_rule + - rule_id: MM-ENT-028 + name: 合同基本信息完整性 + risk: high + score: 2 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 合同编号 + - id: '2' + check: required + field: 签约日期 + logic: 1 AND 2 + messages: + pass: 合同编号与签约日期已填写 + fail: 合同编号或签约日期缺失 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-ENT-029 + name: 银行账户信息完整性 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 收款方开户银行 + - id: '2' + check: required + field: 收款方银行账号 + - id: '3' + check: required + field: 收款方账户名称 + logic: 1 AND 2 AND 3 + messages: + pass: 收款方银行账户信息完整 + fail: 收款方银行账户信息不完整 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-ENT-030 + name: 签署信息完整性 + risk: high + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + - id: '2' + check: required + field: 签约地点 + logic: 1 AND 2 + messages: + pass: 签约日期与签约地点已填写 + fail: 签约日期或签约地点缺失 + references_laws: + - 《民法典》第四百九十条 + type: deterministic + - rule_id: MM-ENT-031 + name: 骑缝章检查 + risk: medium + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: visual + element: 骑缝章 + messages: + pass: 骑缝章齐全 + fail: 缺少骑缝章或骑缝章不规范 + references_laws: + - 《民法典》第四百九十条 + type: deterministic +- group: 条件激活(3 条) + rules: + - rule_id: MM-ENT-032 + name: 保密条款完整性 + risk: medium + score: 2 + activate_if: 涉及保密信息 == '是' + stages: + - id: '1' + check: required + field: 保密条款 + - id: '2' + check: ai + prompt: '请检查保密条款是否完整(合同涉及保密信息时)。 + + + 保密条款:{{保密条款}} + + 委托事项:{{委托事项}} + + + 评查要点(三要素): + + 1. 是否明确了保密信息的范围(商业秘密、技术秘密、客户信息等) + + 2. 是否约定了保密期限(一般覆盖合同期内+合同后若干年) + + 3. 是否约定了违反保密义务的违约责任 + + + 法规依据:民法典§501 + + ' + logic: 1 AND 2 + messages: + pass: 保密条款完整 + fail: 保密条款要素不全 + references_laws: + - 《民法典》第五百零一条 + type: ai_rule + - rule_id: MM-ENT-033 + name: 转委托条款完整 + risk: medium + score: 2 + activate_if: 允许转委托 == '是' + stages: + - id: '1' + check: required + field: 转委托条款 + - id: '2' + check: ai + prompt: '请检查转委托条款是否完整(合同允许转委托时)。 + + + 转委托条款:{{转委托条款}} + + + 评查要点: + + 1. 是否明确了转委托的条件(如需经委托人书面同意) + + 2. 是否明确了转委托的范围 + + 3. 是否约定了受托人对转委托事务的责任承担(§923) + + 4. 转委托后的报告义务是否延续 + + + 法规依据:民法典§923 + + ' + logic: 1 AND 2 + messages: + pass: 转委托条款完整 + fail: 转委托条款要素不全 + references_laws: + - 《民法典》第九百二十三条 + type: ai_rule + - rule_id: MM-ENT-034 + name: 服务项目清单金额校验 + risk: high + score: 5 + activate_if: 含服务项目清单 == '是' + stages: + - id: '1' + check: required + field: 服务项目清单 + - id: '2' + check: ai + prompt: '请检查服务项目清单的金额校验(合同包含清单时)。 + + + 服务项目清单:{{服务项目清单}} + + 服务费金额:{{服务费金额}} + + + 评查要点: + + 1. 各项服务单价×数量是否等于各项合计 + + 2. 各项合计相加是否等于合同服务费总金额 + + 3. 清单中金额和大小写是否一致 + + 4. 是否有项目信息遗漏(单价或数量为空) + + + 法规依据:民法典§470 + + ' + logic: 1 AND 2 + messages: + pass: 服务项目清单金额校验通过 + fail: 服务项目清单金额校验失败 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule diff --git a/rules/contract_entrust/rules.yaml.bak.20260414 b/rules/contract_entrust/rules.yaml.bak.20260414 new file mode 100644 index 0000000..65d2375 --- /dev/null +++ b/rules/contract_entrust/rules.yaml.bak.20260414 @@ -0,0 +1,436 @@ +metadata: + type_id: contract.entrust + name: 通用委托合同 + version: "1.0" + last_updated: "2026-04-12" + description: | + 依据《中华人民共和国民法典》合同编·通则(第470条)及委托合同章(第919-936条)。 + 适用于一般委托服务合同的评查,覆盖签署前审查(draft)和签署后审计(executed)两个阶段。 + 原始规则来源:旧系统 02_委托合同.json(6条委托专项评查点)+ 00_通用规则.json(通用合同评查点)。 + tags: [合同, 委托, 服务] + +# ══════════════════════════════════════════════════════════ +# 字段抽取定义 — 31 个字段,按评查阶段分组 +# ══════════════════════════════════════════════════════════ +extract: + # A. 合同成立要素 — required_from: draft + - {name: 合同名称, type: verbatim, description: "合同的完整名称/项目名称"} + - {name: 甲方, type: verbatim, description: "委托方公司全称"} + - {name: 乙方, type: verbatim, description: "受托方公司全称"} + - {name: 合同金额, type: money, description: "合同总金额(数字)"} + - {name: 合同金额大写, type: verbatim, description: "合同总金额中文大写"} + + # B. 主体资格 + - {name: 甲方法定代表人, type: verbatim, description: "甲方法定代表人姓名"} + - {name: 乙方法定代表人, type: verbatim, description: "乙方法定代表人姓名"} + - {name: 甲方地址, type: verbatim, description: "甲方注册/办公地址"} + - {name: 乙方地址, type: verbatim, description: "乙方注册/办公地址"} + - {name: 甲方统一社会信用代码, type: uscc, required_from: executed, description: "甲方18位统一社会信用代码"} + - {name: 乙方统一社会信用代码, type: uscc, required_from: executed, description: "乙方18位统一社会信用代码"} + + # C. 委托合同核心条款 — required_from: draft + - {name: 委托事项描述, type: string, description: "委托服务的具体内容、范围和标准的完整描述"} + - {name: 付款方式, type: string, description: "付款条件、方式、时间节点的完整描述"} + - {name: 服务项目明细, type: string, description: "服务项目清单(序号、名称、数量、单价等)"} + - {name: 合同期限, type: string, description: "服务期限起止时间描述"} + + # D. 委托合同特有条款 + - {name: 转委托条款, type: string, description: "受托人能否将事务转委托第三人处理的约定"} + - {name: 报告义务条款, type: string, description: "受托人报告义务、报告方式和报告周期的约定"} + - {name: 成果交付与验收, type: string, description: "服务成果形式、验收标准和验收方式的约定"} + - {name: 解除权条款, type: string, description: "任意解除权约定及解除后费用结算方式"} + + # E. 法定/必备条款 — required_from: draft + - {name: 违约责任条款, type: string, description: "违约责任的完整条款内容"} + - {name: 争议解决条款, type: string, description: "争议解决方式(法院/仲裁)的完整描述"} + - {name: 不可抗力条款, type: string, description: "不可抗力相关条款的完整内容"} + - {name: 保密条款, type: string, required_from: executed, description: "保密义务相关条款内容"} + + # F. 签署要素 — required_from: executed + - {name: 签约日期, type: date, required_from: executed, description: "合同签订日期"} + - {name: 合同编号, type: verbatim, required_from: executed, description: "合同唯一编号"} + + # G. 辅助信息 + - {name: 甲方联系人, type: verbatim, required_from: executed, description: "甲方项目联系人姓名"} + - {name: 甲方联系电话, type: verbatim, required_from: executed, description: "甲方联系电话"} + - {name: 乙方联系人, type: verbatim, required_from: executed, description: "乙方项目联系人姓名"} + - {name: 乙方联系电话, type: verbatim, required_from: executed, description: "乙方联系电话"} + - {name: 甲方开户银行, type: verbatim, required_from: executed, description: "甲方银行开户行名称"} + - {name: 甲方银行账号, type: verbatim, required_from: executed, description: "甲方银行账号"} + +# ══════════════════════════════════════════════════════════ +# 评查规则 — 24 条,按评查维度分组 +# ══════════════════════════════════════════════════════════ +rules: + + # ── 完整性(10 条)───────────────────────────── + + - rule_id: WT-001 + name: 合同主体齐全 + risk: high + score: 10 + stages: + - {check: required, field: 甲方} + - {check: required, field: 乙方} + messages: + pass: 甲乙方信息完整 + fail: 缺少甲方或乙方信息,合同主体不明确 + + - rule_id: WT-002 + name: 委托事项与金额必填 + risk: high + score: 10 + stages: + - {check: required, field: 委托事项描述} + - {check: required, field: 合同金额} + messages: + pass: 委托事项与金额信息完整 + fail: 缺少委托事项描述或合同金额 + + - rule_id: WT-003 + name: 合同名称必填 + risk: medium + score: 5 + stages: + - {check: required, field: 合同名称} + messages: + pass: 合同名称已填写 + fail: 缺少合同名称 + + - rule_id: WT-004 + name: 法定代表人齐全 + risk: medium + score: 5 + stages: + - {check: required, field: 甲方法定代表人} + - {check: required, field: 乙方法定代表人} + messages: + pass: 甲乙方法定代表人信息完整 + fail: 缺少甲方或乙方法定代表人信息 + + - rule_id: WT-005 + name: 付款方式必填 + risk: high + score: 8 + stages: + - {check: required, field: 付款方式} + messages: + pass: 付款方式已填写 + fail: 缺少付款方式 + + - rule_id: WT-006 + name: 违约责任条款存在 + risk: high + score: 8 + stages: + - {check: required, field: 违约责任条款} + messages: + pass: 违约责任条款存在 + fail: 缺少违约责任条款 + + - rule_id: WT-007 + name: 争议解决条款存在 + risk: medium + score: 5 + stages: + - {check: required, field: 争议解决条款} + messages: + pass: 争议解决条款存在 + fail: 缺少争议解决条款 + + - rule_id: WT-008 + name: 不可抗力条款存在 + risk: medium + score: 3 + stages: + - {check: required, field: 不可抗力条款} + messages: + pass: 不可抗力条款存在 + fail: 缺少不可抗力条款,建议补充 + + - rule_id: WT-009 + name: 签约日期必填 + risk: high + score: 8 + applies_in: [executed] + stages: + - {check: required, field: 签约日期} + messages: + pass: 签约日期已填写 + fail: 缺少签约日期,合同可能未正式签署 + + - rule_id: WT-010 + name: 合同编号必填 + risk: medium + score: 3 + applies_in: [executed] + stages: + - {check: required, field: 合同编号} + messages: + pass: 合同编号已填写 + fail: 缺少合同编号 + + # ── 规范性(2 条)───────────────────────────── + + - rule_id: WT-011 + name: 甲方信用代码校验 + risk: medium + score: 5 + applies_in: [executed] + stages: + - {check: format, field: 甲方统一社会信用代码, format: uscc} + messages: + pass: 甲方统一社会信用代码校验通过 + fail: 甲方统一社会信用代码校验位错误 + + - rule_id: WT-012 + name: 乙方信用代码校验 + risk: medium + score: 5 + applies_in: [executed] + stages: + - {check: format, field: 乙方统一社会信用代码, format: uscc} + messages: + pass: 乙方统一社会信用代码校验通过 + fail: 乙方统一社会信用代码校验位错误 + + # ── 合理性(3 条)───────────────────────────── + + - rule_id: WT-013 + name: 金额大小写一致 + risk: high + score: 10 + stages: + - {check: amount_match, number: 合同金额, chinese: 合同金额大写} + messages: + pass: 金额大小写一致 + fail: 合同金额数字与大写不一致,存在篡改风险 + + - rule_id: WT-014 + name: 金额为正数 + risk: low + score: 3 + stages: + - {check: compare, left: 合同金额, op: ">", right: 0} + messages: + pass: 合同金额为正数 + fail: 合同金额不为正数,数据异常 + + - rule_id: WT-015 + name: 签约日期不是未来 + risk: low + score: 3 + applies_in: [executed] + stages: + - {check: assert, expr: "parse_date(签约日期) != None and (today() - parse_date(签约日期)).days >= 0 and (today() - parse_date(签约日期)).days <= 3650"} + messages: + pass: 签约日期在合理范围内 + fail: 签约日期为未来日期或距今超过10年 + + # ── 委托合同专项评查(6 条,来源:旧系统 NR-WT-001~006)─────────── + + # 来源: NR-WT-001 委托事项明确性 — §919, §920 + - rule_id: WT-016 + name: 委托事项明确 + risk: high + score: 5 + stages: + - {check: required, field: 委托事项描述} + - check: ai + prompt: | + 请检查委托合同的委托事项是否明确。 + + 服务内容、范围、标准:{{委托事项描述}} + + 评查要点(依据民法典第919-920条): + 1. 委托内容是否具体明确(如提供何种服务、服务对象、服务方式等) + 2. 服务范围是否有清晰边界(哪些属于服务范围内、哪些不属于) + 3. 服务标准/质量要求是否可衡量(如频次、时长、人员配置等) + 4. 是否明确属于特别委托(具体事项)还是概括委托(一切事务) + messages: + pass: 委托事项明确 + fail: 委托事项不够明确,缺少具体服务内容、范围或标准 + + # 来源: NR-WT-003 转委托条款 — §923 + - rule_id: WT-017 + name: 转委托条款完整 + risk: medium + score: 2 + stages: + - {check: required, field: 转委托条款} + - check: ai + prompt: | + 请检查合同是否约定了转委托条款。 + + 转委托约定:{{转委托条款}} + + 评查要点(依据民法典第923条): + 1. 是否明确受托人应当亲自处理委托事务 + 2. 是否约定受托人能否将全部或部分服务转委托第三人 + 3. 如允许转委托,是否约定了需经委托人同意 + 4. 如允许转委托,是否约定了转委托后的责任承担 + + 注意:如合同明确约定"乙方应配备专业人员"或类似亲自履行条款,视为已约定不可转委托,可PASS。 + messages: + pass: 转委托条款已约定 + fail: 转委托条款缺失 + + # 来源: NR-WT-004 报告义务条款 — §924 + - rule_id: WT-018 + name: 报告义务条款完整 + risk: medium + score: 3 + stages: + - {check: required, field: 报告义务条款} + - check: ai + prompt: | + 请检查合同是否约定了受托人的报告义务。 + + 报告义务约定:{{报告义务条款}} + + 评查要点(依据民法典第924条): + 1. 是否约定受托人应定期向委托人报告服务进展情况 + 2. 是否约定报告的方式(书面报告、会议汇报等) + 3. 是否约定服务完成后应提交总结报告或成果报告 + + 注意:如合同约定了"按甲方要求及时调整"等配合条款,可视为隐含报告义务,但建议明确约定。 + messages: + pass: 报告义务条款完整 + fail: 报告义务条款缺失或不完整 + + # 来源: NR-WT-005 服务成果交付与验收 — §927, §928 + - rule_id: WT-019 + name: 服务成果交付与验收完整 + risk: high + score: 3 + stages: + - {check: required, field: 成果交付与验收} + - check: ai + prompt: | + 请检查合同是否约定了服务成果的交付和验收。 + + 成果形式、验收标准、验收方式:{{成果交付与验收}} + + 评查要点(依据民法典第927-928条): + 1. 是否明确服务完成的判定标准(如何判定"服务项目完成") + 2. 是否约定服务成果的形式(咨询报告、测评报告、服务记录等) + 3. 是否约定验收方式(甲方确认、双方签字等) + + 注意:如合同已约定按服务项目清单逐项交付,且付款条件与项目完成挂钩,可视为已有验收安排。 + messages: + pass: 服务成果交付与验收条款完整 + fail: 服务成果交付与验收条款缺失 + + # 来源: NR-WT-002 服务项目清单金额校验 — §928 + - rule_id: WT-020 + name: 服务项目清单金额校验 + risk: high + score: 5 + stages: + - {check: required, field: 服务项目明细} + - {check: required, field: 合同金额} + - check: ai + prompt: | + 请校验合同服务项目清单的金额一致性。 + + 服务项目明细:{{服务项目明细}} + 合同总金额:{{合同金额}} + + 评查要点(依据民法典第928条): + 1. 各项单价×数量是否等于对应项合计(逐项计算校验) + 2. 各项合计之和是否等于合同总金额 + 3. 服务项目描述是否足够具体(非含糊表述) + messages: + pass: 服务项目清单金额校验通过 + fail: 服务项目清单金额不一致 + + # 来源: NR-WT-006 任意解除权与费用结算 — §933, §928 + - rule_id: WT-021 + name: 任意解除权与费用结算 + risk: high + score: 3 + stages: + - {check: required, field: 解除权条款} + - check: ai + prompt: | + 请检查合同是否约定了任意解除权及解除后的费用结算。 + + 任意解除约定与费用结算:{{解除权条款}} + + 评查要点(依据民法典第933条): + 1. 委托合同双方均有随时解除权(法定权利),合同是否对此有约定 + 2. 是否约定了提前解除的通知期限(如提前多少天书面通知) + 3. 是否约定了解除后已完成服务部分的费用结算方式(按实际完成比例结算等) + + 注意: + - 委托合同的任意解除权是法定权利,合同不能排除 + - 如合同仅约定了违约解除而未提及任意解除,视为对任意解除权未作约定 + - 重点关注解除后的费用结算是否公平合理 + messages: + pass: 任意解除权与费用结算条款完整 + fail: 任意解除权或费用结算条款缺失 + + # ── 合规性 · AI 语义判断(3 条,来源:通用规则模式)─────────── + + - rule_id: WT-022 + name: 违约责任条款充分 + risk: medium + score: 5 + stages: + - {check: required, field: 违约责任条款} + - check: ai + prompt: | + 请判断以下违约责任条款是否充分、合规。 + + 条款内容:{{违约责任条款}} + + 充分的违约责任条款应当(依据民法典第577-585条): + 1. 明确违约情形(如逾期付款、逾期交付、服务质量不合格等) + 2. 明确违约金计算方式或赔偿标准(如按日万分之几、赔偿实际损失等) + 3. 不能只是笼统的"违约要赔偿"之类的模糊表述 + 4. 应当对双方(委托方和受托方)的违约责任都有约定 + messages: + pass: 违约责任条款充分 + fail: 违约责任条款不充分,缺少具体违约情形或违约金计算方式 + + - rule_id: WT-023 + name: 争议解决方式明确 + risk: medium + score: 5 + stages: + - {check: required, field: 争议解决条款} + - check: ai + prompt: | + 请判断以下争议解决条款是否符合法律要求。 + + 条款内容:{{争议解决条款}} + + 合规的争议解决条款应当: + 1. 明确指定具体的争议解决方式(仲裁或诉讼,二选一) + 2. 如选择仲裁,应明确仲裁机构名称(如"XX仲裁委员会") + 3. 如选择诉讼,应明确管辖法院(如"XX人民法院") + 4. 不能同时约定仲裁和诉讼 + 5. 不能是模糊表述(如"找人调解"、"双方商量"等) + messages: + pass: 争议解决方式明确 + fail: 争议解决条款缺失或未明确具体的仲裁机构/管辖法院 + + - rule_id: WT-024 + name: 付款条款明确 + risk: medium + score: 5 + stages: + - {check: required, field: 付款方式} + - check: ai + prompt: | + 请判断以下付款条款是否明确。 + + 条款内容:{{付款方式}} + + 明确的付款条款应当包含: + 1. 付款金额或比例(如"支付合同总额的30%") + 2. 付款时间节点或触发条件(如"验收合格后15个工作日内") + 3. 付款方式(如银行转账) + messages: + pass: 付款条款明确 + fail: 付款条款不够明确,缺少金额/时间/方式等关键信息 diff --git a/rules/contract_evaluation/rules.yaml b/rules/contract_evaluation/rules.yaml new file mode 100644 index 0000000..752da41 --- /dev/null +++ b/rules/contract_evaluation/rules.yaml @@ -0,0 +1,136 @@ +metadata: + type_id: contract.evaluation.delegation + name: 委托评估合同 + version: '0.1' + last_updated: '2026-04-14' + parent: contract + classification_keywords: + - 委托评估 + - 评估合同 + - 房地产评估 + description: '最小规则集,用于端到端验证印章 / 签名 / 齐缝章识别流水线。 + + ' +extract: +- group: 默认分组 + fields: + - name: 甲方名称 + type: string + required_from: draft + desc: 委托估价方(甲方)全称 + deep_retry: false + - name: 乙方名称 + type: string + required_from: draft + desc: 受托估价方(乙方、评估机构)全称 + deep_retry: false +visual_elements: + seals: + - id: 乙方评估机构章 + name: 乙方合同专用章 / 公章 + required: true + required_from: executed + allowed_types: + - 合同专用章 + - 公章 + signatures: + - id: 甲乙方代理人签名 + name: 甲方 / 乙方法定代表人或代理人手写签名 + required: true + required_from: executed + cross_page_seals: + - id: 齐缝章 + name: 页间齐缝章 + required: true + required_from: executed +rules: +- group: 印章合规 + rules: + - rule_id: EVAL-SEAL-001 + name: 合同存在合同专用章或公章 + risk: high + score: 10 + applies_in: + - executed + stages: + - id: '1' + check: visual + element: seal + expect: type_in + allowed_types: + - 合同专用章 + - 公章 + logic: '1' + messages: + pass: 检测到合同专用章或公章 + fail: 未检测到合同专用章或公章 + type: deterministic + - rule_id: EVAL-SEAL-002 + name: 乙方评估机构章文字匹配 + risk: medium + score: 10 + applies_in: + - executed + stages: + - id: '1' + check: visual + element: seal + expect: text_match + expected_text: 广东博亿美房地产资产评估有限公司 合同专用章 4453020060917 + logic: '1' + messages: + pass: 乙方合同专用章文字命中 + fail: 乙方合同专用章文字未命中 + type: deterministic + - rule_id: EVAL-CROSS-001 + name: 存在齐缝章 + risk: high + score: 10 + applies_in: + - executed + stages: + - id: '1' + check: visual + element: cross_page_seal + expect: present + min_count: 1 + logic: '1' + messages: + pass: 检测到齐缝章 + fail: 未检测到齐缝章 + type: deterministic + - rule_id: EVAL-CROSS-002 + name: 齐缝章两侧对齐且完整 + risk: medium + score: 10 + applies_in: + - executed + stages: + - id: '1' + check: visual + element: cross_page_seal + expect: complete + logic: '1' + messages: + pass: 齐缝章两半对齐且完整 + fail: 齐缝章仅检测到单侧,无法判定完整性 + type: deterministic +- group: 签字合规 + rules: + - rule_id: EVAL-SIGN-001 + name: 合同尾页存在手写签名 + risk: high + score: 10 + applies_in: + - executed + stages: + - id: '1' + check: visual + element: signature + expect: present + min_count: 2 + logic: '1' + messages: + pass: 合同存在甲乙双方的手写签名(≥2) + fail: 合同缺少甲方或乙方的手写签名 + type: deterministic diff --git a/rules/contract_gift_charity/docs/test_middle.md b/rules/contract_gift_charity/docs/test_middle.md new file mode 100644 index 0000000..0032a41 --- /dev/null +++ b/rules/contract_gift_charity/docs/test_middle.md @@ -0,0 +1,75 @@ +# 定向捐赠协议书 + +**甲方(捐赠人):** 粤北种业发展有限公司 +**地址:** 广东省韶关市武江区新华南路 68 号 +**联系电话:** 0751-8812345 + +**乙方(受赠人):** 韶关市武江区慈善会 +**地址:** 广东省韶关市武江区惠民南路 12 号 +**联系电话:** 0751-8822222 +**法定代表人:** 黄伟 + +**丙方(项目实施方):** 韶关市武江区西河镇人民政府 +**地址:** 广东省韶关市武江区西河镇中心路 8 号 +**联系电话:** 0751-8833333 + +甲、乙、丙三方根据相关法律法规的规定,经平等友好协商,就定向捐赠事宜订立本协议。 + +## 第一条 捐赠内容 + +1.1 甲方自愿向乙方捐赠人民币 50,000.00 元(伍万元整),用于支持西河镇困难群众帮扶。 + +1.2 捐赠资金交付时间:本协议签订后尽快交付。 + +## 第二条 各方权利义务 + +2.1 甲方承诺捐赠的资金来源合法。 + +2.2 乙方收到捐赠资金后及时拨付给丙方。 + +2.3 丙方应按甲方意愿将资金用于困难群众帮扶。 + +2.4 甲方有权监督资金使用情况。 + +## 第三条 交付方式 + +3.1 交付方式:银行转账。 + +3.2 收款账户: + 账户名称:韶关市武江区慈善会 + 开户银行:韶关农村商业银行武江支行 + 银行账号:81020000003344556 + +## 第四条 票据 + +4.1 乙方收到捐赠资金后向甲方开具收据。 + +## 第五条 违约责任 + +5.1 甲方未按时交付捐赠资金的,乙方有权要求甲方继续履行。 + +5.2 丙方未按约定使用捐赠资金的,应退还资金。 + +## 第六条 争议解决 + +6.1 本协议履行过程中发生争议,三方应友好协商解决;协商不成的,依法处理。 + +## 第七条 不可抗力 + +7.1 因不可抗力致使本协议无法履行的,本协议自动解除,各方互不承担违约责任。 + +## 第八条 其他 + +8.1 本协议自三方签字盖章之日起生效。 + +8.2 本协议一式三份,三方各执一份。 + +--- + +**甲方(盖章):** 粤北种业发展有限公司 + +**乙方(盖章):** 韶关市武江区慈善会 + +**丙方(盖章):** 韶关市武江区西河镇人民政府 + +**签约日期:** 2024 年 11 月 15 日 diff --git a/rules/contract_gift_charity/docs/test_negative.md b/rules/contract_gift_charity/docs/test_negative.md new file mode 100644 index 0000000..1b09695 --- /dev/null +++ b/rules/contract_gift_charity/docs/test_negative.md @@ -0,0 +1,25 @@ +# 定向捐赠协议 + +甲方:某公司 + +乙方:某慈善会 + +丙方:某单位 + +甲方向乙方捐赠一笔资金,由乙方拨付给丙方,用于公益事业。 + +乙方应按甲方意愿使用资金。 + +如有违约,按法律处理。 + +如有争议,协商解决。 + +三方盖章签字。 + +--- + +甲方:某公司 + +乙方:某慈善会 + +丙方:某单位 diff --git a/rules/contract_gift_charity/docs/test_positive.md b/rules/contract_gift_charity/docs/test_positive.md new file mode 100644 index 0000000..d588963 --- /dev/null +++ b/rules/contract_gift_charity/docs/test_positive.md @@ -0,0 +1,142 @@ +# 定向公益捐赠协议书 + +**合同编号:** NFZJ-DX-2024-088 + +**甲方(捐赠人):** 南方智能制造股份有限公司 +**地址:** 广东省深圳市南山区科技中一路 8 号南方智造大厦 +**联系电话:** 0755-26681234 +**统一社会信用代码:** 914401017302135875 +**法定代表人:** 陈国强 + +**乙方(受赠人):** 长江公益慈善基金会 +**地址:** 湖北省武汉市武昌区中南路 99 号长江公益大厦 12 层 +**联系电话:** 027-87654321 +**统一社会信用代码:** 51441427506612345G +**法定代表人:** 林芷若 + +**丙方(项目实施方):** 武汉市江夏区慈善总会 +**地址:** 湖北省武汉市江夏区纸坊街文化路 58 号 +**联系电话:** 027-81002233 + +为支持发展慈善公益事业,规范捐赠资金的管理使用,根据《中华人民共和国慈善法》《中华人民共和国公益事业捐赠法》《中华人民共和国民法典》及有关法律法规,甲乙丙三方共同协商,就定向慈善捐赠事宜达成如下协议: + +## 第一条 捐赠标的与定向用途 + +1.1 捐赠金额:人民币贰佰万元整(¥2,000,000.00)。 + +1.2 定向用途:本次捐赠资金定向用于"武汉市江夏区 2024 年 6·18 特大暴雨灾后农村水毁基础设施修复项目",具体用于: + (1)江夏区舒安街道金光村受损农田灌溉渠道修复(约 50 万元); + (2)江夏区山坡街道贺站村倒塌农用机耕道重建(约 80 万元); + (3)江夏区湖泗街道熊咀村塘堰加固及防洪护坡修复(约 70 万元)。 + +1.3 任何一方不得擅自改变上述捐赠资金的定向用途。确需调整用途的,须经甲方书面同意。 + +## 第二条 各方权利义务 + +### 2.1 甲方(捐赠人)的权利义务 +(1)承诺捐赠的资金是甲方有权处分的合法资金,符合国家相关管理规定,与丙方无利害关系; +(2)按本协议约定期限将捐赠资金全额划至乙方指定的银行账户; +(3)有权对捐赠资金的管理使用情况进行查询和监督;可自行或委托第三方审计机构对资金使用情况进行审计; +(4)甲方同意在乙方官方网站公开捐赠人名称及本次捐赠相关信息。 + +### 2.2 乙方(受赠人)的权利义务 +(1)收到捐赠资金后 10 日内向甲方出具财政部门统一监制的《公益事业捐赠专用收据》; +(2)在对丙方项目实施资格和专项资金使用计划完成书面审核后,方可按本协议约定向丙方拨付捐赠资金; +(3)委托有资质的审计机构对捐赠资金管理使用情况进行年度审计并将审计报告书面提交给甲方; +(4)通过乙方官方网站及湖北省慈善信息平台公告定向捐赠财产接收使用情况; +(5)监督丙方合法管理使用捐赠资金,专账管理、专款专用。 + +### 2.3 丙方(项目实施方)的权利义务 +(1)收到捐赠资金后 10 日内向乙方开具合法有效的收款票据; +(2)负责江夏区相关水毁基础设施修复项目的实施、竣工验收、工程结算等全部工作; +(3)按照国家、省、市相关法律法规和本协议约定组织项目实施,不得挪作他用; +(4)捐赠资金到账后,及时登记入账,按照有关财务管理要求专账管理; +(5)项目实施期间,每半年一次将项目实施情况书面向甲、乙方反馈; +(6)项目实施完毕后 30 日内向甲、乙方提交项目完工报告及资金使用情况报告; +(7)自觉接受甲方、乙方及有关部门对捐赠资金管理使用情况的监督检查。 + +## 第三条 交付条款 + +3.1 交付方式:银行转账。 + +3.2 交付时间: + (1)甲方应在本协议签订后 15 个工作日内,将捐赠资金一次性转账至乙方指定账户; + (2)乙方应在收到甲方捐赠资金并审核丙方项目实施资格后 10 个工作日内,将捐赠资金按项目进度拨付至丙方指定账户。 + +3.3 乙方收款账户: + 账户名称:长江公益慈善基金会 + 开户银行:中国建设银行武汉武昌支行 + 银行账号:4200000012345678901 + +## 第四条 专用票据 + +4.1 乙方承诺在收到捐赠资金 10 日内向甲方开具由财政部门统一监制的《公益事业捐赠专用收据》,载明捐赠人名称、捐赠金额、捐赠日期等信息。 + +4.2 丙方承诺在收到乙方拨付的捐赠资金 10 日内向乙方开具合法有效的收款票据。 + +4.3 甲方凭乙方开具的公益事业捐赠专用收据,依法享受国家规定的税前扣除待遇。 + +## 第五条 剩余财产处置 + +5.1 项目实施完毕后,如存在剩余定向捐赠资金,丙方应当退还至乙方,由乙方统一汇缴至长江公益慈善基金会公益储备账户,用于资助其他符合本协议定向用途性质的公益项目。 + +5.2 项目因不可抗力或其他原因终止的,剩余定向捐赠财产的处置按第 5.1 条处理。任何一方不得挪用剩余捐赠资金用于非公益目的。 + +## 第六条 信息公开 + +6.1 甲方同意公开捐赠人名称及捐赠金额、用途等信息(同意☑ 不同意☐)。 + +6.2 乙方应通过本基金会官方网站及湖北省慈善信息平台定期公开本项目捐赠资金接收、管理、使用情况。 + +6.3 甲方有权随时查询捐赠资金的使用情况,乙方、丙方应如实答复并提供相关资料。 + +## 第七条 违约责任 + +7.1 如甲方未按协议约定期限向乙方足额交付捐赠资金,乙、丙方有权要求甲方继续履行捐赠义务,并按未交付金额每日万分之三支付资金占用损失。 + +7.2 如乙方未按协议约定将捐赠资金转交丙方或未按要求开具专用收据,甲、丙方有权要求乙方履行相应义务;因乙方原因造成项目延误的,乙方应承担由此产生的直接经济损失。 + +7.3 如丙方未按协议约定管理使用捐赠资金,存在挪用、截留、擅自改变用途等情形的,甲方或乙方有权终止本协议,丙方应全额返还已拨付的捐赠资金,并向甲方支付相当于挪用金额 20% 的违约金。 + +7.4 任一方造成其他各方损失的,应当赔偿全部直接经济损失。 + +## 第八条 不可抗力 + +8.1 本协议所称不可抗力,系指以各方的能力不能预见、不能抗拒、不能避免的客观情况,包括但不限于:地震、洪水、海啸、台风、战争、政府行为、重大公共卫生事件等。 + +8.2 遭遇不可抗力情形的一方,应当于不可抗力发生之日起 5 日内以书面形式通知其他各方,并在事件结束后 10 日内提供有关部门出具的证明文件。 + +8.3 受不可抗力影响的当事方应当积极采取措施减少损失。因其怠于采取相应措施而致使损失扩大的,不得就扩大的损失部分主张免责。 + +8.4 不可抗力结束后,三方应尽快恢复履行协议约定事项。如不可抗力持续超过 30 日的,任一方有权书面通知解除本协议,剩余定向捐赠财产按第五条约定处置。 + +## 第九条 争议解决 + +9.1 本协议履行过程中发生的争议,三方应首先友好协商解决。 + +9.2 协商不成的,任何一方有权将争议提交乙方所在地(湖北省武汉市武昌区)人民法院通过诉讼方式解决。 + +## 第十条 特别声明 + +10.1 三方确认,依据《中华人民共和国民法典》第六百六十条及《中华人民共和国慈善法》第四十一条之规定,本协议为具有救灾、公益性质的赠与合同,甲方不享有任意撤销权,应当按照本协议约定交付捐赠财产。 + +10.2 因甲方经济状况严重恶化,严重影响其生产经营的,可依《民法典》第六百六十六条不再履行赠与义务,但应当及时书面通知乙、丙方。 + +## 第十一条 其他 + +11.1 本协议自甲、乙、丙三方法定代表人或授权代表签字并加盖单位公章之日起生效。 + +11.2 本协议一式伍份,甲、乙、丙三方各执壹份,乙方另存贰份分别报送慈善登记管理机关和业务主管部门备案,具有同等法律效力。 + +--- + +**甲方(盖章):** 南方智能制造股份有限公司 +**法定代表人/授权代表(签字):** 陈国强 + +**乙方(盖章):** 长江公益慈善基金会 +**法定代表人/授权代表(签字):** 林芷若 + +**丙方(盖章):** 武汉市江夏区慈善总会 +**法定代表人/授权代表(签字):** 王继江 + +**签约日期:** 2024 年 11 月 5 日 diff --git a/rules/contract_gift_charity/rules.yaml b/rules/contract_gift_charity/rules.yaml new file mode 100644 index 0000000..95e87dd --- /dev/null +++ b/rules/contract_gift_charity/rules.yaml @@ -0,0 +1,727 @@ +metadata: + type_id: contract.gift.charity + name: 定向公益捐赠合同 + version: '1.0' + last_updated: '2026-04-14' + tags: + - 合同 + - 赠与 + - 公益捐赠 + references_laws: + - 慈善法第3条 + - 慈善法第34条 + - 慈善法第35条 + - 慈善法第38条 + - 慈善法第41条 + - 慈善法第42条 + - 慈善法第56条 + - 慈善法第69条 + - 慈善法第70条 + - 慈善法第75条 + - 公益事业捐赠法第4条 + - 公益事业捐赠法第6条 + - 公益事业捐赠法第12条 + - 公益事业捐赠法第16条 + - 民法典第660条 + - 民法典第490条 + description: "依据《中华人民共和国慈善法》、《中华人民共和国公益事业捐赠法》和民法典§660,\n适用于三方或四方结构的定向公益捐赠合同:\n 捐赠人 → 受赠人(慈善机构/基金会)→ 项目实施方 →(使用人,仅四方)\n\ + 常见场景:企业通过慈善机构向特定公益项目定向捐赠资金或财产。\n若为普通双方赠与,请使用 contract.gift.general 评查规则。\n" +extract: +- group: 捐赠人(甲方)信息 + fields: + - name: 捐赠人 + type: verbatim + required_from: draft + desc: 捐赠人公司全称或姓名 + deep_retry: false + - name: 捐赠人地址 + type: verbatim + required_from: draft + desc: 捐赠人地址 + deep_retry: false + - name: 捐赠人联系电话 + type: verbatim + required_from: draft + desc: 捐赠人联系电话 + deep_retry: false +- group: 受赠人(慈善机构,乙方)信息 + fields: + - name: 受赠人 + type: verbatim + required_from: draft + desc: 受赠慈善机构/基金会/慈善会的全称 + deep_retry: false + - name: 受赠人地址 + type: verbatim + required_from: draft + desc: 受赠人地址 + deep_retry: false + - name: 受赠人联系电话 + type: verbatim + required_from: draft + desc: 受赠人联系电话 + deep_retry: false + - name: 受赠人法定代表人 + type: verbatim + required_from: draft + desc: 受赠人法定代表人姓名 + deep_retry: false +- group: 项目实施方(丙方)信息 + fields: + - name: 项目实施方 + type: verbatim + required_from: draft + desc: 项目实施方(党政机关、村委会、居委会、合作社等)的全称 + deep_retry: false + - name: 项目实施方地址 + type: verbatim + required_from: draft + desc: 项目实施方地址 + deep_retry: false + - name: 项目实施方联系电话 + type: verbatim + required_from: draft + desc: 项目实施方联系电话 + deep_retry: false +- group: 使用人(丁方,仅四方结构) + fields: + - name: 使用人 + type: verbatim + required_from: draft + desc: 最终使用捐赠财产的单位(如具体合作社、村委会)。仅四方结构填写;三方结构留空 + deep_retry: false +- group: 捐赠标的与条件 + fields: + - name: 捐赠金额 + type: money + required_from: draft + desc: 捐赠资金数额(人民币,元) + deep_retry: true + - name: 捐赠金额大写 + type: verbatim + required_from: draft + desc: 捐赠金额的中文大写 + deep_retry: false + - name: 定向用途 + type: string + required_from: draft + desc: 指定的捐赠用途(项目名称、地域、人群等) + deep_retry: false + - name: 交付时间 + type: string + required_from: draft + desc: 捐赠财产的交付时间/期限约定(含拨付给使用人的环节) + deep_retry: false + - name: 交付方式 + type: string + required_from: draft + desc: 捐赠财产的交付方式(银行转账等) + deep_retry: false +- group: 收款方账户 + fields: + - name: 收款方账户名称 + type: verbatim + required_from: draft + desc: 收款方(通常为受赠人或使用人)的账户名称 + deep_retry: false + - name: 收款方开户银行 + type: verbatim + required_from: draft + desc: 收款方的开户银行 + deep_retry: false + - name: 收款方银行账号 + type: verbatim + required_from: draft + desc: 收款方的银行账号 + deep_retry: false +- group: 重要条款 + fields: + - name: 各方权利义务条款 + type: string + required_from: draft + desc: 各方的权利义务及监督链条约定(通常为合同正文的权利义务章节) + deep_retry: false + - name: 票据义务条款 + type: string + required_from: draft + desc: 关于开具公益事业捐赠专用收据/合法票据的约定 + deep_retry: false + - name: 剩余财产处置 + type: string + required_from: draft + desc: 项目终止或完成后剩余定向捐赠财产的处置约定 + deep_retry: false + - name: 信息公开条款 + type: string + required_from: draft + desc: 捐赠信息公开相关条款(是否公开捐赠人、公告渠道等) + deep_retry: false + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约情形和责任约定 + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式及管辖机构 + deep_retry: false + - name: 不可抗力条款 + type: string + required_from: draft + desc: 不可抗力的定义、通知义务、免责约定 + deep_retry: false +- group: 签署要素 + fields: + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 捐赠人统一社会信用代码 + type: uscc + required_from: executed + desc: 捐赠人 USCC + deep_retry: false + - name: 受赠人统一社会信用代码 + type: uscc + required_from: executed + desc: 受赠人(慈善机构)USCC + deep_retry: false +- group: 合同特征分类 + fields: + - name: 合同方结构 + type: enum + required_from: draft + allowed: + - 三方 + - 四方 + desc: '合同当事方数量结构。 "三方":捐赠人—受赠人(慈善机构)—项目实施方。 "四方":捐赠人—受赠人(慈善机构)—管理人—使用人(如多个具体执行合作社/村委会)。 + + ' + deep_retry: false +rules: +- group: 完整性 + rules: + - rule_id: ZY-CHY-001 + name: 捐赠人信息完整 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 捐赠人 + - id: '2' + check: required + field: 捐赠人地址 + - id: '3' + check: required + field: 捐赠人联系电话 + messages: + pass: 捐赠人信息完整 + fail: 捐赠人信息缺失 + type: deterministic + - rule_id: ZY-CHY-002 + name: 受赠慈善机构信息完整 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 受赠人 + - id: '2' + check: required + field: 受赠人地址 + - id: '3' + check: required + field: 受赠人联系电话 + - id: '4' + check: required + field: 受赠人法定代表人 + messages: + pass: 受赠人信息完整 + fail: 受赠人信息缺失 + type: deterministic + - rule_id: ZY-CHY-003 + name: 项目实施方信息完整 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 项目实施方 + - id: '2' + check: required + field: 项目实施方地址 + - id: '3' + check: required + field: 项目实施方联系电话 + messages: + pass: 项目实施方信息完整 + fail: 项目实施方信息缺失 + type: deterministic + - rule_id: ZY-CHY-004 + name: 使用人信息完整 + risk: medium + score: 5 + activate_if: 合同方结构 == "四方" + stages: + - id: '1' + check: required + field: 使用人 + messages: + pass: 使用人信息完整 + fail: 四方合同缺少使用人信息 + type: deterministic + - rule_id: ZY-CHY-005 + name: 捐赠金额明确 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 捐赠金额 + - id: '2' + check: required + field: 捐赠金额大写 + messages: + pass: 捐赠金额约定明确 + fail: 缺少捐赠金额或大写金额 + type: deterministic + - rule_id: ZY-CHY-006 + name: 定向用途具体明确 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 定向用途 + - id: '2' + check: ai + prompt: '请判断以下定向公益捐赠合同中"定向用途"是否具体明确(依据慈善法§38)。 + + + 定向用途:{{定向用途}} + + + 判断标准: + + 1. 用途是否具体到项目名称(如"灾后重建项目""乡村振兴帮扶项目"等) + + 2. 是否明确了地域范围(如"XX 县""XX 村") + + 3. 是否明确了受益人群或用途细节(如"困难群众""XX 工作""XX 设施修复") + + 4. 是否避免"支持慈善事业""公益用途"等笼统表述 + + 5. 是否有禁止擅自改变用途的条款 + + ' + messages: + pass: 定向用途具体明确 + fail: 定向用途描述过于笼统 + type: ai_rule + - rule_id: ZY-CHY-007 + name: 交付时间与方式明确 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 交付时间 + - id: '2' + check: required + field: 交付方式 + - id: '3' + check: ai + prompt: '请判断以下定向捐赠合同的交付条款是否明确(依据公益事业捐赠法§12)。 + + + 交付时间:{{交付时间}} + + 交付方式:{{交付方式}} + + + 判断标准: + + 1. 交付期限是否以具体工作日或具体日期约定(如"30个工作日内"、"2024年12月31日前") + + 2. 交付方式是否为银行转账等可追溯方式 + + 3. 对于三方/四方结构,是否约定了受赠人→使用人的拨付环节期限 + + 4. 是否避免"尽快""合理期限"等模糊表述 + + ' + messages: + pass: 交付条款明确 + fail: 交付条款不够明确 + type: ai_rule + - rule_id: ZY-CHY-008 + name: 收款方银行账户完整 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 收款方账户名称 + - id: '2' + check: required + field: 收款方开户银行 + - id: '3' + check: required + field: 收款方银行账号 + messages: + pass: 收款账户信息完整 + fail: 收款账户信息缺失 + type: deterministic + - rule_id: ZY-CHY-009 + name: 签约日期齐全 + risk: high + score: 8 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + messages: + pass: 签约日期已填写 + fail: 缺少签约日期 + type: deterministic +- group: 规范性 + rules: + - rule_id: ZY-CHY-010 + name: 捐赠人统一社会信用代码合法 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 捐赠人统一社会信用代码 + format: uscc + messages: + pass: 捐赠人USCC合法 + fail: 捐赠人USCC格式错误或缺失 + type: deterministic + - rule_id: ZY-CHY-011 + name: 受赠人统一社会信用代码合法 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 受赠人统一社会信用代码 + format: uscc + messages: + pass: 受赠人USCC合法 + fail: 受赠人USCC格式错误或缺失 + type: deterministic +- group: 合理性 + rules: + - rule_id: ZY-CHY-012 + name: 捐赠金额大小写一致 + risk: high + score: 10 + stages: + - id: '1' + check: amount_match + number: 捐赠金额 + chinese: 捐赠金额大写 + messages: + pass: 金额大小写一致 + fail: 金额数字与大写不一致 + type: deterministic + - rule_id: ZY-CHY-013 + name: 捐赠金额为正 + risk: low + score: 3 + stages: + - id: '1' + check: compare + left: 捐赠金额 + op: '>' + right: 0 + messages: + pass: 金额为正 + fail: 金额应大于0 + type: deterministic +- group: 合规性 + rules: + - rule_id: ZY-CHY-014 + name: 定向用途属于公益范围 + risk: medium + score: 5 + stages: + - id: '1' + check: ai + prompt: '请判断以下定向捐赠的用途是否属于《慈善法§3》列举的公益范围。 + + + 定向用途:{{定向用途}} + + + 判断标准(慈善法§3 列举的慈善活动): + + 1. 扶贫、济困 + + 2. 扶老、救孤、恤病、助残、优抚 + + 3. 救灾/防控突发公共卫生事件 + + 4. 促进教育、科学、文化、卫生、体育事业发展 + + 5. 防治污染和其他公害,保护和改善生态环境 + + 6. 其他符合社会公共利益的活动 + + + 判断方法:只要用途描述能明确归入上述任一大类即通过,无需强求精确对应。 + + ' + messages: + pass: 用途属于公益范围 + fail: 用途不属于公益慈善范围或属于商业行为 + type: ai_rule + - rule_id: ZY-CHY-015 + name: 监督链条完整 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 各方权利义务条款 + - id: '2' + check: ai + prompt: '请判断以下定向捐赠合同的监督链条是否完整(依据慈善法§75、公益捐赠法§20)。 + + + 各方权利义务条款:{{各方权利义务条款}} + + + 判断标准: + + 1. 捐赠人是否保留对捐赠财产使用情况的查询和监督权 + + 2. 受赠慈善机构是否承担向使用人/项目实施方拨付前的审核义务 + + 3. 项目实施方/使用人是否承担定期向捐赠人/慈善机构反馈项目实施情况的义务 + + 4. 是否约定审计权(如年度审计、完工专项审计) + + 5. 监督权是否具有可操作性(书面反馈、现场检查等) + + ' + messages: + pass: 监督链条完整 + fail: 监督链条不完整或职责不清 + type: ai_rule + - rule_id: ZY-CHY-016 + name: 专用票据义务约定 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 票据义务条款 + - id: '2' + check: ai + prompt: '请判断以下定向捐赠合同中关于票据的约定是否符合要求(依据公益事业捐赠法§16)。 + + + 票据义务条款:{{票据义务条款}} + + + 判断标准: + + 1. 是否约定受赠人向捐赠人开具公益事业捐赠专用收据 + + 2. 票据类型是否明确(财政部门统一印/监制的公益事业捐赠票据) + + 3. 开票时限是否明确(通常为接受捐赠后10日内) + + 4. 如为四方结构,使用人向受赠人开具的合法有效票据是否约定 + + ' + messages: + pass: 票据义务约定明确 + fail: 票据义务未约定或不符合要求 + type: ai_rule + - rule_id: ZY-CHY-017 + name: 剩余财产处置约定 + risk: medium + score: 3 + stages: + - id: '1' + check: ai + prompt: '请判断以下定向捐赠合同对项目终止或完成后剩余财产的处置是否明确(依据慈善法§56)。 + + + 剩余财产处置:{{剩余财产处置}} + + + 判断标准: + + 1. 是否约定项目终止时剩余财产的处置方式 + + 2. 剩余财产归属是否明确(通常汇缴慈善机构用于其他公益或协商另作公益) + + 3. 是否禁止剩余财产被挪作他用 + + ' + messages: + pass: 剩余财产处置约定明确 + fail: 剩余财产处置未约定 + type: ai_rule + - rule_id: ZY-CHY-018 + name: 信息公开条款 + risk: low + score: 3 + stages: + - id: '1' + check: ai + prompt: '请判断以下定向捐赠合同对信息公开的约定是否合理(依据慈善法§69-§73)。 + + + 信息公开条款:{{信息公开条款}} + + + 判断标准: + + 1. 是否约定捐赠人是否同意公开其姓名/名称(通常给出同意/不同意选项) + + 2. 是否约定公告渠道(受赠人网站公告、社会公告等) + + 3. 是否保障捐赠人对捐赠财产的使用情况享有知情权 + + ' + messages: + pass: 信息公开条款合理 + fail: 信息公开条款缺失或不合理 + type: ai_rule + - rule_id: ZY-CHY-019 + name: 违约责任条款充分 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请判断以下定向捐赠合同违约责任条款是否充分。 + + + 违约责任条款:{{违约责任条款}} + + + 判断标准: + + 1. 是否覆盖各方(甲/乙/丙/丁)的违约情形 + + 2. 是否约定捐赠人不按时足额交付的责任 + + 3. 是否约定受赠人/使用人挪用或不按约定管理使用的责任 + + 4. 是否约定终止合同、追回款项等救济手段 + + 5. 是否避免"按法律规定处理"等兜底性表述 + + ' + messages: + pass: 违约责任条款充分 + fail: 违约责任条款不够充分 + type: ai_rule + - rule_id: ZY-CHY-020 + name: 争议解决条款明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请判断以下定向捐赠合同争议解决条款是否明确。 + + + 争议解决条款:{{争议解决条款}} + + + 判断标准: + + 1. 是否约定争议解决方式(协商/仲裁/诉讼) + + 2. 如选择诉讼,是否指定具体管辖法院(受赠人所在地或当地人民法院) + + 3. 是否避免同时约定仲裁和诉讼 + + ' + messages: + pass: 争议解决条款明确 + fail: 争议解决条款不明确 + type: ai_rule + - rule_id: ZY-CHY-021 + name: 不可抗力条款完整 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 不可抗力条款 + - id: '2' + check: ai + prompt: '请判断以下定向捐赠合同不可抗力条款是否完整。 + + + 不可抗力条款:{{不可抗力条款}} + + + 判断标准: + + 1. 是否明确不可抗力的定义或范围(地震、洪水、台风、战争、政府行为等) + + 2. 是否约定通知义务及时限(通常5-10日内书面通知) + + 3. 是否约定法律后果(继续履行/解除合同/免责) + + ' + messages: + pass: 不可抗力条款完整 + fail: 不可抗力条款不完整 + type: ai_rule + - rule_id: ZY-CHY-022 + name: 任意撤销权排除 + risk: low + score: 3 + stages: + - id: '1' + check: ai + prompt: '请判断以下定向公益捐赠合同是否合理处理任意撤销权问题(依据民法典§660、慈善法§41)。 + + + 违约责任条款:{{违约责任条款}} + + 各方权利义务条款:{{各方权利义务条款}} + + + 判断标准: + + 1. 合同是否明示"依法不可任意撤销"或援引民法典§660/慈善法§41 + + 2. 合同条款是否违反公益捐赠不可任意撤销的规定 + + 3. 如仅约定赠与方经济状况严重恶化可终止(民法典§666),是否合理 + + + 注意:公益道德义务性赠与不适用任意撤销权;不硬性要求合同明示,只要条款整体与法律规定不冲突即可 pass。 + + ' + messages: + pass: 合同符合公益捐赠不可任意撤销规定 + fail: 合同存在与公益捐赠不可任意撤销规定冲突的条款 + type: ai_rule diff --git a/rules/contract_gift_general/docs/test_middle.md b/rules/contract_gift_general/docs/test_middle.md new file mode 100644 index 0000000..00e0138 --- /dev/null +++ b/rules/contract_gift_general/docs/test_middle.md @@ -0,0 +1,63 @@ +# 赠与合同 + +**合同编号:** ZY-GR-2024-0088 + +**甲方(赠与方):** 王大年 +**地址:** 上海市浦东新区世纪大道 1200 弄 15 号 202 室 +**联系电话:** 13901234567 + +**乙方(受赠方):** 王小强 +**地址:** 上海市浦东新区世纪大道 1200 弄 15 号 202 室 +**联系电话:** 13907654321 + +甲乙双方系父子关系,甲方自愿将其合法所有的资金赠与乙方,依据《中华人民共和国民法典》合同编相关规定,订立本合同。 + +## 第一条 赠与标的 + +1.1 赠与财产:人民币资金。 +1.2 赠与金额:人民币伍拾万元整(¥500,000.00)。 +1.3 赠与价值:甲方合法所有的自有资金 500,000.00 元,来源为合法工资与投资收益。 + +## 第二条 交付方式 + +2.1 交付方式:银行转账。 +2.2 交付时间:本合同签订之日起 30 日内。 +2.3 登记手续:资金赠与无需登记。 + +## 第三条 附加义务 + +3.1 本赠与为无偿赠与,不附加任何义务。 + +## 第四条 公证 + +4.1 本合同未经公证。 + +## 第五条 撤销权 + +5.1 在赠与财产权利转移之前,甲方可依法撤销赠与。 + +## 第六条 瑕疵责任 + +6.1 甲方对赠与资金的来源合法性负责。 + +## 第七条 违约责任 + +7.1 甲方如未按时交付,每日按未交付金额的万分之三支付违约金。 +7.2 乙方如收到赠与后将其用于违法行为,甲方有权全额追回赠与款项并追究法律责任。 + +## 第八条 争议解决 + +8.1 如发生争议,双方友好协商解决;协商不成可通过法律途径处理。 + +## 第九条 其他 + +9.1 本合同一式两份,甲乙双方各执一份。 +9.2 本合同自双方签字之日起生效。 + +--- + +**甲方(签字):** 王大年 + +**乙方(签字):** 王小强 + +**签约日期:** 2024 年 11 月 8 日 diff --git a/rules/contract_gift_general/docs/test_negative.md b/rules/contract_gift_general/docs/test_negative.md new file mode 100644 index 0000000..14a9349 --- /dev/null +++ b/rules/contract_gift_general/docs/test_negative.md @@ -0,0 +1,19 @@ +# 赠与合同 + +甲方:小王 + +乙方:小李 + +甲方将一些资金赠与乙方,数额约几万元。 + +乙方收到后应妥善使用。 + +如有争议,按法律处理。 + +甲乙双方签字确认。 + +--- + +甲方:小王 + +乙方:小李 diff --git a/rules/contract_gift_general/docs/test_positive.md b/rules/contract_gift_general/docs/test_positive.md new file mode 100644 index 0000000..21163f9 --- /dev/null +++ b/rules/contract_gift_general/docs/test_positive.md @@ -0,0 +1,94 @@ +# 赠与合同 + +**合同编号:** DH-ZY-2024-0001 + +**甲方(赠与方):** 东方光华科技有限公司 +**地址:** 北京市海淀区中关村大街18号光华大厦20层 +**联系电话:** 010-88889999 +**统一社会信用代码:** 91110108MA01H2XY65 +**法定代表人:** 张志远 + +**乙方(受赠方):** 华夏职工福利服务中心 +**地址:** 北京市朝阳区建国路95号福利大厦8层 +**联系电话:** 010-66665555 +**统一社会信用代码:** 91110105MA7K3BQP28 +**法定代表人:** 李慧敏 + +甲乙双方在平等自愿、协商一致的基础上,依据《中华人民共和国民法典》合同编第十一章的相关规定,就甲方向乙方赠与资金事宜,经友好协商,订立本合同,双方共同遵守。 + +## 第一条 赠与标的与价值 + +1.1 赠与财产名称:资金。 +1.2 赠与金额:人民币壹佰万元整(¥1,000,000.00)。 +1.3 赠与价值说明:经甲方自有资金核实,赠与金额为 1,000,000.00 元人民币,为甲方合法所有、可自由处分的财产。 + +## 第二条 赠与目的及附加义务 + +2.1 赠与目的:支持乙方设立并运营"华夏职工医疗互助基金",用于帮助乙方辖下职工因重大疾病、意外伤害所产生的医疗费用补助。 + +2.2 附加义务: +(1)乙方应将全部赠与资金专款专用于职工医疗互助基金,不得挪作他用,不得用于商业投资或其他非医疗互助用途; +(2)乙方应在收到资金后 30 日内建立专账管理,并在每年 12 月 31 日前向甲方提交年度资金使用情况说明及审计报告; +(3)持续履行上述义务直至资金使用完毕。如未履行上述义务,甲方有权撤销赠与并要求乙方返还已拨付资金。 + +## 第三条 交付方式与时间 + +3.1 交付方式:银行转账。 +3.2 交付时间:本合同经公证生效后 15 个工作日内,甲方将赠与资金一次性转账至乙方指定账户。 +3.3 登记手续:本赠与为资金赠与,无需办理不动产登记或权属变更手续。 +3.4 乙方收款账户: + 账户名称:华夏职工福利服务中心 + 开户银行:中国工商银行北京朝阳支行 + 银行账号:0200000009200123456 + +## 第四条 瑕疵责任 + +4.1 甲方保证所赠与的资金来源合法、权属清晰,无任何权利瑕疵。 +4.2 甲方故意不告知瑕疵或保证无瑕疵,造成乙方损失的,应当承担赔偿责任。 +4.3 因本赠与附有义务,甲方在附加义务限度内承担与出卖人相同的瑕疵担保责任。甲方应在签订本合同时书面披露资金来源及权属状况,供乙方核验。 + +## 第五条 公证 + +5.1 本合同已于 2024 年 10 月 20 日经北京市长安公证处公证,公证编号:(2024)京长证字第 1234 号。 +5.2 双方确认:经公证的赠与合同,依照《中华人民共和国民法典》第六百五十八条第二款,赠与方不享有任意撤销权,应当按照本合同约定交付赠与财产。 +5.3 对于大额资金赠与,甲乙双方一致认为通过公证有助于保障赠与行为的法律效力和双方权益。 + +## 第六条 撤销权 + +6.1 **任意撤销权:** 本合同已经公证,甲方不享有《民法典》第六百五十八条第一款规定的赠与财产权利转移前的任意撤销权。 + +6.2 **法定撤销情形:** 受赠人有下列情形之一的,赠与方可以撤销赠与: +(1)严重侵害赠与方或其近亲属合法权益的; +(2)对赠与方有扶养义务而不履行的; +(3)不履行本合同约定的附加义务的。 + +6.3 赠与方的撤销权,自知道或者应当知道撤销事由之日起一年内行使。 + +## 第七条 违约责任 + +7.1 甲方如未按本合同约定时间足额交付赠与资金,每延迟一日应按未交付金额的万分之五向乙方支付违约金,违约金上限为赠与金额的 10%。 + +7.2 乙方如违反第二条约定的附加义务,存在挪用或未按约定用途使用赠与资金情形的,应向甲方支付赠与总额 20% 的违约金,并全额返还已使用的赠与资金。 + +7.3 任一方构成根本违约的,守约方有权解除本合同并要求对方赔偿全部实际损失(包括但不限于直接损失、资金占用损失及合理律师费)。 + +## 第八条 争议解决 + +8.1 本合同履行过程中发生的任何争议,双方应首先通过友好协商方式解决。 + +8.2 协商不成的,任何一方均有权将争议提交甲方所在地(北京市海淀区)人民法院通过诉讼方式解决。 + +## 第九条 其他 + +9.1 本合同自双方法定代表人签字并加盖公章并经公证机关出具公证书之日起生效。 +9.2 本合同一式三份,甲乙双方各执一份,公证机关留存一份,具有同等法律效力。 + +--- + +**甲方(盖章):** 东方光华科技有限公司 +**法定代表人(签字):** 张志远 + +**乙方(盖章):** 华夏职工福利服务中心 +**法定代表人(签字):** 李慧敏 + +**签约日期:** 2024 年 10 月 25 日 diff --git a/rules/contract_gift_general/rules.yaml b/rules/contract_gift_general/rules.yaml new file mode 100644 index 0000000..3626cfe --- /dev/null +++ b/rules/contract_gift_general/rules.yaml @@ -0,0 +1,612 @@ +metadata: + type_id: contract.gift.general + name: 通用赠与合同 + version: '1.0' + last_updated: '2026-04-14' + tags: + - 合同 + - 赠与 + references_laws: + - 民法典第657条 + - 民法典第658条 + - 民法典第659条 + - 民法典第660条 + - 民法典第661条 + - 民法典第662条 + - 民法典第663条 + - 民法典第490条 + description: '依据《中华人民共和国民法典》合同编第十一章(第657-666条),适用于赠与人将 + + 自己的财产无偿给予受赠人的普通赠与合同(双方结构)。 + + 若为三方/四方定向公益捐赠(捐赠人→慈善机构→项目实施方),请使用 + + contract.gift.charity 评查规则。 + + ' +extract: +- group: 赠与方信息 + fields: + - name: 赠与方 + type: verbatim + required_from: draft + desc: 赠与人姓名或公司全称 + deep_retry: false + - name: 赠与方地址 + type: verbatim + required_from: draft + desc: 赠与人住所地或公司注册地址 + deep_retry: false + - name: 赠与方联系电话 + type: verbatim + required_from: draft + desc: 赠与人联系电话 + deep_retry: false +- group: 受赠方信息 + fields: + - name: 受赠方 + type: verbatim + required_from: draft + desc: 受赠人姓名或公司全称 + deep_retry: false + - name: 受赠方地址 + type: verbatim + required_from: draft + desc: 受赠人住所地或公司注册地址 + deep_retry: false + - name: 受赠方联系电话 + type: verbatim + required_from: draft + desc: 受赠人联系电话 + deep_retry: false +- group: 赠与标的与价值 + fields: + - name: 赠与标的 + type: string + required_from: draft + desc: 赠与财产的名称、类型、数量、规格等具体描述 + deep_retry: false + - name: 赠与价值 + type: string + required_from: draft + desc: 赠与财产的价值评估或说明(资金直接描述金额,实物描述市场价/评估价) + deep_retry: false + - name: 赠与金额 + type: money + required_from: draft + desc: 赠与资金数额。仅当赠与标的为资金时填写,实物赠与不填 + deep_retry: true + - name: 赠与金额大写 + type: verbatim + required_from: draft + desc: 赠与资金的中文大写金额。仅当赠与标的为资金时填写 + deep_retry: false +- group: 交付条款 + fields: + - name: 交付方式 + type: string + required_from: draft + desc: 赠与财产的交付方式(银行转账/实物交付/权利转让等) + deep_retry: false + - name: 交付时间 + type: string + required_from: draft + desc: 交付的具体时间或期限 + deep_retry: false + - name: 登记手续 + type: string + required_from: draft + desc: 需办理的登记/过户手续及费用承担约定(如不动产过户、车辆过户) + deep_retry: false +- group: 条件与义务 + fields: + - name: 附加义务 + type: string + required_from: draft + desc: 附义务赠与中受赠人需履行的义务内容。非附义务赠与留空 + deep_retry: false + - name: 履行要求 + type: string + required_from: draft + desc: 附加义务的履行标准、期限和未履行后果。非附义务赠与留空 + deep_retry: false +- group: 撤销权条款 + fields: + - name: 法定撤销情形 + type: string + required_from: draft + desc: 合同中约定的法定撤销情形(如严重侵害赠与人、不履行扶养义务、不履行附加义务等) + deep_retry: false + - name: 任意撤销权 + type: string + required_from: draft + desc: 赠与人任意撤销权的约定(权利转移前可撤销) + deep_retry: false +- group: 其他法定条款 + fields: + - name: 瑕疵责任条款 + type: string + required_from: draft + desc: 赠与财产瑕疵责任的约定(民法典§662) + deep_retry: false + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约情形与违约责任的约定 + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式与管辖机构约定 + deep_retry: false + - name: 是否经过公证 + type: string + required_from: draft + desc: 合同是否约定经过公证,以及公证机关 + deep_retry: false +- group: 签署要素 + fields: + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 合同编号 + type: verbatim + required_from: executed + desc: 合同编号 + deep_retry: false + - name: 赠与方统一社会信用代码 + type: uscc + required_from: executed + desc: 赠与方 USCC(仅赠与方为企业/组织时填写) + deep_retry: false + - name: 受赠方统一社会信用代码 + type: uscc + required_from: executed + desc: 受赠方 USCC(仅受赠方为企业/组织时填写) + deep_retry: false +- group: 合同特征分类 + fields: + - name: 赠与方为企业 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '赠与方是否为企业/组织(而非自然人)。 填"是"的条件:赠与方为公司、事业单位、社会团体、基金会、合作社等组织。 填"否"的条件:赠与方为自然人(个人)。 + + ' + deep_retry: false + - name: 受赠方为企业 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '受赠方是否为企业/组织(而非自然人)。 填"是"的条件:受赠方为公司、事业单位、社会团体、基金会、合作社等组织。 填"否"的条件:受赠方为自然人(个人)。 + + ' + deep_retry: false + - name: 赠与标的类型 + type: enum + required_from: draft + allowed: + - 资金 + - 实物 + - 不动产 + - 股权 + - 其他 + desc: '赠与财产的性质分类。 "资金":现金或银行存款;"实物":动产(设备、物品等); "不动产":土地、房屋;"股权":公司股权/股份; "其他":知识产权、债权等无形财产。 + + ' + deep_retry: false + - name: 是否附义务 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '赠与合同是否约定受赠人需履行特定义务(民法典§661)。 填"是"的条件:合同明确约定受赠人有履行某项义务(如扶养、使用限制、用途约束等)。 填"否"的条件:纯粹无偿赠与,不附加任何义务。 + + ' + deep_retry: false + - name: 是否公益性赠与 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '是否具有救灾、扶贫、助残、慈善等公益、道德义务性质(民法典§658)。 填"是"的条件:赠与用于救灾、扶贫、助残、公益慈善、教育、医疗、科研等社会公益目的。 填"否"的条件:普通民事赠与(亲属间赠与、个人间赠与等)。 注意:具有公益性质的赠与依法不得任意撤销;三方/四方定向公益捐赠应使用 + contract.gift.charity 评查规则。 + + ' + deep_retry: false +rules: +- group: 完整性 + rules: + - rule_id: ZY-GEN-001 + name: 赠与方信息完整 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 赠与方 + - id: '2' + check: required + field: 赠与方地址 + - id: '3' + check: required + field: 赠与方联系电话 + messages: + pass: 赠与方信息完整 + fail: 赠与方信息缺失 + type: deterministic + - rule_id: ZY-GEN-002 + name: 受赠方信息完整 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 受赠方 + - id: '2' + check: required + field: 受赠方地址 + - id: '3' + check: required + field: 受赠方联系电话 + messages: + pass: 受赠方信息完整 + fail: 受赠方信息缺失 + type: deterministic + - rule_id: ZY-GEN-003 + name: 赠与标的明确 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 赠与标的 + - id: '2' + check: required + field: 赠与价值 + - id: '3' + check: ai + prompt: '请判断以下赠与合同中的赠与标的是否明确具体(依据民法典§657)。 + + + 赠与标的描述:{{赠与标的}} + + 赠与价值:{{赠与价值}} + + + 判断标准: + + 1. 是否明确了赠与财产的具体内容(名称、数量、规格等) + + 2. 是否对赠与财产进行了价值评估或说明 + + 3. 描述是否足够具体,不存在"部分财产""相关物品"等模糊表述 + + 4. 如为不动产赠与,是否注明了地址、面积、权属证号等 + + 5. 如为实物赠与,是否注明了品名、型号、规格、数量 + + ' + messages: + pass: 赠与标的约定明确 + fail: 赠与标的约定不明确 + type: ai_rule + - rule_id: ZY-GEN-004 + name: 赠与交付方式明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 交付方式 + - id: '2' + check: ai + prompt: '请判断以下赠与合同的交付条款是否明确(依据民法典§659)。 + + + 交付方式:{{交付方式}} + + 交付时间:{{交付时间}} + + 登记手续:{{登记手续}} + + + 判断标准: + + 1. 是否明确了赠与财产的交付方式(银行转账/实物交付/权利转让等) + + 2. 是否约定了具体的交付时间或期限 + + 3. 如需办理登记(不动产过户、车辆过户、股权变更等),是否约定了办理手续的期限和费用承担 + + 4. 交付的确认方式是否明确(签收、登记完成等) + + ' + messages: + pass: 交付条款明确 + fail: 交付条款不明确 + type: ai_rule + - rule_id: ZY-GEN-005 + name: 签约要素齐全 + risk: high + score: 8 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + - id: '2' + check: required + field: 合同编号 + messages: + pass: 签约要素齐全 + fail: 缺少签约日期或合同编号 + type: deterministic +- group: 规范性 + rules: + - rule_id: ZY-GEN-006 + name: 赠与方统一社会信用代码合法 + risk: medium + score: 5 + applies_in: + - executed + activate_if: 赠与方为企业 == "是" + stages: + - id: '1' + check: format + field: 赠与方统一社会信用代码 + format: uscc + messages: + pass: 赠与方USCC合法 + fail: 赠与方USCC格式错误或缺失 + type: deterministic + - rule_id: ZY-GEN-007 + name: 受赠方统一社会信用代码合法 + risk: medium + score: 5 + applies_in: + - executed + activate_if: 受赠方为企业 == "是" + stages: + - id: '1' + check: format + field: 受赠方统一社会信用代码 + format: uscc + messages: + pass: 受赠方USCC合法 + fail: 受赠方USCC格式错误或缺失 + type: deterministic +- group: 合理性 + rules: + - rule_id: ZY-GEN-008 + name: 赠与金额大小写一致 + risk: high + score: 10 + activate_if: 赠与标的类型 == "资金" + stages: + - id: '1' + check: amount_match + number: 赠与金额 + chinese: 赠与金额大写 + messages: + pass: 金额大小写一致 + fail: 金额数字与大写不一致 + type: deterministic + - rule_id: ZY-GEN-009 + name: 赠与金额为正 + risk: low + score: 3 + activate_if: 赠与标的类型 == "资金" + stages: + - id: '1' + check: compare + left: 赠与金额 + op: '>' + right: 0 + messages: + pass: 金额为正 + fail: 金额应大于0 + type: deterministic +- group: 合规性 + rules: + - rule_id: ZY-GEN-010 + name: 附义务条款明确 + risk: medium + score: 5 + activate_if: 是否附义务 == "是" + stages: + - id: '1' + check: required + field: 附加义务 + - id: '2' + check: ai + prompt: '请判断以下附义务赠与合同中附加义务的约定是否明确(依据民法典§661)。 + + + 附加义务:{{附加义务}} + + 履行要求:{{履行要求}} + + 赠与价值:{{赠与价值}} + + + 判断标准: + + 1. 义务内容是否具体明确(如扶养内容、使用限制、用途约束等) + + 2. 受赠人履行义务的标准和期限是否有明确约定 + + 3. 未履行义务的后果是否约定(赠与人可撤销赠与) + + 4. 附加义务是否明显超过赠与财产的价值(按§662,赠与人在附义务限度内承担瑕疵责任) + + ' + messages: + pass: 附义务条款明确 + fail: 附义务条款不明确 + type: ai_rule + - rule_id: ZY-GEN-011 + name: 撤销权条款约定 + risk: medium + score: 3 + activate_if: 是否公益性赠与 == "否" + stages: + - id: '1' + check: ai + prompt: '请判断以下赠与合同是否合理约定了撤销权条款(依据民法典§658、§663)。 + + + 任意撤销权:{{任意撤销权}} + + 法定撤销情形:{{法定撤销情形}} + + 是否经过公证:{{是否经过公证}} + + + 判断标准: + + 1. 是否约定了赠与人的任意撤销权(权利转移前可撤销,§658) + + 2. 是否列明了法定撤销情形(§663:严重侵害赠与人权益、不履行扶养义务、不履行赠与附加义务) + + 3. 撤销权行使时间是否约定(知道撤销事由之日起1年内,§663) + + 4. 如已公证或属于公益道德义务性赠与,是否提示不可任意撤销 + + ' + messages: + pass: 撤销权条款约定合理 + fail: 撤销权条款缺失或不完整 + type: ai_rule + - rule_id: ZY-GEN-012 + name: 公证条款明确 + risk: low + score: 2 + stages: + - id: '1' + check: ai + prompt: '请判断赠与合同中关于公证的约定是否明确(依据民法典§658、§660)。 + + + 是否经过公证:{{是否经过公证}} + + + 判断标准: + + 1. 合同是否明确说明了是否经过公证 + + 2. 对于不动产、大额资产等重要赠与,是否建议公证以保障受赠人权益 + + 3. 如已公证,是否提示该合同不适用任意撤销权 + + ' + messages: + pass: 公证约定明确 + fail: 公证条款缺失或不明确 + type: ai_rule + - rule_id: ZY-GEN-013 + name: 瑕疵责任约定 + risk: low + score: 3 + activate_if: 是否附义务 == "是" + stages: + - id: '1' + check: ai + prompt: '请判断附义务赠与合同中瑕疵责任的约定是否合理(依据民法典§662)。 + + + 瑕疵责任条款:{{瑕疵责任条款}} + + + 判断标准: + + 1. 是否约定赠与人的告知义务(故意隐瞒瑕疵需担责) + + 2. 是否约定附义务限度内的瑕疵责任承担 + + 3. 瑕疵告知和检验方式是否约定 + + ' + messages: + pass: 瑕疵责任约定合理 + fail: 瑕疵责任未约定或不合理 + type: ai_rule + - rule_id: ZY-GEN-014 + name: 违约责任条款充分 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请判断以下赠与合同违约责任条款是否充分(依据民法典§577-585)。 + + + 违约责任条款:{{违约责任条款}} + + + 判断标准: + + 1. 是否明确了赠与方和受赠方各自的违约情形 + + 2. 是否约定了违约金或赔偿标准 + + 3. 是否覆盖核心违约情形(赠与方不交付、受赠方不履行附加义务等) + + 4. 是否避免"按民法典处理"等兜底性表述 + + ' + messages: + pass: 违约责任条款充分 + fail: 违约责任条款不够充分 + type: ai_rule + - rule_id: ZY-GEN-015 + name: 争议解决条款明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请判断以下赠与合同争议解决条款是否明确。 + + + 争议解决条款:{{争议解决条款}} + + + 判断标准: + + 1. 是否约定了争议解决方式(协商/仲裁/诉讼) + + 2. 如选择仲裁,是否明确指定仲裁机构 + + 3. 如选择诉讼,是否指定管辖法院 + + 4. 不得同时约定仲裁和诉讼 + + ' + messages: + pass: 争议解决条款明确 + fail: 争议解决条款不明确 + type: ai_rule diff --git a/rules/contract_lease/docs/test_middle.md b/rules/contract_lease/docs/test_middle.md new file mode 100644 index 0000000..2aa87f7 --- /dev/null +++ b/rules/contract_lease/docs/test_middle.md @@ -0,0 +1,67 @@ +# 梅城区办公楼租赁合同 + +合同名称:办公用房租赁合同 + +出租方(甲方):梅城区机关事务管理中心 +法定代表人:黄伟强 +地址:广东省梅州市梅城区行政中心C栋3楼 +联系人:刘芳 +联系电话:0753-2188100 + +承租方(乙方):梅州市恒达商贸有限公司 +法定代表人:张贤 +地址:梅州市梅江区彬芳大道158号 +联系人:陈小华 +联系电话:0753-2298888 + +根据《中华人民共和国民法典》等有关法律法规,甲乙双方经协商一致签订本合同。 + +## 一、租赁物 + +甲方将位于梅城区行政中心D栋1楼的临街商铺出租给乙方,面积约120平方米。 + +## 二、租赁用途 + +乙方承租上述房屋用于商业经营。 + +## 三、租赁期限 + +自2024年7月1日至2027年6月30日,共3年。 + +## 四、租金 + +月租金为人民币捌仟元整(¥8000.00元),年租金为人民币玖万陆仟元整。 + +## 五、租金支付 + +乙方按季度支付租金,每季度首月10日前支付当季租金,以银行转账方式支付。 + +## 六、维修 + +房屋维修由甲方负责。 + +## 七、违约责任 + +乙方逾期支付租金超过15天的,甲方有权解除合同。甲方如需收回房屋,应提前30天通知乙方。 + +## 八、争议解决 + +双方如发生争议,应友好协商;协商不成的,提交梅州仲裁委员会仲裁。 + +## 九、不可抗力 + +因不可抗力导致合同无法履行的,双方互不追究责任。 + +## 十、其他 + +本合同一式肆份,甲方贰份,乙方贰份。 + +甲方(盖章):梅城区机关事务管理中心 +法定代表人/委托代理人:黄伟强 +日期:2024年6月25日 + +乙方(盖章):梅州市恒达商贸有限公司 +法定代表人/委托代理人:张贤 +日期:2024年6月25日 + +签约地点:梅州市梅城区行政中心 diff --git a/rules/contract_lease/docs/test_negative.md b/rules/contract_lease/docs/test_negative.md new file mode 100644 index 0000000..0d78195 --- /dev/null +++ b/rules/contract_lease/docs/test_negative.md @@ -0,0 +1,30 @@ +# 房屋租赁协议 + +甲方:某某公司 + +乙方:某某人 + +双方就房屋租赁事宜达成如下协议: + +## 一、租赁内容 + +甲方将其房屋出租给乙方。 + +## 二、租金 + +每月壹万伍仟元(¥12000.00元)。 + +## 三、付款 + +按月付款。 + +## 四、违约 + +违约方承担责任。 + +## 五、其他 + +本协议自签字之日起生效。 + +甲方:某某公司 +乙方:某某人 diff --git a/rules/contract_lease/docs/test_positive.md b/rules/contract_lease/docs/test_positive.md new file mode 100644 index 0000000..4753328 --- /dev/null +++ b/rules/contract_lease/docs/test_positive.md @@ -0,0 +1,89 @@ +# 房屋租赁合同 + +合同名称:办公场地租赁合同 +合同编号:ZL-2025-GZ-0036 + +出租方(甲方):广州恒盛物业管理有限公司 +法定代表人:林建华 +地址:广州市天河区体育西路128号恒盛大厦18楼 +联系人:王晓燕 +联系电话:020-38765432 +开户银行:中国建设银行广州天河支行 +银行账号:44050158360800000456 + +承租方(乙方):广东天宏科技有限公司 +法定代表人:陈志远 +地址:广州市天河区科韵路128号天宏大厦12楼 +联系人:张晓明 +联系电话:020-38891234 + +根据《中华人民共和国民法典》等有关法律法规的规定,甲乙双方在平等、自愿、公平、诚实信用的基础上,就甲方将其合法拥有的房屋出租给乙方使用一事,经协商一致签订本合同。 + +## 一、租赁物 + +甲方将位于广州市天河区体育西路128号恒盛大厦15楼A单元的办公用房出租给乙方使用。该房屋建筑面积为326.5平方米,房屋产权证号为粤(2020)广州市不动产权第0088765号。 + +## 二、租赁用途 + +乙方承租上述房屋仅用于办公场所使用,未经甲方书面同意,不得擅自改变房屋用途。乙方不得在租赁房屋内从事违反法律法规的活动。 + +## 三、租赁期限 + +租赁期限自2025年4月1日起至2028年3月31日止,共计3年。租赁期满,乙方如需继续承租,应提前90日书面通知甲方,在同等条件下乙方享有优先承租权。 + +## 四、租金及支付方式 + +1. 月租金为人民币肆万伍仟元整(¥45000.00元),含物业管理费。 +2. 租金按季度支付,每季度首月5日前支付当季租金。首次支付应在合同签订后5个工作日内完成。 +3. 支付方式为银行转账,转入甲方指定账户。 +4. 乙方逾期支付租金的,每逾期一日,按逾期金额的0.5‰支付违约金。逾期超过30日未支付的,甲方有权解除合同。 + +## 五、维修义务 + +1. 租赁期间,房屋主体结构(包括承重墙、屋顶、外墙、上下水管道主管等)的维修由甲方负责,维修费用由甲方承担。甲方接到乙方维修通知后,应在5个工作日内安排维修。 +2. 房屋内部设施(包括照明灯具、门锁、窗户五金件等日常损耗)的维修由乙方负责,费用由乙方承担。 +3. 因甲方未在合理期限内履行维修义务,乙方可自行维修,维修费用由甲方承担,乙方有权在下期租金中扣减相应金额。 +4. 因乙方使用不当造成房屋或设施损坏的,维修费用由乙方承担。 + +## 六、转租 + +未经甲方书面同意,乙方不得将租赁房屋的全部或部分转租给第三方。乙方违反本条约定擅自转租的,甲方有权解除合同并要求乙方支付月租金两倍的违约金。经甲方书面同意转租的,转租期限不得超过本合同剩余租赁期限。 + +## 七、违约责任 + +1. 甲方违约:甲方未按约定时间交付租赁房屋的,每逾期一日,应向乙方支付月租金1‰的违约金;逾期超过15日的,乙方有权解除合同,甲方应退还乙方已支付的租金及押金,并支付相当于两个月租金的违约金。 +2. 乙方违约:乙方逾期支付租金的,每逾期一日,按逾期金额0.5‰支付违约金;逾期超过30日未支付的,甲方有权解除合同,乙方已支付的租金不予退还,甲方有权从押金中扣除欠付租金和违约金。 +3. 乙方擅自改变房屋用途、擅自转租或进行违法活动的,甲方有权立即解除合同,乙方应支付相当于三个月租金的违约金。 +4. 任何一方因自身原因提前解除合同的,应提前60日书面通知对方,并支付相当于两个月租金的违约金。 + +## 八、合同解除与退租 + +1. 合同期满不再续租的,乙方应在合同期满前30日书面通知甲方,并在期满之日将房屋及附属设施完好交还甲方。 +2. 提前退租的,退租方应提前60日书面通知对方,并按本合同第七条支付违约金。 +3. 退还房屋时,乙方应恢复房屋原状(正常磨损除外),清除所有自行添置的物品。经甲方验收确认后,甲方应在15个工作日内退还剩余押金。 + +## 九、不可抗力 + +1. 不可抗力是指不能预见、不能避免且不能克服的客观事件,包括但不限于自然灾害(地震、洪水、台风等)、政府行为(征收、拆迁等)和社会事件(战争、疫情等)。 +2. 因不可抗力导致合同全部或部分不能履行的,遭受不可抗力的一方应在事件发生后5日内书面通知对方,并在15日内提供不可抗力证明材料。 +3. 因不可抗力致使租赁物部分或全部损毁无法使用的,租金相应减免。不可抗力持续超过60日的,任何一方有权书面通知对方解除合同,双方互不承担违约责任。 + +## 十、争议解决 + +本合同履行过程中发生争议的,双方应首先友好协商解决;协商不成的,任何一方均可向广州市天河区人民法院提起诉讼。 + +## 十一、其他 + +1. 本合同一式肆份,甲方贰份,乙方贰份,均具有同等法律效力。 +2. 本合同自双方签字盖章之日起生效。 +3. 本合同未尽事宜,双方可另行签订补充协议。 + +甲方(盖章):广州恒盛物业管理��限公司 +法定代表人/委托代理人:林建华 +日期:2025年3月20日 + +乙方(盖章):广东天宏科技有限公司 +法定代表人/委托代理人:陈志远 +日期:2025年3月20日 + +签约地点:广州市天河区体育西路128号恒盛大厦18楼 diff --git a/rules/contract_lease/rules.grouped_preview.yaml b/rules/contract_lease/rules.grouped_preview.yaml new file mode 100644 index 0000000..f6c71b1 --- /dev/null +++ b/rules/contract_lease/rules.grouped_preview.yaml @@ -0,0 +1,166 @@ +metadata: + type_id: contract.lease.extract_grouped_preview + name: 不动产租赁合同(extract 分组预览) + version: "2.0-preview-1" + last_updated: "2026-04-18" + description: | + 仅用于展示房屋/不动产租赁合同 extract 的业务分组方案。 + 设计原则: + 1. extract 仍保持平铺列表,不改现有 DSL 形状; + 2. 用显式 group 表达业务分类,便于抽取、展示、报表统一使用; + 3. 保留现有综合字段,避免影响既有 AI 规则 prompt; + 4. 在综合字段旁补充一批原子字段,便于后续做确定性校验和前端结构化展示。 + tags: [合同, 租赁, 不动产, 房屋, extract预览] + references_laws: + - 《民法典》第四百六十七条 + - 《民法典》第四百七十条 + - 《民法典》第四百九十条 + - 《民法典》第七百零三条至第七百三十四条 + +extract: + + # 1. 基础信息 + - {name: 合同名称, type: verbatim, group: 基础信息, desc: "合同标题/项目名称"} + - {name: 合同编号, type: verbatim, required_from: executed, group: 基础信息, desc: "合同唯一编号"} + - {name: 签约日期, type: date, required_from: executed, group: 基础信息, desc: "合同签订日期"} + - {name: 签约地点, type: verbatim, required_from: executed, group: 基础信息, desc: "合同签订地点"} + - {name: 合同份数, type: integer, required_from: executed, group: 基础信息, desc: "合同正本份数"} + - {name: 生效条件, type: string, group: 基础信息, desc: "合同生效条件(签字盖章、批准、备案等)"} + - {name: 签约背景, type: string, group: 基础信息, desc: "合同签约背景/缘由(如招标、协商、续租等)"} + - {name: 引用法律法规, type: string, group: 基础信息, desc: "合同中引用的法律、法规、规章列表"} + + # 2. 主体信息 + - {name: 出租方, type: verbatim, group: 主体信息, desc: "出租方(甲方)全称,个人为姓名,单位为公司名"} + - {name: 出租方主体类型, type: [个人, 单位], group: 主体信息, desc: "根据合同表述判断出租方为个人还是单位"} + - {name: 出租方证件号, type: verbatim, group: 主体信息, desc: "出租方身份证号(个人)或统一社会信用代码(单位)"} + - {name: 出租方法定代表人, type: verbatim, group: 主体信息, desc: "出租方法定代表人或负责人姓名(出租方为单位时)"} + - {name: 出租方地址, type: verbatim, group: 主体信息, desc: "出租方住址或注册地址"} + - {name: 出租方联系电话, type: verbatim, group: 主体信息, desc: "出租方联系电话"} + - {name: 承租方, type: verbatim, group: 主体信息, desc: "承租方(乙方)全称"} + - {name: 承租方主体类型, type: [个人, 单位], group: 主体信息, desc: "根据合同表述判断承租方为个人还是单位"} + - {name: 承租方统一社会信用代码, type: verbatim, required_from: executed, group: 主体信息, desc: "承租方18位统一社会信用代码(单位承租人)。签署阶段必填,draft 阶段可为空。"} + - {name: 承租方法定代表人, type: verbatim, group: 主体信息, desc: "承租方法定代表人或负责人姓名"} + - {name: 承租方地址, type: verbatim, group: 主体信息, desc: "承租方住址或注册地址"} + - {name: 承租方联系电话, type: verbatim, group: 主体信息, desc: "承租方联系电话"} + - name: 共同承租人 + type: multi_entity + group: 主体信息 + desc: "如有,共同承租人的列表" + fields: + - {name: 名称, type: verbatim, required_from: draft} + - {name: 证件号, type: verbatim, required_from: executed} + - {name: 地址, type: verbatim} + - {name: 联系电话, type: verbatim} + - name: 担保人 + type: multi_entity + group: 主体信息 + desc: "如有,担保人/保证人的列表" + fields: + - {name: 名称, type: verbatim, required_from: draft} + - {name: 证件号, type: verbatim, required_from: executed} + - {name: 地址, type: verbatim} + - {name: 联系电话, type: verbatim} + - {name: 担保方式, type: [一般保证, 连带责任保证, 其他], required_from: draft} + + # 3. 标的物 + - {name: 租赁物描述, type: string, group: 标的物, desc: "租赁物的名称、坐落地址、建筑面积的完整描述"} + - {name: 物业地址, type: verbatim, group: 标的物, desc: "租赁房屋/物业的完整地址"} + - {name: 房号, type: verbatim, group: 标的物, desc: "房号、单元号、楼层号等定位信息"} + - {name: 履行地点, type: verbatim, group: 标的物, desc: "租赁房屋坐落地点(履行地点)"} + - {name: 建筑面积, type: number, group: 标的物, desc: "建筑面积数字值,不带平方米单位"} + - {name: 使用面积, type: number, group: 标的物, desc: "使用面积/套内面积数字值,不带平方米单位"} + - {name: 租赁用途, type: string, group: 标的物, desc: "租赁物的约定使用用途(住宅、办公、商业、仓储等)"} + - {name: 附属设施清单, type: string, group: 标的物, desc: "车位、家具、设备、装修现状等附属设施列表"} + - {name: 出租方权属声明, type: string, group: 标的物, desc: "出租方对房屋所有权/处分权、抵押查封情况及责任承担的条款"} + + # 4. 租期 + - {name: 租赁起始日期, type: date, group: 租期, desc: "租赁期限起始日期"} + - {name: 租赁结束日期, type: date, group: 租期, desc: "租赁期限结束日期"} + - {name: 免租期天数, type: integer, group: 租期, desc: "免租期的天数;未约定则为空"} + - {name: 免租期时段, type: string, group: 租期, desc: "免租期对应的起止时段、从何时开始计算"} + - {name: 续租条款, type: string, group: 租期, desc: "续租安排、优先续租、续租通知时间等完整约定"} + - {name: 是否优先续租, type: [是, 否], group: 租期, desc: "是否明确赋予承租方优先续租权。明确写有优先续租/同等条件优先承租填是,否则填否。"} + - {name: 续租条件, type: string, group: 租期, desc: "续租需满足的条件,如提前通知、无违约、租金重议等"} + - {name: 退租返还条款, type: string, group: 租期, desc: "租赁期满返还条件、返还状态、优先续租权的约定"} + + # 5. 租金 + - {name: 租金金额, type: money, deep_retry: true, group: 租金, desc: "租金数字金额(月租、年租或租期总额)"} + - {name: 租金金额大写, type: verbatim, group: 租金, desc: "租金中文大写金额"} + - {name: 币种, type: [人民币, 美元, 欧元, 港币, 其他], group: 租金, desc: "租金使用的币种;未写默认可为空"} + - {name: 租金计算周期, type: string, group: 租金, desc: "租金计算周期(月租、季租、年租、租期总价等)"} + - {name: 支付周期, type: [月付, 季付, 半年付, 年付, 一次性, 其他], group: 租金, desc: "租金支付周期;按合同明示选择"} + - {name: 租金支付方式, type: string, group: 租金, desc: "付款周期、方式、时间节点、逾期处理的完整描述"} + - {name: 付款节点, type: string, group: 租金, desc: "每期租金支付的具体时间点,如每月5日前"} + - {name: 收款方账户名称, type: verbatim, required_from: executed, group: 租金, desc: "收款方账户名称(与出租方主体一致)"} + - {name: 收款方开户银行, type: verbatim, required_from: executed, group: 租金, desc: "收款方(通常为出租方)银行开户行全称"} + - {name: 收款方银行账号, type: verbatim, required_from: executed, group: 租金, desc: "收款方银行账号"} + - {name: 租金是否含税, type: [是, 否], group: 租金, desc: '租金金额是否已包含税费。填"是":合同中明确"含税"或"租金已包含税费";填"否":另行约定税费分担或未说明。'} + - {name: 递增条款, type: string, group: 租金, desc: "租金递增比例、递增周期或递增公式"} + - {name: 逾期利息, type: string, group: 租金, desc: "逾期支付租金的利息、滞纳金或违约金计算标准"} + + # 6. 押金保证金 + - {name: 约定押金, type: [是, 否], group: 押金保证金, desc: '合同中是否约定了押金、保证金或类似担保金额。填"是":明确约定"押金""保证金""定金"及其金额。填"否":未约定任何押金/保证金。'} + - {name: 押金金额, type: money, group: 押金保证金, desc: "押金/保证金数字金额"} + - {name: 押金相当月数, type: integer, group: 押金保证金, desc: "押金折算为几个月租金;未明确写明则为空"} + - {name: 押金退还条件, type: string, group: 押金保证金, desc: "押金返还所需条件,如房屋交还、费用结清、无损坏等"} + - {name: 押金退还期限, type: string, group: 押金保证金, desc: "押金在退租后多少日内返还"} + - {name: 押金扣除情形, type: string, group: 押金保证金, desc: "押金可扣减的情形,如欠租、损坏赔偿、违约金等"} + + # 7. 费用分担 + - {name: 物业费承担方, type: string, group: 费用分担, desc: "物业管理费由哪一方承担"} + - {name: 水电燃气承担方, type: string, group: 费用分担, desc: "水费、电费、燃气费由哪一方承担"} + - {name: 网络暖气承担方, type: string, group: 费用分担, desc: "网络费、暖气费、空调费等由哪一方承担"} + - {name: 税费承担方, type: string, group: 费用分担, desc: "房产税、增值税、印花税等由哪一方承担"} + - {name: 大修责任, type: string, group: 费用分担, desc: "大修责任归属及费用承担"} + - {name: 小修责任, type: string, group: 费用分担, desc: "小修、日常维护责任归属及费用承担"} + - {name: 维修责任条款, type: string, group: 费用分担, desc: "出租方和承租方的维修责任分工、费用负担"} + + # 8. 使用约定与交付 + - {name: 交付方式, type: string, group: 使用约定与交付, desc: "房屋移交的方式和程序:交付时间、交付状态、钥匙和设施移交、验收程序"} + - {name: 允许使用方式, type: string, group: 使用约定与交付, desc: "允许的使用方式、经营范围或使用限制"} + - {name: 装修条款, type: string, group: 使用约定与交付, desc: "是否允许装修、审批流程、装修范围、恢复要求等"} + - {name: 恢复义务, type: string, group: 使用约定与交付, desc: "退租时是否需恢复原状及恢复标准"} + - {name: 转租是否允许, type: [是, 否], group: 使用约定与交付, desc: '是否允许转租/分租。明确允许或附条件允许填"是",明确禁止或未允许填"否"。'} + - {name: 转租条款, type: string, group: 使用约定与交付, desc: "是否允许转租、转租条件、审批要求的完整约定"} + + # 9. 解除与违约 + - {name: 提前解除权主体, type: string, group: 解除与违约, desc: "哪一方享有提前解除权,或双方均可解除"} + - {name: 提前解除通知期, type: string, group: 解除与违约, desc: "提前解除需提前通知多少日/月"} + - {name: 提前解除违约金, type: string, group: 解除与违约, desc: "提前解除时的违约金或赔偿标准"} + - {name: 变更解除终止条款, type: string, group: 解除与违约, desc: "合同变更、解除、终止的条件和程序"} + - {name: 不可抗力条款, type: string, group: 解除与违约, desc: "不可抗力定义、通知义务、免责约定的完整条款"} + - {name: 违约责任条款, type: string, group: 解除与违约, desc: "违约责任的完整条款内容(双方违约情形和责任)"} + - {name: 承租方违约责任, type: string, group: 解除与违约, desc: "承租方违约时的滞纳金、解约赔偿、恢复原状等责任"} + - {name: 出租方违约责任, type: string, group: 解除与违约, desc: "出租方违约时的违约金、返还费用、赔偿责任等"} + - {name: 违约金金额, type: money, group: 解除与违约, desc: "违约金具体金额或计算基数"} + - {name: 违约金计算方式, type: string, group: 解除与违约, desc: "违约金计算标准(固定金额/比例/按日计算等)"} + + # 10. 争议解决与附件 + - {name: 争议解决条款, type: string, group: 争议解决与附件, desc: "争议解决方式的完整条款(协商、诉讼、仲裁)"} + - {name: 管辖机构, type: verbatim, group: 争议解决与附件, desc: "指定的法院或仲裁机构名称"} + - {name: 适用法律, type: string, group: 争议解决与附件, desc: "合同适用的法律,如中华人民共和国法律"} + - {name: 附件列表, type: string, group: 争议解决与附件, desc: "合同附件的序号、名称、类型的列表"} + - {name: 补充协议条款, type: string, group: 争议解决与附件, desc: "未尽事宜补充、补充协议效力等约定"} + + # 11. 合同特征分类字段 + - name: 涉及保密信息 + type: [是, 否] + group: 合同特征分类 + desc: > + 合同中是否存在保密条款或涉及商业秘密、技术秘密、个人信息。 + 填"是"的条件:出现"保密""商业秘密""技术秘密""不得泄露"等关键词且有实质条款。 + 填"否"的条件:普通房屋租赁,无任何保密相关条款。 + - name: 存在共同承租人 + type: [是, 否] + group: 合同特征分类 + desc: > + 合同中是否存在共同承租人。 + 填"是"的条件:除承租方外,还明确列有共同承租人、联名承租人。 + 填"否"的条件:仅有单一承租主体。 + - name: 存在担保人 + type: [是, 否] + group: 合同特征分类 + desc: > + 合同中是否存在担保人、保证人或其他第三方担保安排。 + 填"是"的条件:明确列有担保主体或担保责任条款。 + 填"否"的条件:未约定任何第三方担保安排。 diff --git a/rules/contract_lease/rules.yaml b/rules/contract_lease/rules.yaml new file mode 100644 index 0000000..89ea45b --- /dev/null +++ b/rules/contract_lease/rules.yaml @@ -0,0 +1,1453 @@ +metadata: + type_id: contract.lease + name: 不动产租赁合同 + version: '2.0' + last_updated: '2026-04-14' + tags: + - 合同 + - 租赁 + - 不动产 + - 房屋 + references_laws: + - 《民法典》第四百六十七条 + - 《民法典》第四百七十条 + - 《民法典》第四百九十条 + - 《民法典》第七百零三条至第七百三十四条 + description: '依据《中华人民共和国民法典》合同编·通则(第467、470、490条)及租赁合同章(第703-734条)。 + + 适用于房屋、办公场所、店铺等不动产租赁合同的评查。 + + 覆盖签署前审查(draft)和签署后审计(executed)两个阶段。 + + 基于旧系统 00_通用规则.json + 06_租赁合同.json 合并、去重、样本校准而成(39→33 条)。 + + ' +extract: +- group: 基础信息 + note: 合同基础元信息、签约背景和签署要素 + fields: + - name: 合同名称 + type: verbatim + required_from: draft + desc: 合同标题/项目名称 + deep_retry: false + - name: 签约背景 + type: string + required_from: draft + desc: 合同签约背景/缘由(如招标方式、协商过程等开篇段落) + deep_retry: false + - name: 引用法律法规 + type: string + required_from: draft + desc: 合同引用的法律、法规、规章的列表 + deep_retry: false + - name: 生效条件 + type: string + required_from: draft + desc: 合同生效条件(签字盖章、经批准等) + deep_retry: false + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 签约地点 + type: verbatim + required_from: executed + desc: 合同签订地点 + deep_retry: false + - name: 合同编号 + type: verbatim + required_from: executed + desc: 合同唯一编号 + deep_retry: false + - name: 合同份数 + type: integer + required_from: executed + desc: 合同正本份数 + deep_retry: false +- group: 主体信息 + note: 出租方、承租方及联系方式 + fields: + - name: 出租方 + type: verbatim + required_from: draft + desc: 出租方(甲方)全称,个人为姓名,单位为公司名 + deep_retry: false + - name: 出租方证件号 + type: verbatim + required_from: draft + desc: 出租方身份证号(个人)或统一社会信用代码(单位) + deep_retry: false + - name: 出租方地址 + type: verbatim + required_from: draft + desc: 出租方住址或注册地址 + deep_retry: false + - name: 出租方法定代表人 + type: verbatim + required_from: draft + desc: 出租方法定代表人或负责人姓名(出租方为单位时) + deep_retry: false + - name: 出租方联系电话 + type: verbatim + required_from: draft + desc: 出租方联系电话 + deep_retry: false + - name: 承租方 + type: verbatim + required_from: draft + desc: 承租方(乙方)全称 + deep_retry: false + - name: 承租方统一社会信用代码 + type: verbatim + required_from: executed + desc: 承租方18位统一社会信用代码(单位承租人)。签署阶段必填,draft 阶段可为空。 + deep_retry: false + - name: 承租方地址 + type: verbatim + required_from: draft + desc: 承租方住址或注册地址 + deep_retry: false + - name: 承租方法定代表人 + type: verbatim + required_from: draft + desc: 承租方法定代表人或负责人姓名 + deep_retry: false + - name: 承租方联系电话 + type: verbatim + required_from: draft + desc: 承租方联系电话 + deep_retry: false +- group: 标的物与租期 + note: 租赁标的、交付、权属和租期安排 + fields: + - name: 租赁物描述 + type: string + required_from: draft + desc: 租赁物的名称、坐落地址、建筑面积的完整描述 + deep_retry: false + - name: 租赁用途 + type: string + required_from: draft + desc: 租赁物的约定使用用途(居住、办公、商用等) + deep_retry: false + - name: 交付方式 + type: string + required_from: draft + desc: 房屋移交的方式和程序:交付时间、交付状态(空房/带装修/含家具)、钥匙和设施移交、验收程序。不含租金支付相关内容。 + deep_retry: false + - name: 履行地点 + type: verbatim + required_from: draft + desc: 租赁房屋坐落地点(履行地点) + deep_retry: false + - name: 出租方权属声明 + type: string + required_from: draft + desc: 出租方对房屋所有权/处分权的明确承诺条款原文,以及产权纠纷的责任承担约定。关键词包括'承诺合法取得所有权''有权对房屋进行处分''产权证明''抵押/查封情况'等。若合同未约定,填空字符串。 + deep_retry: false + - name: 租赁起始日期 + type: date + required_from: draft + desc: 租赁期限起始日期 + deep_retry: false + - name: 租赁结束日期 + type: date + required_from: draft + desc: 租赁期限结束日期 + deep_retry: false + - name: 退租返还条款 + type: string + required_from: draft + desc: 租赁期满返还条件、返还状态、优先续租权的约定 + deep_retry: false +- group: 租金与支付 + note: 租金金额、支付安排、税务与押金特征 + fields: + - name: 租金金额 + type: money + required_from: draft + desc: 租金数字金额(月租、年租或租期总额) + deep_retry: true + - name: 租金金额大写 + type: verbatim + required_from: draft + desc: 租金中文大写金额 + deep_retry: false + - name: 租金计算周期 + type: string + required_from: draft + desc: 租金计算周期(月付、年付、一次性等) + deep_retry: false + - name: 租金支付方式 + type: string + required_from: draft + desc: 付款周期、方式、时间节点、逾期处理的完整描述 + deep_retry: false + - name: 收款方开户银行 + type: verbatim + required_from: executed + desc: 收款方(通常为出租方)银行开户行全称 + deep_retry: false + - name: 收款方银行账号 + type: verbatim + required_from: executed + desc: 收款方银行账号 + deep_retry: false + - name: 收款方账户名称 + type: verbatim + required_from: executed + desc: 收款方账户名称(与出租方主体一致) + deep_retry: false + - name: 租金是否含税 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: 租金金额是否已包含税费。填"是":合同中明确"含税"或"租金已包含税费";填"否":另行约定税费分担或未说明。 + deep_retry: false + - name: 约定押金 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否约定了押金、保证金或类似担保金额。 填"是"的条件:明确约定"押金""保证金""定金"及其金额。 填"否"的条件:未约定任何押金/保证金(一次性付清、无需担保等)。 + + ' + deep_retry: false +- group: 使用与费用 + note: 使用方式、转租和维修责任等履约条款 + fields: + - name: 维修责任条款 + type: string + required_from: draft + desc: 出租方和承租方的维修责任分工、费用负担 + deep_retry: false + - name: 转租条款 + type: string + required_from: draft + desc: 是否允许转租、转租条件的完整约定 + deep_retry: false +- group: 违约与争议 + note: 违约责任、解除终止、不可抗力和争议解决 + fields: + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约责任的完整条款内容(双方违约情形和责任) + deep_retry: false + - name: 违约金金额 + type: money + required_from: draft + desc: 违约金具体金额或计算基数 + deep_retry: false + - name: 违约金计算方式 + type: string + required_from: draft + desc: 违约金计算标准(固定金额/比例/按日计算等) + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式的完整条款(协商/诉讼/仲裁) + deep_retry: false + - name: 管辖机构 + type: verbatim + required_from: draft + desc: 指定的法院或仲裁机构名称 + deep_retry: false + - name: 不可抗力条款 + type: string + required_from: draft + desc: 不可抗力定义、通知义务、免责约定的完整条款 + deep_retry: false + - name: 变更解除终止条款 + type: string + required_from: draft + desc: 合同变更、解除、终止的条件和程序 + deep_retry: false +- group: 附件与特征分类 + note: 附件补充条款和条件激活字段 + fields: + - name: 附件列表 + type: string + required_from: draft + desc: 合同附件的序号、名称、类型的列表 + deep_retry: false + - name: 补充协议条款 + type: string + required_from: draft + desc: 未尽事宜补充、补充协议效力等约定 + deep_retry: false + - name: 涉及保密信息 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否存在保密条款或涉及商业秘密、技术秘密。 填"是"的条件:出现"保密""商业秘密""技术秘密""不得泄露"等关键词且有实质条款。 填"否"的条件:普通房屋租赁,无任何保密相关条款。 + + ' + deep_retry: false +visual_elements: + seals: + - id: 出租方签章 + name: 出租方签字或公章 + required: true + required_from: executed + - id: 承租方签章 + name: 承租方盖章 + required: true + required_from: executed + cross_page_seals: + - id: 骑缝章 + name: 合同骑缝章 + required: true + required_from: executed +rules: +- group: 基础信息 + rules: + - rule_id: MM-LEASE-018 + name: 生效条件明确性 + risk: medium + score: 4 + stages: + - id: '1' + check: required + field: 生效条件 + - id: '2' + check: required + field: 合同份数 + logic: 1 AND 2 + messages: + pass: 生效条件和合同份数明确 + fail: 生效条件或合同份数缺失 + references_laws: + - 《民法典》第五百零二条 + type: deterministic + - rule_id: MM-LEASE-021 + name: 签约背景与法律依据 + risk: high + score: 9 + stages: + - id: '1' + check: ai + prompt: '请检查合同的签约背景和法律依据是否准确。 + + + 签约背景:{{签约背景}} + + 引用法律法规:{{引用法律法规}} + + 生效条件:{{生效条件}} + + 变更解除终止条款:{{变更解除终止条款}} + + + 评查要点: + + 1. 签约背景或缘由是否存在(如招标方式、协商过程、签约原因等) + + 2. 合同依据的法律、法规、规章必须准确、有效(不能引用已废止的法律) + + 3. 合同条款不违反法律禁止性规定,并具有实用性 + + 4. 合同按法律法规规定的方式生效、变更、解除并办理相应手续 + + + 法规依据:民法典§153、§502 + + ' + messages: + pass: 签约背景存在且法律依据准确有效 + fail: 签约背景缺失或法律依据存在问题 + references_laws: + - 《民法典》第一百五十三条 + - 《民法典》第五百零二条 + type: ai_rule + - rule_id: MM-LEASE-022 + name: 合同名称合法有效 + risk: medium + score: 2 + stages: + - id: '1' + check: ai + prompt: '请检查合同名称是否合法有效。 + + + 合同名称:{{合同名称}} + + 租赁物描述:{{租赁物描述}} + + 租赁用途:{{租赁用途}} + + + 评查要点: + + 1. 合同名称必须与合同内容一致(名为"租赁合同"且实际为租赁关系) + + 2. 符合民法典有名合同特征的应当采用标准合同名称(如"房屋租赁合同") + + 3. 合同名称不应使用会引起误解的名称 + + + 法规依据:民法典§467 + + ' + messages: + pass: 合同名称与内容一致 + fail: 合同名称与内容不一致 + references_laws: + - 《民法典》第四百六十七条 + type: ai_rule + - rule_id: MM-LEASE-028 + name: 合同基本信息完整性 + risk: high + score: 2 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 合同编号 + - id: '2' + check: required + field: 签约日期 + logic: 1 AND 2 + messages: + pass: 合同编号与签约日期已填写 + fail: 合同编号或签约日期缺失 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-LEASE-031 + name: 签署信息完整性 + risk: high + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + - id: '2' + check: required + field: 签约地点 + logic: 1 AND 2 + messages: + pass: 签约日期与签约地点已填写 + fail: 签约日期或签约地点缺失 + references_laws: + - 《民法典》第四百九十条 + type: deterministic + - rule_id: MM-LEASE-032 + name: 骑缝章检查 + risk: medium + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: visual + element: 骑缝章 + messages: + pass: 骑缝章齐全 + fail: 缺少骑缝章或骑缝章不规范 + references_laws: + - 《民法典》第四百九十条 + type: deterministic +- group: 主体信息 + rules: + - rule_id: MM-LEASE-001 + name: 当事人信息齐全 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 出租方 + - id: '2' + check: required + field: 承租方 + messages: + pass: 出租方和承租方信息齐全 + fail: 缺少出租方或承租方信息 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-LEASE-002 + name: 当事人信息准确完整 + risk: high + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查合同当事人(出租方和承租方)的信息是否准确完整。 + + + 出租方:{{出租方}} + + 出租方法定代表人/负责人:{{出租方法定代表人}} + + 出租方地址:{{出租方地址}} + + 出租方联系电话:{{出租方联系电话}} + + 出租方证件号:{{出租方证件号}} + + + 承租方:{{承租方}} + + 承租方法定代表人:{{承租方法定代表人}} + + 承租方地址:{{承租方地址}} + + 承租方联系电话:{{承租方联系电话}} + + 承租方统一社会信用代码:{{承租方统一社会信用代码}} + + + 评查要点: + + 1. 双方主体名称是否清晰可辨(个人为姓名,单位为公司名) + + 2. 出租方为个人时是否有身份证号;出租方为单位时是否有统一社会信用代码 + + 3. 承租方为单位时是否有法定代表人 + + 4. 双方联系地址和电话是否齐全 + + + 特别说明:承租方统一社会信用代码属于签署阶段(executed)字段, + + 在草稿阶段(draft)合同模板中为空是正常情况,不作为判 fail 依据。 + + 只有在已签署的合同中(合同编号、签约日期已填写)仍缺失 USCC,才应判 fail。 + + + 法规依据:民法典§470 + + ' + messages: + pass: 当事人信息准确完整 + fail: 当事人信息有缺失或不准确 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-LEASE-025 + name: 合同主体合法有效 + risk: high + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查合同主体是否合法有效。 + + + 出租方:{{出租方}} + + 出租方证件号:{{出租方证件号}} + + 承租方:{{承租方}} + + 承租方统一社会信用代码:{{承租方统一社会信用代码}} + + 承租方法定代表人:{{承租方法定代表人}} + + + 评查要点: + + 1. 承租方为单位时是否有法定代表人 + + 2. 出租方身份证号或 USCC 是否齐全 + + 3. 主体身份证明材料格式是否有效(身份证 18 位、USCC 18 位) + + + 特别说明:承租方统一社会信用代码属于签署阶段(executed)字段, + + 在草稿阶段(draft)合同模板中为空是正常情况,不作为判 fail 依据。 + + 只有在已签署的合同中(合同编号、签约日期已填写)仍缺失 USCC,才应判 fail。 + + + 出租方处分权请在 MM-LEASE-026 专门检查,本规则不涉及。 + + + 法规依据:民法典§143、§171 + + ' + messages: + pass: 合同主体合法有效 + fail: 合同主体存在合法性问题 + references_laws: + - 《民法典》第一百四十三条 + - 《民法典》第一百七十一条 + type: ai_rule + - rule_id: MM-LEASE-026 + name: 出租方处分权 + risk: high + score: 4 + stages: + - id: '1' + check: ai + prompt: '请检查出租方是否具有房屋处分权。 + + + 出租方:{{出租方}} + + 租赁物描述:{{租赁物描述}} + + 出租方权属声明:{{出租方权属声明}} + + + 评查要点: + + 1. 合同中是否有出租方"合法取得所有权"或"有权对房屋进行处分"的承诺条款(重点看"出租方权属声明"字段) + + 2. 是否约定了产权纠纷时的责任承担 + + 3. 是否说明了权属证明(房产证、不动产权证、经济联合社证明等) + + 4. 对商业租赁,是否涉及必要的经营许可资质 + + + 注意:评判主要依据"出租方权属声明"字段。若该字段有明确的处分权承诺内容,判 pass 或 warn; + + 若该字段为空或仅有模糊表述(如"双方协商一致"),判 fail。 + + + 法规依据:民法典§505 + + ' + messages: + pass: 出租方处分权已明示 + fail: 缺少出租方处分权说明 + references_laws: + - 《民法典》第五百零五条 + type: ai_rule + - rule_id: MM-LEASE-029 + name: 签署方详细信息校验 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 出租方 + - id: '2' + check: required + field: 承租方 + - id: '3' + check: required + field: 出租方地址 + - id: '4' + check: required + field: 承租方地址 + logic: 1 AND 2 AND 3 AND 4 + messages: + pass: 签署方详细信息完整 + fail: 签署方详细信息有缺失 + type: deterministic +- group: 标的物与租期 + rules: + - rule_id: MM-LEASE-003 + name: 租赁标的明确 + risk: high + score: 5 + stages: + - id: '1' + check: ai + prompt: '请检查租赁合同中租赁标的信息是否明确。 + + + 租赁物描述:{{租赁物描述}} + + 租赁用途:{{租赁用途}} + + + 评查要点: + + 1. 是否明确了租赁物的名称(房屋、办公场所、店铺等) + + 2. 是否明确了租赁物的具体位置/地址 + + 3. 是否明确了租赁物的面积/规格 + + 4. 是否明确了租赁用途(居住、办公、商用等) + + 5. 租赁用途应当合法且与租赁物性质相符 + + + 法规依据:民法典§703、§704 + + ' + messages: + pass: 租赁标的信息明确 + fail: 租赁标的信息不明确或不完整 + references_laws: + - 《民法典》第七百零三条 + - 《民法典》第七百零四条 + type: ai_rule + - rule_id: MM-LEASE-004 + name: 租赁期限合规 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 租赁起始日期 + - id: '2' + check: required + field: 租赁结束日期 + - id: '3' + check: ai + prompt: '请检查租赁合同的租赁期限是否合规。 + + + 起始日期:{{租赁起始日期}} + + 结束日期:{{租赁结束日期}} + + 退租返还条款(含续租约定):{{退租返还条款}} + + + 评查要点: + + 1. 起止日期是否明确 + + 2. 租赁期限是否超过二十年(超过二十年的部分无效) + + 3. 租赁期限六个月以上的应当采用书面形式(本合同为书面) + + 4. 如有续租约定,续租后累计期限是否可能超过二十年 + + + 法规依据:民法典§705、§707 + + ' + logic: 1 AND 2 AND 3 + messages: + pass: 租赁期限明确且合规 + fail: 租赁期限缺失或超过法定上限 + references_laws: + - 《民法典》第七百零五条 + - 《民法典》第七百零七条 + type: ai_rule + - rule_id: MM-LEASE-007 + name: 合同地点具体准确 + risk: medium + score: 5 + stages: + - id: '1' + check: ai + prompt: '请检查合同地点信息是否具体准确。 + + + 履行地点(租赁房屋位置):{{履行地点}} + + 签约地点:{{签约地点}} + + 出租方地址:{{出租方地址}} + + 承租方地址:{{承租方地址}} + + + 评查要点: + + 1. 租赁房屋的坐落地点是否具体(到具体门牌号/楼层) + + 2. 签约地点是否明确 + + 3. 双方地址是否完整可供送达 + + + 法规依据:民法典§470 + + ' + messages: + pass: 合同地点信息具体准确 + fail: 合同地点信息不具体或缺失 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-LEASE-008 + name: 履行方式具体准确 + risk: medium + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查合同履行方式是否具体准确。 + + + 交付方式:{{交付方式}} + + 租赁用途:{{租赁用途}} + + + 评查要点: + + 1. 房屋交付时间和条件是否明确 + + 2. 是否约定了钥匙、设施设备的移交 + + 3. 交付状态(空房/带装修/带家具等)是否明确 + + 4. 验收或确认程序是否约定 + + + 法规依据:民法典§708、§709 + + ' + messages: + pass: 履行方式具体明确 + fail: 履行方式不具体或缺失 + references_laws: + - 《民法典》第七百零八条 + - 《民法典》第七百零九条 + type: ai_rule + - rule_id: MM-LEASE-024 + name: 标的内容合法 + risk: high + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查租赁标的内容是否合法。 + + + 租赁物描述:{{租赁物描述}} + + 租赁用途:{{租赁用途}} + + + 评查要点: + + 1. 租赁物不违反法律、行政法规的强制性规定(如不得租赁违章建筑、查封财产等) + + 2. 租赁用途不违反法律法规(如不得用于违法经营、危险品仓储等超出建筑设计用途的使用) + + 3. 如涉及特殊用途(如商用、经营),是否具备相应资质或许可 + + 4. 不违背公序良俗 + + + 法规依据:民法典§153、§154 + + ' + messages: + pass: 租赁标的内容合法 + fail: 租赁标的内容存在违法情形 + references_laws: + - 《民法典》第一百五十三条 + - 《民法典》第一百五十四条 + type: ai_rule +- group: 租金与支付 + rules: + - rule_id: MM-LEASE-005 + name: 租金金额完整 + risk: high + score: 3 + stages: + - id: '1' + check: required + field: 租金金额 + - id: '2' + check: required + field: 租金金额大写 + - id: '3' + check: required + field: 租金计算周期 + - id: '4' + check: amount_match + number: 租金金额 + chinese: 租金金额大写 + logic: 1 AND 2 AND 3 AND 4 + messages: + pass: 租金金额完整且大小写一致 + fail: 租金金额缺失或大小写不一致 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-LEASE-006 + name: 租金及支付方式完整 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 租金支付方式 + - id: '2' + check: ai + prompt: '请检查租金支付方式是否完整。 + + + 租金支付方式:{{租金支付方式}} + + 收款方开户银行:{{收款方开户银行}} + + 收款方银行账号:{{收款方银行账号}} + + + 评查要点: + + 1. 支付方式是否明确(银行转账、现金等) + + 2. 支付周期是否明确(月付、季付、年付、一次性等) + + 3. 是否约定了逾期支付的后果(滞纳金、解除权等) + + 4. 付款账户信息是否完整(开户行、账号、户名) + + + 法规依据:民法典§721、§722 + + ' + logic: 1 AND 2 + messages: + pass: 租金支付方式约定完整 + fail: 租金支付方式约定不完整 + references_laws: + - 《民法典》第七百二十一条 + - 《民法典》第七百二十二条 + type: ai_rule + - rule_id: MM-LEASE-027 + name: 税务信息完整性 + risk: medium + score: 1 + stages: + - id: '1' + check: ai + prompt: '请检查税务信息是否完整。 + + + 租金支付方式:{{租金支付方式}} + + 租金是否含税:{{租金是否含税}} + + + 评查要点: + + 1. 是否明确了租金是否含税(含税一口价或另行约定税费分担) + + 2. 如租金含税,是否约定由谁开具发票 + + 3. 如租金不含税,是否约定税费承担方 + + + 法规依据:民法典§470 + + ' + messages: + pass: 税务信息完整 + fail: 税务信息不完整 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-LEASE-030 + name: 银行账户信息完整性 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 收款方开户银行 + - id: '2' + check: required + field: 收款方银行账号 + - id: '3' + check: required + field: 收款方账户名称 + logic: 1 AND 2 AND 3 + messages: + pass: 收款方银行账户信息完整 + fail: 收款方银行账户信息不完整 + references_laws: + - 《民法典》第四百七十条 + type: deterministic + - rule_id: MM-LEASE-034 + name: 押金/保证金条款 + risk: medium + score: 2 + activate_if: 约定押金 == '是' + stages: + - id: '1' + check: ai + prompt: '请检查押金/保证金条款是否完整(合同约定押金时)。 + + + 租金支付方式:{{租金支付方式}} + + 退租返还条款:{{退租返还条款}} + + + 评查要点: + + 1. 押金金额是否明确 + + 2. 押金退还的条件是否明确(租赁期满、租赁物完好交还等) + + 3. 押金退还的时间是否明确 + + 4. 是否约定了押金可扣减的情形(欠缴租金、损坏赔偿等) + + 5. 押金金额是否合理(一般为 1-3 个月租金) + + + 法规依据:民法典§586、§587 + + ' + messages: + pass: 押金条款完整 + fail: 押金条款要素不全 + references_laws: + - 《民法典》第五百八十六条 + - 《民法典》第五百八十七条 + type: ai_rule +- group: 使用与费用 + rules: + - rule_id: MM-LEASE-009 + name: 维修责任约定 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 维修责任条款 + - id: '2' + check: ai + prompt: '请检查维修责任条款是否明确。 + + + 维修责任条款:{{维修责任条款}} + + + 评查要点: + + 1. 是否明确了出租方的维修义务范围(主体结构、设施设备等) + + 2. 是否明确了承租方的维修义务范围(日常维护、合理使用等) + + 3. 维修费用的承担方是否明确 + + 4. 是否约定维修期间的租金处理(如长期维修时租金减免) + + 5. 因承租方过错导致损坏的维修责任是否明确 + + + 法规依据:民法典§712、§713 + + ' + logic: 1 AND 2 + messages: + pass: 维修责任约定明确 + fail: 维修责任缺失或不明确 + references_laws: + - 《民法典》第七百一十二条 + - 《民法典》第七百一十三条 + type: ai_rule + - rule_id: MM-LEASE-010 + name: 转租条款 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 转租条款 + - id: '2' + check: ai + prompt: '请检查转租条款是否明确。 + + + 转租条款:{{转租条款}} + + + 评查要点: + + 1. 是否明确约定了是否允许转租 + + 2. 如允许转租,是否约定了转租的条件和程序(如需经出租方书面同意) + + 3. 如禁止转租,是否明确了违反禁止转租的后果 + + 4. 是否约定了转租后的责任承担 + + + 法规依据:民法典§716、§717、§718 + + ' + logic: 1 AND 2 + messages: + pass: 转租条款约定明确 + fail: 转租条款缺失或不明确 + references_laws: + - 《民法典》第七百一十六条 + - 《民法典》第七百一十七条 + - 《民法典》第七百一十八条 + type: ai_rule + - rule_id: MM-LEASE-011 + name: 租赁物返还与退租 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 退租返还条款 + - id: '2' + check: ai + prompt: '请检查退租和返还条款是否完整。 + + + 退租返还条款:{{退租返还条款}} + + + 评查要点: + + 1. 是否约定了租赁物返还的条件和时间 + + 2. 是否约定了返还时租赁物应处的状态(恢复原状、正常损耗等) + + 3. 是否约定了承租方的优先承租权(房屋租赁中法定享有) + + 4. 是否约定了提前退租的条件和违约责任 + + 5. 是否约定了租赁物返还时的交接验收程序 + + + 法规依据:民法典§733、§734 + + ' + logic: 1 AND 2 + messages: + pass: 退租及返还条款完整 + fail: 退租及返还条款不完整 + references_laws: + - 《民法典》第七百三十三条 + - 《民法典》第七百三十四条 + type: ai_rule +- group: 违约与争议 + rules: + - rule_id: MM-LEASE-012 + name: 违约责任形式明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请检查违约责任条款是否形式明确。 + + + 违约责任条款:{{违约责任条款}} + + + 评查要点: + + 1. 是否明确了违约方和违约情形 + + 2. 责任形式是否具体(支付违约金、赔偿损失、继续履行等) + + 3. 是否覆盖双方(出租方违约和承租方违约均有约定) + + 4. 是否有兜底条款(如未尽事宜如何处理) + + + 法规依据:民法典§577 + + ' + logic: 1 AND 2 + messages: + pass: 违约责任形式明确 + fail: 违约责任形式不明确或缺失 + references_laws: + - 《民法典》第五百七十七条 + type: ai_rule + - rule_id: MM-LEASE-013 + name: 违约金条款完整合理 + risk: high + score: 7 + stages: + - id: '1' + check: required + field: 违约金金额 + - id: '2' + check: ai + prompt: '请检查违约金条款是否完整合理。 + + + 违约金金额:{{违约金金额}} + + 违约金计算方式:{{违约金计算方式}} + + 违约责任条款:{{违约责任条款}} + + 租金金额:{{租金金额}} + + + 评查要点: + + 1. 违约金金额或计算方式是否明确 + + 2. 违约金标准是否合理(约定过高可依法调整,一般不超过造成损失的 30%) + + 3. 是否约定了逾期支付租金的违约金 + + 4. 是否覆盖双方违约情形 + + + 法规依据:民法典§585 + + ' + logic: 1 AND 2 + messages: + pass: 违约金条款完整合理 + fail: 违约金条款不完整或标准不合理 + references_laws: + - 《民法典》第五百八十五条 + type: ai_rule + - rule_id: MM-LEASE-014 + name: 争议解决方式明确 + risk: high + score: 4 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请检查争议解决方式是否明确。 + + + 争议解决条款:{{争议解决条款}} + + 管辖机构:{{管辖机构}} + + + 评查要点: + + 1. 是否明确了争议解决方式(协商/诉讼/仲裁,只能择一作为最终方式) + + 2. 不能同时约定仲裁和诉讼(互斥) + + 3. 如约定诉讼,是否指定了具体的管辖法院 + + 4. 如约定仲裁,是否指定了具体的仲裁机构 + + + 法规依据:民法典§470 + + ' + logic: 1 AND 2 + messages: + pass: 争议解决方式明确 + fail: 争议解决方式不明确或约定冲突 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-LEASE-015 + name: 管辖机构名称准确 + risk: medium + score: 3 + stages: + - id: '1' + check: ai + prompt: '请检查管辖机构名称是否准确。 + + + 管辖机构:{{管辖机构}} + + 争议解决条款:{{争议解决条款}} + + + 评查要点: + + 1. 如约定诉讼,法院名称是否准确规范(如"XX市XX区人民法院",而非简称) + + 2. 如约定仲裁,仲裁机构名称是否准确(如"中国国际经济贸易仲裁委员会") + + 3. 指定的机构是否对本合同争议有管辖权 + + 4. 名称不应模糊(如仅写"当地法院"是不合格的) + + + 法规依据:民法典§470 + + ' + messages: + pass: 管辖机构名称准确 + fail: 管辖机构名称不准确或模糊 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-LEASE-016 + name: 不可抗力条款完整性 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 不可抗力条款 + - id: '2' + check: ai + prompt: '请检查不可抗力条款是否完整(三要素)。 + + + 不可抗力条款:{{不可抗力条款}} + + + 评查要点(三要素): + + 1. 是否明确了不可抗力的定义/类型范围 + + 2. 是否约定了通知义务和通知时限 + + 3. 是否约定了免责后果和合同处理方式(如延期履行、解除合同等) + + + 法规依据:民法典§180、§590 + + ' + logic: 1 AND 2 + messages: + pass: 不可抗力条款完整 + fail: 不可抗力条款缺失或要素不全 + references_laws: + - 《民法典》第一百八十条 + - 《民法典》第五百九十条 + type: ai_rule + - rule_id: MM-LEASE-017 + name: 变更解除终止条款完整性 + risk: high + score: 5 + stages: + - id: '1' + check: ai + prompt: '请检查变更、解除、终止条款是否完整。 + + + 变更解除终止条款:{{变更解除终止条款}} + + + 评查要点: + + 1. 是否约定了合同变更的条件和程序 + + 2. 是否约定了合同解除/终止的条件(法定解除、约定解除、协商解除) + + 3. 是否约定了终止通知期限 + + 4. 是否有对己方(采购/承租方)的保护条款 + + 5. 是否约定了合同终止后的处理(结算、返还等) + + + 法规依据:民法典§543、§562、§563 + + ' + messages: + pass: 变更解除终止条款完整 + fail: 变更解除终止条款不完整 + references_laws: + - 《民法典》第五百四十三条 + - 《民法典》第五百六十二条 + - 《民法典》第五百六十三条 + type: ai_rule +- group: 附件与特征分类 + rules: + - rule_id: MM-LEASE-019 + name: 附件条款完整性 + risk: low + score: 2 + stages: + - id: '1' + check: ai + prompt: '请检查附件条款是否具备基本形式要素。 + + + 附件列表:{{附件列表}} + + + 评查要点(满足任一核心要素即可 pass,多缺给 warn,全缺给 fail): + + 1. 【核心】至少列明了附件的名称(如"屋内资产清单""权属证明""家私家电清单"等) + + 2. 【加分】附件有序号标识(如"附件一"、"附件1") + + 3. 【加分】附件与合同正文有引用或关联说明 + + 4. 【加分】有"附件与合同具有同等法律效力"的声明 + + + 注意:租赁合同中附件本身是可选的辅助材料,只要名称清晰就视为合格; + + 只有完全缺失附件名称或无任何可识别附件信息时才判 fail。 + + + 法规依据:民法典§470 + + ' + messages: + pass: 附件条款已列明 + fail: 附件条款完全缺失 + references_laws: + - 《民法典》第四百七十条 + type: ai_rule + - rule_id: MM-LEASE-020 + name: 补充协议条款完整性 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 补充协议条款 + messages: + pass: 补充协议条款存在 + fail: 缺少补充协议兜底条款 + references_laws: + - 《民法典》第五百四十三条 + type: deterministic + - rule_id: MM-LEASE-033 + name: 保密条款完整性 + risk: medium + score: 2 + activate_if: 涉及保密信息 == '是' + stages: + - id: '1' + check: ai + prompt: '请检查保密条款是否完整(合同涉及保密信息时)。 + + + 租赁物描述:{{租赁物描述}} + + 租赁用途:{{租赁用途}} + + + 评查要点(三要素): + + 1. 是否明确了保密信息的范围(商业秘密、技术秘密、个人信息等) + + 2. 是否约定了保密期限 + + 3. 是否约定了违反保密义务的违约责任 + + + 法规依据:民法典§501 + + ' + messages: + pass: 保密条款完整 + fail: 保密条款要素不全 + references_laws: + - 《民法典》第五百零一条 + type: ai_rule diff --git a/rules/contract_lease/rules.yaml.bak.20260414 b/rules/contract_lease/rules.yaml.bak.20260414 new file mode 100644 index 0000000..476bed5 --- /dev/null +++ b/rules/contract_lease/rules.yaml.bak.20260414 @@ -0,0 +1,397 @@ +metadata: + type_id: contract.lease + name: 不动产租赁合同 + version: "1.0" + last_updated: "2026-04-12" + description: | + 依据《中华人民共和国民法典》合同编·通则(第470条)及租赁合同章(第703-734条)。 + 适用于房屋、门店、办公场所等不动产租赁合同的评查。 + 覆盖签署前审查(draft)和签署后审计(executed)两个阶段。 + tags: [合同, 租赁, 不动产] + +# ══════════════════════════════════════════════════════════ +# 字段抽取定义 — 30 个字段,按评查阶段分组 +# ══════════════════════════════════════════════════════════ +extract: + # A. 合同成立要素 — required_from: draft + - {name: 出租方, type: verbatim, description: "出租方(甲方)公司或个人全称"} + - {name: 承租方, type: verbatim, description: "承租方(乙方)公司或个人全称"} + - {name: 租赁物描述, type: string, description: "租赁物的名称、坐落地址、面积等完整描述"} + - {name: 租赁用途, type: string, description: "租赁物的约定使用用途"} + - {name: 租金金额, type: money, description: "租金数字金额(月租或年租)"} + - {name: 租金金额大写, type: verbatim, description: "租金中文大写"} + + # B. 主体资格 + - {name: 出租方法定代表人, type: verbatim, description: "出租方法定代表人或负责人姓名"} + - {name: 承租方法定代表人, type: verbatim, description: "承租方法定代表人或负责人姓名"} + - {name: 出租方地址, type: verbatim, description: "出租方注册地址或住址"} + - {name: 承租方地址, type: verbatim, description: "承租方注册地址或住址"} + + # C. 履约核心条款 — required_from: draft + - {name: 租赁起始日期, type: date, description: "租赁期限的起始日期"} + - {name: 租赁结束日期, type: date, description: "租赁期限的终止日期"} + - {name: 租金支付方式, type: string, description: "租金的支付周期、方式、时间节点的完整描述"} + - {name: 维修义务条款, type: string, description: "出租方和承租方的维修责任分工"} + + # D. 法定/必备条款 — required_from: draft + - {name: 违约责任条款, type: string, description: "违约责任的完整条款内容"} + - {name: 争议解决条款, type: string, description: "争议解决方式(法院/仲裁)"} + + # E. 签署要素 — required_from: executed + - {name: 签约日期, type: date, required_from: executed, description: "合同签订日期"} + - {name: 签约地点, type: verbatim, required_from: executed, description: "合同签订地点"} + - {name: 合同编号, type: verbatim, required_from: executed, description: "合同唯一编号"} + + # F. 建议条款 — required_from: executed + - {name: 转租条款, type: string, required_from: executed, description: "关于转租、转借的约定"} + - {name: 合同解除条款, type: string, required_from: executed, description: "合同提前解除/退租的条件和程序"} + - {name: 不可抗力条款, type: string, required_from: executed, description: "不可抗力相关条款"} + + # G. 辅助信息 + - {name: 合同名称, type: verbatim, required_from: executed, description: "合同的完整名称"} + - {name: 出租方联系人, type: verbatim, required_from: executed, description: "出租方联系人姓名"} + - {name: 出租方联系电话, type: verbatim, required_from: executed, description: "出租方联系电话"} + - {name: 承租方联系人, type: verbatim, required_from: executed, description: "承租方联系人姓名"} + - {name: 承租方联系电话, type: verbatim, required_from: executed, description: "承租方联系电话"} + - {name: 出租方开户银行, type: verbatim, required_from: executed, description: "出租方银行开户行名称"} + - {name: 出租方银行账号, type: verbatim, required_from: executed, description: "出租方银行账号"} + - {name: 合同份数, type: integer, required_from: executed, description: "合同正本份数"} + +# ══════════════════════════════════════════════════════════ +# 评查规则 — 22 条,按评查维度分组 +# ══════════════════════════════════════════════════════════ +rules: + + # ── 完整性(11 条)─────────────────────────────── + + - rule_id: MM-LEASE-001 + name: 当事人信息齐全 + risk: high + score: 10 + stages: + - {check: required, field: 出租方} + - {check: required, field: 承租方} + messages: + pass: 出租方和承租方信息完整 + fail: 缺少出租方或承租方信息 + # 民法典§470① + + - rule_id: MM-LEASE-002 + name: 租赁物明确 + risk: high + score: 10 + stages: + - {check: required, field: 租赁物描述} + messages: + pass: 租赁物描述完整 + fail: 缺少租赁物描述(名称、地址、面积等) + # 民法典§704 + + - rule_id: MM-LEASE-003 + name: 租赁用途明确 + risk: medium + score: 5 + stages: + - {check: required, field: 租赁用途} + messages: + pass: 租赁用途已约定 + fail: 未约定租赁用途 + # 民法典§704 + + - rule_id: MM-LEASE-004 + name: 租赁期限明确 + risk: high + score: 8 + stages: + - {check: required, field: 租赁起始日期} + - {check: required, field: 租赁结束日期} + messages: + pass: 租赁期限起止日期齐全 + fail: 缺少租赁起始日期或结束日期 + # 民法典§704 + + - rule_id: MM-LEASE-005 + name: 租金条款明确 + risk: high + score: 10 + stages: + - {check: required, field: 租金金额} + messages: + pass: 租金金额已约定 + fail: 缺少租金金额 + # 民法典§704 + + - rule_id: MM-LEASE-006 + name: 租金支付方式存在 + risk: high + score: 8 + stages: + - {check: required, field: 租金支付方式} + messages: + pass: 租金支付方式已约定 + fail: 缺少租金支付方式 + # 民法典§704 + + - rule_id: MM-LEASE-007 + name: 维修义务约定 + risk: medium + score: 5 + stages: + - {check: required, field: 维修义务条款} + messages: + pass: 维修义务已约定 + fail: 缺少维修义务约定 + # 民法典§704/§712 + + - rule_id: MM-LEASE-008 + name: 违约责任条款存在 + risk: high + score: 8 + stages: + - {check: required, field: 违约责任条款} + messages: + pass: 违约责任条款存在 + fail: 缺少违约责任条款 + # 民法典§470⑦ + + - rule_id: MM-LEASE-009 + name: 争议解决条款存在 + risk: medium + score: 5 + stages: + - {check: required, field: 争议解决条款} + messages: + pass: 争议解决条款存在 + fail: 缺少争议解决条款 + # 民法典§470⑧ + + - rule_id: MM-LEASE-010 + name: 法定代表人齐全 + risk: medium + score: 5 + stages: + - {check: required, field: 出租方法定代表人} + - {check: required, field: 承租方法定代表人} + messages: + pass: 双方法定代表人信息完整 + fail: 缺少出租方或承租方法定代表人信息 + + - rule_id: MM-LEASE-011 + name: 签署要素齐全 + risk: high + score: 8 + applies_in: [executed] + stages: + - {check: required, field: 签约日期} + - {check: required, field: 合同编号} + messages: + pass: 签约日期和合同编号齐全 + fail: 缺少签约日期或合同编号 + # 民法典§490 + + # ── 合理性(4 条)─────────────────────────────── + + - rule_id: MM-LEASE-012 + name: 租赁期限不超20年 + risk: high + score: 10 + stages: + - check: assert + expr: | + parse_date(租赁起始日期) != None and parse_date(租赁结束日期) != None and (parse_date(租赁结束日期) - parse_date(租赁起始日期)).days <= 7300 + messages: + pass: 租赁期限在20年以内 + fail: 租赁期限超过20年,超过部分无效(民法典§705) + # 民法典§705 —— 租赁合同硬性法规 + + - rule_id: MM-LEASE-013 + name: 租金为正数 + risk: low + score: 3 + stages: + - {check: compare, left: 租金金额, op: ">", right: 0} + messages: + pass: 租金金额为正数 + fail: 租金金额不为正数,数据异常 + + - rule_id: MM-LEASE-014 + name: 租金大小写一致 + risk: high + score: 10 + stages: + - {check: amount_match, number: 租金金额, chinese: 租金金额大写} + messages: + pass: 租金大小写一致 + fail: 租金数字与大写不一致,存在篡改风险 + + - rule_id: MM-LEASE-015 + name: 签约日期合理 + risk: low + score: 3 + applies_in: [executed] + stages: + - check: assert + expr: "parse_date(签约日期) != None and (today() - parse_date(签约日期)).days >= 0 and (today() - parse_date(签约日期)).days <= 3650" + messages: + pass: 签约日期在合理范围内 + fail: 签约日期为未来日期或距今超过10年 + + # ── 合规性 · AI 语义判断(7 条)───────────────── + + - rule_id: MM-LEASE-016 + name: 违约责任条款充分 + risk: low + score: 2 + stages: + - check: required + field: 违约责任条款 + - check: ai + prompt: | + 请判断以下租赁合同的违约责任条款是否充分、合规。 + + 条款内容:{{违约责任条款}} + + 充分的租赁合同违约责任条款应当(依据民法典第577-585条): + 1. 明确承租方违约情形(如逾期支付租金、擅自改变用途、擅自转租等) + 2. 明确出租方违约情形(如未按时交付租赁物、影响正常使用等) + 3. 明确违约金计算方式或赔偿标准(如按日计算逾期租金的违约金) + 4. 不能只是笼统的"违约要赔偿"之类的模糊表述 + messages: + pass: 违约责任条款充分 + fail: 建议完善:违约责任条款可进一步明确双方对等的违约情形和违约金标准 + # 民法典§577-585 + + - rule_id: MM-LEASE-017 + name: 争议解决方式明确 + risk: low + score: 2 + stages: + - check: required + field: 争议解决条款 + - check: ai + prompt: | + 请判断以下争议解决条款是否符合法律要求。 + + 条款内容:{{争议解决条款}} + + 合规的争议解决条款应当: + 1. 明确指定具体的争议解决方式(仲裁或诉讼,二选一) + 2. 如选择仲裁,应明确仲裁机构名称 + 3. 如选择诉讼,应明确管辖法院 + 4. 不能同时约定仲裁和诉讼 + 5. 不能是模糊表述(如"双方商量"等) + messages: + pass: 争议解决方式明确 + fail: 建议完善:争议解决条款应指定具体仲裁机构或管辖法院 + + - rule_id: MM-LEASE-018 + name: 租金支付条款明确 + risk: low + score: 2 + stages: + - check: required + field: 租金支付方式 + - check: ai + prompt: | + 请判断以下租金支付条款是否明确。 + + 条款内容:{{租金支付方式}} + + 依据民法典第721条,明确的租金支付条款应当包含: + 1. 租金金额或计算方式 + 2. 支付周期(月付/季付/年付) + 3. 支付时间节点(如每月N日前) + 4. 支付方式(银行转账/现金等) + 5. 逾期支付的后果 + messages: + pass: 租金支付条款明确 + fail: 建议完善:租金支付条款可补充逾期付款的违约金比例和解除合同的触发条件 + # 民法典§721 + + - rule_id: MM-LEASE-019 + name: 维修义务约定充分 + risk: low + score: 2 + stages: + - check: required + field: 维修义务条款 + - check: ai + prompt: | + 请判断以下租赁合同的维修义务约定是否充分。 + + 条款内容:{{维修义务条款}} + + 依据民法典第712-713条,充分的维修义务约定应当: + 1. 明确出租方和承租方各自的维修范围(如主体结构由出租方、日常维修由承租方) + 2. 明确维修费用的承担方 + 3. 明确紧急维修时的处理方式(如出租方未及时维修时承租方可自行维修并扣减租金) + messages: + pass: 维修义务约定充分 + fail: 建议完善:维修义务可明确主体结构与日常维修的分工及费用承担 + # 民法典§712-713 + + - rule_id: MM-LEASE-020 + name: 转租限制明确 + risk: low + score: 1 + stages: + - check: required + field: 转租条款 + - check: ai + prompt: | + 请判断以下转租条款是否明确。 + + 条款内容:{{转租条款}} + + 依据民法典第716条,明确的转租条款应当: + 1. 明确是否允许转租(禁止/经同意后可转租) + 2. 如允许转租,需明确转租的条件和程序 + 3. 明确违反转租约定的法律后果 + messages: + pass: 转租条款明确 + fail: 建议完善:转租条款可明确转租条件和违反后果 + # 民法典§716 + + - rule_id: MM-LEASE-021 + name: 合同解除/退租条款完整 + risk: low + score: 1 + stages: + - check: required + field: 合同解除条款 + - check: ai + prompt: | + 请判断以下租赁合同的解除/退租条款是否完整。 + + 条款内容:{{合同解除条款}} + + 依据民法典第722、724条,完整的合同解除条款应当: + 1. 明确提前解除/退租的条件(如逾期支付租金达到多久可解除) + 2. 明确解除合同的通知期限(如提前N天书面通知) + 3. 明确退租时的交还程序和恢复原状要求 + messages: + pass: 合同解除/退租条款完整 + fail: 建议完善:退租条款可补充通知期限和恢复原状要求 + # 民法典§722/724 + + - rule_id: MM-LEASE-022 + name: 不可抗力条款完整 + risk: low + score: 1 + stages: + - check: required + field: 不可抗力条款 + - check: ai + prompt: | + 请判断以下不可抗力条款是否完整。 + + 条款内容:{{不可抗力条款}} + + 依据民法典第590条,完整的不可抗力条款应当包含: + 1. 不可抗力的定义或事件范围 + 2. 发生不可抗力后的通知义务和时限 + 3. 不可抗力的法律后果(免责范围、合同处理方式) + messages: + pass: 不可抗力条款完整 + fail: 建议完善:不可抗力条款可补充通知义务时限和法律后果 + # 民法典§590 diff --git a/rules/contract_loan/docs/interest_rate_illegal.md b/rules/contract_loan/docs/interest_rate_illegal.md new file mode 100644 index 0000000..b013395 --- /dev/null +++ b/rules/contract_loan/docs/interest_rate_illegal.md @@ -0,0 +1,47 @@ +# 借款合同(反例:利率超法定上限) + +**合同编号**:JK2024-BAD-001 + +## 第一条 借贷双方 + +**借款人**:张三 +身份证号:110101197001011234 + +**出借人**:李四 +身份证号:310102198505051234 + +## 第二条 借款金额 + +借款本金:人民币 500,000.00 元 +大写:伍拾万元整 + +借款日期:2024 年 6 月 1 日 +还款日期:2025 年 6 月 1 日 + +## 第三条 利率(违法条款) + +**年利率:25%(0.25)** + +本利率远超法定上限(LPR × 4 倍约 13.8%),属于高利贷。 +根据最高人民法院 2020 年修正司法解释,超出部分法院不予保护。 + +## 第四条 担保 + +担保人:王五,身份证:440103199212121234,担保金额:500,000 元。 + +## 第五条 违约责任(违法条款) + +借款人违约的,**未付利息自动计入本金继续计息(利滚利)**。 +逾期每日按 0.5% 计算违约金,上不封顶。 + +## 第六条 借款用途 + +借款用于借款人个人短期资金周转。 + +--- + +借款人签字:张三 日期:2024-06-01 +出借人签字:李四 日期:2024-06-01 + +(本合同有两处违法:1) 利率超过 LPR×4 上限;2) 利滚利条款。 +用于测试 JK-002 和 JK-005 的 fail 路径) diff --git a/rules/contract_loan/docs/multi_guarantor.md b/rules/contract_loan/docs/multi_guarantor.md new file mode 100644 index 0000000..744c5ce --- /dev/null +++ b/rules/contract_loan/docs/multi_guarantor.md @@ -0,0 +1,93 @@ +# 借款合同 — 多担保人场景 + +**合同编号**:JK2024-MG-001 + +## 第一条 借贷双方 + +**借款人**:某某贸易有限公司(法定代表人:张三) +统一信用代码:91310000MA1K3H5K8L +身份证号(法定代表人):110101197001011234 + +**出借人**:李四 +身份证号:310102198505051234 + +## 第二条 借款金额 + +借款本金:人民币 5,000,000.00 元 +大写:伍佰万元整 + +借款日期:2024 年 4 月 1 日 +还款日期:2026 年 4 月 1 日 +借款期限:2 年 + +## 第三条 利率 + +年利率:12%(未超过 LPR × 4 倍上限 13.8%) + +## 第四条 还款方式 + +分期还款,每季度末偿还本金 625,000.00 元和当期利息。 + +## 第五条 担保条款(5 位担保人) + +### 担保人 1:王五 +- 身份证:440103199212121234 +- 住所:广州市越秀区 +- 担保金额:人民币 1,500,000.00 元 +- 担保方式:连带责任保证 + +### 担保人 2:赵六 +- 身份证:330102198811111234 +- 住所:杭州市上城区 +- 担保金额:人民币 1,200,000.00 元 +- 担保方式:连带责任保证 + +### 担保人 3:孙七 +- 身份证:510104199405051234 +- 住所:成都市武侯区 +- 担保金额:人民币 1,000,000.00 元 +- 担保方式:连带责任保证 + +### 担保人 4:周八 +- 身份证:320102199007071234 +- 住所:南京市玄武区 +- 担保金额:人民币 800,000.00 元 +- 担保方式:一般保证 + +### 担保人 5:吴九 +- 身份证:370102198503031234 +- 住所:济南市历下区 +- 担保金额:人民币 700,000.00 元 +- 担保方式:一般保证 + +**担保总额**:人民币 5,200,000.00 元,超出借款本金 200,000.00 元(覆盖充足)。 + +## 第六条 违约责任 + +借款人逾期还款的,按每日 0.03% 支付违约金。违约金总额不超过借款本金的 20%。 +严禁任何形式的利滚利、复利、砍头息。 + +## 第七条 借款用途 + +借款用于借款人经营的某某贸易有限公司对外采购业务资金周转。 + +## 第八条 争议解决 + +提交上海仲裁委员会仲裁。 + +--- + +**签订日期**:2024 年 4 月 1 日 + +借款人(签字盖章):某某贸易有限公司 +[盖章: 某某贸易有限公司合同专用章] +法定代表人签字:[签名: 张三] + +出借人(签字):[签名: 李四] +[盖章: 李四个人签章] + +担保人 1 签字:[签名: 王五] 担保人 2 签字:[签名: 赵六] +担保人 3 签字:[签名: 孙七] 担保人 4 签字:[签名: 周八] +担保人 5 签字:[签名: 吴九] + +(本样本用于测试 JK-003 / JK-004 的 multi_entity 遍历和聚合能力) diff --git a/rules/contract_loan/docs/normal.md b/rules/contract_loan/docs/normal.md new file mode 100644 index 0000000..7da43c8 --- /dev/null +++ b/rules/contract_loan/docs/normal.md @@ -0,0 +1,97 @@ +# 借款合同 + +**合同编号**:JK2024-000456 + +## 第一条 借贷双方 + +**借款人**:张三 +身份证号:110101197001011234 +住所:北京市东城区东华门大街 1 号 + +**出借人**:李四 +身份证号:310102198505051234 +住所:上海市黄浦区南京东路 100 号 + +## 第二条 借款用途 + +借款用于借款人经营的某某贸易有限公司日常经营周转,严禁用于赌博、非法经营或其他违法活动。 + +## 第三条 借款金额及期限 + +**借款本金**:人民币 1,000,000.00 元 +**大写**:壹佰万元整 + +**借款日期**:2024 年 4 月 1 日 +**还款日期**:2025 年 4 月 1 日 +**借款期限**:1 年 + +## 第四条 利率 + +年利率:10%(0.10) + +本利率未超过合同签订时一年期 LPR 的四倍,符合《最高人民法院关于审理民间借贷 +案件适用法律若干问题的规定》(2020 修正)第 25 条之规定。 + +## 第五条 还款方式 + +一次性还本付息。借款人应在还款日当天向出借人支付本金和利息共计 1,100,000.00 元。 + +## 第六条 担保条款 + +本借款由以下三位担保人提供连带责任保证: + +**担保人一**: +- 姓名:王五 +- 身份证号:440103199212121234 +- 住所:广州市越秀区北京路 50 号 +- 担保金额:人民币 500,000.00 元 +- 担保方式:连带责任保证 +- 担保期限:自借款日起至 2027 年 4 月 1 日 + +**担保人二**: +- 姓名:赵六 +- 身份证号:330102198811111234 +- 住所:杭州市上城区解放路 30 号 +- 担保金额:人民币 500,000.00 元 +- 担保方式:连带责任保证 +- 担保期限:自借款日起至 2027 年 4 月 1 日 + +**担保人三**: +- 姓名:孙七 +- 身份证号:510104199405051234 +- 住所:成都市武侯区人民南路 80 号 +- 担保金额:人民币 300,000.00 元 +- 担保方式:一般保证 +- 担保期限:自借款日起至 2027 年 4 月 1 日 + +**担保总额**:人民币 1,300,000.00 元(覆盖借款本金) + +## 第七条 违约责任 + +借款人逾期还款的,按每日 0.05% 向出借人支付违约金。 +**违约金金额**:最高不超过人民币 200,000.00 元(借款本金的 20%)。 +严禁利滚利和复利计算,利息不计入本金。 + +## 第八条 争议解决 + +本合同纠纷由双方协商解决。协商不成的,提交北京仲裁委员会仲裁。 + +## 第九条 其他 + +本合同一式六份,借贷双方及三位担保人各执一份,经各方签字生效。 + +**签订日期**:2024 年 4 月 1 日 + +--- + +借款人(签字):[签名: 张三] 日期:2024-04-01 + +出借人(签字):[签名: 李四] 日期:2024-04-01 + +担保人一(签字):[签名: 王五] 日期:2024-04-01 + +担保人二(签字):[签名: 赵六] 日期:2024-04-01 + +担保人三(签字):[签名: 孙七] 日期:2024-04-01 + +[盖章: 借款人张三] [盖章: 出借人李四] diff --git a/rules/contract_loan/rules.test.yaml b/rules/contract_loan/rules.test.yaml new file mode 100644 index 0000000..a00e76b --- /dev/null +++ b/rules/contract_loan/rules.test.yaml @@ -0,0 +1,322 @@ +# ═════════════════════════════════════════════════════════════════ +# 借款合同 · 回归测试用例 +# ═════════════════════════════════════════════════════════════════ +# 配套文件:contract_loan.yaml +# 重点展示:multi_entity / derived fields / external 数据源 mock + +target: contract_loan.yaml + +# 外部数据源的 mock 值(替代真实 API 调用) +external_mocks: + lpr_lookup: + "1y": 0.0345 # 当前 1 年 LPR = 3.45% + # 推导:LPR_4x = 0.0345 * 4 = 0.138 + +fixtures: + + # ═════════════════════════════════════════════════════════════ + # JK-001 · 借款主体合法性 + # ═════════════════════════════════════════════════════════════ + JK-001: + - name: 已执行-借贷双方合法 + phase: executed + extract: + 借款人姓名: 张三 + 借款人身份证: "110101197001011234" + 出借人姓名: 李四 + 出借人身份证: "310102198505051234" + expected: pass + + - name: 已执行-借款人身份证校验失败 + phase: executed + extract: + 借款人姓名: 张三 + 借款人身份证: "110101197001011230" # 末位错 + 出借人姓名: 李四 + 出借人身份证: "310102198505051234" + expected: fail + + - name: 草稿-只有姓名 + phase: draft + extract: + 借款人姓名: 张三 + 出借人姓名: 李四 + expected: pass # 草稿阶段身份证待补 + + # ═════════════════════════════════════════════════════════════ + # JK-002 · 利率不超过 LPR × 4(核心规则) + # 依赖 external.lpr_lookup mock:LPR_4x = 0.138 + # ═════════════════════════════════════════════════════════════ + JK-002: + - name: 年利率 10% 合规 + phase: executed + extract: + 年利率: 0.10 + # derived.LPR_4x = 0.138(mock 值) + expected: pass + + - name: 年利率 20% 超限 + phase: executed + extract: + 年利率: 0.20 + expected: fail + + - name: 年利率正好等于 LPR×4(边界) + phase: executed + extract: + 年利率: 0.138 + expected: fail # money.lt 严格小于 + + - name: 年利率 0.137 边界内 + phase: executed + extract: + 年利率: 0.137 + expected: pass + + # ═════════════════════════════════════════════════════════════ + # JK-003 · 所有担保人身份合法(multi-entity 核心测试) + # ═════════════════════════════════════════════════════════════ + JK-003: + - name: 三担保人全合法 + phase: executed + extract: + 担保人: + - {姓名: 张三, 身份证号: "110101197001011234", 担保金额: 500000, 担保方式: 连带责任保证} + - {姓名: 李四, 身份证号: "310102198505051234", 担保金额: 800000, 担保方式: 连带责任保证} + - {姓名: 王五, 身份证号: "440103199212121234", 担保金额: 300000, 担保方式: 一般保证} + expected: pass + + - name: 第二个担保人身份证校验失败 + phase: executed + extract: + 担保人: + - {姓名: 张三, 身份证号: "110101197001011234", 担保金额: 500000, 担保方式: 连带责任保证} + - {姓名: 李四, 身份证号: "310102198505051230", 担保金额: 800000, 担保方式: 连带责任保证} # 末位错 + - {姓名: 王五, 身份证号: "440103199212121234", 担保金额: 300000, 担保方式: 一般保证} + expected: fail # [*] 遍历,任一失败整体 fail + + - name: 第一个担保人姓名缺失 + phase: executed + extract: + 担保人: + - {姓名: null, 身份证号: "110101197001011234", 担保金额: 500000, 担保方式: 连带责任保证} + - {姓名: 李四, 身份证号: "310102198505051234", 担保金额: 800000, 担保方式: 连带责任保证} + expected: fail + + - name: 无担保人(规则跳过) + phase: executed + extract: + 担保人: [] + expected: skipped # activate_if 条件不满足 + + # ═════════════════════════════════════════════════════════════ + # JK-004 · 担保总额覆盖借款本金(sum_ge 聚合) + # ═════════════════════════════════════════════════════════════ + JK-004: + - name: 担保覆盖 + phase: executed + extract: + 借款本金: 1500000 + 担保人: + - {姓名: 张三, 担保金额: 500000, 担保方式: 连带责任保证} + - {姓名: 李四, 担保金额: 800000, 担保方式: 连带责任保证} + - {姓名: 王五, 担保金额: 300000, 担保方式: 一般保证} + # derived.担保总额 = 1600000 >= 借款本金 1500000 + expected: pass + + - name: 担保不足 + phase: executed + extract: + 借款本金: 2000000 + 担保人: + - {姓名: 张三, 担保金额: 500000, 担保方式: 连带责任保证} + - {姓名: 李四, 担保金额: 800000, 担保方式: 连带责任保证} + # derived.担保总额 = 1300000 < 借款本金 2000000 + expected: fail + + - name: 担保恰好等于本金 + phase: executed + extract: + 借款本金: 1000000 + 担保人: + - {姓名: 张三, 担保金额: 1000000, 担保方式: 连带责任保证} + expected: pass + + # ═════════════════════════════════════════════════════════════ + # JK-005 · 禁止利滚利 + # ═════════════════════════════════════════════════════════════ + JK-005: + - name: 正常违约条款 + phase: executed + extract: + 违约责任: 借款人逾期还款的,按每日 0.05% 支付违约金,违约金不超过借款本金 30% + 借款用途: 企业日常经营周转 + expected: pass + + - name: 出现利滚利字样 + phase: executed + extract: + 违约责任: 借款人违约的,利息计入本金后继续计息,利滚利 + 借款用途: 企业日常经营周转 + expected: fail + + - name: 借款用途违法 + phase: executed + extract: + 违约责任: 正常违约金条款 + 借款用途: 用于赌博和非法经营活动 + expected: fail + + - name: 出现砍头息 + phase: executed + extract: + 违约责任: 出借人有权预扣利息,砍头息为借款的 10% + 借款用途: 经营周转 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # JK-006 · 违约金不超过 30%(ratio_within) + # ═════════════════════════════════════════════════════════════ + JK-006: + - name: 违约金 20%(合规) + phase: executed + extract: + 借款本金: 1000000 + 违约金金额: 200000 + # derived.违约金比例 = 0.20 + expected: pass + + - name: 违约金 35%(超限) + phase: executed + extract: + 借款本金: 1000000 + 违约金金额: 350000 + expected: fail + + - name: 违约金 30%(边界,恰好到上限) + phase: executed + extract: + 借款本金: 1000000 + 违约金金额: 300000 + expected: pass # ratio_within max=0.30 是闭区间 + + # ═════════════════════════════════════════════════════════════ + # JK-007 · 借款本金大小写一致性 + # ═════════════════════════════════════════════════════════════ + JK-007: + - name: 大小写一致 + phase: executed + extract: + 借款本金: 1000000 + 借款本金大写: 壹佰万元整 + expected: pass + + - name: 大小写不一致 + phase: executed + extract: + 借款本金: 1000000 + 借款本金大写: 壹拾万元整 # 差一位 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # JK-008 · 借款期限合理性(带 depends_on) + # ═════════════════════════════════════════════════════════════ + JK-008: + - name: 正常期限 + phase: executed + extract: + 借款人姓名: 张三 + 借款人身份证: "110101197001011234" + 出借人姓名: 李四 + 出借人身份证: "310102198505051234" + 借款日期: "2024-01-01" + 还款日期: "2025-01-01" + 签订日期: "2024-01-01" + expected: pass + + - name: 借款日期晚于还款日期 + phase: executed + extract: + 借款人姓名: 张三 + 借款人身份证: "110101197001011234" + 出借人姓名: 李四 + 出借人身份证: "310102198505051234" + 借款日期: "2024-06-01" + 还款日期: "2024-01-01" # ← 颠倒 + 签订日期: "2024-01-01" + expected: fail + + - name: 依赖规则失败时本规则被跳过 + phase: executed + extract: + 借款人姓名: 张三 + 借款人身份证: "110101197001011230" # JK-001 会失败 + 出借人姓名: 李四 + 出借人身份证: "310102198505051234" + 借款日期: "2024-01-01" + 还款日期: "2025-01-01" + expected: skipped_dependency # JK-001 失败 → 本规则跳过 + + # ═════════════════════════════════════════════════════════════ + # JK-SEAL-001 · 双方签章 + # ═════════════════════════════════════════════════════════════ + JK-SEAL-001: + - name: 双方签章齐全 + phase: executed + extract: + 借款人姓名: 张三 + 出借人姓名: 李四 + visual_manifest: + seals: + - id: 借款人签章 + detection_score: 0.94 + ocr_text: 张三 + - id: 出借人签章 + detection_score: 0.92 + ocr_text: 李四 + expected: pass + + - name: 缺出借人签章 + phase: executed + extract: + 借款人姓名: 张三 + 出借人姓名: 李四 + visual_manifest: + seals: + - id: 借款人签章 + detection_score: 0.94 + ocr_text: 张三 + expected: fail + + - name: 草稿阶段无签章(规则跳过) + phase: draft + extract: + 借款人姓名: 张三 + 出借人姓名: 李四 + visual_manifest: + seals: [] + expected: skipped_phase + + # ═════════════════════════════════════════════════════════════ + # JK-GROUP-INTEREST · 利率合规总判定(规则组) + # ═════════════════════════════════════════════════════════════ + JK-GROUP-INTEREST: + - name: 全部子规则通过 + phase: executed + extract: + 年利率: 0.10 + 违约责任: 正常违约金条款 + 借款用途: 经营周转 + 借款本金: 1000000 + 违约金金额: 200000 + expected: pass + + - name: 子规则 JK-002 失败导致组失败 + phase: executed + extract: + 年利率: 0.25 # 超限 + 违约责任: 正常违约金条款 + 借款用途: 经营周转 + 借款本金: 1000000 + 违约金金额: 200000 + expected: fail diff --git a/rules/contract_loan/rules.yaml b/rules/contract_loan/rules.yaml new file mode 100644 index 0000000..0eacc65 --- /dev/null +++ b/rules/contract_loan/rules.yaml @@ -0,0 +1,493 @@ +metadata: + type_id: contract.loan.general + name: 借款合同 + version: '1.0' + last_updated: '2026-04-11' + parent: contract + inherits_from: + - base.common + - base.party_info + classification_keywords: + - 借款 + - 借贷 + - 民间借贷 + tags: + - compliance + - high_priority + - prc_civil_code + - usury_check + applies_to_jurisdictions: + - prc + references_laws: + - 《民法典》第 667-680 条(借款合同章) + - 《最高人民法院关于审理民间借贷案件适用法律若干问题的规定》(2020 修正) + - 《民法典》第 387-462 条(担保物权) + description: '适用于民间借贷 / 企业间借款 / 自然人借款等场景。 + + 覆盖民法典第 667-680 条(借款合同章)和最高法民间借贷司法解释。 + + 评查重点:利率合法性、担保完备性、禁止利滚利。 + + ' + confidence_profile: + allow_weight_override: false + field_confidence_defaults: + 借款本金: 0.95 + 年利率: 0.95 +extract: +- group: 当事人 + fields: + - name: 借款人姓名 + type: verbatim + required_from: draft + deep_retry: false + - name: 借款人身份证 + type: chinese-id + required_from: executed + deep_retry: false + - name: 借款人地址 + type: verbatim + required_from: draft + deep_retry: false + - name: 出借人姓名 + type: verbatim + required_from: draft + deep_retry: false + - name: 出借人身份证 + type: chinese-id + required_from: executed + deep_retry: false +- group: 合同信息 + fields: + - name: 合同编号 + type: verbatim + required_from: draft + deep_retry: false + - name: 签订日期 + type: date + required_from: executed + deep_retry: false + - name: 借款日期 + type: date + required_from: executed + deep_retry: false + - name: 还款日期 + type: date + required_from: executed + deep_retry: false +- group: 借款条款 + fields: + - name: 借款本金 + type: money + required_from: draft + deep_retry: false + - name: 借款本金大写 + type: verbatim + required_from: executed + deep_retry: false + - name: 借款用途 + type: string + required_from: draft + deep_retry: false + - name: 年利率 + type: money + required_from: draft + deep_retry: false + - name: 还款方式 + type: enum + required_from: draft + allowed: + - 一次性还本付息 + - 分期还款 + - 先息后本 + deep_retry: false + - name: 违约金金额 + type: money + required_from: draft + deep_retry: false + - name: 违约责任 + type: string + required_from: draft + deep_retry: false + - name: 争议解决 + type: string + required_from: draft + deep_retry: false +- group: 'Multi-entity: 担保人(核心特性展示)' + fields: + - name: 担保人 + type: multi_entity + required_from: draft + fields: + - name: 姓名 + type: verbatim + required_from: draft + deep_retry: false + - name: 身份证号 + type: chinese-id + required_from: executed + deep_retry: false + - name: 地址 + type: verbatim + required_from: draft + deep_retry: false + - name: 担保金额 + type: money + required_from: draft + deep_retry: false + - name: 担保方式 + type: enum + required_from: draft + allowed: + - 一般保证 + - 连带责任保证 + deep_retry: false + - name: 担保期限 + type: date + required_from: draft + deep_retry: false + deep_retry: false +derived_fields: +- name: 借款总天数 + type: integer + compute: (还款日期 - 借款日期).days + depends_on: + - 借款日期 + - 还款日期 +- name: 违约金比例 + type: money + compute: 违约金金额 / 借款本金 + depends_on: + - 违约金金额 + - 借款本金 +- name: 担保总额 + type: money + compute: sum(担保人[*].担保金额) + depends_on: + - 担保人 +- name: 担保人数量 + type: integer + compute: count(担保人) + depends_on: + - 担保人 +- name: LPR_4x + type: money + compute: external.lpr_lookup(tenor='1y') * 4 + depends_on: [] +visual_elements: + seals: + - id: 借款人签章 + name: 借款人签章 + required: true + required_from: executed + expected_text_match: + field: 借款人姓名 + - id: 出借人签章 + name: 出借人签章 + required: true + required_from: executed + expected_text_match: + field: 出借人姓名 + signatures: + - id: 借款人签名 + name: 借款人手写签名 + required: true + required_from: executed + expected_text_match: + field: 借款人姓名 + - id: 出借人签名 + name: 出借人手写签名 + required: true + required_from: executed + expected_text_match: + field: 出借人姓名 +rules: +- group: 合同主体 + rules: + - rule_id: JK-001 + name: 借款主体合法性 + risk: high + score: 10 + stages: + - id: '1' + check: required + fields: + - 借款人姓名 + - 出借人姓名 + logic: and + - id: '2' + check: format + field: 借款人身份证 + format: chinese_id + - id: '3' + check: format + field: 出借人身份证 + format: chinese_id + logic: 1 AND 2 AND 3 + messages: + pass: 借贷双方身份合法 + fail: 借贷双方身份信息不完整或身份证校验失败 + references_laws: + - 《民法典》第 667 条 + type: deterministic +- group: 利率合规 + rules: + - rule_id: JK-002 + name: 利率不超过法定上限(LPR × 4 倍) + risk: high + score: 20 + depends_on: + - when: derived.LPR_4x != null + stages: + - id: '1' + check: required + field: 年利率 + - id: '2' + check: compare + left: 年利率 + op: < + right_field: derived.LPR_4x + logic: 1 AND 2 + messages: + pass: 年利率 {{年利率}} 未超过 LPR 4 倍({{derived.LPR_4x}}) + fail: 年利率 {{年利率}} 超过法定上限 LPR 4 倍({{derived.LPR_4x}}) + references_laws: + - 《最高人民法院关于审理民间借贷案件适用法律若干问题的规定》(2020 修正)第 25 条 + - 《民法典》第 680 条(禁止高利放贷) + remediation: + suggestions: + - 本合同年利率 {{年利率}},超过当前 LPR 4 倍上限 {{derived.LPR_4x}} + - 按 2020 修正司法解释,超出部分法院不予保护 + - 请降低利率至 LPR 4 倍以内 + actions: + - type: edit_field + label: 降低年利率 + field: 年利率 + prompt: 请输入合法年利率(不超过 {{derived.LPR_4x}}) + - type: escalate + label: 疑似高利贷,上报合规组 + role: 合规专员 + type: deterministic + - rule_id: JK-GROUP-INTEREST + name: 利率合规总判定 + risk: high + score: 30 + logic: JK-002 AND JK-005 AND JK-006 + messages: + pass: 利率与违约条款全部合规 + fail: 利率或违约条款有瑕疵,存在合规风险 + type: rule_group + rules: + - JK-002 + - JK-005 + - JK-006 +- group: 担保条款 + rules: + - rule_id: JK-003 + name: 担保人身份合法性 + risk: high + score: 15 + activate_if: derived.担保人数量 > 0 + stages: + - id: '1' + type: multi_entity.count_ge + field: 担保人 + value: 1 + - id: '2' + check: format + field: 担保人[*].身份证号 + format: chinese_id + - id: '3' + check: required + field: 担保人[*].姓名 + logic: 1 AND 2 AND 3 + messages: + pass: 所有 {{derived.担保人数量}} 位担保人身份合法 + fail: 至少一位担保人身份信息缺失或身份证校验失败 + remediation: + suggestions: + - 共 {{derived.担保人数量}} 位担保人,至少一位的身份证校验失败 + - 请逐个核对每位担保人的身份证号 + actions: + - type: recheck_field + label: 重新核对所有担保人身份证 + field: 担保人[*].身份证号 + type: deterministic + - rule_id: JK-004 + name: 担保总额覆盖借款本金 + risk: high + score: 15 + activate_if: derived.担保人数量 > 0 + stages: + - id: '1' + check: compare + left: derived.担保总额 + op: '>=' + right_field: 借款本金 + logic: '1' + messages: + pass: 担保总额 {{derived.担保总额}} 覆盖借款本金 {{借款本金}} + fail: 担保总额 {{derived.担保总额}} 不足以覆盖借款本金 {{借款本金}} + remediation: + suggestions: + - 当前 {{derived.担保人数量}} 位担保人担保总额 {{derived.担保总额}} + - 借款本金 {{借款本金}},担保不足 + - 建议:(1) 增加担保人 (2) 提高现有担保金额 (3) 补充物的担保 + actions: + - type: edit_field + label: 调整担保金额 + field: 担保人[*].担保金额 + - type: escalate + label: 担保不足,上报风控 + role: 风控经理 + type: deterministic +- group: 条款合规 + rules: + - rule_id: JK-005 + name: 禁止利滚利与高利贷条款 + risk: high + score: 15 + stages: + - id: '1' + type: string.must_not_contain + field: 违约责任 + forbidden_keywords: + - 利滚利 + - 复利 + - 利息计入本金 + - 砍头息 + - 预扣利息 + - id: '2' + type: string.must_not_contain + field: 借款用途 + forbidden_keywords: + - 非法经营 + - 赌博 + - 洗钱 + logic: 1 AND 2 + messages: + pass: 未发现利滚利或非法用途条款 + fail: 发现违法条款,建议删除或修改 + references_laws: + - 《民法典》第 680 条 + - 《民法典》第 670 条(禁止预扣利息) + remediation: + suggestions: + - 检出禁止性条款,本合同可能被法院认定为无效或部分无效 + - 请删除违法条款或整体重新起草 + actions: + - type: edit_field + label: 修改违约责任条款 + field: 违约责任 + - type: escalate + label: 涉嫌违法条款,上报法务 + role: 法务经理 + type: deterministic +- group: 违约条款 + rules: + - rule_id: JK-006 + name: 违约金不超过借款本金 30% + risk: medium + score: 10 + stages: + - id: '1' + check: required + fields: + - 违约金金额 + - 借款本金 + logic: and + - id: '2' + type: money.ratio_within + numerator: 违约金金额 + denominator: 借款本金 + min: 0.0 + max: 0.3 + logic: 1 AND 2 + messages: + pass: 违约金比例 {{derived.违约金比例}} 合规 + fail: 违约金 {{违约金金额}} 占借款本金 {{借款本金}} 的比例超过 30% + references_laws: + - 《民法典》第 585 条(违约金不得过分高于损失) + type: deterministic +- group: 金额条款 + rules: + - rule_id: JK-007 + name: 借款本金大小写一致性 + risk: high + score: 10 + stages: + - id: '1' + check: required + fields: + - 借款本金 + - 借款本金大写 + logic: and + - id: '2' + check: amount_match + number: 借款本金 + chinese: 借款本金大写 + logic: 1 AND 2 + messages: + pass: 借款本金大小写一致 + fail: 借款本金大小写不一致,涉嫌篡改 + type: deterministic +- group: 期限条款 + rules: + - rule_id: JK-008 + name: 借款期限合理性 + risk: medium + score: 5 + depends_on: + - when: JK-001.passed + stages: + - id: '1' + check: required + fields: + - 借款日期 + - 还款日期 + logic: and + - id: '2' + type: date.after + field: 还款日期 + ref_field: 借款日期 + - id: '3' + check: assert + expr: parse_date(签订日期) != None and (today() - parse_date(签订日期)).days >= 0 and (today() - parse_date(签订日期)).days <= 1825 + logic: 1 AND 2 AND 3 + messages: + pass: 借款期限合规 + fail: 借款日期颠倒 或 合同签订过旧 + type: deterministic +- group: 印章合规 + rules: + - rule_id: JK-SEAL-001 + name: 借贷双方签章齐全 + risk: high + score: 10 + stages: + - id: '1' + type: seal.present + seal_id: 借款人签章 + - id: '2' + type: seal.present + seal_id: 出借人签章 + logic: 1 AND 2 + messages: + pass: 双方签章齐全 + fail: 缺少借款人或出借人签章 + remediation: + by_phase: + draft: + suggestions: + - 草稿阶段无需盖章 + actions: + - type: noop + executed: + suggestions: + - 民间借贷纠纷中,无签章的合同证据效力较弱 + - 请补盖双方印章或提供签名 + actions: + - type: upload_file + label: 补扫签章页 + file_type: 签章页 + type: deterministic diff --git a/rules/contract_purchase/docs/draft.md b/rules/contract_purchase/docs/draft.md new file mode 100644 index 0000000..2cce4c7 --- /dev/null +++ b/rules/contract_purchase/docs/draft.md @@ -0,0 +1,66 @@ +# 设备采购合同(草稿) + +**合同编号**:HT2024-001234 + +## 第一条 合同当事人 + +**甲方(买方)**:上海某某科技有限公司 +地址:上海市浦东新区张江高科技园区科苑路 88 号 +统一社会信用代码:91310000MA1K3H5K8L +法定代表人:(待签时填写) +联系电话:021-12345678 + +**乙方(卖方)**:北京某某贸易有限公司 +地址:北京市海淀区中关村大街 1 号 +统一社会信用代码:91110000MA01234X5Y +法定代表人:(待签时填写) +联系电话:010-87654321 + +## 第二条 标的物 + +本合同标的物为工业自动化控制设备,具体规格型号: + +- 型号:AUTO-2024-PRO +- 数量:50 套 +- 技术参数:符合 GB/T 12345-2020 国家标准要求 +- 质量等级:一等品 + +## 第三条 合同金额 + +**合同总金额**:人民币 1,500,000.00 元 +**大写**:(待签时补充) + +## 第四条 交付条款 + +交货地点:上海市浦东新区张江高科技园区甲方指定仓库 +交货时间:合同签订后 60 个工作日内 + +## 第五条 质量标准 + +产品质量应符合 GB/T 12345-2020《工业自动化控制设备通用技术条件》国家标准, +并通过 ISO 9001 质量管理体系认证。验收时如发现质量不符,乙方应无条件退换货。 + +## 第六条 付款方式 + +签订合同后 10 个工作日内支付 30% 预付款; +设备到货验收合格后 15 个工作日内支付 60% 货款; +质保期满无故障后支付剩余 10% 尾款。 + +## 第七条 违约责任 + +任何一方违约应向守约方支付合同总金额 10% 的违约金,并赔偿守约方因此遭受的 +直接经济损失。乙方延迟交货每日按合同金额万分之五支付违约金。 + +## 第八条 争议解决 + +本合同争议由双方友好协商解决。协商不成的,提交上海仲裁委员会仲裁。 + +## 第九条 其他 + +本合同一式两份,双方各执一份,经双方签字盖章后生效。 + +--- + +**甲方(盖章)**:(待签) 签订日期:(待签) + +**乙方(盖章)**:(待签) 签订日期:(待签) diff --git a/rules/contract_purchase/docs/executed.md b/rules/contract_purchase/docs/executed.md new file mode 100644 index 0000000..ffa5f08 --- /dev/null +++ b/rules/contract_purchase/docs/executed.md @@ -0,0 +1,80 @@ +# 设备采购合同 + +**合同编号**:HT2024-001234 + +## 第一条 合同当事人 + +**甲方(买方)**:上海某某科技有限公司 +地址:上海市浦东新区张江高科技园区科苑路 88 号 +统一社会信用代码:91310000MA1K3H5K8L +法定代表人:张三 +联系电话:021-12345678 + +**乙方(卖方)**:北京某某贸易有限公司 +地址:北京市海淀区中关村大街 1 号 +统一社会信用代码:91110000MA01234X5Y +法定代表人:李四 +联系电话:010-87654321 + +## 第二条 标的物 + +本合同标的物为工业自动化控制设备,具体规格型号: + +- 型号:AUTO-2024-PRO +- 数量:50 套 +- 技术参数:符合 GB/T 12345-2020 国家标准要求 +- 质量等级:一等品 + +## 第三条 合同金额 + +**合同总金额**:人民币 1,500,000.00 元 +**大写**:壹佰伍拾万元整 + +## 第四条 交付条款 + +交货地点:上海市浦东新区张江高科技园区甲方指定仓库 +交货时间:2024 年 6 月 1 日前 + +## 第五条 质量标准 + +产品质量应符合 GB/T 12345-2020《工业自动化控制设备通用技术条件》国家标准, +并通过 ISO 9001 质量管理体系认证。验收时如发现质量不符,乙方应无条件退换货。 + +## 第六条 付款方式 + +签订合同后 10 个工作日内支付 30% 预付款; +设备到货验收合格后 15 个工作日内支付 60% 货款; +质保期满无故障后支付剩余 10% 尾款。 + +## 第七条 违约责任 + +任何一方违约应向守约方支付合同总金额 10% 的违约金,并赔偿守约方因此遭受的 +直接经济损失。乙方延迟交货每日按合同金额万分之五支付违约金。 + +## 第八条 争议解决 + +本合同争议由双方友好协商解决。协商不成的,提交上海仲裁委员会仲裁。 + +## 第九条 合同期限 + +签订日期:2024 年 4 月 1 日 +生效日期:2024 年 4 月 1 日 +终止日期:2025 年 12 月 31 日 + +## 第十条 其他 + +本合同一式两份,双方各执一份,经双方签字盖章后生效。 + +--- + +**甲方(盖章)**:上海某某科技有限公司 + [盖章: 上海某某科技有限公司合同专用章] + 法定代表人签名:[签名: 张三] + 签订日期:2024 年 4 月 1 日 + +**乙方(盖章)**:北京某某贸易有限公司 + [盖章: 北京某某贸易有限公司合同专用章] + 法定代表人签名:[签名: 李四] + 签订日期:2024 年 4 月 1 日 + +[骑缝章: 上海某某科技有限公司 - 跨越 1-5 页] diff --git a/rules/contract_purchase/docs/executed_with_seal_missing.md b/rules/contract_purchase/docs/executed_with_seal_missing.md new file mode 100644 index 0000000..01b84c8 --- /dev/null +++ b/rules/contract_purchase/docs/executed_with_seal_missing.md @@ -0,0 +1,44 @@ +# 设备采购合同(异常样本:已执行但缺签章) + +**合同编号**:HT2024-005678 + +## 第一条 合同当事人 + +**甲方(买方)**:上海某某科技有限公司 +统一社会信用代码:91310000MA1K3H5K8L +法定代表人:张三 + +**乙方(卖方)**:北京某某贸易有限公司 +统一社会信用代码:91110000MA01234X5Y +法定代表人:李四 + +## 第二条 合同金额 + +合同总金额:人民币 1,500,000.00 元 +大写:壹佰伍拾万元整 + +## 第三条 合同期限 + +签订日期:2024 年 4 月 1 日 +生效日期:2024 年 4 月 1 日 +终止日期:2025 年 12 月 31 日 + +## 第四条 质量标准 + +产品质量应符合 GB/T 12345-2020 国家标准。 + +## 第五条 违约责任 + +任何一方违约应支付合同总金额 10% 的违约金。 + +--- + +**甲方(盖章)**:上海某某科技有限公司 + (签字栏为空 —— 缺章样本) + 签订日期:2024 年 4 月 1 日 + +**乙方(盖章)**:北京某某贸易有限公司 + [盖章: 北京某某贸易有限公司合同专用章] + 签订日期:2024 年 4 月 1 日 + +(此合同甲方未盖章,属于异常样本。用于测试 MM-SEAL-001 的 fail 路径) diff --git a/rules/contract_purchase/rules.test.yaml b/rules/contract_purchase/rules.test.yaml new file mode 100644 index 0000000..0ada16c --- /dev/null +++ b/rules/contract_purchase/rules.test.yaml @@ -0,0 +1,341 @@ +# ═════════════════════════════════════════════════════════════════ +# 买卖合同 · 回归测试用例 +# ═════════════════════════════════════════════════════════════════ +# 配套文件:contract_purchase.yaml +# visual_manifest 段用于 mock 视觉检测器输出(印章/签名) +# +# phase 字段: +# - 默认 executed(按全局 default_phase),可省略 +# - 显式声明 draft → 引擎按草稿阶段评判 +# +# 新增状态: +# - pass / fail / skipped_phase / skipped_gate + +target: contract_purchase.yaml + +fixtures: + + # ═════════════════════════════════════════════════════════════ + # MM-001 · 当事人信息完整性 + # ═════════════════════════════════════════════════════════════ + MM-001: + + # ── Executed 阶段 ── + - name: 已执行-完整合规 + phase: executed + extract: + 甲方名称: 上海某某科技有限公司 + 甲方法定代表人: 张三 + 甲方统一信用代码: "91310000MA1K3H5K8L" + 乙方名称: 北京某某贸易有限公司 + 乙方法定代表人: 李四 + 乙方统一信用代码: "91110000MA01234X5Y" + expected: pass + + - name: 已执行-缺少法定代表人 + phase: executed + extract: + 甲方名称: 上海某某科技有限公司 + 甲方法定代表人: null # executed 阶段缺失 = fail + 乙方名称: 北京某某贸易有限公司 + 乙方法定代表人: 李四 + expected: fail + + - name: 已执行-USCC 校验位错误 + phase: executed + extract: + 甲方名称: 上海某某科技有限公司 + 甲方法定代表人: 张三 + 甲方统一信用代码: "91310000MA1K3H5K80" + 乙方名称: 北京某某贸易有限公司 + 乙方法定代表人: 李四 + 乙方统一信用代码: "91110000MA01234X5Y" + expected: fail + + # ── Draft 阶段(同样的抽取结果,不同的判定)── + - name: 草稿-只有甲乙方名称(执行阶段 fail,草稿阶段 pass) + phase: draft + extract: + 甲方名称: 上海某某科技有限公司 + 乙方名称: 北京某某贸易有限公司 + # 法代、USCC、电话都没填 + expected: pass # 草稿阶段这些是待补项 + + - name: 草稿-连甲乙方名称都没有(仍然 fail) + phase: draft + extract: + 甲方名称: null # draft 阶段 required_from 也必需 + 乙方名称: 北京某某贸易有限公司 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # MM-002 · 合同金额大小写一致性 + # ═════════════════════════════════════════════════════════════ + MM-002: + - name: 大小写一致 + extract: + 合同金额: 1200000.00 + 合同金额大写: 壹佰贰拾万元整 + expected: pass + + - name: 不一致(金额错位) + extract: + 合同金额: 1200000.00 + 合同金额大写: 壹佰贰拾贰万元整 + expected: fail + + - name: 缺少大写金额 + extract: + 合同金额: 1200000.00 + 合同金额大写: null + expected: fail + + # ═════════════════════════════════════════════════════════════ + # MM-003 · 大额合同须招投标 + # ═════════════════════════════════════════════════════════════ + MM-003: + - name: 小额无需招标 + extract: + 合同金额: 500000 + 招标文件编号: null + expected: pass + + - name: 大额有招标 + extract: + 合同金额: 2000000 + 招标文件编号: "ZB2024001" + expected: pass + + - name: 大额无招标 + extract: + 合同金额: 2000000 + 招标文件编号: null + expected: fail + + # ═════════════════════════════════════════════════════════════ + # MM-004 · 合同日期先后关系 + # 签订日期是 required_from: executed,草稿阶段整条规则 skipped + # ═════════════════════════════════════════════════════════════ + MM-004: + - name: 已执行-正常先后 + phase: executed + extract: + 签订日期: "2024-03-15" + 生效日期: "2024-04-01" + 终止日期: "2025-04-01" + expected: pass + + - name: 已执行-签订晚于生效 + phase: executed + extract: + 签订日期: "2024-04-15" + 生效日期: "2024-04-01" + 终止日期: "2025-04-01" + expected: fail + + - name: 已执行-终止早于生效 + phase: executed + extract: + 签订日期: "2024-03-15" + 生效日期: "2024-04-01" + 终止日期: "2024-03-20" + expected: fail + + # 草稿阶段:签订日期还没填,本规则应自动跳过(不是 fail) + - name: 草稿-签订日期未填(规则 skipped) + phase: draft + extract: + 签订日期: null + 生效日期: null + 终止日期: null + expected: skipped_phase + + # ═════════════════════════════════════════════════════════════ + # MM-005 · 质量标准明确性 + # ═════════════════════════════════════════════════════════════ + MM-005: + - name: 有具体国标 + extract: + 质量标准: 产品质量应符合 GB/T 12345-2020《某某产品质量要求》国家标准 + expected: pass + + - name: 过于简略 + extract: + 质量标准: 按国家标准 + expected: fail + + - name: 长度够但无标准引用 + extract: + 质量标准: 产品应符合买方指定的质量要求,包括外观、功能和性能等方面 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # MM-006 · 违约责任条款存在性 + # ═════════════════════════════════════════════════════════════ + MM-006: + - name: 明确违约 + extract: + 违约责任: 任何一方违约应向守约方支付合同总金额 10% 的违约金,并赔偿守约方因此遭受的直接经济损失。 + expected: pass + + - name: 无违约条款 + extract: + 违约责任: null + expected: fail + + # ═════════════════════════════════════════════════════════════ + # MM-SEAL-001 · 双方签章齐全且文字匹配 + # 所有 seal required_from: executed,草稿阶段整条规则 skipped + # ═════════════════════════════════════════════════════════════ + MM-SEAL-001: + + # ── Executed 阶段 ── + - name: 已执行-双方签章齐全且文字匹配 + phase: executed + extract: + 甲方名称: 上海某某科技有限公司 + 乙方名称: 北京某某贸易有限公司 + visual_manifest: + seals: + - id: 甲方签章 + detection_score: 0.95 + ocr_text: 上海某某科技有限公司合同专用章 + color: red + page: 5 + - id: 乙方签章 + detection_score: 0.94 + ocr_text: 北京某某贸易有限公司合同专用章 + color: red + page: 5 + expected: pass + + - name: 已执行-缺乙方签章 + phase: executed + extract: + 甲方名称: 上海某某科技有限公司 + 乙方名称: 北京某某贸易有限公司 + visual_manifest: + seals: + - id: 甲方签章 + detection_score: 0.95 + ocr_text: 上海某某科技有限公司合同专用章 + color: red + page: 5 + # 乙方签章缺失 + expected: fail + + - name: 已执行-甲方印章文字不符(冒章风险) + phase: executed + extract: + 甲方名称: 上海某某科技有限公司 + 乙方名称: 北京某某贸易有限公司 + visual_manifest: + seals: + - id: 甲方签章 + detection_score: 0.92 + ocr_text: 北京其他公司公章 # ← 文字不符 + color: red + - id: 乙方签章 + detection_score: 0.94 + ocr_text: 北京某某贸易有限公司合同专用章 + color: red + expected: fail + + # ── Draft 阶段(草稿无章,应自动跳过)── + - name: 草稿-无任何印章(规则 skipped_phase) + phase: draft + extract: + 甲方名称: 上海某某科技有限公司 + 乙方名称: 北京某某贸易有限公司 + visual_manifest: + seals: [] # 草稿阶段无章 + expected: skipped_phase + + - name: 草稿-即使有章也是 skipped(本规则对 draft 不适用) + phase: draft + extract: + 甲方名称: 上海某某科技有限公司 + 乙方名称: 北京某某贸易有限公司 + visual_manifest: + seals: + - id: 甲方签章 + detection_score: 0.95 + ocr_text: 上海某某科技有限公司合同专用章 + expected: skipped_phase # 即使章齐全,draft 也 skipped + + # ═════════════════════════════════════════════════════════════ + # MM-SEAL-002 · 骑缝章完整 + # ═════════════════════════════════════════════════════════════ + MM-SEAL-002: + - name: 骑缝章完整对齐 + extract: + 甲方名称: 上海某某科技有限公司 + visual_manifest: + cross_page_seals: + - id: 骑缝章 + detection_score: 0.91 + complete: true # 所有相邻页都有 + aligned: true # 拼合正确 + ocr_text: 上海某某科技有限公司 + expected: pass + + - name: 骑缝章部分缺失 + extract: + 甲方名称: 上海某某科技有限公司 + visual_manifest: + cross_page_seals: + - id: 骑缝章 + detection_score: 0.85 + complete: false # 缺少部分页 + aligned: true + expected: fail + + - name: 骑缝章错位 + extract: + 甲方名称: 上海某某科技有限公司 + visual_manifest: + cross_page_seals: + - id: 骑缝章 + detection_score: 0.88 + complete: true + aligned: false # 拼合错位,可能换页 + expected: fail + + # ═════════════════════════════════════════════════════════════ + # MM-SEAL-003 · 法人签名 + 公章双重确认(仅大额触发) + # ═════════════════════════════════════════════════════════════ + MM-SEAL-003: + - name: 小额合同无需双重确认 + extract: + 合同金额: 300000 # < 50 万,规则不触发 + visual_manifest: + seals: [] + signatures: [] + expected: pass + + - name: 大额合同公章 + 签名齐全 + extract: + 合同金额: 800000 + 甲方法定代表人: 张三 + visual_manifest: + seals: + - id: 甲方签章 + detection_score: 0.94 + ocr_text: 上海某某科技有限公司合同专用章 + signatures: + - id: 甲方法人签名 + detection_score: 0.90 + ocr_text: 张三 + expected: pass + + - name: 大额合同缺法人签名 + extract: + 合同金额: 800000 + 甲方法定代表人: 张三 + visual_manifest: + seals: + - id: 甲方签章 + detection_score: 0.94 + ocr_text: 上海某某科技有限公司合同专用章 + signatures: [] # 无签名 + expected: fail diff --git a/rules/contract_purchase/rules.yaml b/rules/contract_purchase/rules.yaml new file mode 100644 index 0000000..7c7e7a4 --- /dev/null +++ b/rules/contract_purchase/rules.yaml @@ -0,0 +1,566 @@ +metadata: + type_id: contract.purchase.general + name: 买卖合同 + version: '1.0' + last_updated: '2026-04-11' + parent: contract + inherits_from: + - base.common + - base.party_info + classification_keywords: + - 买卖 + - 购销 + - 采购 + references_laws: + - 《民法典》第 595-647 条(买卖合同章) + - 《民法典》第 463-594 条(合同编通则) + description: '适用于一般商品买卖合同,覆盖民法典第 595-647 条。 + + 评查重点:当事人合法性、金额一致性、印章合规、交付条款、违约责任。 + + ' + confidence_profile: + allow_weight_override: false + thresholds: + auto_pass: 0.95 + field_confidence_defaults: + 合同金额: 0.95 + 合同金额大写: 0.9 +extract: +- group: 当事人(从起草就应该有) + fields: + - name: 甲方名称 + type: verbatim + required_from: draft + deep_retry: false + - name: 乙方名称 + type: verbatim + required_from: draft + deep_retry: false +- group: 当事人(执行时才必需) + fields: + - name: 甲方法定代表人 + type: verbatim + required_from: executed + deep_retry: false + - name: 甲方统一信用代码 + type: uscc + required_from: executed + deep_retry: false + - name: 甲方联系电话 + type: verbatim + required_from: draft + deep_retry: false + - name: 乙方法定代表人 + type: verbatim + required_from: executed + deep_retry: false + - name: 乙方统一信用代码 + type: uscc + required_from: executed + deep_retry: false + - name: 乙方联系电话 + type: verbatim + required_from: draft + deep_retry: false +- group: 合同基本信息 + fields: + - name: 合同编号 + type: verbatim + required_from: draft + deep_retry: false + - name: 签订日期 + type: date + required_from: executed + deep_retry: false + - name: 生效日期 + type: date + required_from: draft + deep_retry: false + - name: 终止日期 + type: date + required_from: draft + deep_retry: false +- group: 标的与金额 + fields: + - name: 标的物描述 + type: string + required_from: draft + deep_retry: false + - name: 合同金额 + type: money + required_from: draft + deep_retry: false + - name: 合同金额大写 + type: verbatim + required_from: executed + deep_retry: false + - name: 招标文件编号 + type: verbatim + required_from: draft + deep_retry: false +- group: 交付 + fields: + - name: 交货地点 + type: verbatim + required_from: draft + deep_retry: false + - name: 交货时间 + type: date + required_from: draft + deep_retry: false +- group: 关键条款(起草就应该有) + fields: + - name: 质量标准 + type: string + required_from: draft + deep_retry: false + - name: 付款方式 + type: string + required_from: draft + deep_retry: false + - name: 违约责任 + type: string + required_from: draft + deep_retry: false + - name: 争议解决 + type: string + required_from: draft + deep_retry: false +visual_elements: + seals: + - id: 甲方签章 + name: 甲方公章或合同专用章 + required: true + required_from: executed + allowed_types: + - 公章 + - 合同专用章 + - 法人章 + expected_text_match: + field: 甲方名称 + - id: 乙方签章 + name: 乙方公章或合同专用章 + required: true + required_from: executed + allowed_types: + - 公章 + - 合同专用章 + - 法人章 + expected_text_match: + field: 乙方名称 + signatures: + - id: 甲方法人签名 + name: 甲方法定代表人签名 + required: false + required_from: executed + expected_text_match: + field: 甲方法定代表人 + - id: 乙方法人签名 + name: 乙方法定代表人签名 + required: false + required_from: executed + expected_text_match: + field: 乙方法定代表人 + cross_page_seals: + - id: 骑缝章 + name: 合同骑缝章 + required: true + required_from: executed + expected_text_match: + field: 甲方名称 + prompt: '合同每相邻两页之间跨页盖章。 + + 每页只能看到印章的一半,两页拼合后构成完整圆章。 + + 通常在页面右侧边缘或底部,垂直跨越装订线。 + + 不要和页脚日期章或水印混淆。 + + ' +rules: +- group: 合同主体 + rules: + - rule_id: MM-001 + name: 当事人信息完整性 + risk: high + score: 10 + stages: + - id: '1' + check: required + fields: + - 甲方名称 + - 乙方名称 + - 甲方法定代表人 + - 乙方法定代表人 + logic: and + - id: '2' + check: format + field: 甲方统一信用代码 + format: uscc + - id: '3' + check: format + field: 乙方统一信用代码 + format: uscc + logic: 1 AND 2 AND 3 + messages: + pass: 当事人信息完整,统一信用代码校验通过 + fail: 当事人信息缺失或统一信用代码校验失败 + references_laws: + - 《民法典》第 471 条 + remediation: + by_phase: + draft: + suggestions: + - 草稿阶段当事人信息暂缺是正常的,签署前须补齐 + - 建议在定稿前确认:甲乙方名称、法定代表人、统一信用代码三项齐全 + actions: + - type: fill_field + label: 补充甲方法定代表人 + field: 甲方法定代表人 + prompt: 请输入甲方法定代表人姓名 + - type: fill_field + label: 补充乙方法定代表人 + field: 乙方法定代表人 + prompt: 请输入乙方法定代表人姓名 + executed: + suggestions: + - 已执行合同出现当事人信息缺失是严重瑕疵 + - 可能原因:起草遗漏 / OCR 错位 / USCC 校验位错 + - 须补充说明或要求当事人出具澄清 + actions: + - type: recheck_field + label: 核对甲方统一信用代码 + field: 甲方统一信用代码 + hint: 18 位,末位为校验位,请核对营业执照 + - type: recheck_field + label: 核对乙方统一信用代码 + field: 乙方统一信用代码 + - type: link_template + label: 下载主体信息补充说明函模板 + template_id: party_info_addendum + - type: escalate + label: 紧急:执行合同主体信息缺失,上报合规组 + role: 合规专员 + reason: 已执行合同出现当事人瑕疵,可能影响效力 + type: deterministic +- group: 金额与支付 + rules: + - rule_id: MM-002 + name: 合同金额大小写一致性 + risk: high + score: 10 + stages: + - id: '1' + check: required + fields: + - 合同金额 + - 合同金额大写 + logic: and + - id: '2' + check: amount_match + number: 合同金额 + chinese: 合同金额大写 + logic: 1 AND 2 + messages: + pass: 金额大小写一致 + fail: 金额大小写不一致,合同可能被篡改或抽取错误 + references_laws: + - 《民法典》第 470 条 + remediation: + on_rule_fail: + suggestions: + - 小写金额 {{合同金额}} 与大写 {{合同金额大写}} 不一致 + - 如果是 OCR 抽取错误,请人工核对原文 + - 如果合同原件本身不一致,以大写为准(法律惯例)并出具说明 + actions: + - type: recheck_field + label: 核对小写金额 + field: 合同金额 + - type: recheck_field + label: 核对大写金额 + field: 合同金额大写 + - type: link_template + label: 下载金额不一致说明函模板 + template_id: amount_inconsistency_explanation + - type: escalate + label: 涉嫌合同篡改,上报合规组 + role: 合规专员 + reason: 金额大小写不一致,可能存在恶意篡改风险 + on_confidence_low: + suggestions: + - 金额字段抽取置信度低,请人工确认原文 + actions: + - type: recheck_field + label: 重新核对合同金额 + field: 合同金额 + hint: 注意千分位符号、小数点、货币单位 + type: deterministic + - rule_id: MM-003 + name: 大额合同须招投标 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 合同金额 + - id: '2' + check: compare + left: 合同金额 + op: '>' + right: 1000000 + - id: '3' + check: required + required_if: '2' + field: 招标文件编号 + logic: 1 AND (NOT 2 OR 3) + messages: + pass: 小额合同或大额已附招标文件 + fail: 合同金额超过 100 万元,但未提供招标文件编号 + references_laws: + - 《政府采购法》第 27 条 + - 《招标投标法》第 3 条 + remediation: + suggestions: + - 本合同金额 {{合同金额}} 元,超过政府采购 100 万招投标阈值 + - 按《政府采购法》第 27 条,须采取公开招标或提供豁免说明 + - 下面三种操作任选其一即可通过本条规则 + actions: + - type: fill_field + label: 补充招标文件编号 + field: 招标文件编号 + prompt: 请输入招标文件编号(常见格式 ZB2024XXX) + - type: upload_file + label: 上传招标豁免说明函 + file_type: 招标豁免说明 + accept: + - pdf + - docx + - type: link_template + label: 下载招标豁免说明函模板 + template_id: bidding_exemption_letter + - type: escalate + label: 金额过大需采购总监审批 + role: 采购总监 + trigger_if: '{{合同金额}} > 5000000' + reason: 合同金额超过 500 万,需采购总监额外审批 + type: deterministic +- group: 合同期限 + rules: + - rule_id: MM-004 + name: 签订/生效/终止日期先后关系 + risk: high + score: 8 + stages: + - id: '1' + check: required + fields: + - 签订日期 + - 生效日期 + logic: and + - id: '2' + type: date.sequence + fields: + - 签订日期 + - 生效日期 + - 终止日期 + order: le + logic: 1 AND 2 + messages: + pass: 合同日期先后关系合规 + fail: 签订日/生效日/终止日顺序异常 + remediation: + suggestions: + - 签订日期 {{签订日期}} / 生效日期 {{生效日期}} / 终止日期 {{终止日期}} + - 正常顺序应为:签订 ≤ 生效 ≤ 终止 + - 可能原因:日期抽取错位 / OCR 识别错误 / 合同原件笔误 + actions: + - type: recheck_field + label: 核对签订日期 + field: 签订日期 + - type: recheck_field + label: 核对生效日期 + field: 生效日期 + - type: recheck_field + label: 核对终止日期 + field: 终止日期 + type: deterministic +- group: 标的物 + rules: + - rule_id: MM-005 + name: 质量标准明确性 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 质量标准 + - id: '2' + type: string.min_length + field: 质量标准 + min: 20 + - id: '3' + check: contains + field: 质量标准 + any_of: + - GB/T + - ISO + - 国标 + - 行业标准 + - 企业标准 + logic: 1 AND 2 AND 3 + messages: + pass: 质量标准明确(引用了具体标准) + fail: 质量标准过于简略或未引用具体标准 + references_laws: + - 《民法典》第 615 条 + type: deterministic +- group: 违约与争议 + rules: + - rule_id: MM-006 + name: 违约责任条款存在性 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 违约责任 + - id: '2' + type: string.min_length + field: 违约责任 + min: 30 + logic: 1 AND 2 + messages: + pass: 违约责任条款明确 + fail: 违约责任条款缺失或过于简略 + type: deterministic +- group: 印章合规 + rules: + - rule_id: MM-SEAL-001 + name: 合同双方签章齐全 + risk: high + score: 15 + stages: + - id: '1' + type: seal.present + seal_id: 甲方签章 + - id: '2' + type: seal.present + seal_id: 乙方签章 + - id: '3' + type: seal.text_match + seal_id: 甲方签章 + - id: '4' + type: seal.text_match + seal_id: 乙方签章 + logic: 1 AND 2 AND 3 AND 4 + messages: + pass: 合同双方签章齐全且文字匹配当事人名称 + fail: 缺少签章 或 印章文字与当事人名称不一致(可能冒用) + references_laws: + - 《民法典》第 490 条(合同形式) + remediation: + by_phase: + draft: + suggestions: + - 草稿阶段无需盖章。请在定稿签署时加盖甲乙方公章 + - 合同超过一页时建议加盖骑缝章 + actions: + - type: noop + executed: + suggestions: + - 已执行合同缺少签章或印章文字不符,严重影响合同效力 + - 可能原因:(1) 漏扫签章页 (2) 印章是冒章 (3) 合同原件确实未盖章 + - 建议立即补救 + actions: + - type: upload_file + label: 紧急:补扫签章页 + file_type: 签章页 + accept: + - pdf + - jpg + - png + - type: recheck_field + label: 核对甲方印章文字 + field: visual.甲方签章 + hint: 核对印章上的单位名称与甲方名称是否一致 + - type: recheck_field + label: 核对乙方印章文字 + field: visual.乙方签章 + - type: link_template + label: 下载印章缺失情况说明模板 + template_id: seal_missing_statement + - type: escalate + label: 疑似冒章,上报合规组 + role: 合规专员 + reason: 已执行合同印章文字与当事人名称不一致 + type: deterministic + - rule_id: MM-SEAL-002 + name: 合同骑缝章完整 + risk: high + score: 10 + stages: + - id: '1' + type: cross_page_seal.complete + seal_id: 骑缝章 + logic: '1' + messages: + pass: 骑缝章完整 + fail: 骑缝章缺失,合同可能被替换页 + remediation: + suggestions: + - 骑缝章用于防止合同页面被替换。缺失或错位是严重的合规风险 + - 请确认:(1) 是否原件有骑缝章?(2) 扫描时是否漏扫或错位? + - 如原件确实无骑缝章,需双方补盖或出具情况说明 + actions: + - type: upload_file + label: 补扫完整骑缝章 + file_type: 骑缝章扫描件 + accept: + - pdf + - type: link_template + label: 下载印章缺失情况说明模板 + template_id: seal_missing_statement + - type: escalate + label: 疑似合同替换页,上报合规组 + role: 合规专员 + type: deterministic + - rule_id: MM-SEAL-003 + name: 高额合同须法人签名与公章并存 + risk: medium + score: 5 + stages: + - id: '1' + check: compare + left: 合同金额 + op: '>' + right: 500000 + - id: '2' + type: seal.present + required_if: '1' + seal_id: 甲方签章 + - id: '3' + type: signature.present + required_if: '1' + signature_id: 甲方法人签名 + logic: NOT 1 OR (2 AND 3) + messages: + pass: 小额合同或已有公章+法人签名双重确认 + fail: 大额合同缺少公章或法人签名 + remediation: + suggestions: + - 超过 50 万元的合同建议法人亲自签名 + 公章双重确认 + - 缺少任一都属于瑕疵,建议补齐 + actions: + - type: upload_file + label: 补传签章页(含法人签名) + file_type: 签章页 + accept: + - pdf + - jpg + - png + - type: document_override + label: 记录豁免(金额虽大但有特殊约定) + require_reason: true + require_role: 法务经理 + type: deterministic diff --git a/rules/contract_sale.zip b/rules/contract_sale.zip new file mode 100644 index 0000000..85fe843 Binary files /dev/null and b/rules/contract_sale.zip differ diff --git a/rules/contract_sale/docs/real_智慧法务平台采购合同.pdf b/rules/contract_sale/docs/real_智慧法务平台采购合同.pdf new file mode 100644 index 0000000..bf2609c Binary files /dev/null and b/rules/contract_sale/docs/real_智慧法务平台采购合同.pdf differ diff --git a/rules/contract_sale/docs/test_middle.md b/rules/contract_sale/docs/test_middle.md new file mode 100644 index 0000000..9626b6a --- /dev/null +++ b/rules/contract_sale/docs/test_middle.md @@ -0,0 +1,72 @@ +# 梅城区机关事务管理中心办公耗材采购合同 + +合同名称:2025年度办公耗材定点采购合同 + +甲方(采购方):梅城区机关事务管理中心 +法定代表人:黄伟强 +地址:广东省梅州市梅城区行政中心C栋3楼 +联系人:刘芳 +联系电话:0753-2188100 + +乙方(供应商):梅州市恒达办公用品有限公司 +法定代表人:张贤 +地址:梅州市梅江区彬芳大道158号 +联系人:陈小华 +联系电话:0753-2298888 + +根据《中华人民共和国民法典》等有关法律法规,甲乙双方本着平等互利的原则,就甲方采购乙方办公耗材事宜,协商一致签订本合同。 + +## 一、合同标的 + +甲方向乙方采购办公耗材,包括A4复印纸、硒鼓、墨盒、文件夹等日常办公消耗品,具体品种和规格以甲方每次下发的采购订单为准。 + +## 二、合同金额 + +本合同为定点采购框架合同,预计总金额为人民币拾贰万元整(¥120000.00元)。最终金额以实际采购量按单价结算。 + +## 三、付款方式 + +甲方按月与乙方对账结算,在收到乙方开具的增值税普通发票后30个工作日内,通过银行转账方式支付当月货款。 + +## 四、交货时间与地点 + +1. 乙方应在接到甲方订单后2个工作日内送货到位。 +2. 交货地点:梅城区行政中心C栋3楼物资仓库。 + +## 五、质量要求 + +乙方提供的办公耗材应为正品合格产品,质量符合国家标准。如发现假冒伪劣产品,甲方有权退货并要求乙方赔偿。 + +## 六、验收方式 + +甲方收货人员对到货物资进行数量和外观检查,签收即视为验收通过。 + +## 七、违约责任 + +违约方应当赔偿守约方由此造成的全部经济损失。乙方如果延迟交货超过3天,甲方有权扣除当批货款的10%作为违约金。 + +## 八、争议解决 + +双方如发生争议,应友好协商;协商不成的,提交梅州仲裁委员会仲裁。 + +## 九、不可抗力 + +因不可抗力导致合同无法履行的,双方互不追究责任。 + +## 十、合同期限 + +本合同有效期自2025年1月1日至2025年12月31日。合同到期后如双方无异议可续签。 + +## 十一、其他 + +本合同一式肆份,甲方执贰份,乙方执贰份。 + +甲方(盖章):梅城区机关事务管理中心 +法定代表人/委托代理人:黄伟强 +日期:2024年12月25日 + +乙方(盖章):梅州市恒达办公用品有限公司 +法定代表人/委托代理人:张贤 +日期:2024年12月25日 + +签约地点:梅州市梅城区行政中心 diff --git a/rules/contract_sale/docs/test_negative.md b/rules/contract_sale/docs/test_negative.md new file mode 100644 index 0000000..2a60e20 --- /dev/null +++ b/rules/contract_sale/docs/test_negative.md @@ -0,0 +1,34 @@ +# 物资采购协议 + +甲方:某某公司 + +乙方:某供应商 + +经双方友好协商,就物资采购事宜达成如下协议: + +## 一、采购内容 + +甲方向乙方购买一批办公用品。 + +## 二、价款 + +共计壹拾万元整(¥120000.00元)。 + +## 三、付款 + +验收后付款。 + +## 四、交付 + +乙方负责送货。 + +## 五、违约 + +如任何一方违约,则违约方应赔偿对方损失。 + +## 六、其他 + +本协议如有争议,双方协商解决。 + +甲方:某某公司 +乙方:某供应商 diff --git a/rules/contract_sale/docs/test_positive.md b/rules/contract_sale/docs/test_positive.md new file mode 100644 index 0000000..cf4694c --- /dev/null +++ b/rules/contract_sale/docs/test_positive.md @@ -0,0 +1,110 @@ +# 广东天宏科技有限公司办公设备采购合同 + +合同名称:2025年度办公设备采购合同 + +合同编号:TH-2025-CG-0088 + +甲方(采购方):广东天宏科技有限公司 +法定代表人:陈志远 +地址:广东省广州市天河区科韵路128号天宏大厦12楼 +联系人:张晓明 +联系电话:020-38891234 +统一社会信用代码:91440106MA5D2K3R7P +开户银行:中国建设银行广州天河支行 +银行账号:44050158360800000123 + +乙方(供应商):深圳联创信息技术股份有限公司 +法定代表人:王建华 +地址:深圳市南山区科技园南区高新南七道018号深圳软件园T3栋8楼 +联系人:李敏 +联系电话:0755-26738800 +统一社会信用代码:91440300728893145W +开户银行:招商银行深圳科技园支行 +银行账号:755916028210801 + +根据《中华人民共和国民法典》及其他相关法律法规的规定,甲乙双方在平等、自愿、公平、诚实信用的基础上,就甲方采购乙方办公设备事宜达成如下协议,特订立本合同,双方共同遵守。 + +## 一、合同标的 + +甲方向乙方采购以下办公设备:联想ThinkCentre M920台式电脑50台、惠普LaserJet Pro M404dn打印机20台、华为MateStation X一体机10台。具体配置参数、型号和技术要求详见本合同附件一《设备清单及技术规格》。 + +## 二、合同金额 + +本合同总金额为人民币伍拾捌万陆仟元整(¥586000.00元)。该金额已包含设备款、运输费、安装调试费、培训费及税金等全部费用。 + +## 三、付款方式 + +1. 第一期付款:合同签订生效后5个工作日内,甲方向乙方支付合同总额的30%,即人民币175800.00元,作为预付款。 +2. 第二期付款:设备到货并经甲方验收合格后,甲方凭乙方开具的等额增值税专用发票,在15个工作日内支付合同总额的60%,即人民币351600.00元。 +3. 第三期付款:质保期满后15个工作日内,甲方支付合同总额的10%,即人民币58600.00元,作为质保金。 +4. 付款方式:银行转账。 + +## 四、交货时间与地点 + +1. 交货时间:乙方应在合同签订后15个日历天内完成全部设备的交付和安装调试。 +2. 交货地点:广东省广州市天河区科韵路128号天宏大厦12楼。 +3. 运输方式:由乙方负责运输,运输费用包含在合同总价中。运输过程中设备毁损、灭失的风险由乙方承担。 + +## 五、质量要求 + +1. 乙方提供的设备应为全新原装正品,符合GB/T 9813-2016《计算机通用规范》及相关行业标准。 +2. 设备性能指标不低于本合同附件一中的技术参数要求,以附件一为验收依据。 +3. 每台设备须附带出厂检测合格证、使用说明书和保修卡。 +4. 设备外观无划痕、变形、掉漆等瑕疵。 +5. 设备在正常使用条件下的质保期为自验收合格之日起12个月。 + +## 六、验收方式 + +1. 设备送达甲方指定地点后,甲乙双方应在3个工作日内共同进行验收。 +2. 验收内容包括:设备数量、型号、外观、配件完整性以及基本功能测试,验收标准依据附件一《设备清单及技术规格》。 +3. 验收合格后,由甲乙双方签署《设备验收确认书》,作为付款和风险转移的依据。 +4. 如验收不合格,甲方应在验收后3个工作日内书面提出异议并列明不合格项。乙方应在收到异议后5个工作日内免费更换或修复,并重新提交验收。 +5. 对隐蔽缺陷,甲方在质保期内发现的,乙方仍应承担维修或更换责任。因产品质量缺陷致使合同目的不能实现的,甲方有权解除合同并要求赔偿损失。 + +## 七、违约责任 + +1. 乙方逾期交货的,每逾期一日,应向甲方支付合同总额1‰的违约金(年化不超过合同总额的24%);逾期超过15日的,甲方有权解除合同,乙方应退还甲方已支付的全部款项,并支付合同总额5%的违约金。 +2. 乙方交付的设备不符合质量要求的,甲方有权要求乙方在10个工作日内免费更换或修复,乙方应承担由此产生的运输费、安装费等一切费用。因质量问题给甲方造成损失的,乙方应赔偿甲方的直接经济损失。因质量问题导致合同目的不能实现的,甲方有权解除合同。 +3. 甲方逾期付款的,每逾期一日,应向乙方支付逾期金额1‰的违约金(年化不超过逾期金额的24%);逾期超过30日的,乙方有权解除合同,甲方应赔偿乙方的直接经济损失。 +4. 乙方违反本合同保密义务的,应向甲方支付合同总额10%的违约金,并赔偿甲方因此遭受的全部损失。 +5. 任何一方违反本合同约定导致对方损失的,违约方除支付违约金外,如违约金不足以弥补损失的,还应赔偿不足部分。 + +## 八、争议解决 + +本合同履行过程中发生争议的,双方应首先友好协商解决;协商不成的,任何一方均可向广州市天河区人民法院提起诉讼。 + +## 九、不可抗力 + +1. 不可抗力是指不能预见、不能避免且不能克服的客观事件,包括但不限于自然灾害(地震、洪水、台风等)、社会事件(战争、骚乱等)、政府行为(征收、禁令等)和公共卫生事件(重大疫情等)。 +2. 因不可抗力导致合同全部或部分不能履行的,遭受不可抗力的一方应在不可抗力事件发生后5日内以书面方式通知对方,并在15日内提供不可抗力证明文件(包括政府部门、公证机构或权威媒体出具的证明)。 +3. 因不可抗力导致合同不能履行的,根据不可抗力的影响程度部分或全部免除责任,但遭受不可抗力的一方应采取合理措施减少损失。不可抗力事件持续超过30日的,任何一方有权书面通知对方解除合同,双方互不承担违约责任。当事人迟延履行后发生不可抗力的,不能免除责任。 + +## 十、保密条款 + +1. 本合同所称保密信息是指双方因履行本合同而知悉或接收的对方的商业秘密、技术秘密、客户信息、财务数据、经营策略以及其他未经公开披露的信息。 +2. 保密期限自合同签订之日起至合同终止后两年止。合同终止后,接收方应将载有保密信息的文件、资料或软件按提供方要求归还或销毁。 +3. 未经信息提供方书面同意,接收方不得向任何第三方泄露、提供或使用保密信息。即使向与履行本合同有关的人员提供,也应注意保密并限于履行合同所必需的范围。 +4. 违反保密义务的,违约方应赔偿对方因此遭受的全部损失(包括直接损失和合理可得利益损失)。 + +## 十一、知识产权 + +乙方保证其提供的设备不侵犯任何第三方的知识产权。如因设备涉及第三方知识产权纠纷,给甲方造成损失的,由乙方承担全部责任。 + +## 十二、合同期限 + +本合同自双方签字盖章之日起生效,至双方权利义务全部履行完毕之日止。设备质保期为验收合格之日起12个月。 + +## 十三、其他 + +1. 本合同一式肆份,甲方执贰份,乙方执贰份,均具有同等法律效力。 +2. 本合同未尽事宜,双方可另行签订补充协议,补充协议与本合同具有同等效力。 + +甲方(盖章):广东天宏科技有限公司 +法定代表人/委托代理人:陈志远 +日期:2025年3月15日 + +乙方(盖章):深圳联创信息技术股份有限公司 +法定代表人/委托代理人:王建华 +日期:2025年3月15日 + +签约地点:广东省广州市天河区科韵路128号天宏大厦12楼 diff --git a/rules/contract_sale/rules.yaml b/rules/contract_sale/rules.yaml new file mode 100644 index 0000000..870c2a6 --- /dev/null +++ b/rules/contract_sale/rules.yaml @@ -0,0 +1,1020 @@ +metadata: + type_id: contract.sale + name: 通用买卖合同 + version: '2.1' + last_updated: '2026-04-12' + tags: + - 合同 + - 买卖 + - 采购 + - 通用 + description: '依据《中华人民共和国民法典》合同编·通则(第470条)及买卖合同章(第595-647条)。 + + 适用于一般货物/商品/设备/IT系统采购类买卖合同的评查。 + + 原始规则来源:旧系统 01_买卖合同.json(10条买卖专项评查点)+ 通用合同评查点。 + + ' +extract: +- group: 合同成立要素 + fields: + - name: 合同名称 + type: verbatim + required_from: draft + desc: 合同的完整名称/项目名称 + deep_retry: false + - name: 甲方 + type: verbatim + required_from: draft + desc: 买方/采购方公司全称 + deep_retry: false + - name: 乙方 + type: verbatim + required_from: draft + desc: 卖方/供应商公司全称 + deep_retry: false + - name: 合同标的描述 + type: string + required_from: draft + desc: 合同交易的标的物/服务内容概述 + deep_retry: false + - name: 合同金额 + type: money + required_from: draft + desc: 合同总金额(数字) + deep_retry: true + - name: 合同金额大写 + type: verbatim + required_from: draft + desc: 合同总金额中文大写 + deep_retry: true +- group: 主体资格 + fields: + - name: 甲方法定代表人 + type: verbatim + required_from: draft + desc: 甲方法定代表人姓名 + deep_retry: false + - name: 乙方法定代表人 + type: verbatim + required_from: draft + desc: 乙方法定代表人姓名 + deep_retry: false + - name: 甲方地址 + type: verbatim + required_from: draft + desc: 甲方注册/办公地址 + deep_retry: false + - name: 乙方地址 + type: verbatim + required_from: draft + desc: 乙方注册/办公地址 + deep_retry: false + - name: 甲方统一社会信用代码 + type: uscc + required_from: executed + desc: 甲方18位统一社会信用代码 + deep_retry: false + - name: 乙方统一社会信用代码 + type: uscc + required_from: executed + desc: 乙方18位统一社会信用代码 + deep_retry: false +- group: 履约核心条款 + fields: + - name: 付款方式 + type: string + required_from: draft + desc: 付款条件、比例、节点、方式的完整描述 + deep_retry: false + - name: 交货期限 + type: string + required_from: draft + desc: 交货/交付时间要求 + deep_retry: false + - name: 交货地点 + type: verbatim + required_from: draft + desc: 交货/送达地点 + deep_retry: false + - name: 验收条款 + type: string + required_from: draft + desc: 验收标准、验收流程、初验终验时间和不合格处理 + deep_retry: false + - name: 质保期条款 + type: string + required_from: draft + desc: 质保期限、质保范围、故障响应时间和运维服务内容 + deep_retry: false +- group: 买卖合同特有条款 + fields: + - name: 风险转移条款 + type: string + required_from: draft + desc: 标的物风险转移时点和交付确认方式 + deep_retry: false + - name: 履约保证金条款 + type: string + required_from: draft + desc: 保证金金额、缴纳方式、缴纳时间和退还条件 + deep_retry: false + - name: 知识产权条款 + type: string + required_from: draft + desc: 知识产权归属、使用许可范围和侵权责任 + deep_retry: false + - name: 培训条款 + type: string + required_from: draft + desc: 培训内容、培训方式和培训安排 + deep_retry: false + - name: 标的清单明细 + type: string + required_from: draft + desc: 标的清单(序号、名称、数量、单价等明细及总价) + deep_retry: false + - name: 招投标信息 + type: string + required_from: draft + desc: 招标文件编号、项目编号、中标通知书等招投标依据 + deep_retry: false +- group: 法定/必备条款 + fields: + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约责任的完整条款内容 + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式(法院/仲裁)的完整描述 + deep_retry: false + - name: 不可抗力条款 + type: string + required_from: draft + desc: 不可抗力相关条款的完整内容 + deep_retry: false +- group: 签署要素 + fields: + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 合同编号 + type: verbatim + required_from: executed + desc: 合同唯一编号 + deep_retry: false +- group: 辅助信息 + fields: + - name: 甲方联系人 + type: verbatim + required_from: draft + desc: 甲方项目联系人姓名 + deep_retry: false + - name: 甲方联系电话 + type: verbatim + required_from: draft + desc: 甲方联系电话 + deep_retry: false + - name: 乙方联系人 + type: verbatim + required_from: draft + desc: 乙方项目联系人姓名 + deep_retry: false + - name: 乙方联系电话 + type: verbatim + required_from: draft + desc: 乙方联系电话 + deep_retry: false + - name: 收款方开户银行 + type: verbatim + required_from: draft + desc: 收款方(通常为供应商/卖方/乙方)的银行开户行名称 + deep_retry: false + - name: 收款方银行账号 + type: verbatim + required_from: draft + desc: 收款方的银行账号 + deep_retry: false +- group: 其他条款 + fields: + - name: 保密条款 + type: string + required_from: draft + desc: 保密义务相关条款内容,如果有保密条款附件,总结附件的内容,限制在100字内 + deep_retry: false +- group: 判定原则:只有合同中明确出现相关条款时才填"是",没有提及就填"否"。不要推测。 + fields: + - name: 涉及知识产权 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否存在知识产权相关条款(如知识产权归属、授权许可、源代码交付、专利使用等)。 填"是"的条件:合同正文中明确出现"知识产权""版权""专利""著作权""源代码"等关键词且有实质条款。 填"否"的条件:合同为普通货物采购(设备、物资、服装、食品、原材料等)且无任何知识产权条款。 + + ' + deep_retry: false + - name: 涉及保密信息 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否存在保密条款(如保密义务、保密期限、泄密责任等)。 填"是"的条件:合同正文中明确出现"保密""机密""不得泄露"等关键词且有实质保密条款。 填"否"的条件:合同中没有任何保密相关条款。 + + ' + deep_retry: false + - name: 涉及培训服务 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否包含培训服务条款(如培训内容、培训人数、培训地点等)。 填"是"的条件:合同正文中明确约定了培训相关的服务内容和安排。 填"否"的条件:合同为纯货物采购,没有任何培训条款。 + + ' + deep_retry: false +rules: +- group: 完整性(11 条) + rules: + - rule_id: MM-001 + name: 合同主体齐全 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 甲方 + - id: '2' + check: required + field: 乙方 + messages: + pass: 甲乙方信息完整 + fail: 缺少甲方或乙方信息 + type: deterministic + - rule_id: MM-002 + name: 标的物与金额必填 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 合同标的描述 + - id: '2' + check: required + field: 合同金额 + messages: + pass: 标的物与金额信息完整 + fail: 缺少标的物描述或合同金额 + type: deterministic + - rule_id: MM-003 + name: 合同名称必填 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 合同名称 + messages: + pass: 合同名称已填写 + fail: 缺少合同名称 + type: deterministic + - rule_id: MM-004 + name: 法定代表人齐全 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 甲方法定代表人 + - id: '2' + check: required + field: 乙方法定代表人 + messages: + pass: 甲乙方法定代表人信息完整 + fail: 缺少甲方或乙方法定代表人信息 + type: deterministic + - rule_id: MM-005 + name: 交货期限必填 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 交货期限 + messages: + pass: 交货期限已约定 + fail: 交货期限未约定 + type: deterministic + - rule_id: MM-006 + name: 验收条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 验收条款 + messages: + pass: 验收条款存在 + fail: 缺少验收条款 + type: deterministic + - rule_id: MM-007 + name: 违约责任条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 违约责任条款 + messages: + pass: 违约责任条款存在 + fail: 缺少违约责任条款 + type: deterministic + - rule_id: MM-008 + name: 争议解决条款存在 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + messages: + pass: 争议解决条款存在 + fail: 缺少争议解决条款 + type: deterministic + - rule_id: MM-009 + name: 培训条款存在 + risk: low + score: 2 + activate_if: 涉及培训服务 == "是" + stages: + - id: '1' + check: required + field: 培训条款 + messages: + pass: 培训条款已约定 + fail: 培训条款缺失 + type: deterministic + - rule_id: MM-010 + name: 签约日期必填 + risk: high + score: 8 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + messages: + pass: 签约日期已填写 + fail: 缺少签约日期 + type: deterministic + - rule_id: MM-011 + name: 合同编号必填 + risk: medium + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 合同编号 + messages: + pass: 合同编号已填写 + fail: 缺少合同编号 + type: deterministic +- group: 规范性(2 条) + rules: + - rule_id: MM-012 + name: 甲方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 甲方统一社会信用代码 + format: uscc + messages: + pass: 甲方统一社会信用代码校验通过 + fail: 甲方统一社会信用代码校验位错误 + type: deterministic + - rule_id: MM-013 + name: 乙方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 乙方统一社会信用代码 + format: uscc + messages: + pass: 乙方统一社会信用代码校验通过 + fail: 乙方统一社会信用代码校验位错误 + type: deterministic +- group: 合理性(3 条) + rules: + - rule_id: MM-014 + name: 金额大小写一致 + risk: high + score: 10 + stages: + - id: '1' + check: amount_match + number: 合同金额 + chinese: 合同金额大写 + messages: + pass: 金额大小写一致 + fail: 合同金额数字与大写不一致 + type: deterministic + - rule_id: MM-015 + name: 金额为正数 + risk: low + score: 3 + stages: + - id: '1' + check: compare + left: 合同金额 + op: '>' + right: 0 + messages: + pass: 合同金额为正数 + fail: 合同金额不为正数 + type: deterministic + - rule_id: MM-016 + name: 签约日期不是未来 + risk: low + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: assert + expr: parse_date(签约日期) != None and (today() - parse_date(签约日期)).days >= 0 and (today() - parse_date(签约日期)).days <= 3650 + messages: + pass: 签约日期在合理范围内 + fail: 签约日期为未来日期或距今超过10年 + type: deterministic +- group: '来源: NR-MM-002 标的物检验期限约定 — §620-622' + rules: + - rule_id: MM-017 + name: 验收条款完整 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 验收条款 + - id: '2' + check: ai + prompt: '请检查合同的验收/检验条款是否完整。 + + + 验收条款:{{验收条款}} + + + 评查要点(依据民法典第620-622条): + + 1. 是否约定了明确的检验/验收期限 + + 2. 是否约定了验收标准(国家标准、行业标准、招标文件要求等) + + 3. 是否约定了验收流程(谁组织、谁参与) + + 4. 检验期限是否合理 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 验收条款完整 + fail: 验收条款不完整 + type: ai_rule +- group: '来源: NR-MM-004 风险转移条款 — §604-607' + rules: + - rule_id: MM-018 + name: 风险转移条款明确 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 风险转移条款 + - id: '2' + check: ai + prompt: '请检查合同中是否有关于标的物/服务交付后风险转移的约定。 + + + 风险转移条款:{{风险转移条款}} + + + 评查要点(依据民法典第604-607条): + + 1. 是否明确了风险转移的时点(交付时、验收时或其他约定时点) + + 2. 对于软件/系统类标的,风险转移通常与验收挂钩 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 风险转移条款约定明确 + fail: 风险转移条款缺失或不明确 + type: ai_rule +- group: '来源: NR-MM-005 质保期条款完整性 — §617, §621' + rules: + - rule_id: MM-019 + name: 质保期条款完整 + risk: high + score: 3 + stages: + - id: '1' + check: required + field: 质保期条款 + - id: '2' + check: ai + prompt: '请检查合同的质保条款是否完整。 + + + 质保条款:{{质保期条款}} + + + 评查要点(依据民法典第617、621条): + + 1. 质保期限是否明确(起算时间、结束时间) + + 2. 质保范围是否清晰(哪些属于质保范围内、哪些除外) + + 3. 故障响应时间是否合理 + + 4. 是否约定了质保期内的服务标准 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 质保期条款完整 + fail: 质保期条款不完整 + type: ai_rule +- group: '来源: NR-MM-006 履约保证金条款 — §586-587' + rules: + - rule_id: MM-020 + name: 履约保证金条款完整 + risk: medium + score: 3 + activate_if: 履约保证金条款 != None + stages: + - id: '1' + check: required + field: 履约保证金条款 + - id: '2' + check: ai + prompt: '请检查合同中履约保证金条款是否完整。 + + + 保证金条款:{{履约保证金条款}} + + + 评查要点(依据民法典第586-587条): + + 1. 保证金金额是否明确 + + 2. 缴纳时间和方式是否清楚 + + 3. 退还条件是否合理、具体 + + 4. 退还时间是否明确 + + 5. 保证金比例一般不超过合同金额的10% + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 履约保证金条款完整 + fail: 履约保证金条款不完整 + type: ai_rule +- group: '来源: NR-MM-009 分期付款条款合理性 — §626-634' + rules: + - rule_id: MM-021 + name: 分期付款条款合理 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 付款方式 + - id: '2' + check: required + field: 合同金额 + - id: '3' + check: ai + prompt: '请审查合同分期付款条款的合理性。 + + + 付款条款:{{付款方式}} + + 合同总金额:{{合同金额}} + + 联合采购信息:{{联合采购信息}} + + + 评查要点(依据民法典第626-634条): + + 1. 各期付款比例之和是否覆盖应付总额(联合采购时:各期比例之和=本单位分摊比例即为100%覆盖,如4单位各付25%,则5%+10%+10%=25%=该单位全额,判为pass) + + 2. 预付款不超过30% + + 3. 付款节点与交付验收挂钩 + + 4. 有付款前置条件(发票、验收报告等) + + 请简洁回答,reason不超过100字。 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 分期付款条款合理 + fail: 分期付款条款存在问题 + type: ai_rule +- group: '来源: NR-MM-007 知识产权归属约定 — §600' + rules: + - rule_id: MM-022 + name: 知识产权条款完整 + risk: high + score: 3 + activate_if: 涉及知识产权 == "是" + stages: + - id: '1' + check: required + field: 知识产权条款 + - id: '2' + check: ai + prompt: '请检查合同中知识产权条款是否完整。 + + + 知识产权条款:{{知识产权条款}} + + + 评查要点(依据民法典第600条): + + 1. 是否明确了知识产权的归属(买方/卖方/共有) + + 2. 是否约定了使用许可的范围和方式 + + 3. 是否约定了第三方知识产权侵权的责任承担 + + 4. 对于软件/系统类采购,应特别关注源代码、数据归属 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 知识产权条款完整 + fail: 知识产权条款不完整 + type: ai_rule +- group: '来源: NR-MM-012 标的清单金额校验 — §595-596' + rules: + - rule_id: MM-023 + name: 标的清单金额校验 + risk: high + score: 5 + activate_if: 标的清单明细 != None + stages: + - id: '1' + check: required + field: 标的清单明细 + - id: '2' + check: required + field: 合同金额 + - id: '3' + check: ai + prompt: '请校验合同标的清单的金额一致性。 + + + 标的清单明细:{{标的清单明细}} + + 合同总金额:{{合同金额}} + + + 评查要点(依据民法典第595-596条): + + 1. 各项单价x数量是否等于对应项总价(逐项计算校验) + + 2. 标的清单总价是否等于合同总金额 + + 3. 服务范围描述是否足够具体(非含糊表述) + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 标的清单金额校验通过 + fail: 标的清单金额不一致或服务范围不明确 + type: ai_rule +- group: '来源: NR-MM-014 招投标一致性 — §644' + rules: + - rule_id: MM-024 + name: 招投标信息引用完整 + risk: high + score: 3 + activate_if: 招投标信息 != None + stages: + - id: '1' + check: required + field: 招投标信息 + - id: '2' + check: ai + prompt: '请检查合同是否明确引用了招投标文件。 + + + 招投标信息:{{招投标信息}} + + + 评查要点: + + 1. 合同是否引用了招标文件编号/项目编号 + + 2. 合同是否将招标文件、投标文件作为合同附件或组成部分 + + 3. 合同主要条款不应实质性变更招投标内容 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 合同与招投标文件一致 + fail: 合同与招投标文件引用不完整 + type: ai_rule +- group: 合规性 · AI 语义判断(4 条) + rules: + - rule_id: MM-025 + name: 违约责任条款充分 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请判断以下违约责任条款是否充分、合规。 + + + 条款内容:{{违约责任条款}} + + + 充分的违约责任条款应当(依据民法典第577-585条): + + 1. 明确违约情形(如逾期付款、逾期交货、质量不合格等) + + 2. 明确违约金计算方式或赔偿标准 + + 3. 不能只是笼统的模糊表述 + + 4. 应当对双方的违约责任都有约定 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 违约责任条款充分 + fail: 违约责任条款不充分 + type: ai_rule + - rule_id: MM-026 + name: 争议解决方式明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请判断以下争议解决条款是否符合法律要求。 + + + 条款内容:{{争议解决条款}} + + + 合规的争议解决条款应当: + + 1. 明确指定具体的争议解决方式(仲裁或诉讼,二选一) + + 2. 如选择仲裁,应明确仲裁机构名称 + + 3. 如选择诉讼,应明确管辖法院 + + 4. 不能同时约定仲裁和诉讼 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 争议解决方式明确 + fail: 争议解决条款未明确具体的仲裁机构/管辖法院 + type: ai_rule + - rule_id: MM-027 + name: 付款条款明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 付款方式 + - id: '2' + check: ai + prompt: '请判断以下付款条款是否明确。 + + + 条款内容:{{付款方式}} + + + 明确的付款条款应当包含: + + 1. 付款金额或比例 + + 2. 付款时间节点或触发条件 + + 3. 付款方式(如银行转账) + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 付款条款明确 + fail: 付款条款不够明确 + type: ai_rule + - rule_id: MM-028 + name: 保密条款完整 + risk: low + score: 3 + activate_if: 涉及保密信息 == "是" + stages: + - id: '1' + check: required + field: 保密条款 + - id: '2' + check: ai + prompt: '请判断以下保密条款是否完整。 + + + 条款内容:{{保密条款}} + + + 完整的保密条款应当包含: + + 1. 保密信息的范围定义 + + 2. 保密义务的期限 + + 3. 违反保密义务的法律后果 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 保密条款完整 + fail: 保密条款不够完整 + type: ai_rule +- group: 银行信息 + rules: + - rule_id: MM-029 + name: 收款方银行信息完整 + risk: high + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: required + fields: + - 收款方开户银行 + - 收款方银行账号 + messages: + pass: 收款方银行信息完整 + fail: 缺少收款方银行开户行或账号,付款无法执行 + type: deterministic diff --git a/rules/contract_sale/rules.yaml.bak b/rules/contract_sale/rules.yaml.bak new file mode 100644 index 0000000..870c2a6 --- /dev/null +++ b/rules/contract_sale/rules.yaml.bak @@ -0,0 +1,1020 @@ +metadata: + type_id: contract.sale + name: 通用买卖合同 + version: '2.1' + last_updated: '2026-04-12' + tags: + - 合同 + - 买卖 + - 采购 + - 通用 + description: '依据《中华人民共和国民法典》合同编·通则(第470条)及买卖合同章(第595-647条)。 + + 适用于一般货物/商品/设备/IT系统采购类买卖合同的评查。 + + 原始规则来源:旧系统 01_买卖合同.json(10条买卖专项评查点)+ 通用合同评查点。 + + ' +extract: +- group: 合同成立要素 + fields: + - name: 合同名称 + type: verbatim + required_from: draft + desc: 合同的完整名称/项目名称 + deep_retry: false + - name: 甲方 + type: verbatim + required_from: draft + desc: 买方/采购方公司全称 + deep_retry: false + - name: 乙方 + type: verbatim + required_from: draft + desc: 卖方/供应商公司全称 + deep_retry: false + - name: 合同标的描述 + type: string + required_from: draft + desc: 合同交易的标的物/服务内容概述 + deep_retry: false + - name: 合同金额 + type: money + required_from: draft + desc: 合同总金额(数字) + deep_retry: true + - name: 合同金额大写 + type: verbatim + required_from: draft + desc: 合同总金额中文大写 + deep_retry: true +- group: 主体资格 + fields: + - name: 甲方法定代表人 + type: verbatim + required_from: draft + desc: 甲方法定代表人姓名 + deep_retry: false + - name: 乙方法定代表人 + type: verbatim + required_from: draft + desc: 乙方法定代表人姓名 + deep_retry: false + - name: 甲方地址 + type: verbatim + required_from: draft + desc: 甲方注册/办公地址 + deep_retry: false + - name: 乙方地址 + type: verbatim + required_from: draft + desc: 乙方注册/办公地址 + deep_retry: false + - name: 甲方统一社会信用代码 + type: uscc + required_from: executed + desc: 甲方18位统一社会信用代码 + deep_retry: false + - name: 乙方统一社会信用代码 + type: uscc + required_from: executed + desc: 乙方18位统一社会信用代码 + deep_retry: false +- group: 履约核心条款 + fields: + - name: 付款方式 + type: string + required_from: draft + desc: 付款条件、比例、节点、方式的完整描述 + deep_retry: false + - name: 交货期限 + type: string + required_from: draft + desc: 交货/交付时间要求 + deep_retry: false + - name: 交货地点 + type: verbatim + required_from: draft + desc: 交货/送达地点 + deep_retry: false + - name: 验收条款 + type: string + required_from: draft + desc: 验收标准、验收流程、初验终验时间和不合格处理 + deep_retry: false + - name: 质保期条款 + type: string + required_from: draft + desc: 质保期限、质保范围、故障响应时间和运维服务内容 + deep_retry: false +- group: 买卖合同特有条款 + fields: + - name: 风险转移条款 + type: string + required_from: draft + desc: 标的物风险转移时点和交付确认方式 + deep_retry: false + - name: 履约保证金条款 + type: string + required_from: draft + desc: 保证金金额、缴纳方式、缴纳时间和退还条件 + deep_retry: false + - name: 知识产权条款 + type: string + required_from: draft + desc: 知识产权归属、使用许可范围和侵权责任 + deep_retry: false + - name: 培训条款 + type: string + required_from: draft + desc: 培训内容、培训方式和培训安排 + deep_retry: false + - name: 标的清单明细 + type: string + required_from: draft + desc: 标的清单(序号、名称、数量、单价等明细及总价) + deep_retry: false + - name: 招投标信息 + type: string + required_from: draft + desc: 招标文件编号、项目编号、中标通知书等招投标依据 + deep_retry: false +- group: 法定/必备条款 + fields: + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约责任的完整条款内容 + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式(法院/仲裁)的完整描述 + deep_retry: false + - name: 不可抗力条款 + type: string + required_from: draft + desc: 不可抗力相关条款的完整内容 + deep_retry: false +- group: 签署要素 + fields: + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 合同编号 + type: verbatim + required_from: executed + desc: 合同唯一编号 + deep_retry: false +- group: 辅助信息 + fields: + - name: 甲方联系人 + type: verbatim + required_from: draft + desc: 甲方项目联系人姓名 + deep_retry: false + - name: 甲方联系电话 + type: verbatim + required_from: draft + desc: 甲方联系电话 + deep_retry: false + - name: 乙方联系人 + type: verbatim + required_from: draft + desc: 乙方项目联系人姓名 + deep_retry: false + - name: 乙方联系电话 + type: verbatim + required_from: draft + desc: 乙方联系电话 + deep_retry: false + - name: 收款方开户银行 + type: verbatim + required_from: draft + desc: 收款方(通常为供应商/卖方/乙方)的银行开户行名称 + deep_retry: false + - name: 收款方银行账号 + type: verbatim + required_from: draft + desc: 收款方的银行账号 + deep_retry: false +- group: 其他条款 + fields: + - name: 保密条款 + type: string + required_from: draft + desc: 保密义务相关条款内容,如果有保密条款附件,总结附件的内容,限制在100字内 + deep_retry: false +- group: 判定原则:只有合同中明确出现相关条款时才填"是",没有提及就填"否"。不要推测。 + fields: + - name: 涉及知识产权 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否存在知识产权相关条款(如知识产权归属、授权许可、源代码交付、专利使用等)。 填"是"的条件:合同正文中明确出现"知识产权""版权""专利""著作权""源代码"等关键词且有实质条款。 填"否"的条件:合同为普通货物采购(设备、物资、服装、食品、原材料等)且无任何知识产权条款。 + + ' + deep_retry: false + - name: 涉及保密信息 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否存在保密条款(如保密义务、保密期限、泄密责任等)。 填"是"的条件:合同正文中明确出现"保密""机密""不得泄露"等关键词且有实质保密条款。 填"否"的条件:合同中没有任何保密相关条款。 + + ' + deep_retry: false + - name: 涉及培训服务 + type: + - 是 + - 否 + required_from: draft + allowed: + - 是 + - 否 + desc: '合同中是否包含培训服务条款(如培训内容、培训人数、培训地点等)。 填"是"的条件:合同正文中明确约定了培训相关的服务内容和安排。 填"否"的条件:合同为纯货物采购,没有任何培训条款。 + + ' + deep_retry: false +rules: +- group: 完整性(11 条) + rules: + - rule_id: MM-001 + name: 合同主体齐全 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 甲方 + - id: '2' + check: required + field: 乙方 + messages: + pass: 甲乙方信息完整 + fail: 缺少甲方或乙方信息 + type: deterministic + - rule_id: MM-002 + name: 标的物与金额必填 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 合同标的描述 + - id: '2' + check: required + field: 合同金额 + messages: + pass: 标的物与金额信息完整 + fail: 缺少标的物描述或合同金额 + type: deterministic + - rule_id: MM-003 + name: 合同名称必填 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 合同名称 + messages: + pass: 合同名称已填写 + fail: 缺少合同名称 + type: deterministic + - rule_id: MM-004 + name: 法定代表人齐全 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 甲方法定代表人 + - id: '2' + check: required + field: 乙方法定代表人 + messages: + pass: 甲乙方法定代表人信息完整 + fail: 缺少甲方或乙方法定代表人信息 + type: deterministic + - rule_id: MM-005 + name: 交货期限必填 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 交货期限 + messages: + pass: 交货期限已约定 + fail: 交货期限未约定 + type: deterministic + - rule_id: MM-006 + name: 验收条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 验收条款 + messages: + pass: 验收条款存在 + fail: 缺少验收条款 + type: deterministic + - rule_id: MM-007 + name: 违约责任条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 违约责任条款 + messages: + pass: 违约责任条款存在 + fail: 缺少违约责任条款 + type: deterministic + - rule_id: MM-008 + name: 争议解决条款存在 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + messages: + pass: 争议解决条款存在 + fail: 缺少争议解决条款 + type: deterministic + - rule_id: MM-009 + name: 培训条款存在 + risk: low + score: 2 + activate_if: 涉及培训服务 == "是" + stages: + - id: '1' + check: required + field: 培训条款 + messages: + pass: 培训条款已约定 + fail: 培训条款缺失 + type: deterministic + - rule_id: MM-010 + name: 签约日期必填 + risk: high + score: 8 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + messages: + pass: 签约日期已填写 + fail: 缺少签约日期 + type: deterministic + - rule_id: MM-011 + name: 合同编号必填 + risk: medium + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 合同编号 + messages: + pass: 合同编号已填写 + fail: 缺少合同编号 + type: deterministic +- group: 规范性(2 条) + rules: + - rule_id: MM-012 + name: 甲方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 甲方统一社会信用代码 + format: uscc + messages: + pass: 甲方统一社会信用代码校验通过 + fail: 甲方统一社会信用代码校验位错误 + type: deterministic + - rule_id: MM-013 + name: 乙方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 乙方统一社会信用代码 + format: uscc + messages: + pass: 乙方统一社会信用代码校验通过 + fail: 乙方统一社会信用代码校验位错误 + type: deterministic +- group: 合理性(3 条) + rules: + - rule_id: MM-014 + name: 金额大小写一致 + risk: high + score: 10 + stages: + - id: '1' + check: amount_match + number: 合同金额 + chinese: 合同金额大写 + messages: + pass: 金额大小写一致 + fail: 合同金额数字与大写不一致 + type: deterministic + - rule_id: MM-015 + name: 金额为正数 + risk: low + score: 3 + stages: + - id: '1' + check: compare + left: 合同金额 + op: '>' + right: 0 + messages: + pass: 合同金额为正数 + fail: 合同金额不为正数 + type: deterministic + - rule_id: MM-016 + name: 签约日期不是未来 + risk: low + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: assert + expr: parse_date(签约日期) != None and (today() - parse_date(签约日期)).days >= 0 and (today() - parse_date(签约日期)).days <= 3650 + messages: + pass: 签约日期在合理范围内 + fail: 签约日期为未来日期或距今超过10年 + type: deterministic +- group: '来源: NR-MM-002 标的物检验期限约定 — §620-622' + rules: + - rule_id: MM-017 + name: 验收条款完整 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 验收条款 + - id: '2' + check: ai + prompt: '请检查合同的验收/检验条款是否完整。 + + + 验收条款:{{验收条款}} + + + 评查要点(依据民法典第620-622条): + + 1. 是否约定了明确的检验/验收期限 + + 2. 是否约定了验收标准(国家标准、行业标准、招标文件要求等) + + 3. 是否约定了验收流程(谁组织、谁参与) + + 4. 检验期限是否合理 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 验收条款完整 + fail: 验收条款不完整 + type: ai_rule +- group: '来源: NR-MM-004 风险转移条款 — §604-607' + rules: + - rule_id: MM-018 + name: 风险转移条款明确 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 风险转移条款 + - id: '2' + check: ai + prompt: '请检查合同中是否有关于标的物/服务交付后风险转移的约定。 + + + 风险转移条款:{{风险转移条款}} + + + 评查要点(依据民法典第604-607条): + + 1. 是否明确了风险转移的时点(交付时、验收时或其他约定时点) + + 2. 对于软件/系统类标的,风险转移通常与验收挂钩 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 风险转移条款约定明确 + fail: 风险转移条款缺失或不明确 + type: ai_rule +- group: '来源: NR-MM-005 质保期条款完整性 — §617, §621' + rules: + - rule_id: MM-019 + name: 质保期条款完整 + risk: high + score: 3 + stages: + - id: '1' + check: required + field: 质保期条款 + - id: '2' + check: ai + prompt: '请检查合同的质保条款是否完整。 + + + 质保条款:{{质保期条款}} + + + 评查要点(依据民法典第617、621条): + + 1. 质保期限是否明确(起算时间、结束时间) + + 2. 质保范围是否清晰(哪些属于质保范围内、哪些除外) + + 3. 故障响应时间是否合理 + + 4. 是否约定了质保期内的服务标准 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 质保期条款完整 + fail: 质保期条款不完整 + type: ai_rule +- group: '来源: NR-MM-006 履约保证金条款 — §586-587' + rules: + - rule_id: MM-020 + name: 履约保证金条款完整 + risk: medium + score: 3 + activate_if: 履约保证金条款 != None + stages: + - id: '1' + check: required + field: 履约保证金条款 + - id: '2' + check: ai + prompt: '请检查合同中履约保证金条款是否完整。 + + + 保证金条款:{{履约保证金条款}} + + + 评查要点(依据民法典第586-587条): + + 1. 保证金金额是否明确 + + 2. 缴纳时间和方式是否清楚 + + 3. 退还条件是否合理、具体 + + 4. 退还时间是否明确 + + 5. 保证金比例一般不超过合同金额的10% + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 履约保证金条款完整 + fail: 履约保证金条款不完整 + type: ai_rule +- group: '来源: NR-MM-009 分期付款条款合理性 — §626-634' + rules: + - rule_id: MM-021 + name: 分期付款条款合理 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 付款方式 + - id: '2' + check: required + field: 合同金额 + - id: '3' + check: ai + prompt: '请审查合同分期付款条款的合理性。 + + + 付款条款:{{付款方式}} + + 合同总金额:{{合同金额}} + + 联合采购信息:{{联合采购信息}} + + + 评查要点(依据民法典第626-634条): + + 1. 各期付款比例之和是否覆盖应付总额(联合采购时:各期比例之和=本单位分摊比例即为100%覆盖,如4单位各付25%,则5%+10%+10%=25%=该单位全额,判为pass) + + 2. 预付款不超过30% + + 3. 付款节点与交付验收挂钩 + + 4. 有付款前置条件(发票、验收报告等) + + 请简洁回答,reason不超过100字。 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 分期付款条款合理 + fail: 分期付款条款存在问题 + type: ai_rule +- group: '来源: NR-MM-007 知识产权归属约定 — §600' + rules: + - rule_id: MM-022 + name: 知识产权条款完整 + risk: high + score: 3 + activate_if: 涉及知识产权 == "是" + stages: + - id: '1' + check: required + field: 知识产权条款 + - id: '2' + check: ai + prompt: '请检查合同中知识产权条款是否完整。 + + + 知识产权条款:{{知识产权条款}} + + + 评查要点(依据民法典第600条): + + 1. 是否明确了知识产权的归属(买方/卖方/共有) + + 2. 是否约定了使用许可的范围和方式 + + 3. 是否约定了第三方知识产权侵权的责任承担 + + 4. 对于软件/系统类采购,应特别关注源代码、数据归属 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 知识产权条款完整 + fail: 知识产权条款不完整 + type: ai_rule +- group: '来源: NR-MM-012 标的清单金额校验 — §595-596' + rules: + - rule_id: MM-023 + name: 标的清单金额校验 + risk: high + score: 5 + activate_if: 标的清单明细 != None + stages: + - id: '1' + check: required + field: 标的清单明细 + - id: '2' + check: required + field: 合同金额 + - id: '3' + check: ai + prompt: '请校验合同标的清单的金额一致性。 + + + 标的清单明细:{{标的清单明细}} + + 合同总金额:{{合同金额}} + + + 评查要点(依据民法典第595-596条): + + 1. 各项单价x数量是否等于对应项总价(逐项计算校验) + + 2. 标的清单总价是否等于合同总金额 + + 3. 服务范围描述是否足够具体(非含糊表述) + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 标的清单金额校验通过 + fail: 标的清单金额不一致或服务范围不明确 + type: ai_rule +- group: '来源: NR-MM-014 招投标一致性 — §644' + rules: + - rule_id: MM-024 + name: 招投标信息引用完整 + risk: high + score: 3 + activate_if: 招投标信息 != None + stages: + - id: '1' + check: required + field: 招投标信息 + - id: '2' + check: ai + prompt: '请检查合同是否明确引用了招投标文件。 + + + 招投标信息:{{招投标信息}} + + + 评查要点: + + 1. 合同是否引用了招标文件编号/项目编号 + + 2. 合同是否将招标文件、投标文件作为合同附件或组成部分 + + 3. 合同主要条款不应实质性变更招投标内容 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 合同与招投标文件一致 + fail: 合同与招投标文件引用不完整 + type: ai_rule +- group: 合规性 · AI 语义判断(4 条) + rules: + - rule_id: MM-025 + name: 违约责任条款充分 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请判断以下违约责任条款是否充分、合规。 + + + 条款内容:{{违约责任条款}} + + + 充分的违约责任条款应当(依据民法典第577-585条): + + 1. 明确违约情形(如逾期付款、逾期交货、质量不合格等) + + 2. 明确违约金计算方式或赔偿标准 + + 3. 不能只是笼统的模糊表述 + + 4. 应当对双方的违约责任都有约定 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 违约责任条款充分 + fail: 违约责任条款不充分 + type: ai_rule + - rule_id: MM-026 + name: 争议解决方式明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请判断以下争议解决条款是否符合法律要求。 + + + 条款内容:{{争议解决条款}} + + + 合规的争议解决条款应当: + + 1. 明确指定具体的争议解决方式(仲裁或诉讼,二选一) + + 2. 如选择仲裁,应明确仲裁机构名称 + + 3. 如选择诉讼,应明确管辖法院 + + 4. 不能同时约定仲裁和诉讼 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 争议解决方式明确 + fail: 争议解决条款未明确具体的仲裁机构/管辖法院 + type: ai_rule + - rule_id: MM-027 + name: 付款条款明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 付款方式 + - id: '2' + check: ai + prompt: '请判断以下付款条款是否明确。 + + + 条款内容:{{付款方式}} + + + 明确的付款条款应当包含: + + 1. 付款金额或比例 + + 2. 付款时间节点或触发条件 + + 3. 付款方式(如银行转账) + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 付款条款明确 + fail: 付款条款不够明确 + type: ai_rule + - rule_id: MM-028 + name: 保密条款完整 + risk: low + score: 3 + activate_if: 涉及保密信息 == "是" + stages: + - id: '1' + check: required + field: 保密条款 + - id: '2' + check: ai + prompt: '请判断以下保密条款是否完整。 + + + 条款内容:{{保密条款}} + + + 完整的保密条款应当包含: + + 1. 保密信息的范围定义 + + 2. 保密义务的期限 + + 3. 违反保密义务的法律后果 + + + 请以JSON格式回答:{"result": "pass/warn/fail", "reason": "简要说明", "suggestion": "改进建议(仅warn/fail时填写)"} + + 判断标准: + + - pass:条款基本合理,能达到法律基本要求,道理上说得通即可 + + - warn:条款主体合理但有改进空间,不影响合同效力(如缺少锦上添花的条款、表述可以更精确等) + + - fail:条款存在严重缺陷,可能导致法律风险或合同纠纷(如完全缺失关键要素、违反强制性规定、金额计算错误等) + + ' + messages: + pass: 保密条款完整 + fail: 保密条款不够完整 + type: ai_rule +- group: 银行信息 + rules: + - rule_id: MM-029 + name: 收款方银行信息完整 + risk: high + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: required + fields: + - 收款方开户银行 + - 收款方银行账号 + messages: + pass: 收款方银行信息完整 + fail: 缺少收款方银行开户行或账号,付款无法执行 + type: deterministic diff --git a/rules/contract_tech/docs/real_智慧法务平台采购合同.docx b/rules/contract_tech/docs/real_智慧法务平台采购合同.docx new file mode 100644 index 0000000..8898db2 Binary files /dev/null and b/rules/contract_tech/docs/real_智慧法务平台采购合同.docx differ diff --git a/rules/contract_tech/docs/test_middle.md b/rules/contract_tech/docs/test_middle.md new file mode 100644 index 0000000..f102e8b --- /dev/null +++ b/rules/contract_tech/docs/test_middle.md @@ -0,0 +1,96 @@ +# 智慧园区综合管理平台建设合同 + +合同名称:佛山市南海区智慧园区综合管理平台技术开发合同 +合同编号:NHYQ-2025-DEV-0088 + +甲方(委托方):佛山市南海区产业园管理服务中心 +法定代表人:黄建平 +地址:佛山市南海区桂城街道桂澜北路28号南海行政服务中心9楼 +统一社会信用代码:91440105MA5DRF6N1R +联系人:吴思颖 +联系电话:0757-86328800 +开户银行:中国农业银行佛山南海支行 + +乙方(研发方):深圳市锐视达软件科技有限公司 +法定代表人:赵明哲 +地址:深圳市南山区高新南一道中科大厦A座16楼 +统一社会信用代码:91440106MA5ETBW920 +联系人:孙磊 +联系电话:0755-26718899 + +依据《中华人民共和国民法典》等相关法律法规,甲乙双方经友好协商,就智慧园区综合管理平台建设事宜达成如下合同条款: + +## 第一条 技术目标与方案 + +乙方负责为甲方设计、开发并部署智慧园区综合管理平台,实现园区企业管理、物业管理、能耗监控、安防监控和数据分析等功能模块,满足甲方日常管理需求。系统应具有良好的用户体验和稳定的运行表现。 + +## 第二条 实施计划 + +项目实施分为以下阶段: + +第一阶段:需求调研与方案设计(约3周) +完成需求调研,输出设计方案。 + +第二阶段:系统开发与测试(约6周) +完成各功能模块的开发与内部测试。 + +第三阶段:部署上线与验收(约2周) +系统部署至甲方服务器环境,组织验收。 + +总工期约80个工作日。 + +## 第三条 交货期限 + +乙方应在合同签订后80个工作日内完成系统交付。 + +## 第四条 验收标准与流程 + +项目验收按国家标准进行验收。验收合格后双方签署验收确认书。验收不合格的,乙方负责整改。 + +## 第五条 质保期条款 + +质保期为验收合格后12个月。质保期内乙方免费修复系统缺陷。 + +## 第六条 知识产权条款 + +本项目产生的技术成果,包括软件系统、技术文档和设计方案,其知识产权归甲方所有。乙方不得将项目成果用于其他项目。乙方自有的通用组件和框架知识产权仍归乙方所有。 + +## 第七条 付款方式 + +合同总金额为人民币壹佰叁拾伍万元整(¥1350000.00元),付款安排如下: + +1. 合同签订后10个工作日内,甲方支付合同总额的30%,即人民币肆拾万伍仟元整(¥405000.00元),作为预付款; +2. 系统通过验收后15个工作日内,甲方支付合同总额的60%,即人民币捌拾壹万元整(¥810000.00元); +3. 质保期满后15个工作日内,甲方支付合同总额的10%,即人民币壹拾叁万伍仟元整(¥135000.00元)。 + +上述款项以银行转账方式支付。 + +## 第八条 违约责任 + +一、甲方违约责任: +甲方逾期支付合同款项的,每逾期一日应向乙方支付逾期金额0.5‰的违约金。逾期超过30日的,乙方有权解除合同。 + +二、乙方违约责任: +1. 乙方逾期交付系统的,每逾期一个工作日应向甲方支付合同总额0.3‰的违约金,累计不超过合同总额的8%; +2. 乙方交付的系统经两次整改仍不能通过验收的,甲方有权解除合同,乙方退还已收款项并支付合同总额10%的违约金。 + +## 第九条 争议解决 + +本合同履行过程中发生争议的,双方应首先友好协商;协商不成的,任何一方均可向佛山市南海区人民法院提起诉讼。 + +## 第十条 不可抗力 + +因不可抗力导致合同不能履行的,受影响方应在事件发生后及时通知对方,双方协商处理。 + +## 第十一条 其他 + +1. 本合同一式肆份,甲方贰份,乙方贰份,具有同等法律效力。 +2. 本合同自双方签字盖章之日起生效。 + +甲方(盖章):佛山市南海区产业园管理服务中心 +法定代表人/授权代表:黄建平 +日期:2025年3月10日 + +乙方(盖章):深圳市锐视达软件科技有限公司 +法定代表人/授权代表:赵明哲 +日期:2025年3月10日 diff --git a/rules/contract_tech/docs/test_negative.md b/rules/contract_tech/docs/test_negative.md new file mode 100644 index 0000000..a0c216d --- /dev/null +++ b/rules/contract_tech/docs/test_negative.md @@ -0,0 +1,38 @@ +# 软件开发协议 + +甲方:天河数据局 + +乙方:云启科技 + +双方就软件系统开发事宜达成如下协议: + +## 一、项目内容 + +甲方委托乙方开发一套管理系统。 + +## 二、合同金额 + +合同总价:大写 壹佰万元整(¥128000.00元)。 + +## 三、付款 + +项目完成后一次性付款。 + +## 四、交付 + +尽快完成交付。 + +## 五、违约 + +如一方违约,按法律处理。 + +## 六、争议 + +如发生争议,双方友好协商解决。 + +## 七、其他 + +本协议自签字起生效。 + +甲方:天河数据局 +乙方:云启科技 diff --git a/rules/contract_tech/docs/test_positive.md b/rules/contract_tech/docs/test_positive.md new file mode 100644 index 0000000..003bb39 --- /dev/null +++ b/rules/contract_tech/docs/test_positive.md @@ -0,0 +1,221 @@ +# 智慧政务服务平台建设项目技术开发合同 + +合同名称:广州市天河区智慧政务服务平台建设项目技术开发合同 +合同编号:THZW-2025-IT-0036 + +甲方(委托方):广州市天河区政务服务数据管理局 +法定代表人:刘志强 +地址:广州市天河区天府路1号天河区行政服务中心6楼 +统一社会信用代码:91440106MA5CYJ2P3J +联系人:何嘉敏 +联系电话:020-38627788 +开户银行:中国工商银行广州天河支行 +银行账号:3602028209200068812 + +乙方(研发方):广州云启信息科技有限公司 +法定代表人:陈宇辉 +地址:广州市天河区科韵路16号广州信息港C栋12楼 +统一社会信用代码:91440101MA9UBN7K8B +联系人:林浩然 +联系电话:020-32108866 +开户银行:招商银行广州科韵路支行 +银行账号:120911878910501 + +依据《中华人民共和国民法典》合同编及技术合同章相关规定,甲乙双方在平等、自愿、公平、诚实信用的基础上,就甲方委托乙方建设智慧政务服务平台事宜,经充分协商,达成如下合同条款: + +## 第一条 技术目标与方案 + +一、项目概述 + +乙方负责为甲方设计、开发并部署「智慧政务服务平台」(以下简称「本平台」),实现政务事项在线办理、智能审批、数据汇聚和效能监测等核心功能。 + +二、技术方案 + +本平台采用微服务架构,前端基于 Vue 3 + TypeScript 构建,后端基于 Spring Cloud 微服务框架,数据库采用 PostgreSQL 16 + Redis 7 集群方案,消息中间件采用 RabbitMQ。平台部署于甲方政务云环境,采用 Kubernetes 容器化部署方案。 + +三、技术指标 + +1. 系统响应时间:核心业务页面加载时间不超过2秒,API接口平均响应时间不超过500毫秒,复杂查询响应时间不超过3秒; +2. 数据处理精度:表单数据录入准确率不低于99.9%,OCR识别准确率不低于95%,智能分类准确率不低于90%; +3. 系统可用性:年可用率不低于99.95%,计划内维护窗口每月不超过4小时,单点故障自动切换时间不超过30秒; +4. 并发能力:支持不少于2000并发用户同时在线,峰值处理能力不低于每秒500笔事务(TPS); +5. 安全等级:达到信息系统安全等级保护第三级(等保三级)要求。 + +## 第二条 技术标准与规范 + +本项目开发与验收应遵循以下技术标准: +1. GB/T 25000.51-2016《系统与软件工程 系统与软件质量要求和评价(SQuaRE)第51部分:就绪可用软件产品(RUSP)的质量要求和测试细则》; +2. GB/T 28827.1-2012《信息技术服务 运行维护 第1部分:通用要求》; +3. GB/T 22239-2019《信息安全技术 网络安全等级保护基本要求》(等保2.0); +4. GB/T 35273-2020《信息安全技术 个人信息安全规范》; +5. GA/T 1390-2017《信息安全技术 网络安全等级保护基本要求 第3部分:安全管理中心》。 + +乙方应确保平台符合上述所有标准的技术要求,并在验收阶段提供相应的合规性检测报告。 + +## 第三条 实施计划与里程碑 + +项目总工期为90个工作日,自合同签订之日起计算,具体分为以下阶段: + +第一阶段:需求分析与方案设计(第1-20个工作日) +- 里程碑M1(第10个工作日):完成需求调研,提交《需求分析报告》; +- 里程碑M2(第20个工作日):完成方案设计,提交《系统概要设计说明书》和《详细设计说明书》; +- 交付物:需求分析报告、概要设计说明书、详细设计说明书、数据库设计文档、接口设计文档。 + +第二阶段:系统开发与单元测试(第21-55个工作日) +- 里程碑M3(第35个工作日):完成核心模块开发,进行第一次内部演示; +- 里程碑M4(第55个工作日):完成全部功能开发及单元测试; +- 交付物:源代码、单元测试报告、代码审查记录。 + +第三阶段:集成测试与部署(第56-75个工作日) +- 里程碑M5(第65个工作日):完成集成测试,提交《集成测试报告》; +- 里程碑M6(第75个工作日):完成系统部署及初步验收准备; +- 交付物:集成测试报告、部署文档、用户操作手册。 + +第四阶段:验收与试运行(第76-90个工作日) +- 里程碑M7(第82个工作日):完成初验; +- 里程碑M8(第90个工作日):完成终验,项目整体交付。 +- 交付物:验收报告、项目总结报告、运维手册。 + +## 第四条 交货期限 + +乙方应在合同签订之日起90个工作日内完成全部系统开发、测试、部署和验收工作。如遇不可抗力或甲方原因导致工期延误,经双方书面协商后可适当顺延。 + +## 第五条 验收标准与流程 + +一、验收分为初验和终验两个阶段。 + +二、初验(第一阶段验收): +1. 在系统开发完成并部署至甲方测试环境后进行; +2. 验收标准包括:功能验收(全部需求功能点覆盖率100%)、性能验收(符合第一条技术指标要求)、安全验收(通过等保三级测评机构检测); +3. 甲方组织验收小组,在收到乙方书面验收申请后10个工作日内完成初验; +4. 初验不合格的,乙方应在收到甲方书面意见后10个工作日内完成整改并重新申请初验,整改次数不超过两次。 + +三、终验(最终验收): +1. 系统通过初验后进入30个自然日的试运行期; +2. 试运行期间系统可用率应达到99.95%以上,严重故障(导致核心业务中断超过1小时)不超过1次; +3. 试运行结束后,甲方组织终验,终验合格标志项目整体交付; +4. 终验不合格的,乙方应在15个工作日内完成整改。 + +## 第六条 质保期条款 + +一、质保期为终验合格之日起12个月(壹年)。 + +二、质保期内,乙方提供以下服务: +1. 系统缺陷修复:一般缺陷在2个工作日内修复,严重缺陷在4小时内响应、24小时内修复; +2. 系统运维支持:7x24小时运维值班,工作时间15分钟内电话响应; +3. 免费版本升级:提供不超过2次的小版本功能优化升级。 + +三、质保期满后,甲方如需继续获得技术支持,双方另行签订运维服务合同。 + +## 第七条 培训条款 + +一、乙方应在系统终验前完成以下培训: +1. 系统管理员培训:针对甲方技术人员,培训内容包括系统部署、配置管理、日常运维、故障排查,培训时长不少于3天(每天6学时); +2. 业务操作培训:针对甲方业务人员,培训内容包括系统功能操作、业务流程使用,培训时长不少于2天(每天6学时); +3. 培训方式:现场集中授课+实操演练,乙方提供培训教材和操作手册。 + +二、乙方应确保培训效果,甲方培训人员考核通过率不低于90%。 + +## 第八条 知识产权条款 + +一、本合同项下产生的全部技术成果,包括但不限于软件源代码、数据库结构及数据、技术文档、系统设计方案、算法模型,其知识产权(含著作权、专利申请权、技术秘密)均归甲方所有。 + +二、乙方不得将本项目开发过程中产生的技术成果用于其他项目或向第三方许可、转让。 + +三、乙方在本项目开发前已独立拥有的基础平台框架和通用工具组件的知识产权仍归乙方所有,但乙方授予甲方在本项目范围内永久、免费、不可撤销的使用权。 + +四、如本项目技术成果涉及第三方知识产权,乙方应事先取得合法授权并承担全部费用,因此产生的知识产权纠纷由乙方承担全部责任。 + +## 第九条 技术风险分担 + +一、在项目实施过程中,如遇因现有技术条件无法克服的技术困难(如与甲方现有系统接口不兼容、政务云环境特殊限制等),导致项目部分功能无法实现或需要调整技术方案的,乙方应在发现问题后3个工作日内书面通知甲方,并提出替代解决方案。 + +二、因不可归责于任何一方的客观技术原因导致项目部分失败的,双方按以下方式分担风险: +1. 已完成部分的研发费用由甲方按实际工作量支付; +2. 未完成部分的研发费用由双方各承担50%; +3. 已产生的技术成果归甲方所有。 + +三、因乙方技术能力不足导致的项目失败,不适用本条风险分担条款,乙方应按第十三条违约责任条款承担责任。 + +## 第十条 技术支持与资料移交 + +一、技术支持方式: +1. 电话支持:工作日 9:00-18:00,响应时间不超过15分钟; +2. 远程支持:通过VPN远程协助,响应时间不超过30分钟; +3. 现场支持:紧急情况下4小时内到达甲方现场。 + +二、技术资料移交清单(在终验合格后15个工作日内完成移交): +1. 全套源代码(含版本管理库完整历史); +2. 数据库设计文档及数据字典; +3. 系统架构设计文档; +4. API接口文档; +5. 系统部署文档和运维手册; +6. 用户操作手册; +7. 测试用例及测试报告; +8. 第三方组件清单及授权文件。 + +## 第十一条 付款方式 + +合同总金额为人民币壹佰玖拾陆万元整(¥1960000.00元),付款按以下方式分期支付: + +1. 预付款:合同签订后10个工作日内,甲方向乙方支付合同总额的20%,即人民币叁拾玖万贰仟元整(¥392000.00元),作为项目启动资金; +2. 阶段款(初验款):系统通过初验后10个工作日内,甲方向乙方支付合同总额的40%,即人民币柒拾捌万肆仟元整(¥784000.00元); +3. 验收款(终验款):系统通过终验后10个工作日内,甲方向乙方支付合同总额的30%,即人民币伍拾捌万捌仟元整(¥588000.00元); +4. 质保金:质保期满且无未解决质量问题后15个工作日内,甲方向乙方支付合同总额的10%,即人民币壹拾玖万陆仟元整(¥196000.00元)。 + +上述各期款项均以银行转账方式支付至乙方指定账户,乙方在收到款项前应向甲方开具等额的增值税专用发票。 + +## 第十二条 履约保证金 + +一、合同签订后5个工作日内,乙方应向甲方缴纳合同总额5%的履约保证金,即人民币玖万捌仟元整(¥98000.00元)。 + +二、缴纳方式为银行转账至甲方指定账户,或提交等额银行保函。 + +三、项目通过终验后15个工作日内,甲方将无息退还履约保证金。如乙方存在违约行为,甲方有权从履约保证金中扣除相应违约金。 + +## 第十三条 违约责任 + +一、甲方违约责任: +1. 甲方逾期支付合同款项的,每逾期一日,应向乙方支付逾期金额0.5‰的违约金;逾期超过30日的,乙方有权书面通知甲方解除合同; +2. 因甲方原因导致项目延期的,工期相应顺延,甲方承担乙方因此增加的合理费用。 + +二、乙方违约责任: +1. 乙方逾期交付的,每逾期一个工作日,应向甲方支付合同总额0.5‰的违约金,累计不超过合同总额的10%;逾期超过30个工作日的,甲方有权解除合同,乙方应退还已收取的全部款项并赔偿甲方损失; +2. 乙方交付的系统不符合验收标准,经两次整改仍不合格的,甲方有权解除合同,乙方应退还已收取的全部款项并支付合同总额15%的违约金; +3. 乙方擅自将项目转包或分包给第三方的,甲方有权立即解除合同,乙方应支付合同总额20%的违约金。 + +## 第十四条 争议解决 + +本合同履行过程中发生争议的,双方应首先友好协商解决;协商不成的,任何一方均可向广州市天河区人民法院提起诉讼。 + +## 第十五条 不可抗力 + +一、不可抗力定义:不可抗力是指不能预见、不能避免且不能克服的客观事件,包括但不限于自然灾害(地震、洪水、台风、疫情等)、政府行为(法律法规变更、政策调整、行政命令等)和社会事件(战争、暴乱、罢工等)。 + +二、通知义务:遭受不可抗力的一方应在事件发生后5日内以书面形式通知对方,并在15日内提供相关证明材料(包括但不限于政府公告、公证文书、新闻报道等)。 + +三、法律后果:因不可抗力导致合同全部或部分不能履行的,根据不可抗力的影响程度,部分或全部免除受影响一方的责任。不可抗力事件持续超过60日的,任何一方有权书面通知对方解除合同,双方互不承担违约责任。合同解除后,甲方应支付乙方已完成工作的合理费用。 + +## 第十六条 保密条款 + +一、保密范围:本合同及其附件内容、项目技术方案、源代码、业务数据、用户信息、双方商业秘密及在履行合同过程中知悉的对方未公开信息,均属于保密信息。 + +二、保密期限:保密义务自合同签订之日起生效,至合同终止或解除之日起2年后届满。 + +三、违约后果:任何一方违反保密义务的,应向对方赔偿因此造成的全部损失,包括直接损失和合理的间接损失。情节严重的,守约方有权解除合同并要求违约方支付合同总额10%的违约金。 + +## 第十七条 其他条款 + +1. 本合同一式陆份,甲方叁份,乙方叁份,均具有同等法律效力。 +2. 本合同未尽事宜,由双方另行协商签订补充协议,补充协议与本合同具有同等法律效力。 +3. 本合同自双方签字盖章之日起生效。 + +甲方(盖章):广州市天河区政务服务数据管理局 +法定代表人/授权代表:刘志强 +日期:2025年1月15日 + +乙方(盖章):广州云启信息科技有限公司 +法定代表人/授权代表:陈宇辉 +日期:2025年1月15日 + +签约地点:广州市天河区 diff --git a/rules/contract_tech/rules.yaml b/rules/contract_tech/rules.yaml new file mode 100644 index 0000000..0b9e8e9 --- /dev/null +++ b/rules/contract_tech/rules.yaml @@ -0,0 +1,786 @@ +metadata: + type_id: contract.tech + name: 技术合同 + version: '1.0' + last_updated: '2026-04-12' + tags: + - 合同 + - 技术 + - 开发 + - IT采购 + description: '依据《中华人民共和国民法典》合同编·通则(第470条)及技术合同章(第843-887条)。 + + 适用于技术开发、技术服务、IT系统建设采购等技术类合同的评查, + + 覆盖签署前审查(draft)和签署后审计(executed)两个阶段。 + + 原始规则来源:旧系统 08_技术合同.json(7条技术专项评查点)+ 通用合同评查点。 + + ' +extract: +- group: '合同成立要素 — required_from: draft' + fields: + - name: 合同名称 + type: verbatim + required_from: draft + desc: 合同的完整名称/项目名称 + deep_retry: false + - name: 甲方 + type: verbatim + required_from: draft + desc: 委托方/采购方公司全称 + deep_retry: false + - name: 乙方 + type: verbatim + required_from: draft + desc: 研发方/供应商公司全称 + deep_retry: false + - name: 合同金额 + type: money + required_from: draft + desc: 合同总金额(数字) + deep_retry: false + - name: 合同金额大写 + type: verbatim + required_from: draft + desc: 合同总金额中文大写 + deep_retry: false +- group: 主体资格 + fields: + - name: 甲方法定代表人 + type: verbatim + required_from: draft + desc: 甲方法定代表人姓名 + deep_retry: false + - name: 乙方法定代表人 + type: verbatim + required_from: draft + desc: 乙方法定代表人姓名 + deep_retry: false + - name: 甲方地址 + type: verbatim + required_from: draft + desc: 甲方注册/办公地址 + deep_retry: false + - name: 乙方地址 + type: verbatim + required_from: draft + desc: 乙方注册/办公地址 + deep_retry: false + - name: 甲方统一社会信用代码 + type: uscc + required_from: executed + desc: 甲方18位统一社会信用代码 + deep_retry: false + - name: 乙方统一社会信用代码 + type: uscc + required_from: executed + desc: 乙方18位统一社会信用代码 + deep_retry: false +- group: '技术合同核心条款 — required_from: draft' + fields: + - name: 技术目标与方案 + type: string + required_from: draft + desc: 技术方案、技术目标、技术指标的完整描述 + deep_retry: false + - name: 技术标准与规范 + type: string + required_from: draft + desc: 引用的技术规范、行业标准(名称和编号) + deep_retry: false + - name: 实施计划与里程碑 + type: string + required_from: draft + desc: 实施阶段划分、里程碑节点和各阶段交付物 + deep_retry: false + - name: 交货期限 + type: string + required_from: draft + desc: 交货/交付时间要求 + deep_retry: false + - name: 付款方式 + type: string + required_from: draft + desc: 付款条件、方式、时间节点的完整描述 + deep_retry: false +- group: 验收与质保 + fields: + - name: 验收标准与流程 + type: string + required_from: draft + desc: 验收标准、验收流程和不合格处理方式 + deep_retry: false + - name: 质保期条款 + type: string + required_from: executed + desc: 质保期限、质保范围和质保服务内容 + deep_retry: false + - name: 培训条款 + type: string + required_from: executed + desc: 培训内容、培训方式和培训安排 + deep_retry: false +- group: 技术权利 + fields: + - name: 知识产权条款 + type: string + required_from: draft + desc: 技术成果归属、使用许可和后续改进分享 + deep_retry: false + - name: 技术风险分担 + type: string + required_from: draft + desc: 技术困难导致失败时的风险分担方式和通知义务 + deep_retry: false + - name: 技术支持与资料移交 + type: string + required_from: draft + desc: 技术支持方式、响应时间和技术资料移交清单 + deep_retry: false +- group: 法定/必备条款 + fields: + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约责任的完整条款内容 + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式(法院/仲裁)的完整描述 + deep_retry: false + - name: 不可抗力条款 + type: string + required_from: executed + desc: 不可抗力相关条款的完整内容 + deep_retry: false + - name: 保密条款 + type: string + required_from: draft + desc: 保密义务相关条款内容 + deep_retry: false + - name: 履约保证金条款 + type: string + required_from: executed + desc: 履约保证金金额、缴纳方式和退还条件 + deep_retry: false +- group: '签署要素 — required_from: executed' + fields: + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 合同编号 + type: verbatim + required_from: executed + desc: 合同唯一编号 + deep_retry: false +- group: 辅助信息 + fields: + - name: 甲方联系人 + type: verbatim + required_from: executed + desc: 甲方项目联系人姓名 + deep_retry: false + - name: 甲方联系电话 + type: verbatim + required_from: executed + desc: 甲方联系电话 + deep_retry: false + - name: 乙方联系人 + type: verbatim + required_from: executed + desc: 乙方项目联系人姓名 + deep_retry: false + - name: 乙方联系电话 + type: verbatim + required_from: executed + desc: 乙方联系电话 + deep_retry: false + - name: 甲方开户银行 + type: verbatim + required_from: executed + desc: 甲方银行开户行名称 + deep_retry: false +rules: +- group: 完整性(11 条) + rules: + - rule_id: JS-001 + name: 合同主体齐全 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 甲方 + - id: '2' + check: required + field: 乙方 + messages: + pass: 甲乙方信息完整 + fail: 缺少甲方或乙方信息,合同主体不明确 + type: deterministic + - rule_id: JS-002 + name: 技术目标与金额必填 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 技术目标与方案 + - id: '2' + check: required + field: 合同金额 + messages: + pass: 技术目标与金额信息完整 + fail: 缺少技术目标描述或合同金额 + type: deterministic + - rule_id: JS-003 + name: 合同名称必填 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 合同名称 + messages: + pass: 合同名称已填写 + fail: 缺少合同名称 + type: deterministic + - rule_id: JS-004 + name: 法定代表人齐全 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 甲方法定代表人 + - id: '2' + check: required + field: 乙方法定代表人 + messages: + pass: 甲乙方法定代表人信息完整 + fail: 缺少甲方或乙方法定代表人信息 + type: deterministic + - rule_id: JS-005 + name: 付款方式必填 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 付款方式 + messages: + pass: 付款方式已填写 + fail: 缺少付款方式 + type: deterministic + - rule_id: JS-006 + name: 知识产权条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 知识产权条款 + messages: + pass: 知识产权条款存在 + fail: 缺少知识产权条款,技术合同必须约定成果归属 + type: deterministic + - rule_id: JS-007 + name: 违约责任条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 违约责任条款 + messages: + pass: 违约责任条款存在 + fail: 缺少违约责任条款 + type: deterministic + - rule_id: JS-008 + name: 争议解决条款存在 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + messages: + pass: 争议解决条款存在 + fail: 缺少争议解决条款 + type: deterministic + - rule_id: JS-009 + name: 验收标准存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 验收标准与流程 + messages: + pass: 验收标准已约定 + fail: 缺少验收标准,技术合同必须约定验收方式 + type: deterministic + - rule_id: JS-010 + name: 签约日期必填 + risk: high + score: 8 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + messages: + pass: 签约日期已填写 + fail: 缺少签约日期 + type: deterministic + - rule_id: JS-011 + name: 合同编号必填 + risk: medium + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 合同编号 + messages: + pass: 合同编号已填写 + fail: 缺少合同编号 + type: deterministic +- group: 规范性(2 条) + rules: + - rule_id: JS-012 + name: 甲方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 甲方统一社会信用代码 + format: uscc + messages: + pass: 甲方统一社会信用代码校验通过 + fail: 甲方统一社会信用代码校验位错误 + type: deterministic + - rule_id: JS-013 + name: 乙方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 乙方统一社会信用代码 + format: uscc + messages: + pass: 乙方统一社会信用代码校验通过 + fail: 乙方统一社会信用代码校验位错误 + type: deterministic +- group: 合理性(3 条) + rules: + - rule_id: JS-014 + name: 金额大小写一致 + risk: high + score: 10 + stages: + - id: '1' + check: amount_match + number: 合同金额 + chinese: 合同金额大写 + messages: + pass: 金额大小写一致 + fail: 合同金额数字与大写不一致,存在篡改风险 + type: deterministic + - rule_id: JS-015 + name: 金额为正数 + risk: low + score: 3 + stages: + - id: '1' + check: compare + left: 合同金额 + op: '>' + right: 0 + messages: + pass: 合同金额为正数 + fail: 合同金额不为正数,数据异常 + type: deterministic + - rule_id: JS-016 + name: 签约日期不是未来 + risk: low + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: assert + expr: parse_date(签约日期) != None and (today() - parse_date(签约日期)).days >= 0 and (today() - parse_date(签约日期)).days <= 3650 + messages: + pass: 签约日期在合理范围内 + fail: 签约日期为未来日期或距今超过10年 + type: deterministic +- group: '来源: NR-JS-001 技术目标与指标明确性 — §843, §845' + rules: + - rule_id: JS-017 + name: 技术目标与指标明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 技术目标与方案 + - id: '2' + check: ai + prompt: '请检查技术合同中技术目标与指标的明确性。 + + + 技术方案/目标/指标:{{技术目标与方案}} + + + 评查要点(依据民法典第843、845条): + + 1. 技术方案是否具体描述了技术路线、方法论和实现方式 + + 2. 技术目标是否明确、可衡量,不能仅有「满足需求」等含糊表述 + + 3. 技术指标是否有量化参数(性能指标、精度要求、响应时间等) + + 4. 技术方案与技术目标是否匹配 + + ' + messages: + pass: 技术目标与指标约定明确 + fail: 技术目标与指标约定不明确 + type: ai_rule +- group: '来源: NR-JS-002 技术标准与规范 — §845' + rules: + - rule_id: JS-018 + name: 技术标准与规范引用明确 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 技术标准与规范 + - id: '2' + check: ai + prompt: '请检查技术合同中技术标准与规范的引用情况。 + + + 技术规范/行业标准:{{技术标准与规范}} + + + 评查要点(依据民法典第845条): + + 1. 是否引用了具体的技术规范文件(名称、编号) + + 2. 是否引用了适用的国家标准(GB)、行业标准或国际标准 + + 3. 标准引用是否完整(标准号、标准名称、版本年份) + + 4. 不能仅有「符合相关标准」等含糊表述 + + ' + messages: + pass: 技术标准与规范引用明确 + fail: 技术标准与规范引用不明确 + type: ai_rule +- group: '来源: NR-JS-003 实施计划与里程碑 — §845, §853' + rules: + - rule_id: JS-019 + name: 实施计划与里程碑完整 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 实施计划与里程碑 + - id: '2' + check: ai + prompt: '请检查技术合同中实施计划与里程碑的完整性。 + + + 实施阶段/里程碑/交付物:{{实施计划与里程碑}} + + + 评查要点(依据民法典第845、853条): + + 1. 是否明确划分了实施阶段(需求分析、方案设计、开发实施、测试验收等) + + 2. 各阶段是否有明确的时间节点或里程碑 + + 3. 各阶段是否明确了应交付的成果物 + + 4. 总工期是否合理 + + ' + messages: + pass: 实施计划与里程碑约定完整 + fail: 实施计划与里程碑约定不完整 + type: ai_rule +- group: '来源: NR-JS-006 技术验收标准 — §845' + rules: + - rule_id: JS-020 + name: 技术验收标准完整 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 验收标准与流程 + - id: '2' + check: ai + prompt: '请检查技术合同中验收标准条款的完整性。 + + + 验收标准/流程/不合格处理:{{验收标准与流程}} + + + 评查要点(依据民法典第845条): + + 1. 验收标准是否明确(功能验收、性能验收、安全验收等各项标准) + + 2. 验收流程是否清晰(验收组织方、参与方、验收步骤、验收期限) + + 3. 是否约定了验收不合格时的整改要求和处理方式 + + 4. 是否约定了分阶段验收(初验/终验)还是整体验收 + + ' + messages: + pass: 技术验收标准约定完整 + fail: 技术验收标准约定不完整 + type: ai_rule +- group: '来源: NR-JS-004 知识产权归属 — §859, §860, §861' + rules: + - rule_id: JS-021 + name: 知识产权归属明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 知识产权条款 + - id: '2' + check: ai + prompt: '请检查技术合同中知识产权归属条款的完整性。 + + + 知识产权条款:{{知识产权条款}} + + + 评查要点(依据民法典第859-861条): + + 1. 是否明确约定技术成果(专利、软件著作权、技术秘密等)的归属 + + 2. 是否区分委托方和研发方各自的权利 + + 3. 是否约定了技术成果使用许可的范围和方式 + + 4. 对于软件开发类合同,应特别关注源代码、数据的归属 + + 5. 民法典规定委托开发的专利申请权默认属于研发方,如需归委托方应明确约定 + + ' + messages: + pass: 知识产权归属约定明确 + fail: 知识产权归属约定不明确 + type: ai_rule +- group: '来源: NR-JS-007 技术风险分担 — §858' + rules: + - rule_id: JS-022 + name: 技术风险分担明确 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 技术风险分担 + - id: '2' + check: ai + prompt: '请检查技术合同中技术风险分担条款的完整性。 + + + 风险分担条款:{{技术风险分担}} + + + 评查要点(依据民法典第858条): + + 1. 是否约定了因技术困难导致研发失败或部分失败时的风险分担方式 + + 2. 是否约定了研发过程中遇到技术困难时的通知义务和时限 + + 3. 风险分担方式是否合理(费用分担、成果归属等) + + 4. 是否区分了可归责于一方的失败和不可归责的技术风险 + + ' + messages: + pass: 技术风险分担约定明确 + fail: 技术风险分担约定缺失或不明确 + type: ai_rule +- group: '来源: NR-JS-008 技术支持与资料移交 — §853, §880' + rules: + - rule_id: JS-023 + name: 技术支持与资料移交完整 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 技术支持与资料移交 + - id: '2' + check: ai + prompt: '请检查技术合同中技术支持与资料移交条款的完整性。 + + + 技术支持条款:{{技术支持与资料移交}} + + + 评查要点(依据民法典第853、880条): + + 1. 是否约定了技术支持的方式(现场、远程、电话等) + + 2. 是否约定了技术问题的响应时间和解决时限 + + 3. 是否列明了应移交的技术资料清单(技术文档、操作手册、源代码等) + + 4. 技术资料的移交时间和方式是否明确 + + ' + messages: + pass: 技术支持与资料移交条款完整 + fail: 技术支持与资料移交条款不完整 + type: ai_rule +- group: 合规性 · AI 语义判断(4 条) + rules: + - rule_id: JS-024 + name: 违约责任条款充分 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请判断以下违约责任条款是否充分、合规。 + + + 条款内容:{{违约责任条款}} + + + 充分的违约责任条款应当(依据民法典第577-585条): + + 1. 明确违约情形(如逾期付款、逾期交付、质量不合格、擅自转包等) + + 2. 明确违约金计算方式或赔偿标准 + + 3. 不能只是笼统的「违约要赔偿」之类的模糊表述 + + 4. 应当对双方的违约责任都有约定 + + ' + messages: + pass: 违约责任条款充分 + fail: 违约责任条款不充分 + type: ai_rule + - rule_id: JS-025 + name: 争议解决方式明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请判断以下争议解决条款是否符合法律要求。 + + + 条款内容:{{争议解决条款}} + + + 合规的争议解决条款应当: + + 1. 明确指定具体的争议解决方式(仲裁或诉讼,二选一) + + 2. 如选择仲裁,应明确仲裁机构名称 + + 3. 如选择诉讼,应明确管辖法院 + + 4. 不能同时约定仲裁和诉讼 + + ' + messages: + pass: 争议解决方式明确 + fail: 争议解决条款缺失或未明确具体的仲裁机构/管辖法院 + type: ai_rule + - rule_id: JS-026 + name: 付款条款明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 付款方式 + - id: '2' + check: ai + prompt: '请判断以下付款条款是否明确。 + + + 条款内容:{{付款方式}} + + + 明确的付款条款应当包含: + + 1. 付款金额或比例(如「支付合同总额的30%」) + + 2. 付款时间节点或触发条件(如「验收合格后15个工作日内」) + + 3. 付款方式(如银行转账) + + 4. 对技术合同,通常应有分期付款安排(预付款、阶段款、验收款、质保金) + + ' + messages: + pass: 付款条款明确 + fail: 付款条款不够明确 + type: ai_rule + - rule_id: JS-027 + name: 保密条款完整 + risk: low + score: 3 + stages: + - id: '1' + check: required + field: 保密条款 + - id: '2' + check: ai + prompt: '请判断以下保密条款是否完整。 + + + 条款内容:{{保密条款}} + + + 完整的保密条款应当包含: + + 1. 保密信息的范围定义(哪些信息属于保密信息) + + 2. 保密义务的期限(合同期内还是延伸到终止后) + + 3. 违反保密义务的法律后果 + + ' + messages: + pass: 保密条款完整 + fail: 保密条款不够完整 + type: ai_rule diff --git a/rules/contract_tech/rules.yaml.bak b/rules/contract_tech/rules.yaml.bak new file mode 100644 index 0000000..0b9e8e9 --- /dev/null +++ b/rules/contract_tech/rules.yaml.bak @@ -0,0 +1,786 @@ +metadata: + type_id: contract.tech + name: 技术合同 + version: '1.0' + last_updated: '2026-04-12' + tags: + - 合同 + - 技术 + - 开发 + - IT采购 + description: '依据《中华人民共和国民法典》合同编·通则(第470条)及技术合同章(第843-887条)。 + + 适用于技术开发、技术服务、IT系统建设采购等技术类合同的评查, + + 覆盖签署前审查(draft)和签署后审计(executed)两个阶段。 + + 原始规则来源:旧系统 08_技术合同.json(7条技术专项评查点)+ 通用合同评查点。 + + ' +extract: +- group: '合同成立要素 — required_from: draft' + fields: + - name: 合同名称 + type: verbatim + required_from: draft + desc: 合同的完整名称/项目名称 + deep_retry: false + - name: 甲方 + type: verbatim + required_from: draft + desc: 委托方/采购方公司全称 + deep_retry: false + - name: 乙方 + type: verbatim + required_from: draft + desc: 研发方/供应商公司全称 + deep_retry: false + - name: 合同金额 + type: money + required_from: draft + desc: 合同总金额(数字) + deep_retry: false + - name: 合同金额大写 + type: verbatim + required_from: draft + desc: 合同总金额中文大写 + deep_retry: false +- group: 主体资格 + fields: + - name: 甲方法定代表人 + type: verbatim + required_from: draft + desc: 甲方法定代表人姓名 + deep_retry: false + - name: 乙方法定代表人 + type: verbatim + required_from: draft + desc: 乙方法定代表人姓名 + deep_retry: false + - name: 甲方地址 + type: verbatim + required_from: draft + desc: 甲方注册/办公地址 + deep_retry: false + - name: 乙方地址 + type: verbatim + required_from: draft + desc: 乙方注册/办公地址 + deep_retry: false + - name: 甲方统一社会信用代码 + type: uscc + required_from: executed + desc: 甲方18位统一社会信用代码 + deep_retry: false + - name: 乙方统一社会信用代码 + type: uscc + required_from: executed + desc: 乙方18位统一社会信用代码 + deep_retry: false +- group: '技术合同核心条款 — required_from: draft' + fields: + - name: 技术目标与方案 + type: string + required_from: draft + desc: 技术方案、技术目标、技术指标的完整描述 + deep_retry: false + - name: 技术标准与规范 + type: string + required_from: draft + desc: 引用的技术规范、行业标准(名称和编号) + deep_retry: false + - name: 实施计划与里程碑 + type: string + required_from: draft + desc: 实施阶段划分、里程碑节点和各阶段交付物 + deep_retry: false + - name: 交货期限 + type: string + required_from: draft + desc: 交货/交付时间要求 + deep_retry: false + - name: 付款方式 + type: string + required_from: draft + desc: 付款条件、方式、时间节点的完整描述 + deep_retry: false +- group: 验收与质保 + fields: + - name: 验收标准与流程 + type: string + required_from: draft + desc: 验收标准、验收流程和不合格处理方式 + deep_retry: false + - name: 质保期条款 + type: string + required_from: executed + desc: 质保期限、质保范围和质保服务内容 + deep_retry: false + - name: 培训条款 + type: string + required_from: executed + desc: 培训内容、培训方式和培训安排 + deep_retry: false +- group: 技术权利 + fields: + - name: 知识产权条款 + type: string + required_from: draft + desc: 技术成果归属、使用许可和后续改进分享 + deep_retry: false + - name: 技术风险分担 + type: string + required_from: draft + desc: 技术困难导致失败时的风险分担方式和通知义务 + deep_retry: false + - name: 技术支持与资料移交 + type: string + required_from: draft + desc: 技术支持方式、响应时间和技术资料移交清单 + deep_retry: false +- group: 法定/必备条款 + fields: + - name: 违约责任条款 + type: string + required_from: draft + desc: 违约责任的完整条款内容 + deep_retry: false + - name: 争议解决条款 + type: string + required_from: draft + desc: 争议解决方式(法院/仲裁)的完整描述 + deep_retry: false + - name: 不可抗力条款 + type: string + required_from: executed + desc: 不可抗力相关条款的完整内容 + deep_retry: false + - name: 保密条款 + type: string + required_from: draft + desc: 保密义务相关条款内容 + deep_retry: false + - name: 履约保证金条款 + type: string + required_from: executed + desc: 履约保证金金额、缴纳方式和退还条件 + deep_retry: false +- group: '签署要素 — required_from: executed' + fields: + - name: 签约日期 + type: date + required_from: executed + desc: 合同签订日期 + deep_retry: false + - name: 合同编号 + type: verbatim + required_from: executed + desc: 合同唯一编号 + deep_retry: false +- group: 辅助信息 + fields: + - name: 甲方联系人 + type: verbatim + required_from: executed + desc: 甲方项目联系人姓名 + deep_retry: false + - name: 甲方联系电话 + type: verbatim + required_from: executed + desc: 甲方联系电话 + deep_retry: false + - name: 乙方联系人 + type: verbatim + required_from: executed + desc: 乙方项目联系人姓名 + deep_retry: false + - name: 乙方联系电话 + type: verbatim + required_from: executed + desc: 乙方联系电话 + deep_retry: false + - name: 甲方开户银行 + type: verbatim + required_from: executed + desc: 甲方银行开户行名称 + deep_retry: false +rules: +- group: 完整性(11 条) + rules: + - rule_id: JS-001 + name: 合同主体齐全 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 甲方 + - id: '2' + check: required + field: 乙方 + messages: + pass: 甲乙方信息完整 + fail: 缺少甲方或乙方信息,合同主体不明确 + type: deterministic + - rule_id: JS-002 + name: 技术目标与金额必填 + risk: high + score: 10 + stages: + - id: '1' + check: required + field: 技术目标与方案 + - id: '2' + check: required + field: 合同金额 + messages: + pass: 技术目标与金额信息完整 + fail: 缺少技术目标描述或合同金额 + type: deterministic + - rule_id: JS-003 + name: 合同名称必填 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 合同名称 + messages: + pass: 合同名称已填写 + fail: 缺少合同名称 + type: deterministic + - rule_id: JS-004 + name: 法定代表人齐全 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 甲方法定代表人 + - id: '2' + check: required + field: 乙方法定代表人 + messages: + pass: 甲乙方法定代表人信息完整 + fail: 缺少甲方或乙方法定代表人信息 + type: deterministic + - rule_id: JS-005 + name: 付款方式必填 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 付款方式 + messages: + pass: 付款方式已填写 + fail: 缺少付款方式 + type: deterministic + - rule_id: JS-006 + name: 知识产权条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 知识产权条款 + messages: + pass: 知识产权条款存在 + fail: 缺少知识产权条款,技术合同必须约定成果归属 + type: deterministic + - rule_id: JS-007 + name: 违约责任条款存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 违约责任条款 + messages: + pass: 违约责任条款存在 + fail: 缺少违约责任条款 + type: deterministic + - rule_id: JS-008 + name: 争议解决条款存在 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + messages: + pass: 争议解决条款存在 + fail: 缺少争议解决条款 + type: deterministic + - rule_id: JS-009 + name: 验收标准存在 + risk: high + score: 8 + stages: + - id: '1' + check: required + field: 验收标准与流程 + messages: + pass: 验收标准已约定 + fail: 缺少验收标准,技术合同必须约定验收方式 + type: deterministic + - rule_id: JS-010 + name: 签约日期必填 + risk: high + score: 8 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 签约日期 + messages: + pass: 签约日期已填写 + fail: 缺少签约日期 + type: deterministic + - rule_id: JS-011 + name: 合同编号必填 + risk: medium + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: required + field: 合同编号 + messages: + pass: 合同编号已填写 + fail: 缺少合同编号 + type: deterministic +- group: 规范性(2 条) + rules: + - rule_id: JS-012 + name: 甲方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 甲方统一社会信用代码 + format: uscc + messages: + pass: 甲方统一社会信用代码校验通过 + fail: 甲方统一社会信用代码校验位错误 + type: deterministic + - rule_id: JS-013 + name: 乙方信用代码校验 + risk: medium + score: 5 + applies_in: + - executed + stages: + - id: '1' + check: format + field: 乙方统一社会信用代码 + format: uscc + messages: + pass: 乙方统一社会信用代码校验通过 + fail: 乙方统一社会信用代码校验位错误 + type: deterministic +- group: 合理性(3 条) + rules: + - rule_id: JS-014 + name: 金额大小写一致 + risk: high + score: 10 + stages: + - id: '1' + check: amount_match + number: 合同金额 + chinese: 合同金额大写 + messages: + pass: 金额大小写一致 + fail: 合同金额数字与大写不一致,存在篡改风险 + type: deterministic + - rule_id: JS-015 + name: 金额为正数 + risk: low + score: 3 + stages: + - id: '1' + check: compare + left: 合同金额 + op: '>' + right: 0 + messages: + pass: 合同金额为正数 + fail: 合同金额不为正数,数据异常 + type: deterministic + - rule_id: JS-016 + name: 签约日期不是未来 + risk: low + score: 3 + applies_in: + - executed + stages: + - id: '1' + check: assert + expr: parse_date(签约日期) != None and (today() - parse_date(签约日期)).days >= 0 and (today() - parse_date(签约日期)).days <= 3650 + messages: + pass: 签约日期在合理范围内 + fail: 签约日期为未来日期或距今超过10年 + type: deterministic +- group: '来源: NR-JS-001 技术目标与指标明确性 — §843, §845' + rules: + - rule_id: JS-017 + name: 技术目标与指标明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 技术目标与方案 + - id: '2' + check: ai + prompt: '请检查技术合同中技术目标与指标的明确性。 + + + 技术方案/目标/指标:{{技术目标与方案}} + + + 评查要点(依据民法典第843、845条): + + 1. 技术方案是否具体描述了技术路线、方法论和实现方式 + + 2. 技术目标是否明确、可衡量,不能仅有「满足需求」等含糊表述 + + 3. 技术指标是否有量化参数(性能指标、精度要求、响应时间等) + + 4. 技术方案与技术目标是否匹配 + + ' + messages: + pass: 技术目标与指标约定明确 + fail: 技术目标与指标约定不明确 + type: ai_rule +- group: '来源: NR-JS-002 技术标准与规范 — §845' + rules: + - rule_id: JS-018 + name: 技术标准与规范引用明确 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 技术标准与规范 + - id: '2' + check: ai + prompt: '请检查技术合同中技术标准与规范的引用情况。 + + + 技术规范/行业标准:{{技术标准与规范}} + + + 评查要点(依据民法典第845条): + + 1. 是否引用了具体的技术规范文件(名称、编号) + + 2. 是否引用了适用的国家标准(GB)、行业标准或国际标准 + + 3. 标准引用是否完整(标准号、标准名称、版本年份) + + 4. 不能仅有「符合相关标准」等含糊表述 + + ' + messages: + pass: 技术标准与规范引用明确 + fail: 技术标准与规范引用不明确 + type: ai_rule +- group: '来源: NR-JS-003 实施计划与里程碑 — §845, §853' + rules: + - rule_id: JS-019 + name: 实施计划与里程碑完整 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 实施计划与里程碑 + - id: '2' + check: ai + prompt: '请检查技术合同中实施计划与里程碑的完整性。 + + + 实施阶段/里程碑/交付物:{{实施计划与里程碑}} + + + 评查要点(依据民法典第845、853条): + + 1. 是否明确划分了实施阶段(需求分析、方案设计、开发实施、测试验收等) + + 2. 各阶段是否有明确的时间节点或里程碑 + + 3. 各阶段是否明确了应交付的成果物 + + 4. 总工期是否合理 + + ' + messages: + pass: 实施计划与里程碑约定完整 + fail: 实施计划与里程碑约定不完整 + type: ai_rule +- group: '来源: NR-JS-006 技术验收标准 — §845' + rules: + - rule_id: JS-020 + name: 技术验收标准完整 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 验收标准与流程 + - id: '2' + check: ai + prompt: '请检查技术合同中验收标准条款的完整性。 + + + 验收标准/流程/不合格处理:{{验收标准与流程}} + + + 评查要点(依据民法典第845条): + + 1. 验收标准是否明确(功能验收、性能验收、安全验收等各项标准) + + 2. 验收流程是否清晰(验收组织方、参与方、验收步骤、验收期限) + + 3. 是否约定了验收不合格时的整改要求和处理方式 + + 4. 是否约定了分阶段验收(初验/终验)还是整体验收 + + ' + messages: + pass: 技术验收标准约定完整 + fail: 技术验收标准约定不完整 + type: ai_rule +- group: '来源: NR-JS-004 知识产权归属 — §859, §860, §861' + rules: + - rule_id: JS-021 + name: 知识产权归属明确 + risk: high + score: 5 + stages: + - id: '1' + check: required + field: 知识产权条款 + - id: '2' + check: ai + prompt: '请检查技术合同中知识产权归属条款的完整性。 + + + 知识产权条款:{{知识产权条款}} + + + 评查要点(依据民法典第859-861条): + + 1. 是否明确约定技术成果(专利、软件著作权、技术秘密等)的归属 + + 2. 是否区分委托方和研发方各自的权利 + + 3. 是否约定了技术成果使用许可的范围和方式 + + 4. 对于软件开发类合同,应特别关注源代码、数据的归属 + + 5. 民法典规定委托开发的专利申请权默认属于研发方,如需归委托方应明确约定 + + ' + messages: + pass: 知识产权归属约定明确 + fail: 知识产权归属约定不明确 + type: ai_rule +- group: '来源: NR-JS-007 技术风险分担 — §858' + rules: + - rule_id: JS-022 + name: 技术风险分担明确 + risk: medium + score: 3 + stages: + - id: '1' + check: required + field: 技术风险分担 + - id: '2' + check: ai + prompt: '请检查技术合同中技术风险分担条款的完整性。 + + + 风险分担条款:{{技术风险分担}} + + + 评查要点(依据民法典第858条): + + 1. 是否约定了因技术困难导致研发失败或部分失败时的风险分担方式 + + 2. 是否约定了研发过程中遇到技术困难时的通知义务和时限 + + 3. 风险分担方式是否合理(费用分担、成果归属等) + + 4. 是否区分了可归责于一方的失败和不可归责的技术风险 + + ' + messages: + pass: 技术风险分担约定明确 + fail: 技术风险分担约定缺失或不明确 + type: ai_rule +- group: '来源: NR-JS-008 技术支持与资料移交 — §853, §880' + rules: + - rule_id: JS-023 + name: 技术支持与资料移交完整 + risk: medium + score: 2 + stages: + - id: '1' + check: required + field: 技术支持与资料移交 + - id: '2' + check: ai + prompt: '请检查技术合同中技术支持与资料移交条款的完整性。 + + + 技术支持条款:{{技术支持与资料移交}} + + + 评查要点(依据民法典第853、880条): + + 1. 是否约定了技术支持的方式(现场、远程、电话等) + + 2. 是否约定了技术问题的响应时间和解决时限 + + 3. 是否列明了应移交的技术资料清单(技术文档、操作手册、源代码等) + + 4. 技术资料的移交时间和方式是否明确 + + ' + messages: + pass: 技术支持与资料移交条款完整 + fail: 技术支持与资料移交条款不完整 + type: ai_rule +- group: 合规性 · AI 语义判断(4 条) + rules: + - rule_id: JS-024 + name: 违约责任条款充分 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 违约责任条款 + - id: '2' + check: ai + prompt: '请判断以下违约责任条款是否充分、合规。 + + + 条款内容:{{违约责任条款}} + + + 充分的违约责任条款应当(依据民法典第577-585条): + + 1. 明确违约情形(如逾期付款、逾期交付、质量不合格、擅自转包等) + + 2. 明确违约金计算方式或赔偿标准 + + 3. 不能只是笼统的「违约要赔偿」之类的模糊表述 + + 4. 应当对双方的违约责任都有约定 + + ' + messages: + pass: 违约责任条款充分 + fail: 违约责任条款不充分 + type: ai_rule + - rule_id: JS-025 + name: 争议解决方式明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 争议解决条款 + - id: '2' + check: ai + prompt: '请判断以下争议解决条款是否符合法律要求。 + + + 条款内容:{{争议解决条款}} + + + 合规的争议解决条款应当: + + 1. 明确指定具体的争议解决方式(仲裁或诉讼,二选一) + + 2. 如选择仲裁,应明确仲裁机构名称 + + 3. 如选择诉讼,应明确管辖法院 + + 4. 不能同时约定仲裁和诉讼 + + ' + messages: + pass: 争议解决方式明确 + fail: 争议解决条款缺失或未明确具体的仲裁机构/管辖法院 + type: ai_rule + - rule_id: JS-026 + name: 付款条款明确 + risk: medium + score: 5 + stages: + - id: '1' + check: required + field: 付款方式 + - id: '2' + check: ai + prompt: '请判断以下付款条款是否明确。 + + + 条款内容:{{付款方式}} + + + 明确的付款条款应当包含: + + 1. 付款金额或比例(如「支付合同总额的30%」) + + 2. 付款时间节点或触发条件(如「验收合格后15个工作日内」) + + 3. 付款方式(如银行转账) + + 4. 对技术合同,通常应有分期付款安排(预付款、阶段款、验收款、质保金) + + ' + messages: + pass: 付款条款明确 + fail: 付款条款不够明确 + type: ai_rule + - rule_id: JS-027 + name: 保密条款完整 + risk: low + score: 3 + stages: + - id: '1' + check: required + field: 保密条款 + - id: '2' + check: ai + prompt: '请判断以下保密条款是否完整。 + + + 条款内容:{{保密条款}} + + + 完整的保密条款应当包含: + + 1. 保密信息的范围定义(哪些信息属于保密信息) + + 2. 保密义务的期限(合同期内还是延伸到终止后) + + 3. 违反保密义务的法律后果 + + ' + messages: + pass: 保密条款完整 + fail: 保密条款不够完整 + type: ai_rule diff --git a/rules/行政处罚/rules.test.yaml b/rules/行政处罚/rules.test.yaml new file mode 100644 index 0000000..08f2970 --- /dev/null +++ b/rules/行政处罚/rules.test.yaml @@ -0,0 +1 @@ +cases: [] diff --git a/rules/行政处罚/rules.yaml b/rules/行政处罚/rules.yaml new file mode 100644 index 0000000..cf5a576 --- /dev/null +++ b/rules/行政处罚/rules.yaml @@ -0,0 +1,2898 @@ +metadata: + type_id: 行政卷宗.行政处罚 + name: 烟草专卖行政处罚卷宗 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗 + inherits_from: + - base.common + - base.administrative_case + classification_keywords: + - 行政处罚 + - 烟草专卖 + - 处罚决定书 + - 立案报告 + - 询问笔录 + description: '烟草专卖行政处罚卷宗审核。 + + 覆盖:立案、现场检查、证据先行登记保存、取证核价、询问笔录、权利告知、 + + 调查终结、处理审批、事先告知、处罚决定、送达、执行、结案全流程。 + + ' + # 开 medium 风险规则的 LLM 救援(跨子文档对齐失败交给 rescue 模块 + # 的 L1 判定语义等价,如"投诉举报" vs "举报")。 + rescue_profile: + rescue_risk: [medium] + +# TOC 页定位(dossier_segmenter 使用) +# keywords: 本类卷宗的目录标题(OCR 空白自动规整,"卷 宗 目 录" 也命中) +# anti_keywords: 卷内"内部目录",避免被误判为卷宗级 TOC +# 两个列表均为"扩展默认值",下面显式列出本类卷宗实际会遇到的项 —— +# 默认的 卷宗目录 / 卷内目录 / Contents 等仍自动生效。 +toc: + keywords: + # 实际 OCR 观察到的目录标题(均为 defaults 一部分,显式列出作自注释) + - 卷宗目录 + - 卷内目录 + anti_keywords: + # 卷内子文档自带的"目录"标题,不是卷宗级 TOC —— 必须排除 + - 证据材料目录 # 重大执法行为法制审核送审表 里的证据清单 + - 物品目录 # 抽样取证物品清单等 + +# 跨子文档派生字段 —— 给规则里的 `activate_if` / 对级 `when` 用 +derived_fields: + # 当事人类型:决定一条规则里"个人字段 pair"还是"单位字段 pair"该不该对齐 + # + # 按 USCC 第 2 位判定(GB 32100-2015 法人和其他组织统一社会信用代码): + # 1 = 机关 → 单位 + # 2 = 个体工商户 → 个人(法律归类:自然人工商业) + # 3 = 农民专业合作社 → 单位 + # 4 = 事业单位 → 单位 + # 5 = 企业 → 单位 + # 8 = 社团 → 单位 + # 9 = 其他组织 → 单位 + # + # 个体户虽然有 USCC 和营业执照,但当事人栏填个人信息(姓名/身份证), + # 所以单位 pair 应跳过;执照字段作为辅助证据另行处理。 + # + # 注:不看"字号"——当前 OCR 常把案件文号误抽到 字号 字段; + # 执照名称/执照统一社会信用代码 在个体户里也存在,因此不作为单位标志。 + # 表达式必须单行(evaluate 不支持多行条件)。 + - name: 当事人类型 + type: string + # 嵌套 IfExp 走短路(BoolOp 求值所有分支,`not None` 会走 null-propagation + # 返回 None 而被 IfExp 当 False 走到 else,导致对 None 调 .startswith 崩溃) + # - USCC 空/缺失 → 个人 + # - USCC 以 '92' 开头 → 个人(个体工商户) + # - 其它 (91/93/94/95/… 开头) → 单位 + compute: "'个人' if 处罚决定书.统一社会信用代码 == None else ('个人' if 处罚决定书.统一社会信用代码.startswith('92') else '单位')" + desc: 案件当事人类型(个人 / 单位)—— 按 USCC 第 2 位判,个体户 (92xxx) 判为个人 + + # 证据复制(提取)单可能同时存在多张居民身份证(当事人、举报人、 + # 未成年人、相关人等)。抽取侧把整组居民身份证记录按 multi_entity 抽 + # 下来,由这里挑出归属当事人的那一份;规则再用 + # `证据复制(提取)单当事人.身份证*` 对齐处罚决定书/审批表/终结报告。 + # 只有一张身份证时引擎自动短路,不计 LLM 调用。 + - name: 证据复制(提取)单当事人 + type: object + compute_by: llm + prompt: |- + 以下是证据复制(提取)单中全部居民身份证记录: + + {居民身份证} + + 当事人姓名:{处罚决定书.当事人} + 当事人身份证号:{处罚决定书.身份证号码} + + 请挑出归属「当事人本人」(被处罚对象)的那一份身份证,按原字段 + 结构返回一个 JSON 对象(严格包含 身份证姓名/身份证性别/身份证民族/ + 身份证住址/身份证号/身份证背面,空值写 null)。 + + 优先以身份证号匹配当事人身份证号;若号码缺失,用姓名匹配。匹配不到 + 或无法判断归属时返回 JSON null。除该 JSON 外不要输出任何解释文字。 + depends_on: + - 居民身份证 + - 处罚决定书.当事人 + - 处罚决定书.身份证号码 + + # 询问笔录可能包含多份笔录记录(同一卷宗针对多人询问)。抽取侧把所 + # 有被询问人按 multi_entity 抽下来,由这里挑当事人那份;规则再用 + # `询问笔录当事人.被询问人*` 做一致性校验。只有一份被询问人记录时 + # 引擎自动短路,不计 LLM 调用。 + - name: 询问笔录当事人 + type: object + compute_by: llm + prompt: |- + 以下是询问笔录中全部「被询问人」记录: + + {被询问人} + + 当事人姓名:{处罚决定书.当事人} + 当事人身份证号(若有):{处罚决定书.身份证号码} + + 请挑出归属「当事人本人」(被处罚对象)的那一份笔录记录,按原字段 + 结构返回一个 JSON 对象(严格包含 被询问人姓名/被询问人性别/被询问人民族/ + 被询问人证件/被询问人电话/被询问人住址/被询问人经营地址,空值写 null)。 + + 优先以证件号匹配当事人身份证号;若号码缺失,用姓名匹配。匹配不到 + 或无法判断归属时返回 JSON null。除该 JSON 外不要输出任何解释文字。 + depends_on: + - 被询问人 + - 处罚决定书.当事人 + - 处罚决定书.身份证号码 + +sub_documents: +- id: 先行登记保存证据处理通知书 + name: 先行登记保存证据处理通知书 + required: false + classifier: + title_patterns: + - 先行登记保存证据处理通知书 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 处理方式 + type: verbatim + vlm_extract_mode: always + desc: 证据做出如下处理→选中的选项,要看打勾的选项 +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: + title_patterns: + - 卷内备考表 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 立卷时间 + type: verbatim + desc: 立卷时间 +- id: 卷宗封面 + name: 卷宗封面 + required: false + classifier: + title_patterns: + - ^##?\s*卷\s*宗\s*$ + keywords: + - 此卷共计 + - 归档日期 + - 保存期限 + min_score: 1.0 + extract: + - group: 基本信息 + fields: + - name: 处理结果 + type: string + desc: 处理结果 +- id: 处罚决定书 + name: 处罚决定书 + required: true + classifier: + title_patterns: + - 处罚决定书 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 字号 + type: verbatim + desc: 字号 + - name: 当事人 + type: verbatim + desc: 当事人 + - name: 性别 + type: enum + allowed: + - 男 + - 女 + desc: 性别 + - name: 民族 + type: verbatim + desc: 民族 + - name: 烟草专卖许可证号 + type: verbatim + desc: 烟草专卖许可证号 + - name: 经营地址 + type: string + desc: 经营地址 + - name: 统一社会信用代码 + type: uscc + desc: 统一社会信用代码 + - name: 落款日期 + type: date + desc: 落款日期 + - name: 身份证住址 + type: string + desc: 身份证住址 + - name: 身份证号码 + type: chinese-id + desc: 身份证号码 + - group: 罚款信息 + fields: + - name: 罚款项目 + type: string + desc: 正文→罚款项目 + - name: 罚款基数 + type: money + desc: 正文→罚款项目金额基数 + - name: 罚款比例 + type: string + desc: 正文→罚款百分比 保留原格式如"50%" + - name: 罚款总额 + type: money + desc: 正文→罚款总金额 + - name: 罚款说明 + type: string + desc: 正文→罚款说明 + - name: 证据列举 + type: string + desc: 正文→证据列举 + - group: 权利告知 + fields: + - name: 救济途径 + type: string + desc: 正文→救济途径 +- id: 抽样取证物品清单 + name: 抽样取证物品清单 + required: false + classifier: + title_patterns: + - 抽样取证物品清单 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 品种规格 + type: string + desc: 表格内容→品种规格、样品基数 + - name: 表格有内容 + type: enum + allowed: + - 有 + - 无 + desc: 表格是否有内容 输出 有/无 + - name: 当事人签名 + type: enum + allowed: + - 有 + - 无 + desc: 当事人签名栏 输出 有/无 +- id: 案件处理审批表 + name: 案件处理审批表 + required: true + classifier: + title_patterns: + - 案件处理审批表 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 立案编号 + type: verbatim + desc: 立案编号 + - name: 立案日期 + type: date + desc: 立案日期 + - name: 案由 + type: string + desc: 案由 + - name: 案件来源 + type: string + desc: 案件来源 + - group: 当事人-单位 + fields: + - name: 单位名称 + type: string + desc: 当事人→单位→名称 + - name: 单位法代 + type: verbatim + desc: 当事人→单位→法定代表人(负责人) + - name: 单位电话 + type: verbatim + desc: 当事人→单位→联系电话 + - name: 单位地址 + type: string + desc: 当事人→单位→地址 + - group: 当事人-个人 + fields: + - name: 个人姓名 + type: verbatim + desc: 当事人→个人(个体工商户)→姓名 + - name: 个人性别 + type: verbatim + desc: 当事人→个人→性别 + - name: 个人年龄 + type: verbatim + desc: 当事人→个人→年龄 + - name: 个人民族 + type: verbatim + desc: 当事人→个人→民族 + - name: 个人证件 + type: verbatim + desc: 当事人→个人→证件类型及号码 + - name: 个人电话 + type: verbatim + desc: 当事人→个人→联系电话 + - name: 个人住址 + type: string + desc: 当事人→个人→住址 + - group: 审批意见 + fields: + - name: 承办人意见 + type: string + desc: 承办人意见→内容 + - name: 承办人日期 + type: date + desc: 承办人意见→日期 + - name: 承办人签名1 + type: enum + allowed: + - 有 + - 无 + desc: 承办人意见→签名1 输出 有/无 + - name: 承办人签名2 + type: enum + allowed: + - 有 + - 无 + desc: 承办人意见→签名2 输出 有/无 + - name: 承办部门意见 + type: string + desc: 承办部门意见→内容 + - name: 承办部门日期 + type: date + desc: 承办部门意见→日期 + - name: 承办部门签名 + type: enum + allowed: + - 有 + - 无 + desc: 承办部门意见→签名 输出 有/无 + - name: 法制部门意见 + type: string + desc: 法制部门意见→内容 + - name: 法制部门日期 + type: date + desc: 法制部门意见→日期 + - name: 法制部门审核人签名 + type: enum + allowed: + - 有 + - 无 + desc: 法制部门意见→审核人签名 输出 有/无 + - name: 法制部门负责人签名 + type: enum + allowed: + - 有 + - 无 + desc: 法制部门意见→负责人签名 输出 有/无 + - name: 负责人意见 + type: string + desc: 负责人意见→内容 + - name: 负责人日期 + type: date + desc: 负责人意见→日期 + - name: 负责人签名 + type: enum + allowed: + - 有 + - 无 + desc: 负责人意见→签名 输出 有/无 +- id: 案件调查终结报告 + name: 案件调查终结报告 + required: true + classifier: + title_patterns: + - 案件调查终结报告 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 立案日期 + type: date + desc: 立案日期 + - name: 案由 + type: string + desc: 案由 + - name: 案件来源 + type: string + desc: 案件来源 + - group: 当事人-单位 + fields: + - name: 单位名称 + type: string + desc: 当事人→单位→名称 + - name: 单位法代 + type: verbatim + desc: 当事人→单位→法定代表人(负责人) + - name: 单位电话 + type: verbatim + desc: 当事人→单位→联系电话 + - name: 单位地址 + type: string + desc: 当事人→单位→地址 + - group: 当事人-个人 + fields: + - name: 个人姓名 + type: verbatim + desc: 当事人→个人(个体工商户)→姓名 + - name: 个人性别 + type: enum + allowed: + - 男 + - 女 + desc: 当事人→个人→性别 + - name: 个人年龄 + type: verbatim + desc: 当事人→个人→年龄 + - name: 个人民族 + type: verbatim + desc: 当事人→个人→民族 + - name: 个人证件 + type: verbatim + desc: 当事人→个人→证件类型及号码 + - name: 个人电话 + type: verbatim + desc: 当事人→个人→联系电话 + - name: 个人住址 + type: string + desc: 当事人→个人→住址 + - group: 处理意见 + fields: + - name: 处理意见日期 + type: date + desc: 处理意见→日期 + - name: 处理意见承办人签名1 + type: enum + allowed: + - 有 + - 无 + desc: 处理意见→承办人签名1 输出 有/无 + - name: 处理意见承办人签名2 + type: enum + allowed: + - 有 + - 无 + desc: 处理意见→承办人签名2 输出 有/无 +- id: 涉案物品核价表 + name: 涉案物品核价表 + required: false + classifier: + title_patterns: + - 涉案物品核价表 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 核价组印章 + type: enum + allowed: + - 有 + - 无 + desc: 涉案卷烟价格管理小组印章 输出 有/无 + - name: 核价明细 + type: string + desc: 表格内容→品种规格、数量(单位:条)、单价(元)、合计(元)、备注 + - name: 表格全文 + type: string + desc: 核价表完整内容 +- id: 涉案物品返还清单 + name: 涉案物品返还清单 + required: false + classifier: + title_patterns: + - 涉案物品返还清单 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 日期 + type: date + desc: 日期 + - name: 补偿信息 + type: verbatim + desc: 补偿信息 + - name: 返还明细 + type: string + desc: 表格内容→品种规格、数量(单位:条)、单价(元)、合计(元)、备注 + - name: 返还确认 + type: verbatim + desc: 返还确认 + - name: 接收人签名 + type: enum + allowed: + - 有 + - 无 + desc: 接收人→签名 输出 有/无 + - name: 接收单位印章 + type: enum + allowed: + - 有 + - 无 + desc: 接收单位→印章 输出 有/无 +- id: 现场笔录 + name: 现场笔录 + required: true + classifier: + title_patterns: + - 现场笔录 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 检查时间 + type: verbatim + desc: 检查时间 + - name: 检查地点 + type: verbatim + desc: 检查地点 + - group: 被检查人 + fields: + - name: 单位名称 + type: string + desc: 被检查人→单位→名称 + - name: 单位法代 + type: verbatim + desc: 法定代表人(负责人) + - name: 单位许可证号 + type: verbatim + desc: 烟草专卖许可证号码 + - name: 个人姓名 + type: verbatim + desc: 被检查人→个人→姓名 + - name: 个人性别 + type: enum + allowed: + - 男 + - 女 + desc: 被检查人→个人→性别 + - name: 个人证件 + type: verbatim + desc: 被检查人→个人→证件类型及号码 + - name: 地址 + type: string + desc: 被检查人→地址 + - name: 电话 + type: verbatim + desc: 被检查人→联系电话 + - name: 现场负责人 + type: verbatim + desc: 现场负责人→姓名、性别、证件类型及号码、与被检查人关系 + - group: 签名意见 + fields: + - name: 意见 + type: verbatim + desc: 被检查人或现场负责人→意见 + - name: 意见日期 + type: date + desc: 被检查人或现场负责人(签名)→日期 + - name: 意见签名 + type: enum + allowed: + - 有 + - 无 + desc: 被检查人或现场负责人(签名)输出 有/无 +- id: 立案报告表 + name: 立案报告表 + required: true + classifier: + title_patterns: + - 立案报告表 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 立案编号 + type: verbatim + desc: 立案编号 如"郁烟立〔2024〕第35号" + - name: 案由 + type: string + desc: 案由 + - name: 案件来源 + type: string + desc: 案件来源 如"投诉举报" + - name: 案发时间 + type: verbatim + desc: 案发时间 + - name: 案发地点 + type: verbatim + desc: 案发地点 + - group: 当事人-单位 + fields: + - name: 单位名称 + type: string + desc: 当事人→单位→名称 + - name: 单位法代 + type: verbatim + desc: 当事人→单位→法定代表人(负责人) + - name: 单位电话 + type: verbatim + desc: 当事人→单位→联系电话 + - name: 单位地址 + type: string + desc: 当事人→单位→地址 + - group: 当事人-个人 + fields: + - name: 个人姓名 + type: verbatim + desc: 当事人→个人(个体工商户)→姓名 + - name: 个人性别 + type: verbatim + desc: 当事人→个人→性别 + - name: 个人年龄 + type: verbatim + desc: 当事人→个人→年龄 + - name: 个人民族 + type: verbatim + desc: 当事人→个人→民族 + - name: 个人证件 + type: verbatim + desc: 当事人→个人→证件类型及号码 + - name: 个人身份证号 + type: chinese-id + desc: 当事人→个人→居民身份证号码 + - name: 个人电话 + type: verbatim + desc: 当事人→个人→联系电话 + - name: 个人住址 + type: string + desc: 当事人→个人→住址 + - group: 案情 + fields: + - name: 案情摘要 + type: string + desc: 案情摘要正文 + - name: 案情品种 + type: string + desc: 案情摘要中的品种规格、单位、数量 + - group: 审批意见 + fields: + - name: 承办人意见 + type: string + desc: 承办人意见→意见 + - name: 承办人日期 + type: date + desc: 承办人意见→日期 + - name: 承办人签名1 + type: enum + allowed: + - 有 + - 无 + desc: 承办人意见→签名1 输出 有/无 + - name: 承办人签名2 + type: enum + allowed: + - 有 + - 无 + desc: 承办人意见→签名2 输出 有/无 + - name: 承办部门意见 + type: string + desc: 承办部门意见→意见 + - name: 承办部门日期 + type: date + desc: 承办部门意见→日期 + - name: 承办部门签名 + type: enum + allowed: + - 有 + - 无 + desc: 承办部门意见→签名 输出 有/无 + - name: 负责人意见 + type: string + desc: 负责人意见→意见内容 + - name: 负责人日期 + type: date + desc: 负责人意见→日期 + - name: 负责人签名 + type: enum + allowed: + - 有 + - 无 + desc: 负责人意见→签名 输出 有/无 +- id: 结案报告表 + name: 结案报告表 + required: true + classifier: + title_patterns: + - 结案报告表 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 当事人 + type: verbatim + desc: 当事人 + - name: 执行情况 + type: string + desc: 执行情况 + - group: 审批意见 + fields: + - name: 承办人结案理由 + type: string + desc: 承办人结案理由→内容 + - name: 承办人结案日期 + type: date + desc: 承办人结案理由→日期 + - name: 承办人结案签名1 + type: enum + allowed: + - 有 + - 无 + desc: 承办人结案理由→签名1 输出 有/无 + - name: 承办人结案签名2 + type: enum + allowed: + - 有 + - 无 + desc: 承办人结案理由→签名2 输出 有/无 + - name: 承办部门意见 + type: string + desc: 承办部门意见→内容 + - name: 承办部门日期 + type: date + desc: 承办部门意见→日期 + - name: 承办部门签名 + type: enum + allowed: + - 有 + - 无 + desc: 承办部门意见→签名 输出 有/无 + - name: 负责人意见 + type: string + desc: 负责人意见→内容 + - name: 负责人日期 + type: date + desc: 负责人意见→日期 + - name: 负责人签名 + type: enum + allowed: + - 有 + - 无 + desc: 负责人意见→签名 输出 有/无 +- id: 缴款凭证 + name: 缴款凭证 + required: false + classifier: + title_patterns: + - 缴款凭证 + - 广东省非税收入一般缴款书[((]电子[))] + - 广东省非税收入一般缴款书(电子) + keywords: + - 非税收入 + - 缴款书 + - 收费项目 + - 收入项目 + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 收入项目 + type: string + desc: 收入项目名称(电子非税缴款书上可能写作"收费项目") + - name: 金额 + type: money + desc: 金额 + - name: 备注 + type: verbatim + desc: 备注 +- id: 行政处罚事先告知书 + name: 行政处罚事先告知书 + required: true + classifier: + title_patterns: + - 行政处罚事先告知书 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 当事人 + type: verbatim + desc: 当事人 + - name: 正文前称呼 + type: string + desc: 正文前称呼 + - name: 权利告知 + type: string + desc: 正文→权利告知 +- id: 证据先行登记保存批准书 + name: 证据先行登记保存批准书 + required: false + classifier: + title_patterns: + - 证据先行登记保存批准书 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 标题下方文本 + type: string + desc: 标题下方文本 + - name: 表格下方文字 + type: string + desc: 表格下方文字 含"对先行登记保存的证据,应当在...日内处理" + - name: 表格品规 + type: string + desc: 表格内容→品种规格、单位、数量 + - name: 表格全文 + type: string + desc: 表格完整内容 + - name: 盖章 + type: enum + allowed: + - 有 + - 无 + desc: 行政机关盖章 输出 有/无 + - group: 承办人 + fields: + - name: 承办人日期 + type: date + desc: 承办人→日期 + - name: 承办人签名1 + type: enum + allowed: + - 有 + - 无 + desc: 承办人→签名1 输出 有/无 + - name: 承办人签名2 + type: enum + allowed: + - 有 + - 无 + desc: 承办人→签名2 输出 有/无 + - group: 负责人 + fields: + - name: 负责人意见 + type: verbatim + desc: 负责人意见并签名→意见内容 + - name: 负责人意见有无 + type: enum + allowed: + - 有 + - 无 + desc: 负责人意见并签名→是否有意见 输出 有/无 + - name: 负责人日期 + type: date + desc: 负责人意见并签名→日期 + - name: 负责人签名姓名 + type: verbatim + desc: 负责人意见并签名→签名姓名 + - name: 负责人签名有无 + type: enum + allowed: + - 有 + - 无 + desc: 负责人意见并签名→是否有签名 输出 有/无 +- id: 证据先行登记保存通知书 + name: 证据先行登记保存通知书 + required: false + classifier: + title_patterns: + - 证据先行登记保存通知书 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 表格下方文字 + type: string + desc: 表格下方文字 + - name: 表格品规 + type: string + desc: 表格内容→品种规格、单位、数量 + - name: 表格全文 + type: string + desc: 表格完整内容 + - name: 盖章 + type: enum + allowed: + - 有 + - 无 + desc: 行政机关盖章 输出 有/无 + - name: 拒绝签名说明 + type: string + desc: 正文→拒绝签名说明 + - name: 当事人签名 + type: enum + allowed: + - 有 + - 无 + desc: 当事人签名 输出 有/无 + - group: 承办人 + fields: + - name: 承办人日期 + type: date + desc: 承办人→日期 + - name: 承办人签名1 + type: enum + allowed: + - 有 + - 无 + desc: 承办人→签名1 输出 有/无 + - name: 承办人签名2 + type: enum + allowed: + - 有 + - 无 + desc: 承办人→签名2 输出 有/无 +- id: 证据复制(提取)单 + name: 证据复制(提取)单 + required: true + classifier: + title_patterns: + - 证据复制[((]提取[))]单 + - 证据复制(提取)单 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 复制时间 + type: verbatim + desc: |- + 证据复制(提取)单每页末尾的「复制(提取)时间」字段。 + 一份卷宗通常有多份证据(每页一份,说明事项各异)。 + 当**多份存在**时,取**第一份**的时间(整体活动起点, + 通常也是询问笔录期间制作的那份)。 + 示例:"2024 年 4 月 19 日 19 时 30 分"。 + - name: 复制地点 + type: verbatim + desc: |- + 证据复制(提取)单每页末尾的「复制(提取)地点」字段。 + 多份存在时取**第一份**的地点(与 复制时间 同一页)。 + 示例:"郁南县南江口镇西江路 124 号"。 + - name: 现场时间 + type: verbatim + desc: |- + 证据复制(提取)单中**现场检查相片**所属那份证据的 + 「复制(提取)时间」。特征:说明事项含"现场/外观/ + 查获时拍摄/查获违法走私卷烟时"等,与执法人员到场 + 同一时段。用于和 现场笔录.检查时间 对齐。 + 如没有纯"现场检查"相片,取第一份时间。 + - name: 现场地址 + type: string + desc: |- + 证据复制(提取)单中**现场检查相片**所属那份证据的 + 「复制(提取)地点」,与 现场时间 同一份。 + 用于和 现场笔录.检查地点 对齐。 + - name: 邮件回执 + type: verbatim + desc: 邮件回执 + - group: 居民身份证 + fields: + - name: 居民身份证 + type: multi_entity + desc: |- + 证据复制(提取)单中**每一张**居民身份证图片对应的一份记录。 + 一份证据复制单通常包含多张身份证(当事人、举报人、未成年人、相关人等), + 请把每张身份证都抽取为数组中的一项,**不要**只抽"当事人那份"。 + 由派生字段「证据复制(提取)单当事人」按姓名+身份证号挑出归属当事人的那一份。 + 如果只有一张身份证,返回只包含一项的数组即可(引擎会自动把那一项判为当事人)。 + fields: + - name: 身份证姓名 + type: verbatim + desc: 该份身份证上印的姓名 + - name: 身份证性别 + type: verbatim + desc: 该份身份证上印的性别(男/女) + - name: 身份证民族 + type: verbatim + desc: 该份身份证上印的民族 + - name: 身份证住址 + type: string + desc: 该份身份证上印的住址 + - name: 身份证号 + type: chinese-id + desc: 该份身份证上印的公民身份号码(18 位) + - name: 身份证背面 + type: enum + allowed: + - 有 + - 无 + desc: 该份身份证是否包含背面(签发机关/有效期那面)有/无 + - group: 许可证 + fields: + - name: 许可证企业名称 + type: string + desc: 烟草专卖零售许可证→企业名称 + - name: 许可证经营场所 + type: string + desc: 烟草专卖零售许可证→经营场所 + - name: 许可证号 + type: verbatim + desc: 烟草专卖零售许可证→许可证号 + - name: 许可证负责人 + type: verbatim + desc: 烟草专卖零售许可证→负责人姓名 + - group: 营业执照 + fields: + - name: 执照名称 + type: string + desc: 营业执照→名称 + - name: 执照住所 + type: string + desc: 营业执照→住所 + - name: 执照法代 + type: verbatim + desc: 营业执照→法定代表人 + - name: 执照统一社会信用代码 + type: uscc + desc: 营业执照→统一社会信用代码 +- id: 询问笔录 + name: 询问笔录 + required: true + classifier: + title_patterns: + - 询问笔录 + keywords: [] + min_score: 0.5 + extract: + - group: 基本信息 + fields: + - name: 询问时间 + type: verbatim + desc: 询问时间 + - name: 询问地点 + type: verbatim + desc: 询问地点 + - group: 被询问人 + fields: + - name: 被询问人 + type: multi_entity + desc: |- + 询问笔录中**每一份**笔录记录对应的被询问人基本信息。 + 一份卷宗可能包含多次询问笔录(针对不同人员),请把**每一份**笔录 + 中的被询问人都抽取为数组中的一项,**不要**只抽"当事人那份"。 + 由派生字段「询问笔录当事人」按姓名+证件号挑出归属当事人的那一份。 + 只有一份被询问人记录时,引擎自动把那一份判为当事人。 + fields: + - name: 被询问人姓名 + type: verbatim + desc: 被询问人→姓名 + - name: 被询问人性别 + type: enum + allowed: + - 男 + - 女 + desc: 被询问人→性别 + - name: 被询问人民族 + type: verbatim + desc: 被询问人→民族 + - name: 被询问人证件 + type: verbatim + desc: 被询问人→证件类型及号码(通常是"居民身份证:xxx") + - name: 被询问人电话 + type: verbatim + desc: 被询问人→联系电话 + - name: 被询问人住址 + type: string + desc: 被询问人→住址 + - name: 被询问人经营地址 + type: string + desc: 被询问人→经营地址 + - group: 笔录正文 + fields: + - name: 执法人员信息 + type: string + desc: 正文→执法人员信息 + - name: 权利告知 + type: string + desc: 正文→权利告知内容 + - name: 被询问人核实 + type: string + desc: 正文→被询问人核实 + - name: 拒绝签名说明 + type: string + desc: 正文→拒绝签名说明 + - group: 签名 + fields: + - name: 被询问人签名 + type: enum + allowed: + - 有 + - 无 + desc: 被询问人(签名)输出 有/无 + - name: 询问人签名1 + type: enum + allowed: + - 有 + - 无 + desc: 询问人(签名)1 输出 有/无 + - name: 询问人签名2 + type: enum + allowed: + - 有 + - 无 + desc: 询问人(签名)2 输出 有/无 +- id: 送达回证 + name: 送达回证 + required: true + classifier: + title_patterns: + - 送达回证 + keywords: [] + min_score: 0.5 + # 注意:本子文档内可能拼接多份送达回证表格(立案通知/先行登记保存通知/事先告知书/ + # 处罚决定书等各一份)。以下字段只抽取"送达文书名称"含"行政处罚决定书"的那份; + # 其他送达回证忽略(由专门的规则处理)。 + extract: + - group: 基本信息 + fields: + - name: 受送达人 + type: verbatim + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"那份表格里的受送达人 + - name: 回证编号 + type: verbatim + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"那份表格上方的回证编号 + - name: 送达方式 + type: verbatim + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"那份的送达方式 + - name: 送达地点 + type: verbatim + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"那份的送达地点 + - name: 送达文书名称 + type: string + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"的那一项(作为后续其他字段的定位基准) + - name: 送达文书文号 + type: verbatim + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"那份的送达文书文号 + - group: 签收 + fields: + - name: 签收日期 + type: date + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"那份的签收日期 + - name: 代收理由 + type: string + desc: 本子文档内若含多份送达回证,只抽"送达文书名称"含"行政处罚决定书"那份的代收人代收理由 + - name: 印章 + type: enum + allowed: + - 有 + - 无 + desc: 印章 输出 有/无 + vlm_extract_mode: always + - name: 收件人签名 + type: enum + allowed: + - 有 + - 无 + desc: 收件人签名或盖章→签名 输出 有/无 + vlm_extract_mode: always + - name: 收件人盖章 + type: enum + allowed: + - 有 + - 无 + desc: 收件人签名或盖章→盖章 输出 有/无 + vlm_extract_mode: always + - group: 送达人 + fields: + - name: 送达人签名 + type: enum + allowed: + - 有 + - 无 + desc: 送达人签名 输出 有/无 + vlm_extract_mode: always +rules: +- group: JZG-JD + rules: + - rule_id: JZ-JD-001 + name: 当事人基本情况或立案情况记载准确性 + desc: 若当事人信息与证据复制(提取)单中信息不一致,则扣分。 + risk: medium + score: 5 + scope: + - 案件处理审批表 + - 案件调查终结报告 + - 立案报告表 + - 证据复制(提取)单 + stages: + - id: '1' + check: match + pairs: + - source: 案件处理审批表.案由 + target: 案件调查终结报告.案由 + - source: 案件处理审批表.案件来源 + target: 案件调查终结报告.案件来源 + # 案件来源是开放词汇(投诉举报/群众举报/电话举报/来电举报/上级交办… + # 无穷枚举),不用 canonicalize 字典维护。字面不等时走 rescue L1 + # match 做语义等价判定。 + - source: 案件处理审批表.立案编号 + target: 立案报告表.立案编号 + - source: 案件处理审批表.立案日期 + target: 案件调查终结报告.立案日期 + - source: 案件处理审批表.单位名称 + target: 案件调查终结报告.单位名称 + when: "当事人类型 != '个人'" + - source: 案件调查终结报告.单位名称 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + - source: 案件处理审批表.单位法代 + target: 案件调查终结报告.单位法代 + when: "当事人类型 != '个人'" + - source: 案件调查终结报告.单位法代 + target: 证据复制(提取)单.执照法代 + when: "当事人类型 != '个人'" + - source: 案件处理审批表.单位地址 + target: 案件调查终结报告.单位地址 + when: "当事人类型 != '个人'" + - source: 案件调查终结报告.单位地址 + target: 证据复制(提取)单.执照住所 + when: "当事人类型 != '个人'" + - id: '2' + check: match + pairs: + - source: 案件处理审批表.案由 + target: 案件调查终结报告.案由 + - source: 案件处理审批表.案件来源 + target: 案件调查终结报告.案件来源 + # 案件来源是开放词汇(投诉举报/群众举报/电话举报/来电举报/上级交办… + # 无穷枚举),不用 canonicalize 字典维护。字面不等时走 rescue L1 + # match 做语义等价判定。 + - source: 案件处理审批表.立案日期 + target: 案件调查终结报告.立案日期 + - source: 案件处理审批表.立案编号 + target: 立案报告表.立案编号 + - source: 案件处理审批表.个人姓名 + target: 案件调查终结报告.个人姓名 + when: "当事人类型 != '单位'" + - source: 案件处理审批表.个人性别 + target: 证据复制(提取)单当事人.身份证性别 + when: "当事人类型 != '单位'" + - source: 案件调查终结报告.个人民族 + target: 证据复制(提取)单当事人.身份证民族 + when: "当事人类型 != '单位'" + - source: 案件调查终结报告.个人证件 + target: 证据复制(提取)单当事人.身份证号 + when: "当事人类型 != '单位'" + method: substring + - source: 案件处理审批表.个人住址 + target: 案件调查终结报告.个人住址 + when: "当事人类型 != '单位'" + - id: '3' + check: ai + prompt: "请根据以下卷宗信息,判断当事人基本情况及立案情况的记载是否准确一致。\n\n 【第一步:判断案件类型】\n\n 检查\"案件处理审批表\"\ + 中的当事人单位名称字段值:\n {{案件处理审批表.单位名称}}\n\n - 如果该值为 \"/\"、\"-\"、空或其他占位符 → 这是**个人案件**,执行个人案件检查\n\ + \ - 如果该值是真实的单位名称 → 这是**单位案件**,执行单位案件检查\n\n ---\n\n 【第二步-A:单位案件检查】(当事人为单位时执行)\n\ + \n 请逐一比对以下字段,判断是否一致:\n\n 1. 案由\n - 案件处理审批表:{{案件处理审批表.案由}}\n - 案件调查终结报告:{{案件调查终结报告.案由}}\n\ + \n 2. 案件来源\n - 案件处理审批表:{{案件处理审批表.案件来源}}\n - 案件调查终结报告:{{案件调查终结报告.案件来源}}\n\n\ + \ 3. 立案编号\n - 案件处理审批表:{{案件处理审批表.立案编号}}\n - 立案报告表:{{立案报告表.立案编号}}\n\n 4. 立案日期\n\ + \ - 案件处理审批表:{{案件处理审批表.立案日期}}\n - 案件调查终结报告:{{案件调查终结报告.立案日期}}\n\n 5. 单位名称(三方核对)\n\ + \ - 案件处理审批表:{{案件处理审批表.单位名称}}\n - 案件调查终结报告:{{案件调查终结报告.单位名称}}\n - 证据复制(提取)单-营业执照:{{证据复制(提取)单.执照名称}}\n\ + \n 6. 法定代表人(三方核对)\n - 案件处理审批表:{{案件处理审批表.单位法代}}\n - 案件调查终结报告:{{案件调查终结报告.单位法代}}\n\ + \ - 证据复制(提取)单-营业执照:{{证据复制(提取)单.执照法代}}\n\n 7. 单位地址(三方核对)\n - 案件处理审批表:{{案件处理审批表.单位地址}}\n\ + \ - 案件调查终结报告:{{案件调查终结报告.单位地址}}\n - 证据复制(提取)单-营业执照:{{证据复制(提取)单.执照住所}}\n\n \ + \ ---\n\n 【第二步-B:个人案件检查】(当事人为个人或个体工商户时执行)\n\n 请逐一比对以下字段,判断是否一致:\n\n 1.\ + \ 案由\n - 案件处理审批表:{{案件处理审批表.案由}}\n - 案件调查终结报告:{{案件调查终结报告.案由}}\n\n 2. 案件来源\n\ + \ - 案件处理审批表:{{案件处理审批表.案件来源}}\n - 案件调查终结报告:{{案件调查终结报告.案件来源}}\n\n 3. 立案编号\n\ + \ - 案件处理审批表:{{案件处理审批表.立案编号}}\n - 立案报告表:{{立案报告表.立案编号}}\n\n 4. 立案日期\n - 案件处理审批表:{{案件处理审批表.立案日期}}\n\ + \ - 案件调查终结报告:{{案件调查终结报告.立案日期}}\n\n 5. 姓名\n - 案件处理审批表:{{案件处理审批表.个人姓名}}\n -\ + \ 案件调查终结报告:{{案件调查终结报告.个人姓名}}\n\n 6. 性别\n - 案件处理审批表:{{案件处理审批表.个人性别}}\n - 证据复制(提取)单-居民身份证:{{证据复制(提取)单当事人.身份证性别}}\n\ + \n 7. 民族\n - 案件调查终结报告:{{案件调查终结报告.个人民族}}\n - 证据复制(提取)单-居民身份证:{{证据复制(提取)单当事人.身份证民族}}\n\ + \n 8. 证件号码(包含匹配)\n - 案件调查终结报告:{{案件调查终结报告.个人证件}}\n - 证据复制(提取)单-居民身份证:{{证据复制(提取)单当事人.身份证号}}\n\ + \ - 注意:审批表中证件字段格式可能为\"居民身份证:44xxxxxxxx\",判断时应提取纯号码部分进行比对\n\n 9. 住址\n - 案件处理审批表:{{案件处理审批表.个人住址}}\n\ + \ - 证据复制(提取)单-居民身份证:{{证据复制(提取)单当事人.身份证住址}}\n\n ---\n\n 【判断规则】\n\n - \"/\"\ + 、\"-\"、\"—\" 等符号代表该字段不适用,不是有效值,遇到此类值的比对项直接跳过\n - 只要有任意一个有效字段不一致,判定为**不通过**\n\ + \ - 所有有效字段均一致(或均为占位符可跳过),判定为**通过**\n" + logic: 1 OR 2 OR 3 + messages: + pass: 文档检查通过,符合规范要求。 + fail: 文档存在以下问题,请修改后重新提交。 + references_laws: + - 《中华人民共和国行政处罚法》第五十九条 + type: ai_rule + - rule_id: JZ-JD-002 + name: 处罚决定书证据列举 + desc: 若找不到"证据:"或者"证据:"之后无内容,则扣分。 + risk: medium + score: 10 + scope: + - 处罚决定书 + stages: + - id: '1' + check: required + field: 处罚决定书.证据列举 + messages: + pass: 处罚决定书已列出相关证据。 + fail: 罚决定书未列出相关证据,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十九条 + type: deterministic + - rule_id: JZ-JD-003 + name: 救济途径或期限告知明确性 + desc: 若未找到文本匹配内容,则扣分。 + risk: medium + score: 5 + scope: + - 处罚决定书 + stages: + - id: '1' + check: required + field: 处罚决定书.救济途径 + messages: + pass: 已告知救济途径和期限。 + fail: 救济途径或期限告知不明确或不正确,请核对。 + references_laws: + - 《中华人民共和国烟草专卖法》第四十一条 + type: deterministic + - rule_id: JZ-JD-004 + name: 行政处罚决定当事人基本情况记载准确性 + desc: 检查首段信息是否填写齐全,若存在未填内容,(字号:可为空),若不齐全,则扣分。 若当事人信息与证据中提取的信息不一致,则扣分。 + risk: medium + score: 10 + scope: + - 处罚决定书 + - 证据复制(提取)单 + stages: + - id: '1' + check: match + pairs: + - source: 处罚决定书.当事人 + target: 证据复制(提取)单.许可证企业名称 + when: "当事人类型 != '个人'" + - source: 处罚决定书.字号 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + - source: 处罚决定书.统一社会信用代码 + target: 证据复制(提取)单.执照统一社会信用代码 + when: "当事人类型 != '个人'" + - source: 处罚决定书.经营地址 + target: 证据复制(提取)单.许可证经营场所 + when: "当事人类型 != '个人'" + - source: 证据复制(提取)单.许可证经营场所 + target: 证据复制(提取)单.执照住所 + when: "当事人类型 != '个人'" + - id: '2' + check: match + pairs: + - source: 处罚决定书.当事人 + target: 证据复制(提取)单当事人.身份证姓名 + when: "当事人类型 != '单位'" + - source: 处罚决定书.性别 + target: 证据复制(提取)单当事人.身份证性别 + when: "当事人类型 != '单位'" + - source: 处罚决定书.民族 + target: 证据复制(提取)单当事人.身份证民族 + when: "当事人类型 != '单位'" + - source: 处罚决定书.身份证住址 + target: 证据复制(提取)单当事人.身份证住址 + when: "当事人类型 != '单位'" + - source: 处罚决定书.身份证号码 + target: 证据复制(提取)单当事人.身份证号 + when: "当事人类型 != '单位'" + - source: 处罚决定书.经营地址 + target: 证据复制(提取)单.许可证经营场所 + when: "当事人类型 != '个人'" + - source: 证据复制(提取)单.许可证经营场所 + target: 证据复制(提取)单.执照住所 + when: "当事人类型 != '个人'" + - source: 处罚决定书.字号 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + logic: 1 OR 2 + messages: + pass: 当事人的基本情况记载齐全且准确。 + fail: 当事人的基本情况记载不齐全或不准确,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十九条 + type: deterministic +- group: JZG-SD + rules: + - rule_id: JZ-SD-001 + name: 法定时限送达 + desc: 若处罚决定书文尾的日期与处罚决定书的送达回证中的"签收日期",之间的范围不在法定时限内,则扣分。 + risk: medium + score: 10 + scope: + - 处罚决定书 + - 送达回证 + stages: + - id: '1' + check: required + fields: + - 送达回证.签收日期 + - 处罚决定书.落款日期 + messages: + pass: 文档检查通过,符合规范要求。 + fail: 文档存在以下问题,请修改后重新提交。 + references_laws: + - 《中华人民共和国行政处罚法》第六十一条 + type: deterministic + - rule_id: JZ-SD-002 + name: 送达回证基本信息规范 + desc: 若收件人签名、签收时间、送达人签名、印章任意一项不存在,则扣分 + risk: medium + score: 10 + scope: + - 送达回证 + stages: + - id: '1' + check: required + fields: + - 送达回证.回证编号 + - 送达回证.送达文书名称 + - 送达回证.送达方式 + - 送达回证.签收日期 + messages: + pass: 办案单位印章、送达人签名、收件人签名及签收时间填写规范。 + fail: 填写不规范,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第六十一条 + type: deterministic +- group: JZG-XC + rules: + - rule_id: JZ-XC-001 + name: 现场笔录时间地点完整性 + desc: 若现场笔录中时间或地点未记载,则扣分;若记载的时间与证据提取单中的时间、地点不一致,也扣分。 + risk: medium + score: 10 + scope: + - 现场笔录 + - 证据复制(提取)单 + stages: + # 地点是文字型字段,用确定性 match 足够(fuzzy 可容忍小差异) + - id: '1' + check: match + pairs: + - source: 现场笔录.检查地点 + target: 证据复制(提取)单.现场地址 + method: fuzzy + # 时间是语义型字段 —— 现场笔录.检查时间常是时间段("16:10至17:00"), + # 证据复制(提取)单.现场时间常是时间点("16:20")。不写字符串 parser, + # 直接让 LLM 按业务语义判定(点落在段内视为一致)。 + - id: '2' + check: ai + prompt: | + 判断以下两个时间在业务上是否一致: + + - 现场笔录.检查时间:{{现场笔录.检查时间}} + - 证据复制(提取)单.现场时间:{{证据复制(提取)单.现场时间}} + + 判断原则: + - 若两者都是时间点且值相同 → 一致 + - 若一方是时间段,另一方是时间点,且**点落在段内** → 一致 + - 若两者都是时间段且有重叠 → 一致 + - 若完全无关或对不上 → 不一致 + + 只判时间业务语义,不判格式差异("2024 年 11 月 18 日"和"2024-11-18"视为同日)。 + logic: 1 AND 2 + messages: + pass: 时间地点记录准确。 + fail: 时间地点记录缺失或与实际不一致,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + - rule_id: JZ-XC-002 + name: 被检查人基本情况记载完整性-有无 + desc: 被检查人基本情况记载 + risk: medium + score: 10 + scope: + - 现场笔录 + stages: + - id: '1' + check: required + fields: + - 现场笔录.单位名称 + - 现场笔录.单位法代 + - 现场笔录.地址 + - 现场笔录.电话 + - 现场笔录.单位许可证号 + - id: '2' + check: required + fields: + - 现场笔录.个人姓名 + - 现场笔录.个人性别 + - 现场笔录.个人证件 + - 现场笔录.地址 + - 现场笔录.电话 + - id: '3' + check: required + fields: + - 现场笔录.现场负责人 + - 现场笔录.电话 + - 现场笔录.地址 + logic: (1 OR 2) AND 3 + messages: + pass: 被检查人姓名、身份证号、地址、许可证号与证据一致,请检查其余基本信息是否完整准确。 + fail: 被检查人基本情况记录有误或缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + - rule_id: JZ-XC-003 + name: 被检查人基本情况记载完整性-一致 + desc: 检查现场笔录中被检查人信息与身份证/营业执照/许可证信息是否一致 + risk: medium + score: 10 + scope: + - 现场笔录 + - 立案报告表 + - 证据复制(提取)单 + stages: + - id: '1' + check: match + pairs: + - source: 现场笔录.单位名称 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + - source: 现场笔录.单位法代 + target: 证据复制(提取)单.执照法代 + when: "当事人类型 != '个人'" + - source: 现场笔录.单位许可证号 + target: 证据复制(提取)单.许可证号 + when: "当事人类型 != '个人'" + - source: 证据复制(提取)单.许可证企业名称 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + - source: 证据复制(提取)单.许可证负责人 + target: 证据复制(提取)单.执照法代 + when: "当事人类型 != '个人'" + - source: 立案报告表.单位名称 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + - source: 立案报告表.单位法代 + target: 证据复制(提取)单.执照法代 + when: "当事人类型 != '个人'" + - source: 立案报告表.单位地址 + target: 证据复制(提取)单.执照住所 + when: "当事人类型 != '个人'" + - id: '2' + check: match + pairs: + - source: 现场笔录.个人姓名 + target: 立案报告表.个人姓名 + when: "当事人类型 != '单位'" + - source: 立案报告表.个人姓名 + target: 证据复制(提取)单当事人.身份证姓名 + when: "当事人类型 != '单位'" + - source: 现场笔录.个人性别 + target: 立案报告表.个人性别 + when: "当事人类型 != '单位'" + - source: 立案报告表.个人性别 + target: 证据复制(提取)单当事人.身份证性别 + when: "当事人类型 != '单位'" + - source: 现场笔录.个人证件 + target: 证据复制(提取)单当事人.身份证号 + when: "当事人类型 != '单位'" + - source: 现场笔录.地址 + target: 立案报告表.个人住址 + when: "当事人类型 != '单位'" + - source: 立案报告表.个人住址 + target: 证据复制(提取)单当事人.身份证住址 + when: "当事人类型 != '单位'" + logic: 1 OR 2 + messages: + pass: 文档检查通过,符合规范要求。 + fail: 文档存在以下问题,请修改后重新提交。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + - rule_id: JZ-XC-004 + name: 被检查人签署意见合规性 + desc: 若被检查人拒绝签署意见及姓名,且执法人员未说明情况,则扣分。 + risk: medium + score: 10 + scope: + - 现场笔录 + stages: + - id: '1' + check: required + fields: + - 现场笔录.意见 + - 现场笔录.意见日期 + - 现场笔录.意见签名 + - id: '2' + check: required + field: 现场笔录.意见 + messages: + pass: 被检查人已签署意见及姓名,或执法人员已说明拒绝签署的情况。 + fail: 被检查人拒绝签署但执法人员未说明情况,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic +- group: JZG-DJ + rules: + - rule_id: JZ-DJ-001 + name: 批准保存时间记载完整性 + desc: 若负责人意见并签名栏后没有日期信息,则扣分。 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + stages: + - id: '1' + check: required + field: 证据先行登记保存批准书.负责人日期 + messages: + pass: 已记载批准保存时间。 + fail: 批准保存时间未记载,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None + - rule_id: JZ-DJ-002 + name: 证据先行登记保存批准书负责人意见并签名 + desc: 若行政机关负责人没有签署意见或姓名,则扣分。 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + stages: + - id: '1' + check: required + fields: + - 证据先行登记保存批准书.负责人签名姓名 + - 证据先行登记保存批准书.负责人意见 + - 证据先行登记保存批准书.负责人日期 + messages: + pass: 行政机关负责人已签署意见和姓名。 + fail: 行政机关负责人未签署意见或姓名,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None + - rule_id: JZ-DJ-003 + name: 先行登记保存证据期限记载 + desc: 若没有文中"对先行登记保存的证据,应当在.....日内及时作出处理决定。"的描述,则扣分。 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + - 证据先行登记保存通知书 + stages: + - id: '1' + check: required + fields: + - 证据先行登记保存批准书.表格下方文字 + - 证据先行登记保存通知书.表格下方文字 + messages: + pass: 已注明先行登记保存证据期限和处理决定期限。 + fail: 未注明相关期限,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None and 证据先行登记保存通知书 != None + - rule_id: JZ-DJ-004 + name: 先行登记保存批准书或通知书文件校验 + desc: 若现场笔录中的情况说明中出现物品名称及规格描述,且文件中无批准书或通知书,则扣分。 + risk: medium + score: 10 + scope: + - 证据先行登记保存批准书 + - 证据先行登记保存通知书 + stages: + - id: '1' + check: required + fields: + - 证据先行登记保存批准书.表格品规 + - 证据先行登记保存通知书.表格品规 + - id: '2' + check: ai + prompt: '请判断以下 {{证据先行登记保存批准书.表格全文}} 和 {{证据先行登记保存通知书.表格全文}} 表述和数量一致 + + ' + messages: + pass: 存在先行登记保存批准书或通知书。 + fail: 缺少先行登记保存批准书或通知书,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: ai_rule + activate_if: 证据先行登记保存批准书 != None and 证据先行登记保存通知书 != None + - rule_id: JZ-DJ-005 + name: 批准书与通知书内容一致性 + desc: 若批准书和通知书内容不一致,则直接扣分;若一致,则与抽样清单中的物品数量进行比对,如果抽样清单中同一品种有多条记录则提示。 若当事人和见证人栏均无签名,则扣分 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + - 证据先行登记保存通知书 + stages: + - id: '1' + check: match + pairs: + - source: 证据先行登记保存通知书.表格品规 + target: 证据先行登记保存批准书.表格品规 + messages: + pass: 批准书与通知书内容一致 + fail: 批准书与通知书内容不一致,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None and 证据先行登记保存通知书 != None + - rule_id: JZ-DJ-006 + name: 证据先行登记保存批准/通知书承办人签名日期 + desc: 若没有证据先行登记保存批准/通知书承办人签字或盖章,则扣分。 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + - 证据先行登记保存通知书 + stages: + - id: '1' + check: required + fields: + - 证据先行登记保存批准书.承办人日期 + - 证据先行登记保存通知书.承办人日期 + - 证据先行登记保存批准书.承办人签名1 + - 证据先行登记保存批准书.承办人签名2 + - 证据先行登记保存通知书.承办人签名1 + - 证据先行登记保存通知书.承办人签名2 + messages: + pass: 有日期,案件承办人已签字或盖章。 + fail: 缺少印章、日期或承办人签字盖章,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None and 证据先行登记保存通知书 != None + - rule_id: JZ-DJ-007 + name: 证据先行登记保存批准书负责人意见并签名 + desc: 若没有填写两名承办人意见及签名,负责人意见及签名,则扣分。 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + stages: + - id: '1' + check: required + fields: + - 证据先行登记保存批准书.负责人日期 + - 证据先行登记保存批准书.负责人签名有无 + - 证据先行登记保存批准书.负责人意见有无 + messages: + pass: 两名承办人签名,负责人意见及签名完整。 + fail: 两名承办人签名或负责人意见及签名缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None + - rule_id: JZ-DJ-008 + name: 保存理由和内容记载完整性 + desc: 若首部没有保存理由描述,表格中没有规格和数量信息,则扣分。 + risk: medium + score: 10 + scope: + - 立案报告表 + - 证据先行登记保存批准书 + stages: + - id: '1' + check: ai + prompt: '{{立案报告表.案由}} + + {{证据先行登记保存批准书.标题下方文本}} + + 案由应该要和标题下方文本同一个意思,案由会比较少字。帮我评查这个案由是否存在 在标题下方文本 中 + + ' + - id: '2' + check: ai + prompt: '{{立案报告表.案情品种}}中提及的具体规格品种、数量应出现在{{证据先行登记保存批准书.表格品规}}中,但案情摘要中不一定会将全部规格品种都写全,评查尺度可以适当放松 + + ' + - id: '3' + check: ai + prompt: '请根据以下信息判断案件类型,对个人(个体工商户)案件单独评查证据先行登记保存批准书内容是否完整。 + + + 当事人-单位-名称: {{立案报告表.单位名称}} + + 当事人-个人(个体工商户)-姓名: {{立案报告表.个人姓名}} + + 证据先行登记保存批准书-表格内容-品种规格、单位、数量: {{证据先行登记保存批准书.表格品规}} + + + 判断逻辑: + + 1. 如果单位-名称为空或为"/",且个人-姓名不为空,则这是个人(个体工商户)案件 + + 2. 对于个人案件:只要证据先行登记保存批准书-表格内容-品种规格、单位、数量有内容(非空);若为空 + + 3. 如果单位-名称有实际值(非空、非"/") + + ' + logic: (1 AND 2) OR 3 + messages: + pass: 已注明保存理由和内容。 + fail: 保存理由和内容未注明,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: ai_rule + activate_if: 证据先行登记保存批准书 != None + - rule_id: JZ-DJ-009 + name: 先行登记保存物品处理通知书当事人签字 + desc: 若通知书中当事人未签字或没有其他内容说明,则扣分。 + risk: medium + score: 5 + scope: + - 证据先行登记保存通知书 + stages: + - id: '1' + check: required + field: 证据先行登记保存通知书.当事人签名 + - id: '2' + check: required + field: 证据先行登记保存通知书.拒绝签名说明 + logic: 1 OR 2 + messages: + pass: 当事人已在先行登记保存物品处理通知书上签字。 + fail: 当事人未签字或i没有情况说明,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 证据先行登记保存通知书 != None + - rule_id: JZ-DJ-010 + name: 证据先行登记保存批准书负责人意见并签名 + desc: 检查涉案物品返还清单接收人签名、日期和印章是否完整,并通过正则检查损耗/返还信息 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + stages: + - id: '1' + check: required + fields: + - 证据先行登记保存批准书.负责人意见 + - 证据先行登记保存批准书.负责人签名姓名 + messages: + pass: 文档检查通过,符合规范要求。 + fail: 文档存在以下问题,请修改后重新提交。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None + - rule_id: JZ-DJ-011 + name: 证据先行登记保存批准/通知书盖章 + desc: 检查先行登记保存批准书和通知书是否加盖行政机关印章 + risk: medium + score: 5 + scope: + - 证据先行登记保存批准书 + - 证据先行登记保存通知书 + stages: + - id: '1' + check: required + fields: + - 证据先行登记保存批准书.盖章 + - 证据先行登记保存通知书.盖章 + messages: + pass: 有行政机关印章 + fail: 缺少印章,请核对 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 证据先行登记保存批准书 != None and 证据先行登记保存通知书 != None +- group: JZG-QR + rules: + - rule_id: JZ-QR-001 + name: 陈述申辩权利告知和听取 + desc: 若表述中不包含"享有陈述权和申辩权"、"...日内"、"...视为放弃",任意一项,则扣分, + risk: medium + score: 10 + scope: + - 行政处罚事先告知书 + stages: + - id: '1' + check: required + field: 行政处罚事先告知书.权利告知 + messages: + pass: 已告知当事人陈述申辩权利。 + fail: 未告知当事人陈述申辩相关权力,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第四十四条 + type: deterministic + - rule_id: JZ-QR-002 + name: 行政处罚事先告知对象准确性 + desc: 若告知书首句中的姓名与当事人意见中的签名不一致,则扣分。 + risk: medium + score: 10 + scope: + - 行政处罚事先告知书 + stages: + - id: '1' + check: match + pairs: + - source: 行政处罚事先告知书.当事人 + target: 行政处罚事先告知书.正文前称呼 + messages: + pass: 行政处罚事先告知对象正确。 + fail: 行政处罚事先告知对象错误,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第四十四条 + type: deterministic +- group: JZG-QZ + rules: + - rule_id: JZ-QZ-001 + name: 当事人身份证明提取规范性 + desc: 若没有提取当事人身份证明,则扣分。 + risk: medium + score: 10 + scope: + - 证据复制(提取)单 + stages: + - id: '1' + check: required + fields: + - 证据复制(提取)单当事人.身份证号 + - 证据复制(提取)单当事人.身份证背面 + messages: + pass: 当事人身份证明已规范提取。 + fail: 当事人身份证明提取不规范或缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + - rule_id: JZ-QZ-002 + name: 查获物品情况记载准确性、合规性 + desc: 若批准书和通知书内容不一致,则直接扣分;若一致,则与抽样清单中的物品数量进行比对,如果抽样清单中同一品种有多条记录则提示。 若当事人和见证人栏均无签名,则扣分 + risk: medium + score: 10 + scope: + - 抽样取证物品清单 + - 涉案物品核价表 + - 证据先行登记保存批准书 + - 证据先行登记保存通知书 + stages: + - id: '1' + check: ai + prompt: '请判断{{抽样取证物品清单.品种规格}}(若有)或{{涉案物品核价表.核价明细}},以及{{证据先行登记保存批准书.表格品规}}、{{证据先行登记保存通知书.表格品规}}表述和数量一致。 + + 如果{{抽样取证物品清单.品种规格}}、{{涉案物品核价表.核价明细}}都不存在,则只需判断{{证据先行登记保存批准书.表格品规}}和{{证据先行登记保存通知书.表格品规}}的一致性 + + ' + messages: + pass: 查获物品情况、数量及当事人或见证人姓名记录准确。 + fail: 记录不准确或缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: ai_rule + - rule_id: JZ-QZ-003 + name: 核价文书记录的准确性(盖章) + desc: 检查涉案物品核价表是否有涉案卷烟价格管理小组印章 + risk: medium + score: 5 + scope: + - 涉案物品核价表 + stages: + - id: '1' + check: required + field: 涉案物品核价表.核价组印章 + messages: + pass: 已正确加盖印章。 + fail: 印章加盖错误,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 涉案物品核价表 != None + - rule_id: JZ-QZ-004 + name: 抽样取证物品清单完整性 + desc: 先行登记保存证据处理通知书"处理"方式选择第2项"送交...鉴定"时,卷宗内没有抽样取证物品清单,则扣分。 + risk: medium + score: 10 + scope: + - 先行登记保存证据处理通知书 + - 抽样取证物品清单 + stages: + - id: '1' + check: required + field: 先行登记保存证据处理通知书.处理方式 + - id: '2' + check: required + fields: + - 抽样取证物品清单.表格有内容 + - 抽样取证物品清单.当事人签名 + logic: (1 AND 2) OR (NOT 1) + messages: + pass: 抽样提取物证时有完整的物品清单。 + fail: 抽样提取物证时缺少物品清单,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 先行登记保存证据处理通知书 != None + - rule_id: JZ-QZ-005 + name: 核价文书记录准确性 + desc: 若核价文书或记录中没有准确记载(计算核价结果错误)涉案物品情况,核价错误,则扣分。 + risk: medium + score: 5 + scope: + - 涉案物品核价表 + stages: + - id: '1' + check: ai + prompt: '{{涉案物品核价表.表格全文}} + + 请判断以表格中各品种规格的数量、单价计算的合计金额是否正确,各品种规格合计金额计算总计金额是否正确,请在计算的时候保留小数点后两位 + + ' + messages: + pass: 涉案物件核价表存在 + fail: 涉案物件核价表不存在或者信息内容有误 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: ai_rule + - rule_id: JZ-QZ-006 + name: 价格证明合规性 + desc: 若批准书与通知书内容不一致,核价表中数量与批准书或通知书中不一致,则扣分。 + risk: medium + score: 10 + scope: + - 涉案物品核价表 + - 证据先行登记保存批准书 + - 证据先行登记保存通知书 + stages: + - id: '1' + check: ai + prompt: '请判断以下三个表格物品和数量是否对应 + + {{涉案物品核价表.核价明细}} + + {{证据先行登记保存批准书.表格品规}} + + {{证据先行登记保存通知书.表格品规}} + + ' + messages: + pass: 价格证明符合要求,且有涉案物品核价依据或价格来源。 + fail: 价格证明不符合要求或缺少依据,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: ai_rule +- group: JZG-XW + rules: + - rule_id: JZ-XW-001 + name: 被询问人签署"记录属实"合规性 + desc: 若每页页尾被询问人处没有签名,则扣分;如果最后一页没有手写内容则提示。 + risk: medium + score: 10 + scope: + - 询问笔录 + stages: + - id: '1' + check: required + field: 询问笔录.被询问人核实 + messages: + pass: 被询问人已签署"记录属实"且逐页签名。 + fail: 被询问人未签署或未逐页签名,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十五条 + type: deterministic + - rule_id: JZ-XW-002 + name: 询问笔录合规性 + desc: 通过AI判断询问笔录格式是否符合规范要求 + risk: medium + score: 10 + scope: + - 询问笔录 + stages: + - id: '1' + check: ai + prompt: '请判断以下询问笔录中是否只有一名被询问人。被询问人信息:{{询问笔录当事人.被询问人姓名}} + + ' + messages: + pass: 笔录仅询问一名被询问人。 + fail: 一份笔录询问多名被询问人,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十五条 + type: ai_rule + - rule_id: JZ-XW-003 + name: 执法人员身份表明和权利告知 + desc: 若未在询问开始时表明执法人员身份,并告知当事人享有陈述申辩权和申请回避权,则扣分。 + risk: medium + score: 5 + scope: + - 询问笔录 + stages: + - id: '1' + check: required + fields: + - 询问笔录.执法人员信息 + - 询问笔录.权利告知 + messages: + pass: 执法人员已表明身份并告知相关权利。 + fail: 未表明身份或未告知权利,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十五条 + type: deterministic + - rule_id: JZ-XW-004 + name: 执法人员签名合规性 + desc: 若执法人员没有签名或只有一人签名,则扣分。 + risk: medium + score: 10 + scope: + - 询问笔录 + stages: + - id: '1' + check: required + fields: + - 询问笔录.询问人签名1 + - 询问笔录.询问人签名2 + messages: + pass: 执法人员已签名,且有两人以上签名。 + fail: 执法人员签名缺失或不足两人,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第四十二条 + type: deterministic + - rule_id: JZ-XW-005 + name: 被询问人基本情况记载全面性 + desc: 被询问人基本情况填写不全,或询问时间、地点未准确记载,则扣分。 + risk: medium + score: 5 + scope: + - 证据复制(提取)单 + - 询问笔录 + stages: + - id: '1' + check: match + pairs: + - source: 询问笔录.询问地点 + target: 证据复制(提取)单.复制地点 + - source: 询问笔录当事人.被询问人姓名 + target: 证据复制(提取)单当事人.身份证姓名 + when: "当事人类型 != '单位'" + - source: 询问笔录当事人.被询问人性别 + target: 证据复制(提取)单当事人.身份证性别 + when: "当事人类型 != '单位'" + - source: 询问笔录当事人.被询问人民族 + target: 证据复制(提取)单当事人.身份证民族 + when: "当事人类型 != '单位'" + - source: 询问笔录当事人.被询问人证件 + target: 证据复制(提取)单当事人.身份证号 + when: "当事人类型 != '单位'" + - source: 询问笔录当事人.被询问人住址 + target: 证据复制(提取)单当事人.身份证住址 + when: "当事人类型 != '单位'" + - source: 询问笔录.询问时间 + target: 证据复制(提取)单.复制时间 + method: fuzzy + - source: 询问笔录当事人.被询问人经营地址 + target: 证据复制(提取)单.许可证经营场所 + when: "当事人类型 != '个人'" + messages: + pass: 被询问人基本情况、询问时间地点记录完整准确。 + fail: 记录不完整或不准确,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十五条 + type: deterministic + - rule_id: JZ-XW-006 + name: 被询问人拒绝签署处理合规性 + desc: 检查被询问人拒绝签名时是否有情况说明记录 + risk: medium + score: 10 + scope: + - 询问笔录 + stages: + - id: '1' + check: required + field: 询问笔录.被询问人签名 + - id: '2' + check: required + field: 询问笔录.拒绝签名说明 + logic: 1 OR 2 + messages: + pass: 被询问人已签署或已记载拒绝情况。 + fail: 被询问人未签署且未记录情况说明,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十五条 + type: deterministic +- group: JZG-LA + rules: + - rule_id: JZ-LA-001 + name: 当事人基本情况记载完整、准确 + desc: 若当事人姓名、有效证件号码和地址未记载或与身份证中信息不一致,则扣分。 + risk: medium + score: 10 + scope: + - 立案报告表 + - 证据复制(提取)单 + stages: + - id: '1' + check: required + fields: + - 立案报告表.单位名称 + - 立案报告表.单位法代 + - 立案报告表.单位电话 + - 立案报告表.单位地址 + - id: '2' + check: required + fields: + - 立案报告表.个人姓名 + - 立案报告表.个人性别 + - 立案报告表.个人年龄 + - 立案报告表.个人民族 + - 立案报告表.个人证件 + - 立案报告表.个人电话 + - 立案报告表.个人住址 + - id: '3' + check: match + pairs: + - source: 立案报告表.个人姓名 + target: 证据复制(提取)单当事人.身份证姓名 + when: "当事人类型 != '单位'" + - source: 立案报告表.个人性别 + target: 证据复制(提取)单当事人.身份证性别 + when: "当事人类型 != '单位'" + - source: 立案报告表.个人民族 + target: 证据复制(提取)单当事人.身份证民族 + when: "当事人类型 != '单位'" + - source: 立案报告表.个人住址 + target: 证据复制(提取)单当事人.身份证住址 + when: "当事人类型 != '单位'" + - source: 立案报告表.个人证件 + target: 证据复制(提取)单当事人.身份证号 + when: "当事人类型 != '单位'" + - id: '4' + check: match + pairs: + - source: 立案报告表.单位名称 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + - source: 立案报告表.单位法代 + target: 证据复制(提取)单.执照法代 + when: "当事人类型 != '个人'" + - source: 立案报告表.单位地址 + target: 证据复制(提取)单.执照住所 + when: "当事人类型 != '个人'" + - id: '5' + check: match + pairs: + - source: 立案报告表.个人姓名 + target: 证据复制(提取)单.执照法代 + when: "当事人类型 != '个人'" + - source: 立案报告表.个人住址 + target: 证据复制(提取)单.执照住所 + when: "当事人类型 != '个人'" + - id: '6' + check: ai + prompt: '请根据以下信息判断案件类型(个人案件或单位案件),并评查当事人基本情况是否记载完整。 + + + 当事人-单位-名称: {{立案报告表.单位名称}} + + 当事人-单位-法定代表人(负责人): {{立案报告表.单位法代}} + + 当事人-个人(个体工商户)-姓名: {{立案报告表.个人姓名}} + + 当事人-个人(个体工商户)-性别: {{立案报告表.个人性别}} + + 当事人-个人(个体工商户)-年龄: {{立案报告表.个人年龄}} + + 当事人-个人(个体工商户)-民族: {{立案报告表.个人民族}} + + 当事人-个人(个体工商户)-证件类型及号码: {{立案报告表.个人证件}} + + 当事人-个人(个体工商户)-联系电话: {{立案报告表.个人电话}} + + 当事人-个人(个体工商户)-住址: {{立案报告表.个人住址}} + + + 判断逻辑: + + 1. 如果单位-名称为空或为"/",且个人-姓名不为空,则这是个人(个体工商户)案件 + + 2. 对于个人案件:检查个人字段(姓名、性别、年龄、民族、证件类型及号码、联系电话、住址)是否都不为空—— + + 3. 如果单位-名称有实际值(非空、非"/") + + ' + logic: (1 AND 4) OR 6 + messages: + pass: 当事人基本情况记录完整,与身份证信息一致。 + fail: 当事人基本情况记录有误或缺失,请核对。 + references_laws: + - 《中华人民共和国烟草专卖法》第三十八条 + type: ai_rule + - rule_id: JZ-LA-002 + name: 案由、发案时间和发案地点记载准确性-有无 + desc: 若案由、发案时间和发案地点未记载或错误记载,则扣分。 + risk: medium + score: 10 + scope: + - 立案报告表 + stages: + - id: '1' + check: required + field: 立案报告表.案由 + messages: + pass: 案由、发案时间和发案地点记录准确。 + fail: 案由、发案时间和发案地点记录有误或缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十四条 + type: deterministic + - rule_id: JZ-LA-003 + name: 案件来源有无一致性校验 + desc: 若三处文档中的案件来源信息不一致或者存在未填写的情况,则扣分。 + risk: medium + score: 5 + scope: + - 案件处理审批表 + - 案件调查终结报告 + - 立案报告表 + stages: + - id: '1' + check: required + fields: + - 立案报告表.案件来源 + - 案件处理审批表.案件来源 + - 案件调查终结报告.案件来源 + - id: '2' + check: match + pairs: + - source: 立案报告表.案件来源 + target: 案件处理审批表.案件来源 + - source: 案件处理审批表.案件来源 + target: 案件调查终结报告.案件来源 + # 案件来源是开放词汇(投诉举报/群众举报/电话举报/来电举报/上级交办… + # 无穷枚举),不用 canonicalize 字典维护。字面不等时走 rescue L1 + # match 做语义等价判定。 + messages: + pass: 案件来源完整 + fail: 没有记载案件来源或案件来源与其他文书不一致,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十四条 + type: deterministic + - rule_id: JZ-LA-004 + name: 案由、发案时间和发案地点记载准确性-一致 + desc: 检查立案报告表案发时间/地点与现场笔录检查时间/地点是否一致 + risk: medium + score: 10 + scope: + - 现场笔录 + - 立案报告表 + stages: + - id: '1' + check: required + fields: + - 立案报告表.案发时间 + - 立案报告表.案发地点 + - 现场笔录.检查时间 + - 现场笔录.检查地点 + - id: '2' + check: match + pairs: + - source: 立案报告表.案发时间 + target: 现场笔录.检查时间 + method: substring + - id: '3' + check: match + pairs: + - source: 现场笔录.检查地点 + target: 立案报告表.案发地点 + messages: + pass: 案由、发案时间和发案地点记录准确。 + fail: 案由、发案时间和发案地点记录有误或缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + - rule_id: JZ-LA-005 + name: 承办人和承办部门意见 + desc: 承办人栏无描述、无签名、承办部门处无描述、无签名,出现任一一项则扣分。 + risk: medium + score: 5 + scope: + - 立案报告表 + stages: + - id: '1' + check: required + fields: + - 立案报告表.承办部门意见 + - 立案报告表.承办部门日期 + - 立案报告表.承办人意见 + - 立案报告表.承办人日期 + - 立案报告表.承办部门签名 + - 立案报告表.承办人签名2 + - 立案报告表.承办人签名1 + messages: + pass: 承办人和承办部门意见及签名完整。 + fail: 承办人和承办部门意见及签名存在缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十四条 + type: deterministic + - rule_id: JZ-LA-006 + name: 行政机关负责人明确意见、签字和日期 + desc: 若"负责人意见"栏中存在"不同意"或"不同意和意见描述",留空则扣分。;负责人意见栏无描述、无签名、无日期,出现任一一项则扣分。 + risk: medium + score: 10 + scope: + - 立案报告表 + stages: + - id: '1' + check: required + fields: + - 立案报告表.负责人意见 + - 立案报告表.负责人签名 + messages: + pass: 行政机关负责人意见、签字和日期完整。 + fail: 行政机关负责人意见、签字和日期缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic + - rule_id: JZ-LA-007 + name: 立案文书完整性检查(签名) + desc: 检查立案报告表负责人意见处是否有签名 + risk: medium + score: 10 + scope: + - 立案报告表 + stages: + - id: '1' + check: required + field: 立案报告表.负责人签名 + messages: + pass: 文档检查通过,符合规范要求。 + fail: 文档存在以下问题,请修改后重新提交。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic + - rule_id: JZ-LA-008 + name: 案件情况清晰 + desc: 通过AI检查立案报告表案由和案情摘要表述是否清晰;若案件情况描述中,需出现案件时间、货物名称、(案由描述+条款引用)中所有信息,未出现任一一项则扣分。 + risk: low + score: 1 + scope: + - 立案报告表 + stages: + - id: '1' + check: ai + prompt: | + 检查 案情摘要 是否覆盖以下 4 项要素(任一缺失才扣分): + 1. 案件时间(检查/发案时间) + 2. 涉案货物名称或品种 + 3. 案由描述(违法行为的事实陈述) + 4. 相关条款或法律依据的引用 + + 案由:{{立案报告表.案由}} + 案情摘要:{{立案报告表.案情摘要}} + + 判定规则: + - 4 项要素齐全 → pass + - 有缺项 → fail + - **不要**对文字风格、段落重复、句式冗余等格式问题扣分,只看内容是否齐全。 + messages: + pass: 案件情况描述清晰。 + fail: 案件情况记录不清晰或缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十四条 + type: ai_rule +- group: JZG-ZJ + rules: + - rule_id: JZ-ZJ-001 + name: 调查终结报告文件校验 + desc: 若没有调查终结报告,则扣分 + risk: medium + score: 10 + scope: + - 案件调查终结报告 + stages: + - id: '1' + check: required + field: 案件调查终结报告.案由 + messages: + pass: 存在完整的调查终结报告。 + fail: 缺少调查终结报告,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic + - rule_id: JZ-ZJ-002 + name: 案由、立案时间和当事人基本情况记载 + desc: 若当事人信息与提取出的信息不一致,则扣分。 + risk: medium + score: 5 + scope: + - 案件调查终结报告 + - 证据复制(提取)单 + stages: + - id: '1' + check: required + fields: + - 案件调查终结报告.案件来源 + - 案件调查终结报告.案由 + - 案件调查终结报告.立案日期 + - 案件调查终结报告.单位名称 + - 案件调查终结报告.单位法代 + - 案件调查终结报告.单位电话 + - 案件调查终结报告.单位地址 + - id: '2' + check: required + fields: + - 案件调查终结报告.案件来源 + - 案件调查终结报告.案由 + - 案件调查终结报告.立案日期 + - 案件调查终结报告.个人姓名 + - 案件调查终结报告.个人性别 + - 案件调查终结报告.个人年龄 + - 案件调查终结报告.个人民族 + - 案件调查终结报告.个人电话 + - 案件调查终结报告.个人证件 + - 案件调查终结报告.个人住址 + - id: '3' + check: match + pairs: + - source: 案件调查终结报告.单位名称 + target: 证据复制(提取)单.执照名称 + when: "当事人类型 != '个人'" + - source: 案件调查终结报告.单位法代 + target: 证据复制(提取)单.执照法代 + when: "当事人类型 != '个人'" + - source: 案件调查终结报告.单位地址 + target: 证据复制(提取)单.执照住所 + when: "当事人类型 != '个人'" + - id: '4' + check: match + pairs: + - source: 案件调查终结报告.个人姓名 + target: 证据复制(提取)单当事人.身份证姓名 + when: "当事人类型 != '单位'" + - source: 案件调查终结报告.个人性别 + target: 证据复制(提取)单当事人.身份证性别 + when: "当事人类型 != '单位'" + - source: 案件调查终结报告.个人民族 + target: 证据复制(提取)单当事人.身份证民族 + when: "当事人类型 != '单位'" + - source: 案件调查终结报告.个人住址 + target: 证据复制(提取)单当事人.身份证住址 + when: "当事人类型 != '单位'" + - source: 案件调查终结报告.个人证件 + target: 证据复制(提取)单当事人.身份证号 + when: "当事人类型 != '单位'" + logic: (1 AND 3) OR (2 AND 4) + messages: + pass: 当事人基本情况记载准确。请检查案后及时间是否正确。 + fail: 记载不准确或缺失,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic + - rule_id: JZ-ZJ-003 + name: 当事人基本情况记载-一致 + desc: 检查调查终结报告中当事人基本信息与身份证信息是否一致 + risk: medium + score: 1 + scope: + - 案件调查终结报告 + - 证据复制(提取)单 + stages: + - id: '1' + check: match + pairs: + - source: 案件调查终结报告.个人姓名 + target: 证据复制(提取)单当事人.身份证姓名 + - source: 案件调查终结报告.个人性别 + target: 证据复制(提取)单当事人.身份证性别 + - source: 案件调查终结报告.个人民族 + target: 证据复制(提取)单当事人.身份证民族 + - source: 案件调查终结报告.个人住址 + target: 证据复制(提取)单当事人.身份证住址 + - source: 案件调查终结报告.个人证件 + target: 证据复制(提取)单当事人.身份证号 + messages: + pass: 文档检查通过,符合规范要求。 + fail: 文档存在以下问题,请修改后重新提交。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic + - rule_id: JZ-ZJ-004 + name: 案件调查终结报告承办人及承办部门负责人签字日期 + desc: 若没有承办人及承办人负责人签字、或者没有签字日期,则扣分。 + risk: medium + score: 5 + scope: + - 案件调查终结报告 + stages: + - id: '1' + check: required + fields: + - 案件调查终结报告.处理意见日期 + - 案件调查终结报告.处理意见承办人签名1 + - 案件调查终结报告.处理意见承办人签名2 + messages: + pass: 承办人及承办部门负责人已签字并签署日期。 + fail: 缺少签字或日期,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic +- group: JZG-CL + rules: + - rule_id: JZ-CL-001 + name: 法制部门或法制员意见明确性 + desc: 若法制部门意见栏无文字描述内容,则扣分。 + risk: medium + score: 10 + scope: + - 案件处理审批表 + stages: + - id: '1' + check: required + fields: + - 案件处理审批表.法制部门意见 + - 案件处理审批表.法制部门日期 + - 案件处理审批表.法制部门审核人签名 + - 案件处理审批表.法制部门负责人签名 + messages: + pass: 法制部门或法制员意见明确。 + fail: 法制部门或法制员意见缺失或不明确,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十八条 + type: deterministic + - rule_id: JZ-CL-002 + name: 案件处理审批表承办人意见和签名 + desc: 若承办人意见栏中无文字内容或无签名日期,则扣分。 + risk: medium + score: 5 + scope: + - 案件处理审批表 + stages: + - id: '1' + check: required + fields: + - 案件处理审批表.承办人意见 + - 案件处理审批表.承办人日期 + - 案件处理审批表.承办部门意见 + - 案件处理审批表.承办部门日期 + - 案件处理审批表.承办部门签名 + - 案件处理审批表.承办人签名1 + - 案件处理审批表.承办人签名2 + messages: + pass: 承办人意见和签名完整。 + fail: 缺少承办人意见或签名,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十八条 + type: deterministic + - rule_id: JZ-CL-003 + name: 案件处理审批表负责人审批意见明确性 + desc: 检查案件处理审批表负责人审批意见内容和日期是否完整 + risk: medium + score: 10 + scope: + - 案件处理审批表 + stages: + - id: '1' + check: required + fields: + - 案件处理审批表.负责人日期 + - 案件处理审批表.负责人意见 + - 案件处理审批表.负责人签名 + messages: + pass: 行政机关负责人审批意见明确,签名和审批时间规范。 + fail: 审批意见不明确或签名审批时间不规范,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十七条 + type: deterministic +- group: JZG-ZG + rules: + - rule_id: JZ-ZG-001 + name: 行政处罚事先告知书送达 + desc: 若送达方式为"直接送达",则收件人签名或盖章栏无信息,则扣分。 若送达方式为"邮寄送达",则校验证据复制(提取)中是否有邮件回执,若不存在,则扣分。 + risk: medium + score: 10 + scope: + - 证据复制(提取)单 + - 送达回证 + stages: + - id: '1' + check: contains + field: 送达回证.送达方式 + value: 直接送达 + - id: '2' + check: contains + field: 送达回证.送达方式 + value: 邮寄送达 + - id: '3' + check: required + field: 证据复制(提取)单.邮件回执 + logic: 1 OR (2 AND 3) + messages: + pass: 事先告知书已送达当事人。 + fail: 事先告知书可能未送达当事人,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第六十一条 + type: deterministic +- group: JZG-ZX + rules: + - rule_id: JZ-ZX-001 + name: 罚款、没收违法所得处罚执行规范性 + desc: 若不存在《缴款凭证》(含《广东省非税收入一般缴款书(电子)》及其收款证明等任何形式的缴款凭证),则扣分。若缴款书中金额与处罚决定书中金额总计不一致,则扣分。 + risk: medium + score: 10 + scope: + - 处罚决定书 + - 缴款凭证 + stages: + - id: '1' + check: required + fields: + - 缴款凭证.金额 + - 缴款凭证.收入项目 + - 处罚决定书.罚款项目 + - 处罚决定书.罚款基数 + - 处罚决定书.罚款比例 + - 处罚决定书.罚款总额 + - id: '2' + check: ai + prompt: '请分析{{处罚决定书.罚款项目}}对应{{处罚决定书.罚款基数}}乘{{处罚决定书.罚款比例}},计算并校对与{{处罚决定书.罚款总额}}一致,同时{{处罚决定书.罚款总额}}与{{缴款凭证.金额}}需一致 + + ' + messages: + pass: 罚款、没收违法所得处罚已开具缴款书,有银行缴费收款证明,且与处罚决定书一致。 + fail: 未开具缴款书或无银行缴费证明,或与处罚决定书不一致,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第六十六条、第六十七条 + type: ai_rule + activate_if: 缴款凭证 != None + - rule_id: JZ-ZX-002 + name: 发还当事人物品与先行登记保存物品-一致 + desc: 若两份文件表格中,数量不一致,则涉案物品返还清单中备注一列需要有内容,没有内容则扣分。 + risk: medium + score: 10 + scope: + - 涉案物品返还清单 + - 证据先行登记保存批准书 + stages: + - id: '1' + check: ai + prompt: '{{证据先行登记保存批准书.表格品规}}和{{涉案物品返还清单.返还明细}}表格中的物品和数量应当一致,若 涉案物品返还清单表格中的具体的品种规格和数量行列数据不一致,则通过涉案物品返还清单的备注的内容进一步判断是否一致(即数量+损耗数量) + + ' + messages: + pass: 发还物品与先行登记保存物品一致,或不一致时已说明原因。 + fail: 发还物品与先行登记保存物品不一致且未说明原因,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: ai_rule + - rule_id: JZ-ZX-003 + name: 损耗费用返还合规性 + desc: 若签名或盖章不存在,或日期未填写,则扣分。 + risk: medium + score: 10 + scope: + - 卷宗封面 + - 涉案物品返还清单 + stages: + - id: '1' + check: contains + field: 卷宗封面.处理结果 + value: 销毁 + - id: '2' + check: required + field: 卷宗封面.处理结果 + - id: '3' + check: required + fields: + - 涉案物品返还清单.日期 + - 涉案物品返还清单.补偿信息 + - 涉案物品返还清单.返还确认 + - 涉案物品返还清单.接收人签名 + - id: '4' + check: required + fields: + - 涉案物品返还清单.日期 + - 涉案物品返还清单.接收单位印章 + - 涉案物品返还清单.补偿信息 + - 涉案物品返还清单.返还确认 + logic: (1 AND 2) OR ((NOT 1) AND 2 AND (3 OR 4)) + messages: + pass: 已全部返还留样卷烟或鉴别检验损耗费用。 + fail: 未全部返还,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十六条 + type: deterministic + activate_if: 涉案物品返还清单 != None or (卷宗封面 != None and 卷宗封面.处理结果 != None) + - rule_id: JZ-ZX-004 + name: 缴款凭证填写规范性 + desc: 若处罚中有没收而文件中不存在没收收据,则扣分。 + risk: medium + score: 5 + scope: + - 处罚决定书 + - 缴款凭证 + stages: + - id: '1' + check: required + fields: + - 处罚决定书.罚款说明 + - 缴款凭证.备注 + messages: + pass: 存在缴款凭证,请进一步确认填写是否规范。 + fail: 未找到缴款凭证,请核对文书是否齐全 + references_laws: + - 《中华人民共和国行政处罚法》第六十七条 + type: deterministic + activate_if: 缴款凭证 != None +- group: JZG-JA + rules: + - rule_id: JZ-JA-001 + name: 当事人名称、违法事实和处罚内容记载准确性 + desc: 若两份文书中的当事人名称不一致,则扣分。 + risk: medium + score: 10 + scope: + - 处罚决定书 + - 结案报告表 + stages: + - id: '1' + check: match + pairs: + - source: 结案报告表.当事人 + target: 处罚决定书.当事人 + messages: + pass: 当事人名称、处罚内容记载一致,请进一步检查违法事实是否一致。 + fail: 当事人记载不准确,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第五十九条 + type: deterministic + - rule_id: JZ-JA-002 + name: 行政处罚决定的执行结果记载 + desc: 若执行情况栏后不存在描述内容,则扣分。 + risk: medium + score: 10 + scope: + - 结案报告表 + stages: + - id: '1' + check: required + field: 结案报告表.执行情况 + messages: + pass: 行政处罚决定的执行结果存在对应记载内容。 + fail: 执行结果记载不准确,请核对。 + references_laws: + - 《中华人民共和国行政处罚法》第七十一条 + type: deterministic + - rule_id: JZ-JA-003 + name: 结案意见、签名及其时间填写规范性 + desc: 若承办人、承办机构负责人和办案单位负责人的意见、签名及其时间任意一项未找到,则扣分。 + risk: medium + score: 10 + scope: + - 结案报告表 + stages: + - id: '1' + check: required + fields: + - 结案报告表.承办人结案理由 + - 结案报告表.承办人结案日期 + - 结案报告表.承办部门意见 + - 结案报告表.承办部门日期 + - 结案报告表.负责人意见 + - 结案报告表.负责人日期 + - 结案报告表.负责人签名 + - 结案报告表.承办人结案签名1 + - 结案报告表.承办人结案签名2 + - 结案报告表.承办部门签名 + messages: + pass: 意见、签名及其时间填写规范。 + fail: 填写不规范,请核对并更正。 + references_laws: + - 《中华人民共和国行政处罚法》第五十四条 + type: deterministic + - rule_id: JZ-JA-004 + name: 结案后按期立卷归档 + desc: 通过AI检查结案后是否在10日内立卷归档 + risk: medium + score: 10 + scope: + - 卷内备考表 + - 结案报告表 + stages: + - id: '1' + check: ai + prompt: '请你判断{{卷内备考表.立卷时间}}与{{结案报告表.负责人日期}}是否相差小于10天 + + ' + messages: + pass: 结案后已按期立卷归档。 + fail: 结案后未按期立卷归档,请核对。 + references_laws: + - 《烟草专卖行政处罚程序规定》 + type: ai_rule diff --git a/rules/行政许可_停业/rules.test.yaml b/rules/行政许可_停业/rules.test.yaml new file mode 100644 index 0000000..59eda31 --- /dev/null +++ b/rules/行政许可_停业/rules.test.yaml @@ -0,0 +1,7 @@ +# ═════════════════════════════════════════════════════════════════ +# 烟草专卖零售许可证-停业办理 · 回归测试用例 +# ═════════════════════════════════════════════════════════════════ +# 配套文件:rules.yaml +target: rules.yaml + +cases: [] diff --git a/rules/行政许可_停业/rules.yaml b/rules/行政许可_停业/rules.yaml new file mode 100644 index 0000000..9bec4c2 --- /dev/null +++ b/rules/行政许可_停业/rules.yaml @@ -0,0 +1,410 @@ +metadata: + type_id: 行政卷宗.行政许可.停业 + name: 烟草专卖零售许可证-停业办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [停业, 烟草专卖零售许可证, 停业申请] + description: '烟草专卖零售许可证停业办理卷宗审核。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证处理、送达、归档。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 烟草专卖零售许可证许可类事项申请表 + name: 烟草专卖零售许可证许可类事项申请表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 烟草专卖零售许可证许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + name: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 烟草专卖零售许可证受理单 + name: 烟草专卖零售许可证受理单 + required: true + classifier: {title_patterns: [烟草专卖零售许可证受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 烟草专卖零售许可证实地核查记录表 + name: 烟草专卖零售许可证实地核查记录表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证(正、副本) + name: 烟草专卖零售许可证(正、副本) + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 烟草专卖零售许可证许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证许可类事项申请表, 营业执照, 个体工商户经营者、法定代表人或其他组织负责人的身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 烟草专卖零售许可证许可类事项申请表.证件住址 + - 烟草专卖零售许可证许可类事项申请表.企业类型 + - 烟草专卖零售许可证许可类事项申请表.统一社会信用代码 + - 烟草专卖零售许可证许可类事项申请表.有效期限 + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.性别 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.民族 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.住址 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 烟草专卖零售许可证受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 烟草专卖零售许可证实地核查记录表] + stages: + - {id: '1', check: contains, field: 烟草专卖零售许可证许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证实地核查记录表.标题 + - 烟草专卖零售许可证实地核查记录表.核查人员签名1 + - 烟草专卖零售许可证实地核查记录表.核查人员签名2 + - 烟草专卖零售许可证实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{烟草专卖零售许可证受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证(正、副本)] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证(正、副本).许可证号, 烟草专卖零售许可证(正、副本).副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule diff --git a/rules/行政许可_变更/rules.test.yaml b/rules/行政许可_变更/rules.test.yaml new file mode 100644 index 0000000..e97e634 --- /dev/null +++ b/rules/行政许可_变更/rules.test.yaml @@ -0,0 +1,3 @@ +# 烟草专卖零售许可证-变更办理 · 测试夹具 +# 测试用例待补充 +cases: [] diff --git a/rules/行政许可_变更/rules.yaml b/rules/行政许可_变更/rules.yaml new file mode 100644 index 0000000..41031d7 --- /dev/null +++ b/rules/行政许可_变更/rules.yaml @@ -0,0 +1,410 @@ +metadata: + type_id: 行政卷宗.行政许可.变更 + name: 烟草专卖零售许可证-变更办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [变更, 烟草专卖零售许可证, 变更申请] + description: '烟草专卖零售许可证变更办理卷宗审核。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证颁发、送达、归档。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 烟草专卖零售许可证许可类事项申请表 + name: 烟草专卖零售许可证许可类事项申请表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 烟草专卖零售许可证许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + name: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 烟草专卖零售许可证受理单 + name: 烟草专卖零售许可证受理单 + required: true + classifier: {title_patterns: [烟草专卖零售许可证受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 烟草专卖零售许可证实地核查记录表 + name: 烟草专卖零售许可证实地核查记录表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证(正、副本) + name: 烟草专卖零售许可证(正、副本) + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 烟草专卖零售许可证许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证许可类事项申请表, 营业执照, 个体工商户经营者、法定代表人或其他组织负责人的身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 烟草专卖零售许可证许可类事项申请表.证件住址 + - 烟草专卖零售许可证许可类事项申请表.企业类型 + - 烟草专卖零售许可证许可类事项申请表.统一社会信用代码 + - 烟草专卖零售许可证许可类事项申请表.有效期限 + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.性别 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.民族 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.住址 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 烟草专卖零售许可证受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 烟草专卖零售许可证实地核查记录表] + stages: + - {id: '1', check: contains, field: 烟草专卖零售许可证许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证实地核查记录表.标题 + - 烟草专卖零售许可证实地核查记录表.核查人员签名1 + - 烟草专卖零售许可证实地核查记录表.核查人员签名2 + - 烟草专卖零售许可证实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{烟草专卖零售许可证受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证(正、副本)] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证(正、副本).许可证号, 烟草专卖零售许可证(正、副本).副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule diff --git a/rules/行政许可_延续/rules.test.yaml b/rules/行政许可_延续/rules.test.yaml new file mode 100644 index 0000000..97a00ad --- /dev/null +++ b/rules/行政许可_延续/rules.test.yaml @@ -0,0 +1,7 @@ +# ═════════════════════════════════════════════════════════════════ +# 烟草专卖零售许可证-延续办理 · 测试用例 +# ═════════════════════════════════════════════════════════════════ +# 对应规则文件 rules.yaml +# 测试用例待补充:请在 cases 列表中添加带有实际抽取结果的案例。 + +cases: [] diff --git a/rules/行政许可_延续/rules.yaml b/rules/行政许可_延续/rules.yaml new file mode 100644 index 0000000..d5959bc --- /dev/null +++ b/rules/行政许可_延续/rules.yaml @@ -0,0 +1,410 @@ +metadata: + type_id: 行政卷宗.行政许可.延续 + name: 烟草专卖零售许可证-延续办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [延续, 烟草专卖零售许可证, 续期, 延期] + description: '烟草专卖零售许可证延续办理卷宗审核(许可证到期续期)。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证颁发、送达、归档。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 烟草专卖零售许可证许可类事项申请表 + name: 烟草专卖零售许可证许可类事项申请表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 烟草专卖零售许可证许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 身份证明 + name: 身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 烟草专卖零售许可证受理单 + name: 烟草专卖零售许可证受理单 + required: true + classifier: {title_patterns: [烟草专卖零售许可证受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 烟草专卖零售许可证实地核查记录表 + name: 烟草专卖零售许可证实地核查记录表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证 + name: 烟草专卖零售许可证 + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 烟草专卖零售许可证许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证许可类事项申请表, 营业执照, 身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 身份证明.身份证号 + - 身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 烟草专卖零售许可证许可类事项申请表.证件住址 + - 烟草专卖零售许可证许可类事项申请表.企业类型 + - 烟草专卖零售许可证许可类事项申请表.统一社会信用代码 + - 烟草专卖零售许可证许可类事项申请表.有效期限 + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 身份证明.姓名 + - 身份证明.性别 + - 身份证明.民族 + - 身份证明.住址 + - 身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 烟草专卖零售许可证受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 烟草专卖零售许可证实地核查记录表] + stages: + - {id: '1', check: contains, field: 烟草专卖零售许可证许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证实地核查记录表.标题 + - 烟草专卖零售许可证实地核查记录表.核查人员签名1 + - 烟草专卖零售许可证实地核查记录表.核查人员签名2 + - 烟草专卖零售许可证实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{烟草专卖零售许可证受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证.许可证号, 烟草专卖零售许可证.副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule diff --git a/rules/行政许可_恢复营业/rules.test.yaml b/rules/行政许可_恢复营业/rules.test.yaml new file mode 100644 index 0000000..147448a --- /dev/null +++ b/rules/行政许可_恢复营业/rules.test.yaml @@ -0,0 +1,5 @@ +# ═════════════════════════════════════════════════════════════════ +# 烟草专卖零售许可证-恢复营业办理 · 测试用例 +# ═════════════════════════════════════════════════════════════════ + +cases: [] diff --git a/rules/行政许可_恢复营业/rules.yaml b/rules/行政许可_恢复营业/rules.yaml new file mode 100644 index 0000000..68b17a0 --- /dev/null +++ b/rules/行政许可_恢复营业/rules.yaml @@ -0,0 +1,410 @@ +metadata: + type_id: 行政卷宗.行政许可.恢复营业 + name: 烟草专卖零售许可证-恢复营业办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [恢复营业, 烟草专卖零售许可证, 复业] + description: '烟草专卖零售许可证恢复营业办理卷宗审核(停业期满或提前复业)。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证颁发、送达、归档。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 烟草专卖零售许可证许可类事项申请表 + name: 烟草专卖零售许可证许可类事项申请表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 烟草专卖零售许可证许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + name: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 烟草专卖零售许可证受理单 + name: 烟草专卖零售许可证受理单 + required: true + classifier: {title_patterns: [烟草专卖零售许可证受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 烟草专卖零售许可证实地核查记录表 + name: 烟草专卖零售许可证实地核查记录表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证(正、副本) + name: 烟草专卖零售许可证(正、副本) + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 烟草专卖零售许可证许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证许可类事项申请表, 营业执照, 个体工商户经营者、法定代表人或其他组织负责人的身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 烟草专卖零售许可证许可类事项申请表.证件住址 + - 烟草专卖零售许可证许可类事项申请表.企业类型 + - 烟草专卖零售许可证许可类事项申请表.统一社会信用代码 + - 烟草专卖零售许可证许可类事项申请表.有效期限 + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.性别 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.民族 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.住址 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 烟草专卖零售许可证受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 烟草专卖零售许可证实地核查记录表] + stages: + - {id: '1', check: contains, field: 烟草专卖零售许可证许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证实地核查记录表.标题 + - 烟草专卖零售许可证实地核查记录表.核查人员签名1 + - 烟草专卖零售许可证实地核查记录表.核查人员签名2 + - 烟草专卖零售许可证实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{烟草专卖零售许可证受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证(正、副本)] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证(正、副本).许可证号, 烟草专卖零售许可证(正、副本).副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule diff --git a/rules/行政许可_收回/rules.test.yaml b/rules/行政许可_收回/rules.test.yaml new file mode 100644 index 0000000..08f2970 --- /dev/null +++ b/rules/行政许可_收回/rules.test.yaml @@ -0,0 +1 @@ +cases: [] diff --git a/rules/行政许可_收回/rules.yaml b/rules/行政许可_收回/rules.yaml new file mode 100644 index 0000000..34197d8 --- /dev/null +++ b/rules/行政许可_收回/rules.yaml @@ -0,0 +1,519 @@ +metadata: + type_id: 行政卷宗.行政许可.收回 + name: 烟草专卖零售许可证-收回办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [收回, 烟草专卖零售许可证, 依职权收回] + description: '烟草专卖零售许可证收回办理卷宗审核(行政机关依职权收回许可证)。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证处理、送达、归档、收回资料。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 许可类事项申请表 + name: 许可类事项申请表 + required: true + classifier: {title_patterns: [许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 身份证明 + name: 身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 受理单 + name: 受理单 + required: true + classifier: {title_patterns: [受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 实地核查记录表 + name: 实地核查记录表 + required: true + classifier: {title_patterns: [实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + - {name: 标题, type: verbatim, desc: 公告标题} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证正副本 + name: 烟草专卖零售许可证正副本 + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +- id: 内部沟通表 + name: 内部沟通表 + required: conditional + required_if: 卷宗封面.申请类型 contains "收回" + classifier: {title_patterns: [内部沟通表], keywords: [存在的主要问题及建议, 受理核查及处理结果, 处理结果跟踪及信息反馈], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 填报部门, type: verbatim, desc: 填报部门} + - group: 主要问题及建议 + fields: + - {name: 问题许可证号, type: verbatim, desc: 存在的主要问题及建议→许可证号} + - {name: 问题经营地址, type: verbatim, desc: 存在的主要问题及建议→经营地址} + - {name: 问题描述, type: string, desc: 存在的主要问题及建议→问题及建议描述} + - {name: 问题负责人签名, type: enum, allowed: [有, 无], desc: 存在的主要问题及建议→负责人签名 输出 有/无} + - group: 受理核查及处理结果 + fields: + - {name: 受理部门, type: verbatim, desc: 受理核查及处理结果→受理部门} + - {name: 处理结果, type: string, desc: 受理核查及处理结果→处理结果} + - {name: 受理负责人签名, type: enum, allowed: [有, 无], desc: 受理核查及处理结果→负责人签名 输出 有/无} + - group: 处理结果跟踪及信息反馈 + fields: + - {name: 反馈填报部门, type: verbatim, desc: 处理结果跟踪及信息反馈→填报部门} + - {name: 反馈内容, type: string, desc: 处理结果跟踪及信息反馈→信息反馈内容} + - {name: 反馈负责人签名, type: enum, allowed: [有, 无], desc: 处理结果跟踪及信息反馈→负责人签名 输出 有/无} + +- id: 情况反馈表 + name: 情况反馈表 + required: conditional + required_if: 卷宗封面.申请类型 contains "收回" + classifier: {title_patterns: [情况反馈表], keywords: [稽查大队长审核意见, 证件管理员核实情况], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 稽查大队长签名, type: enum, allowed: [有, 无], desc: 稽查大队长审核意见→负责人 输出 有/无} + - {name: 证件管理员签名, type: enum, allowed: [有, 无], desc: 证件管理员核实情况意见反馈→证件管理员 输出 有/无} + - {name: 卷烟营销负责人签名, type: enum, allowed: [有, 无], desc: 卷烟营销部门根据反馈情况确认→负责人 输出 有/无} + - {name: 稽查员签名, type: enum, allowed: [有, 无], desc: 稽查员实地核查情况处理确认→核查人 输出 有/无} + +- id: 职权办理审批表 + name: 职权办理审批表 + required: conditional + required_if: 卷宗封面.申请类型 contains "收回" + classifier: {title_patterns: [职权办理审批表, 依职权办理审批表], keywords: [承办人意见, 审核意见, 审批意见], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - {name: 承办人签名, type: enum, allowed: [有, 无], desc: 承办人意见→承办人 输出 有/无} + - {name: 审核人签名, type: enum, allowed: [有, 无], desc: 审核意见(无审核环节不填)→审核人 输出 有/无} + - {name: 法制负责人签名, type: enum, allowed: [有, 无], desc: 法制部门意见(无审核环节不填)→法制部门负责人 输出 有/无} + - {name: 审批人签名, type: enum, allowed: [有, 无], desc: 审批意见→审批人 输出 有/无} + +- id: 实地走访照片 + name: 实地走访照片 + required: conditional + required_if: 卷宗封面.申请类型 contains "收回" + classifier: {title_patterns: [实地走访照片, 走访照片], keywords: [照片], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 照片, type: verbatim, desc: 照片(有/无 或 描述)} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可类事项申请表, 营业执照, 身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 许可类事项申请表.企业名称 + - 许可类事项申请表.经营地址 + - 许可类事项申请表.经营者 + - 许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 身份证明.身份证号 + - 身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 许可类事项申请表.经营地址 + - 许可类事项申请表.经营者 + - 许可类事项申请表.证件号 + - 许可类事项申请表.证件住址 + - 许可类事项申请表.企业类型 + - 许可类事项申请表.统一社会信用代码 + - 许可类事项申请表.有效期限 + - 许可类事项申请表.企业名称 + - 许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 身份证明.姓名 + - 身份证明.性别 + - 身份证明.民族 + - 身份证明.住址 + - 身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [许可类事项申请表, 实地核查记录表] + stages: + - {id: '1', check: contains, field: 许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 实地核查记录表.标题 + - 实地核查记录表.核查人员签名1 + - 实地核查记录表.核查人员签名2 + - 实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证正副本] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证正副本.许可证号, 烟草专卖零售许可证正副本.副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule +- group: JZG-XK-SHW + rules: + - rule_id: JZ-XK-SHW-001 + name: 收回烟草专卖零售许可证资料完整性 + desc: 收回许可证需提供内部沟通表、情况反馈表、职权办理审批表及实地走访照片等资料,缺失则扣分。 + risk: low + score: 10 + scope: [内部沟通表, 情况反馈表, 公告, 职权办理审批表, 实地走访照片, 卷宗封面] + stages: + - id: '1' + check: required + fields: + - 内部沟通表.填报部门 + - 内部沟通表.问题许可证号 + - 内部沟通表.问题经营地址 + - 内部沟通表.问题描述 + - 内部沟通表.受理部门 + - 内部沟通表.处理结果 + - 内部沟通表.反馈填报部门 + - 内部沟通表.反馈内容 + - 情况反馈表.许可证号 + - 职权办理审批表.标题 + - 公告.标题 + - 内部沟通表.问题负责人签名 + - 内部沟通表.受理负责人签名 + - 内部沟通表.反馈负责人签名 + - 职权办理审批表.承办人签名 + - 职权办理审批表.审核人签名 + - 职权办理审批表.法制负责人签名 + - 职权办理审批表.审批人签名 + - 实地走访照片.照片 + - 情况反馈表.稽查员签名 + - 情况反馈表.卷烟营销负责人签名 + - 情况反馈表.证件管理员签名 + - 情况反馈表.稽查大队长签名 + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 AND 2) OR (NOT 2) AND 3 + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第四十五条, 《烟草专卖许可证管理办法》第五十条] + remediation: + suggestions: + - 收回许可证需提供内部沟通表、情况反馈表、职权办理审批表及实地走访照片等资料,缺失则扣分。 + type: deterministic diff --git a/rules/行政许可_新办/rules.test.yaml b/rules/行政许可_新办/rules.test.yaml new file mode 100644 index 0000000..08f2970 --- /dev/null +++ b/rules/行政许可_新办/rules.test.yaml @@ -0,0 +1 @@ +cases: [] diff --git a/rules/行政许可_新办/rules.yaml b/rules/行政许可_新办/rules.yaml new file mode 100644 index 0000000..1ea73bc --- /dev/null +++ b/rules/行政许可_新办/rules.yaml @@ -0,0 +1,410 @@ +metadata: + type_id: 行政卷宗.行政许可.新办 + name: 烟草专卖零售许可证-新办办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [新办, 烟草专卖零售许可证, 新申请, 申领] + description: '烟草专卖零售许可证新办办理卷宗审核(首次申领)。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证颁发、送达、归档。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 申请表 + name: 申请表 + required: true + classifier: {title_patterns: [申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 身份证明 + name: 身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 受理单 + name: 受理单 + required: true + classifier: {title_patterns: [受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 实地核查记录表 + name: 实地核查记录表 + required: true + classifier: {title_patterns: [实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 许可证 + name: 许可证 + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [申请表, 委托书] + stages: + - {id: '1', check: required, field: 申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 申请表, 营业执照, 身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 申请表.企业名称 + - 申请表.经营地址 + - 申请表.经营者 + - 申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 身份证明.身份证号 + - 身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 申请表.经营地址 + - 申请表.经营者 + - 申请表.证件号 + - 申请表.证件住址 + - 申请表.企业类型 + - 申请表.统一社会信用代码 + - 申请表.有效期限 + - 申请表.企业名称 + - 申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 身份证明.姓名 + - 身份证明.性别 + - 身份证明.民族 + - 身份证明.住址 + - 身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [申请表, 实地核查记录表] + stages: + - {id: '1', check: contains, field: 申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 实地核查记录表.标题 + - 实地核查记录表.核查人员签名1 + - 实地核查记录表.核查人员签名2 + - 实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可证] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [许可证.许可证号, 许可证.副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule diff --git a/rules/行政许可_歇业/rules.test.yaml b/rules/行政许可_歇业/rules.test.yaml new file mode 100644 index 0000000..08f2970 --- /dev/null +++ b/rules/行政许可_歇业/rules.test.yaml @@ -0,0 +1 @@ +cases: [] diff --git a/rules/行政许可_歇业/rules.yaml b/rules/行政许可_歇业/rules.yaml new file mode 100644 index 0000000..0de62fc --- /dev/null +++ b/rules/行政许可_歇业/rules.yaml @@ -0,0 +1,410 @@ +metadata: + type_id: 行政卷宗.行政许可.歇业 + name: 烟草专卖零售许可证-歇业办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [歇业, 烟草专卖零售许可证, 歇业申请] + description: '烟草专卖零售许可证歇业办理卷宗审核。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证处理、送达、归档。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 烟草专卖零售许可证许可类事项申请表 + name: 烟草专卖零售许可证许可类事项申请表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 烟草专卖零售许可证许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + name: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 烟草专卖零售许可证受理单 + name: 烟草专卖零售许可证受理单 + required: true + classifier: {title_patterns: [烟草专卖零售许可证受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 烟草专卖零售许可证实地核查记录表 + name: 烟草专卖零售许可证实地核查记录表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证(正、副本) + name: 烟草专卖零售许可证(正、副本) + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 烟草专卖零售许可证许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证许可类事项申请表, 营业执照, 个体工商户经营者、法定代表人或其他组织负责人的身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 烟草专卖零售许可证许可类事项申请表.证件住址 + - 烟草专卖零售许可证许可类事项申请表.企业类型 + - 烟草专卖零售许可证许可类事项申请表.统一社会信用代码 + - 烟草专卖零售许可证许可类事项申请表.有效期限 + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.性别 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.民族 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.住址 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 烟草专卖零售许可证受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 烟草专卖零售许可证实地核查记录表] + stages: + - {id: '1', check: contains, field: 烟草专卖零售许可证许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证实地核查记录表.标题 + - 烟草专卖零售许可证实地核查记录表.核查人员签名1 + - 烟草专卖零售许可证实地核查记录表.核查人员签名2 + - 烟草专卖零售许可证实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{烟草专卖零售许可证受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证(正、副本)] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证(正、副本).许可证号, 烟草专卖零售许可证(正、副本).副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule diff --git a/rules/行政许可_注销/rules.test.yaml b/rules/行政许可_注销/rules.test.yaml new file mode 100644 index 0000000..315cd9d --- /dev/null +++ b/rules/行政许可_注销/rules.test.yaml @@ -0,0 +1,6 @@ +# ═════════════════════════════════════════════════════════════════ +# 烟草专卖零售许可证-注销办理 · 测试夹具 +# ═════════════════════════════════════════════════════════════════ +# 对应规则文件: rules.yaml + +cases: [] diff --git a/rules/行政许可_注销/rules.yaml b/rules/行政许可_注销/rules.yaml new file mode 100644 index 0000000..3dc6d11 --- /dev/null +++ b/rules/行政许可_注销/rules.yaml @@ -0,0 +1,451 @@ +metadata: + type_id: 行政卷宗.行政许可.注销 + name: 烟草专卖零售许可证-注销办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [注销, 烟草专卖零售许可证, 注销申请] + description: '烟草专卖零售许可证注销办理卷宗审核。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证处理、送达、归档、注销审批。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 烟草专卖零售许可证许可类事项申请表 + name: 烟草专卖零售许可证许可类事项申请表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 烟草专卖零售许可证许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + name: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 烟草专卖零售许可证受理单 + name: 烟草专卖零售许可证受理单 + required: true + classifier: {title_patterns: [烟草专卖零售许可证受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 烟草专卖零售许可证实地核查记录表 + name: 烟草专卖零售许可证实地核查记录表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证(正、副本) + name: 烟草专卖零售许可证(正、副本) + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +- id: 烟草专卖许可证依职权办理审批表 + name: 烟草专卖许可证依职权办理审批表 + required: conditional + required_if: 卷宗封面.申请类型 contains "注销" + classifier: {title_patterns: [烟草专卖许可证依职权办理审批表, 依职权办理审批表], keywords: [持证人基本信息, 内部审批意见], min_score: 0.5} + extract: + - group: 持证人 + fields: + - {name: 许可证号, type: verbatim, desc: 持证人基本信息→许可证号} + - {name: 许可证有效期, type: verbatim, desc: 持证人基本信息→许可证有效期} + - group: 内部审批 + fields: + - {name: 承办人签名, type: enum, allowed: [有, 无], desc: 内部审批意见→承办人意见→承办人 输出 有/无} + - {name: 审核人签名, type: enum, allowed: [有, 无], desc: 内部审批意见→审核意见→审核人 输出 有/无} + - {name: 法制负责人签名, type: enum, allowed: [有, 无], desc: 内部审批意见→法制部门意见→法制部门负责人 输出 有/无} + - {name: 审批人签名, type: enum, allowed: [有, 无], desc: 内部审批意见→审批意见→审批人 输出 有/无} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 烟草专卖零售许可证许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证许可类事项申请表, 营业执照, 个体工商户经营者、法定代表人或其他组织负责人的身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 烟草专卖零售许可证许可类事项申请表.证件住址 + - 烟草专卖零售许可证许可类事项申请表.企业类型 + - 烟草专卖零售许可证许可类事项申请表.统一社会信用代码 + - 烟草专卖零售许可证许可类事项申请表.有效期限 + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.性别 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.民族 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.住址 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 烟草专卖零售许可证受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 烟草专卖零售许可证实地核查记录表] + stages: + - {id: '1', check: contains, field: 烟草专卖零售许可证许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证实地核查记录表.标题 + - 烟草专卖零售许可证实地核查记录表.核查人员签名1 + - 烟草专卖零售许可证实地核查记录表.核查人员签名2 + - 烟草专卖零售许可证实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{烟草专卖零售许可证受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证(正、副本)] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证(正、副本).许可证号, 烟草专卖零售许可证(正、副本).副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule +- group: JZG-XK-ZX + rules: + - rule_id: JZ-XK-ZX-001 + name: 注销烟草专卖零售许可证审批表合规性 + desc: 注销许可需填写依职权办理审批表,包含许可证号、有效期及各级审批人签名,缺失则扣分。 + risk: medium + score: 5 + scope: [卷宗封面, 烟草专卖许可证依职权办理审批表] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销]} + - id: '2' + check: required + fields: + - 烟草专卖许可证依职权办理审批表.许可证号 + - 烟草专卖许可证依职权办理审批表.许可证有效期 + - 烟草专卖许可证依职权办理审批表.承办人签名 + - 烟草专卖许可证依职权办理审批表.审核人签名 + - 烟草专卖许可证依职权办理审批表.法制负责人签名 + - 烟草专卖许可证依职权办理审批表.审批人签名 + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 AND 2) OR (NOT 1) AND 3 + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第四十八条] + type: deterministic diff --git a/rules/行政许可_补办/rules.test.yaml b/rules/行政许可_补办/rules.test.yaml new file mode 100644 index 0000000..22315ab --- /dev/null +++ b/rules/行政许可_补办/rules.test.yaml @@ -0,0 +1,2 @@ +# 烟草专卖零售许可证-补办办理 · 测试夹具 +cases: [] diff --git a/rules/行政许可_补办/rules.yaml b/rules/行政许可_补办/rules.yaml new file mode 100644 index 0000000..15f1bef --- /dev/null +++ b/rules/行政许可_补办/rules.yaml @@ -0,0 +1,410 @@ +metadata: + type_id: 行政卷宗.行政许可.补办 + name: 烟草专卖零售许可证-补办办理 + version: '1.0' + last_updated: '2026-04-18' + parent: 行政卷宗.行政许可 + inherits_from: [base.common, base.administrative_case] + classification_keywords: [补办, 烟草专卖零售许可证, 补办申请, 遗失] + description: '烟草专卖零售许可证补办办理卷宗审核(许可证遗失后补发)。 + + 覆盖:申请材料、受理、实地核查、审批决定、许可证颁发、送达、归档。 + + ' +sub_documents: + +- id: 卷宗封面 + name: 卷宗封面 + required: true + classifier: {title_patterns: [卷宗封面], keywords: [办理类型, 依申请办理, 行政决定], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 办理类型→依申请办理→申请类型} + - {name: 行政决定, type: verbatim, desc: 办理类型→依申请办理→行政决定} + - {name: 行政决定日期, type: date, desc: 办理类型→依申请办理→行政决定作出日期} + +- id: 烟草专卖零售许可证许可类事项申请表 + name: 烟草专卖零售许可证许可类事项申请表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证许可类事项申请表, 许可类事项申请表], keywords: [申请事项基本信息, 申请人基本信息], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请类型, type: verbatim, desc: 申请类型} + - {name: 联系人, type: verbatim, desc: 申请事项基本信息→联系人} + - {name: 委托代理人, type: verbatim, desc: 申请事项基本信息→委托代理人} + - group: 申请人 + fields: + - {name: 企业名称, type: verbatim, desc: 申请人基本信息→企业名称/个体工商户字号} + - {name: 企业类型, type: verbatim, desc: 申请人基本信息→企业类型} + - {name: 群体类型, type: verbatim, desc: 申请人基本信息→群体类型} + - {name: 经营者, type: verbatim, desc: 申请人基本信息→经营者/法定代表人(负责人)} + - {name: 证件号, type: verbatim, desc: 申请人基本信息→证件类型及号码} + - {name: 证件住址, type: verbatim, desc: 申请人基本信息→证件登记住址} + - {name: 经营地址, type: verbatim, desc: 申请人基本信息→经营地址} + - {name: 有效期限, type: verbatim, desc: 申请人基本信息→有效期限} + - {name: 统一社会信用代码, type: uscc, desc: 申请人基本信息→统一社会信用代码/注册号} + +- id: 委托书 + name: 授权委托书 + required: conditional + required_if: 烟草专卖零售许可证许可类事项申请表.委托代理人 != null + classifier: {title_patterns: [委托书, 授权委托书], keywords: [兹委托, 被授权委托人], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 被授权委托人, type: verbatim, desc: 被授权委托人(乙方)} + +- id: 营业执照 + name: 营业执照 + required: true + classifier: {title_patterns: [营业执照], keywords: [统一社会信用代码, 营业执照, 经营场所], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 名称, type: verbatim, desc: 名称} + - {name: 类型, type: verbatim, desc: 类型} + - {name: 经营者, type: verbatim, desc: 经营者} + - {name: 经营场所, type: verbatim, desc: 经营场所} + - {name: 注册日期, type: date, desc: 注册日期} + - {name: 统一社会信用代码, type: uscc, desc: 统一社会信用代码/注册号} + +- id: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + name: 个体工商户经营者、法定代表人或其他组织负责人的身份证明 + required: true + classifier: {title_patterns: [身份证, 居民身份证], keywords: [中华人民共和国居民身份证, 公民身份号码], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 姓名, type: verbatim, desc: 姓名} + - {name: 性别, type: enum, allowed: [男, 女], desc: 性别} + - {name: 民族, type: verbatim, desc: 民族} + - {name: 住址, type: verbatim, desc: 住址} + - {name: 身份证号, type: chinese-id, desc: 公民身份号码} + +- id: 烟草专卖零售许可证受理单 + name: 烟草专卖零售许可证受理单 + required: true + classifier: {title_patterns: [烟草专卖零售许可证受理单, 受理单], keywords: [签收时间, 承诺办结时限], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 签收时间, type: date, desc: 签收时间} + - {name: 承诺办结时限, type: verbatim, desc: 说明→承诺办结时限} + +- id: 烟草专卖零售许可证实地核查记录表 + name: 烟草专卖零售许可证实地核查记录表 + required: true + classifier: {title_patterns: [烟草专卖零售许可证实地核查记录表, 实地核查记录表], keywords: [核查人员, 被核查方], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + - group: 签名 + fields: + - {name: 核查人员签名1, type: enum, allowed: [有, 无], desc: 核查人员→签名1 输出 有/无} + - {name: 核查人员签名2, type: enum, allowed: [有, 无], desc: 核查人员→签名2 输出 有/无} + - {name: 被核查方签名, type: enum, allowed: [有, 无], desc: 被核查方→签名 输出 有/无} + +- id: 许可决定书 + name: 许可决定书 + required: true + classifier: {title_patterns: [许可决定书, 准予许可决定书], keywords: [决定如下, 落款], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 申请日期, type: date, desc: 申请日期} + - {name: 正文日期, type: date, desc: 正文→日期} + - {name: 落款日期, type: date, desc: 落款→日期} + +- id: 送达回证 + name: 送达回证 + required: true + classifier: {title_patterns: [送达回证], keywords: [送达日期, 送达地点, 文书送达方式], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 受送达人, type: verbatim, desc: 受送达人} + - {name: 送达方式, type: verbatim, desc: 文书送达方式} + - {name: 送达文书名称, type: verbatim, desc: 送达内容→送达文书名称} + - {name: 送达文书编号, type: verbatim, desc: 送达内容→送达文书编号} + - {name: 送达地点, type: verbatim, desc: 送达地点} + - {name: 送达日期, type: date, desc: 送达日期} + - group: 签收 + fields: + - {name: 收件人签名, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→签名 输出 有/无} + - {name: 收件人盖章, type: enum, allowed: [有, 无], desc: 受送达人(签字或盖章)→盖章 输出 有/无} + - group: 送达人 + fields: + - {name: 送达人签名1, type: enum, allowed: [有, 无], desc: 送达人→签名1 输出 有/无} + - {name: 送达人签名2, type: enum, allowed: [有, 无], desc: 送达人→签名2 输出 有/无} + +- id: 挂号信回执 + name: 挂号信回执 + required: true + classifier: {title_patterns: [挂号信回执], keywords: [挂号信], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 正文, type: string, desc: 挂号信回执正文} + +- id: 公告 + name: 公告 + required: true + classifier: {title_patterns: [公告], keywords: [公告编号], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 编号, type: verbatim, desc: 公告编号} + +- id: 延长审批期限批准书 + name: 延长审批期限批准书 + required: true + classifier: {title_patterns: [延长审批期限批准书], keywords: [延长审批, 批准], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 标题, type: verbatim, desc: 标题} + +- id: 烟草专卖零售许可证(正、副本) + name: 烟草专卖零售许可证(正、副本) + required: true + classifier: {title_patterns: [烟草专卖零售许可证], keywords: [许可证号, 副本], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 许可证号, type: verbatim, desc: 许可证号} + - {name: 副本, type: verbatim, desc: 副本标识(是否为副本)} + +- id: 卷内备考表 + name: 卷内备考表 + required: true + classifier: {title_patterns: [卷内备考表], keywords: [立卷时间], min_score: 0.5} + extract: + - group: 基本信息 + fields: + - {name: 立卷时间, type: date, desc: 立卷时间} + +rules: +- group: JZG-XK-SQ + rules: + - rule_id: JZ-XK-SQ-001 + name: 代理人授权委托书文件校验 + desc: 若未找到授权委托书,则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 委托书] + stages: + - {id: '1', check: required, field: 烟草专卖零售许可证许可类事项申请表.委托代理人} + - {id: '2', check: required, field: 委托书.被授权委托人} + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.联系人} + logic: (3 AND (NOT 1)) OR (1 AND 2) + messages: {pass: 找到对应的授权委托书。, fail: 未出具授权委托书,请核对。} + references_laws: [《烟草专卖许可证管理办法》第九条, 《烟草专卖许可证管理办法》第四十一条] + type: deterministic + - rule_id: JZ-XK-SQ-002 + name: 申请人主体资格材料完整性 + desc: 若对应的资格材料文件不存在,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证许可类事项申请表, 营业执照, 个体工商户经营者、法定代表人或其他组织负责人的身份证明] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, any_of: [补办, 歇业, 停业, 恢复营业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 营业执照.名称 + - {id: '3', check: contains, field: 卷宗封面.申请类型, any_of: [新办, 延续, 变更]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证许可类事项申请表.经营地址 + - 烟草专卖零售许可证许可类事项申请表.经营者 + - 烟草专卖零售许可证许可类事项申请表.证件号 + - 烟草专卖零售许可证许可类事项申请表.证件住址 + - 烟草专卖零售许可证许可类事项申请表.企业类型 + - 烟草专卖零售许可证许可类事项申请表.统一社会信用代码 + - 烟草专卖零售许可证许可类事项申请表.有效期限 + - 烟草专卖零售许可证许可类事项申请表.企业名称 + - 烟草专卖零售许可证许可类事项申请表.群体类型 + - 营业执照.名称 + - 营业执照.统一社会信用代码 + - 营业执照.注册日期 + - 营业执照.类型 + - 营业执照.经营场所 + - 营业执照.经营者 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.姓名 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.性别 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.民族 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.住址 + - 个体工商户经营者、法定代表人或其他组织负责人的身份证明.身份证号 + - {id: '5', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (3 AND 4) OR (NOT (1 AND 3))) AND 5 + messages: {pass: 申请人主体资格材料齐全,请进一步检查准确性。, fail: 申请人主体资格材料不齐全,请核对。} + references_laws: [《烟草专卖许可证管理办法》第十三条, 《烟草专卖许可证管理办法》第二十一条] + type: deterministic +- group: JZG-XK-SL + rules: + - rule_id: JZ-XK-SL-001 + name: 受理通知书日期记载准确性 + desc: 若签收时间处没有完整手写年月日,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [注销, 收回]} + - {id: '2', check: required, field: 烟草专卖零售许可证受理单.签收时间} + logic: ((NOT 1) AND 2) OR 1 + messages: {pass: 受理通知书日期记载完整。, fail: 受理通知书日期记载不准确,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十一条, 《烟草专卖许可证管理办法》第二十二条] + type: deterministic +- group: JZG-XK-HC + rules: + - rule_id: JZ-XK-HC-001 + name: 实地核查执法人员人数合规性 + desc: 新办、延续、变更、恢复营业、歇业类许可需实地核查,核查记录表应至少有两名执法人员签名及被核查方签名,缺少则扣分。 + risk: medium + score: 10 + scope: [烟草专卖零售许可证许可类事项申请表, 烟草专卖零售许可证实地核查记录表] + stages: + - {id: '1', check: contains, field: 烟草专卖零售许可证许可类事项申请表.申请类型, any_of: [新办, 延续, 变更, 恢复营业, 歇业]} + - id: '2' + check: required + fields: + - 烟草专卖零售许可证实地核查记录表.标题 + - 烟草专卖零售许可证实地核查记录表.核查人员签名1 + - 烟草专卖零售许可证实地核查记录表.核查人员签名2 + - 烟草专卖零售许可证实地核查记录表.被核查方签名 + - {id: '3', check: required, field: 烟草专卖零售许可证许可类事项申请表.申请类型} + logic: 1 OR ((NOT 1) AND 2) AND 3 + messages: {pass: 无需实地核查或实地核查执法人员人数符合要求。, fail: 缺少实地核查记录表或实地核查执法人员人数不足,应至少有两名执法人员,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: deterministic +- group: JZG-XK-SP + rules: + - rule_id: JZ-XK-SP-001 + name: 烟草专卖许可证颁发时效合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 许可决定书, 送达回证] + stages: + - id: '1' + check: ai + prompt: '请判断 {{送达回证.送达日期}} 是否晚于 {{许可决定书.落款日期}},且差值小于10天; + + 若早于或差值大于10天为不符合。 + + ' + - {id: '2', check: contains, field: 卷宗封面.申请类型, value: 收回} + - {id: '3', check: required, field: 卷宗封面.申请类型} + logic: (1 OR 2) AND 3 + messages: {pass: 烟草专卖许可证已在规定时效内颁发。, fail: 烟草专卖许可证颁发超出规定时效,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule + - rule_id: JZ-XK-SP-002 + name: 延长审批期限告知文件校验 + desc: 若未找到延长审批期限告知书,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证受理单, 延长审批期限批准书, 许可决定书] + stages: + - id: '1' + check: ai + prompt: '请判断 {{许可决定书.落款日期}} 减去 {{许可决定书.正文日期}}, + + 是否在 {{烟草专卖零售许可证受理单.承诺办结时限}} 的工作日数内, + + 差值超过承诺办结时间为不符合。 + + ' + - {id: '2', check: required, field: 延长审批期限批准书.标题} + - {id: '3', check: contains, field: 卷宗封面.申请类型, none_of: [注销, 收回]} + - id: '4' + check: required + fields: + - 烟草专卖零售许可证受理单.承诺办结时限 + - 卷宗封面.申请类型 + - 卷宗封面.行政决定 + - 许可决定书.落款日期 + - 许可决定书.正文日期 + logic: 1 OR ((NOT 1) AND 2) OR (3 AND 4) + messages: {pass: 文档检查通过,符合规范要求。, fail: 文档存在以下问题,请修改后重新提交。} + references_laws: [《烟草专卖许可证管理办法》第二十三条] + type: ai_rule +- group: JZG-XK-XZ + rules: + - rule_id: JZ-XK-XZ-001 + name: 烟草专卖许可证颁发合规性 + desc: 若所有许可证图片中,均未找到"副本"字样,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 烟草专卖零售许可证(正、副本)] + stages: + - {id: '1', check: contains, field: 卷宗封面.申请类型, all_of: [新办, 补办, 延续, 变更]} + - {id: '2', check: required, fields: [烟草专卖零售许可证(正、副本).许可证号, 烟草专卖零售许可证(正、副本).副本]} + - {id: '3', check: required, fields: [卷宗封面.申请类型, 卷宗封面.行政决定]} + logic: ((1 AND 2) OR (NOT 1)) AND 3 + messages: {pass: 已颁发加盖印章的烟草专卖许可证正副本。, fail: 未全部颁发加盖印章的烟草专卖许可证,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第二十四条] + type: deterministic +- group: JZG-XK-SD + rules: + - rule_id: JZ-XK-SD-001 + name: 送达回证信息完整性 + desc: 若基础字段有漏填,则扣分。 若受送达人处无签名或盖章,则扣分。 + risk: medium + score: 10 + scope: [送达回证, 挂号信回执, 公告] + stages: + - id: '1' + check: required + fields: + - 送达回证.受送达人 + - 送达回证.送达文书名称 + - 送达回证.送达文书编号 + - 送达回证.送达日期 + - 送达回证.送达地点 + - 送达回证.送达人签名1 + - 送达回证.送达人签名2 + - {id: '2', check: contains, field: 送达回证.送达方式, any_of: [直接送达, 代收送达, 留置送达]} + - {id: '3', check: required, fields: [送达回证.收件人签名, 送达回证.收件人盖章], logic: or} + - {id: '4', check: contains, field: 送达回证.送达方式, value: 公告送达} + - {id: '5', check: required, field: 公告.编号} + - {id: '6', check: contains, field: 送达回证.送达方式, value: 挂号信} + - {id: '7', check: required, field: 挂号信回执.正文} + logic: 1 AND (2 AND 3) OR (4 AND 5) OR (6 AND 7) + messages: {pass: 送达回证填写完整。, fail: 送达回证填写不完整,请核对。} + references_laws: [《烟草专卖许可证管理办法》第二十三条, 《烟草专卖许可证管理办法》第六十一条] + type: deterministic +- group: JZG-XK-GD + rules: + - rule_id: JZ-XK-GD-001 + name: 行政许可案件归档合规性 + desc: 若两个时间之间的差值大于60天,则扣分。 + risk: medium + score: 10 + scope: [卷宗封面, 卷内备考表] + stages: + - id: '1' + check: ai + prompt: '请判断 {{卷内备考表.立卷时间}} 是否晚于 {{卷宗封面.行政决定日期}}, + + 且差值小于60天;早于或差值超过60天为不符合。 + + ' + messages: {pass: 行政许可案件已及时归档并制作案卷。, fail: 行政许可案件未及时归档,请核对。} + references_laws: [《烟草专卖许可证管理办法》第三十八条] + type: ai_rule diff --git a/run.py b/run.py new file mode 100644 index 0000000..1d1e5a3 --- /dev/null +++ b/run.py @@ -0,0 +1,20 @@ +"""开发启动脚本。""" + +from __future__ import annotations + +import uvicorn + +from fastapi_admin.config import APP_HOST, APP_PORT + + +def main(): + uvicorn.run( + "fastapi_admin.app:app", + host=APP_HOST, + port=APP_PORT, + reload=True, + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/schema_v2_add_evaluation_tables.sql b/scripts/schema_v2_add_evaluation_tables.sql new file mode 100644 index 0000000..6b2035f --- /dev/null +++ b/scripts/schema_v2_add_evaluation_tables.sql @@ -0,0 +1,557 @@ +-- ============================================================================ +-- LeAudit Platform — 补充评查点规则组、规则点、文档类型、入口模块表 +-- + 全部表中文注释补充 +-- 数据库: leaudit_platform @ nas.7bm.co:54302 +-- ============================================================================ + +BEGIN; + +-- ============================================================================ +-- 1. 新表:入口模块 (leaudit_entry_modules) +-- ============================================================================ +CREATE TABLE IF NOT EXISTS leaudit_entry_modules ( + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + name VARCHAR(100) NOT NULL UNIQUE, + description TEXT, + path VARCHAR(255), + icon_path VARCHAR(255), + areas JSONB, + sort_order INTEGER NOT NULL DEFAULT 0, + is_enabled BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +COMMENT ON TABLE leaudit_entry_modules IS '入口模块表 — 定义前端导航入口菜单及其区域配置'; + +COMMENT ON COLUMN leaudit_entry_modules.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_entry_modules.name IS '入口模块名称,唯一且非空'; +COMMENT ON COLUMN leaudit_entry_modules.description IS '模块描述'; +COMMENT ON COLUMN leaudit_entry_modules.path IS '前端路由路径'; +COMMENT ON COLUMN leaudit_entry_modules.icon_path IS '入口菜单图标OSS路径'; +COMMENT ON COLUMN leaudit_entry_modules.areas IS '区域配置JSON,格式: [{"area":"梅州","enabled":true,"sort_order":1}]'; +COMMENT ON COLUMN leaudit_entry_modules.sort_order IS '排序序号'; +COMMENT ON COLUMN leaudit_entry_modules.is_enabled IS '是否启用'; +COMMENT ON COLUMN leaudit_entry_modules.created_at IS '创建时间'; +COMMENT ON COLUMN leaudit_entry_modules.updated_at IS '更新时间'; + + +-- ============================================================================ +-- 2. 新表:文档类型定义 (leaudit_document_types) +-- ============================================================================ +CREATE TABLE IF NOT EXISTS leaudit_document_types ( + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + code VARCHAR(100) UNIQUE, + name VARCHAR(100) NOT NULL, + description TEXT, + entry_module_id BIGINT, + classification_keywords JSONB, + classification_tags JSONB, + extraction_mode VARCHAR(20) NOT NULL DEFAULT 'single', + prompt_config JSONB, + is_enabled BOOLEAN NOT NULL DEFAULT true, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + deleted_at TIMESTAMPTZ +); + +COMMENT ON TABLE leaudit_document_types IS '文档类型定义表 — 定义系统支持的文档类型及其分类/抽取配置'; + +COMMENT ON COLUMN leaudit_document_types.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_document_types.code IS '文档类型编码,唯一,对应DSL的type_id(如 contract.entrust)'; +COMMENT ON COLUMN leaudit_document_types.name IS '文档类型名称'; +COMMENT ON COLUMN leaudit_document_types.description IS '类型描述'; +COMMENT ON COLUMN leaudit_document_types.entry_module_id IS '所属入口模块ID,外键引用 leaudit_entry_modules.id'; +COMMENT ON COLUMN leaudit_document_types.classification_keywords IS '分类关键词JSON,用于自动识别文档类型'; +COMMENT ON COLUMN leaudit_document_types.classification_tags IS '分类标签JSON,用于前端筛选展示'; +COMMENT ON COLUMN leaudit_document_types.extraction_mode IS '抽取模式: single(单实体) | multi_entity(多实体) | case_file(案卷)'; +COMMENT ON COLUMN leaudit_document_types.prompt_config IS '提示词配置JSON,覆盖默认的LLM提示词模板'; +COMMENT ON COLUMN leaudit_document_types.is_enabled IS '是否启用'; +COMMENT ON COLUMN leaudit_document_types.sort_order IS '排序序号'; +COMMENT ON COLUMN leaudit_document_types.created_at IS '创建时间'; +COMMENT ON COLUMN leaudit_document_types.updated_at IS '更新时间'; +COMMENT ON COLUMN leaudit_document_types.deleted_at IS '软删除时间,NULL表示未删除'; + + +-- ============================================================================ +-- 3. 新表:评查点规则组 (leaudit_evaluation_point_groups) +-- ============================================================================ +CREATE TABLE IF NOT EXISTS leaudit_evaluation_point_groups ( + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + pid BIGINT, + code VARCHAR(50) NOT NULL UNIQUE, + name VARCHAR(100) NOT NULL, + description TEXT, + rule_set_id BIGINT, + sort_order INTEGER NOT NULL DEFAULT 0, + is_enabled BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + deleted_at TIMESTAMPTZ +); + +COMMENT ON TABLE leaudit_evaluation_point_groups IS '评查点规则组表 — 评查点的树形分组结构,支持PID层级嵌套'; + +COMMENT ON COLUMN leaudit_evaluation_point_groups.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.pid IS '父级分组ID,NULL表示根节点,自引用外键'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.code IS '分组编码,全局唯一,用于前后端识别'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.name IS '分组名称'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.description IS '分组描述'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.rule_set_id IS '关联的规则集ID,外键引用 leaudit_rule_sets.id'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.sort_order IS '同级排序序号'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.is_enabled IS '是否启用'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.created_at IS '创建时间'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.updated_at IS '更新时间'; +COMMENT ON COLUMN leaudit_evaluation_point_groups.deleted_at IS '软删除时间,NULL表示未删除'; + + +-- ============================================================================ +-- 4. 新表:规则点/评查点 (leaudit_evaluation_points) +-- ============================================================================ +CREATE TABLE IF NOT EXISTS leaudit_evaluation_points ( + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + group_id BIGINT NOT NULL, + code VARCHAR(100) NOT NULL UNIQUE, + name VARCHAR(200) NOT NULL, + rule_set_id BIGINT, + rule_id VARCHAR(100), + risk VARCHAR(10) NOT NULL DEFAULT 'medium', + score NUMERIC(5,2) NOT NULL DEFAULT 0, + description TEXT, + is_enabled BOOLEAN NOT NULL DEFAULT true, + is_system BOOLEAN NOT NULL DEFAULT false, + evaluation_type VARCHAR(20) NOT NULL DEFAULT 'boolean', + pass_threshold INTEGER DEFAULT 60, + scoring_config JSONB, + pass_message TEXT, + fail_message TEXT, + suggestion_message TEXT, + suggestion_message_type VARCHAR(20) DEFAULT 'warning', + references_laws JSONB, + post_action VARCHAR(50), + action_config TEXT, + document_attribute_type VARCHAR(20) DEFAULT 'ALL', + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + deleted_at TIMESTAMPTZ +); + +COMMENT ON TABLE leaudit_evaluation_points IS '规则点(评查点)表 — 评查点的完整元数据定义,与DSL YAML中的rule一一对应'; + +COMMENT ON COLUMN leaudit_evaluation_points.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_evaluation_points.group_id IS '所属分组ID,外键引用 leaudit_evaluation_point_groups.id'; +COMMENT ON COLUMN leaudit_evaluation_points.code IS '规则点编码,全局唯一(对应DSL YAML中的 rule_id)'; +COMMENT ON COLUMN leaudit_evaluation_points.name IS '规则点名称'; +COMMENT ON COLUMN leaudit_evaluation_points.rule_set_id IS '所属规则集ID,外键引用 leaudit_rule_sets.id'; +COMMENT ON COLUMN leaudit_evaluation_points.rule_id IS 'DSL YAML文件中的原始 rule_id,用于跨系统关联'; +COMMENT ON COLUMN leaudit_evaluation_points.risk IS '风险等级: high(高) | medium(中) | low(低)'; +COMMENT ON COLUMN leaudit_evaluation_points.score IS '评查点分值权重'; +COMMENT ON COLUMN leaudit_evaluation_points.description IS '规则点详细描述'; +COMMENT ON COLUMN leaudit_evaluation_points.is_enabled IS '是否启用,禁用后该规则在所有评查中被跳过'; +COMMENT ON COLUMN leaudit_evaluation_points.is_system IS '是否为系统级规则点,系统级对用户隐藏,仅用于内部逻辑判断'; +COMMENT ON COLUMN leaudit_evaluation_points.evaluation_type IS '评查类型: boolean(传统PASS/FAIL判定) | scored(权重积分制)'; +COMMENT ON COLUMN leaudit_evaluation_points.pass_threshold IS '通过阈值(百分比),仅scored类型使用,默认60'; +COMMENT ON COLUMN leaudit_evaluation_points.scoring_config IS '分数配置JSON,仅scored类型使用。结构: {field_weights: {字段名: {weight: 分值, section: 分组}}, pass_threshold: 60}'; +COMMENT ON COLUMN leaudit_evaluation_points.pass_message IS '通过时的反馈文案'; +COMMENT ON COLUMN leaudit_evaluation_points.fail_message IS '不通过时的反馈文案'; +COMMENT ON COLUMN leaudit_evaluation_points.suggestion_message IS '修正建议文案'; +COMMENT ON COLUMN leaudit_evaluation_points.suggestion_message_type IS '建议类型: info(信息) | warning(警告) | error(错误)'; +COMMENT ON COLUMN leaudit_evaluation_points.references_laws IS '引用法典列表JSON,如 ["《民法典》第467条","《民法典》第470条"]'; +COMMENT ON COLUMN leaudit_evaluation_points.post_action IS '评查后动作: none(无) | manual(人工复核) | replace(自动替换)'; +COMMENT ON COLUMN leaudit_evaluation_points.action_config IS '动作配置文本,配合 post_action 使用'; +COMMENT ON COLUMN leaudit_evaluation_points.document_attribute_type IS '适用文档属性: ALL(通用) | SALE(买卖) | LEASE(租赁) | SERVICE(服务) | MANDATE(委托) | CONSTRUCTION(建设工程) | TRAINING(培训) | TECHNOLOGY(技术) | DONATION(赠与) | TRANSPORT(运输) | STORAGE(仓储) | COOPERATION(合作) | UNDERTAKING(承揽)'; +COMMENT ON COLUMN leaudit_evaluation_points.sort_order IS '排序序号'; +COMMENT ON COLUMN leaudit_evaluation_points.created_at IS '创建时间'; +COMMENT ON COLUMN leaudit_evaluation_points.updated_at IS '更新时间'; +COMMENT ON COLUMN leaudit_evaluation_points.deleted_at IS '软删除时间,NULL表示未删除'; + + +-- ============================================================================ +-- 5. 已有表补充中文注释 +-- ============================================================================ + +-- -------------------------------------------------------------------------- +-- 5.1 jwt_tokens +-- -------------------------------------------------------------------------- +COMMENT ON TABLE jwt_tokens IS 'JWT令牌表 — 管理用户登录令牌的签发、刷新、吊销全生命周期'; + +COMMENT ON COLUMN jwt_tokens.id IS '主键,自增'; +COMMENT ON COLUMN jwt_tokens.user_id IS '用户ID,关联 sso_users.id'; +COMMENT ON COLUMN jwt_tokens.token_jti IS 'JWT唯一标识符(JTI),用于令牌吊销黑名单'; +COMMENT ON COLUMN jwt_tokens.token_hash IS 'Access Token的SHA256哈希值,用于令牌有效性校验'; +COMMENT ON COLUMN jwt_tokens.refresh_token_hash IS 'Refresh Token的SHA256哈希值'; +COMMENT ON COLUMN jwt_tokens.token_type IS '令牌类型: ACCESS | REFRESH'; +COMMENT ON COLUMN jwt_tokens.device_id IS '设备唯一标识'; +COMMENT ON COLUMN jwt_tokens.device_name IS '设备名称/型号'; +COMMENT ON COLUMN jwt_tokens.user_agent IS '客户端User-Agent字符串'; +COMMENT ON COLUMN jwt_tokens.ip_address IS '签发时的客户端IP地址'; +COMMENT ON COLUMN jwt_tokens.issued_at IS '令牌签发时间'; +COMMENT ON COLUMN jwt_tokens.expires_at IS 'Access Token过期时间'; +COMMENT ON COLUMN jwt_tokens.refresh_expires_at IS 'Refresh Token过期时间'; +COMMENT ON COLUMN jwt_tokens.last_used_at IS '令牌最近一次使用时间'; +COMMENT ON COLUMN jwt_tokens.is_revoked IS '是否已被吊销'; +COMMENT ON COLUMN jwt_tokens.revoked_at IS '吊销时间'; +COMMENT ON COLUMN jwt_tokens.revoke_reason IS '吊销原因: logout(主动登出) | password_change(密码修改) | admin(管理员强制) | security(安全事件)'; +COMMENT ON COLUMN jwt_tokens.created_at IS '记录创建时间'; +COMMENT ON COLUMN jwt_tokens.updated_at IS '记录更新时间'; + + +-- -------------------------------------------------------------------------- +-- 5.2 leaudit_documents +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_documents IS '文档主表 — 每个上传的业务文档对应一条记录,跟踪评查处理状态'; + +COMMENT ON COLUMN leaudit_documents.id IS '主键,自增(leaudit内部文档ID)'; +COMMENT ON COLUMN leaudit_documents.biz_document_id IS '业务系统文档ID,关联旧系统 documents.id,用于跨系统追溯'; +COMMENT ON COLUMN leaudit_documents.type_id IS '文档类型ID,外键引用 leaudit_document_types.id'; +COMMENT ON COLUMN leaudit_documents.processing_status IS '处理状态: waiting(等待处理) | running(处理中) | completed(已完成) | failed(失败)'; +COMMENT ON COLUMN leaudit_documents.current_run_id IS '当前活跃的评查运行ID,外键引用 leaudit_audit_runs.id'; +COMMENT ON COLUMN leaudit_documents.created_at IS '记录创建时间'; +COMMENT ON COLUMN leaudit_documents.updated_at IS '记录更新时间'; + + +-- -------------------------------------------------------------------------- +-- 5.3 leaudit_document_files +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_document_files IS '文档文件表 — 一个文档可能包含多个文件(主文件、附件、扫描件等)'; + +COMMENT ON COLUMN leaudit_document_files.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_document_files.document_id IS '所属文档ID,外键引用 leaudit_documents.id'; +COMMENT ON COLUMN leaudit_document_files.file_role IS '文件角色: primary(主文档) | attachment(附件) | scan(扫描件) | ocr_result(OCR结果)'; +COMMENT ON COLUMN leaudit_document_files.file_name IS '原始文件名'; +COMMENT ON COLUMN leaudit_document_files.file_ext IS '文件扩展名(不含点)'; +COMMENT ON COLUMN leaudit_document_files.mime_type IS '文件MIME类型'; +COMMENT ON COLUMN leaudit_document_files.file_size IS '文件大小(字节)'; +COMMENT ON COLUMN leaudit_document_files.sha256 IS '文件SHA256哈希值,用于去重和完整性校验'; +COMMENT ON COLUMN leaudit_document_files.local_path IS '本地临时存储路径'; +COMMENT ON COLUMN leaudit_document_files.oss_url IS 'OSS对象存储URL(唯一真源)'; +COMMENT ON COLUMN leaudit_document_files.storage_provider IS '存储提供商: minio | aliyun_oss | local'; +COMMENT ON COLUMN leaudit_document_files.is_active IS '是否为当前活跃版本'; +COMMENT ON COLUMN leaudit_document_files.created_by IS '上传者用户ID,关联 sso_users.id'; +COMMENT ON COLUMN leaudit_document_files.created_at IS '记录创建时间'; + + +-- -------------------------------------------------------------------------- +-- 5.4 leaudit_audit_runs +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_audit_runs IS '评查运行表 — 一次评查执行的核心记录,跟踪7阶段流水线进度和结果汇总'; + +COMMENT ON COLUMN leaudit_audit_runs.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_audit_runs.document_id IS '被评查的文档ID,外键引用 leaudit_documents.id'; +COMMENT ON COLUMN leaudit_audit_runs.document_file_id IS '被评查的具体文件ID,外键引用 leaudit_document_files.id'; +COMMENT ON COLUMN leaudit_audit_runs.run_no IS '运行序号(同一文档多次运行的递增编号)'; +COMMENT ON COLUMN leaudit_audit_runs.trigger_source IS '触发来源: manual(手动) | api(API调用) | schedule(定时任务) | webhook(Webhook回调)'; +COMMENT ON COLUMN leaudit_audit_runs.trigger_user_id IS '触发用户ID,外键引用 sso_users.id'; +COMMENT ON COLUMN leaudit_audit_runs.task_id IS 'Celery任务ID,用于跟踪异步任务状态'; +COMMENT ON COLUMN leaudit_audit_runs.status IS '运行状态: pending(等待) | running(执行中) | completed(完成) | failed(失败) | cancelled(取消)'; +COMMENT ON COLUMN leaudit_audit_runs.phase IS '当前流水线阶段: normalize | extract | evaluate | rescue | persist'; +COMMENT ON COLUMN leaudit_audit_runs.rule_set_id IS '使用的规则集ID,外键引用 leaudit_rule_sets.id'; +COMMENT ON COLUMN leaudit_audit_runs.rule_version_id IS '使用的规则版本ID,外键引用 leaudit_rule_versions.id'; +COMMENT ON COLUMN leaudit_audit_runs.rule_type_id IS '规则类型ID(DSL metadata.type_id),如 contract.entrust'; +COMMENT ON COLUMN leaudit_audit_runs.rule_source_oss_url IS '规则YAML文件的OSS存储URL'; +COMMENT ON COLUMN leaudit_audit_runs.rule_source_sha256 IS '规则文件SHA256哈希,用于校验规则版本一致性'; +COMMENT ON COLUMN leaudit_audit_runs.rule_local_cache_path IS '规则文件本地缓存路径'; +COMMENT ON COLUMN leaudit_audit_runs.engine_version IS 'LeAudit引擎版本号(pip包版本)'; +COMMENT ON COLUMN leaudit_audit_runs.llm_provider IS 'LLM提供商标识'; +COMMENT ON COLUMN leaudit_audit_runs.llm_model IS 'LLM模型名称'; +COMMENT ON COLUMN leaudit_audit_runs.vlm_provider IS 'VLM提供商标识'; +COMMENT ON COLUMN leaudit_audit_runs.vlm_model IS 'VLM模型名称'; +COMMENT ON COLUMN leaudit_audit_runs.ocr_provider IS 'OCR提供商标识'; +COMMENT ON COLUMN leaudit_audit_runs.ocr_model IS 'OCR模型名称'; +COMMENT ON COLUMN leaudit_audit_runs.rescue_mode IS '补救模式: auto(自动) | manual(人工) | disabled(禁用)'; +COMMENT ON COLUMN leaudit_audit_runs.rescue_applied IS '本次运行是否触发了补救流程'; +COMMENT ON COLUMN leaudit_audit_runs.total_score IS '评查总分'; +COMMENT ON COLUMN leaudit_audit_runs.passed_count IS '通过的规则数'; +COMMENT ON COLUMN leaudit_audit_runs.failed_count IS '未通过的规则数'; +COMMENT ON COLUMN leaudit_audit_runs.skipped_count IS '跳过的规则数(条件不满足或被禁用)'; +COMMENT ON COLUMN leaudit_audit_runs.result_status IS '整体结果: pass(通过) | fail(不通过) | partial(部分通过) | review(需人工复核)'; +COMMENT ON COLUMN leaudit_audit_runs.started_at IS '评查开始时间'; +COMMENT ON COLUMN leaudit_audit_runs.finished_at IS '评查结束时间'; +COMMENT ON COLUMN leaudit_audit_runs.created_at IS '记录创建时间'; +COMMENT ON COLUMN leaudit_audit_runs.updated_at IS '记录更新时间'; + + +-- -------------------------------------------------------------------------- +-- 5.5 leaudit_artifacts +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_artifacts IS '评查产物表 — 统一管理评查各阶段产出的所有文件/数据,OSS为真源、DB为索引'; + +COMMENT ON COLUMN leaudit_artifacts.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_artifacts.run_id IS '所属评查运行ID,外键引用 leaudit_audit_runs.id'; +COMMENT ON COLUMN leaudit_artifacts.document_id IS '所属文档ID,外键引用 leaudit_documents.id'; +COMMENT ON COLUMN leaudit_artifacts.artifact_type IS '产物类型: original_doc | normalized_doc | render_png | render_pdf | ocr_json | extract_json | evaluate_json | rescue_json | quality_report | diff_report | cross_review | merged_result | final_report | vlm_render | vlm_vis_page | vlm_vis_subdoc | vlm_vis_field | vlm_debug | rescue_debug | pipeline_log'; +COMMENT ON COLUMN leaudit_artifacts.artifact_role IS '产物角色: input | output | intermediate | debug | log'; +COMMENT ON COLUMN leaudit_artifacts.file_name IS '文件名'; +COMMENT ON COLUMN leaudit_artifacts.file_ext IS '文件扩展名'; +COMMENT ON COLUMN leaudit_artifacts.mime_type IS 'MIME类型'; +COMMENT ON COLUMN leaudit_artifacts.file_size IS '文件大小(字节)'; +COMMENT ON COLUMN leaudit_artifacts.sha256 IS '文件SHA256哈希值'; +COMMENT ON COLUMN leaudit_artifacts.page_no IS '关联的页面编号(PDF渲染产物)'; +COMMENT ON COLUMN leaudit_artifacts.sub_doc_id IS '关联的子文档ID(子文档级别的产物)'; +COMMENT ON COLUMN leaudit_artifacts.field_name IS '关联的字段名(字段级别的可视化产物)'; +COMMENT ON COLUMN leaudit_artifacts.rule_id IS '关联的规则ID(规则级别的产物)'; +COMMENT ON COLUMN leaudit_artifacts.local_path IS '本地临时文件路径'; +COMMENT ON COLUMN leaudit_artifacts.oss_url IS 'OSS对象存储URL(唯一真源)'; +COMMENT ON COLUMN leaudit_artifacts.storage_provider IS '存储提供商: minio | aliyun_oss | local'; +COMMENT ON COLUMN leaudit_artifacts.is_persisted IS '是否已持久化到OSS'; +COMMENT ON COLUMN leaudit_artifacts.retention_policy IS '保留策略: temp(临时) | run_life(评查周期) | permanent(永久)'; +COMMENT ON COLUMN leaudit_artifacts.created_at IS '记录创建时间'; + + +-- -------------------------------------------------------------------------- +-- 5.6 leaudit_rule_results +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_rule_results IS '规则评查结果表 — 每次评查中每条规则的判断结果,含详细评分和补救信息'; + +COMMENT ON COLUMN leaudit_rule_results.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_rule_results.run_id IS '所属评查运行ID,外键引用 leaudit_audit_runs.id'; +COMMENT ON COLUMN leaudit_rule_results.rule_version_id IS '使用的规则版本ID,外键引用 leaudit_rule_versions.id'; +COMMENT ON COLUMN leaudit_rule_results.document_id IS '被评查文档ID,外键引用 leaudit_documents.id'; +COMMENT ON COLUMN leaudit_rule_results.rule_id IS '规则ID(DSL YAML中的 rule_id)'; +COMMENT ON COLUMN leaudit_rule_results.rule_name IS '规则名称'; +COMMENT ON COLUMN leaudit_rule_results.risk IS '风险等级: high | medium | low'; +COMMENT ON COLUMN leaudit_rule_results.score IS '规则得分'; +COMMENT ON COLUMN leaudit_rule_results.passed IS '是否通过'; +COMMENT ON COLUMN leaudit_rule_results.status IS '规则状态: pending | passed | failed | skipped | error'; +COMMENT ON COLUMN leaudit_rule_results.skip_reason IS '跳过原因(条件不满足时记录)'; +COMMENT ON COLUMN leaudit_rule_results.confidence IS '置信度分数(0-1)'; +COMMENT ON COLUMN leaudit_rule_results.pass_message IS '通过时的反馈文案'; +COMMENT ON COLUMN leaudit_rule_results.fail_message IS '不通过时的反馈文案'; +COMMENT ON COLUMN leaudit_rule_results.stages IS '各阶段执行详情JSON,记录每个stage的判断过程'; +COMMENT ON COLUMN leaudit_rule_results.extracted_fields IS '抽取到的字段值JSON,{field_name: {value, confidence, grounding, ...}}'; +COMMENT ON COLUMN leaudit_rule_results.field_positions IS '字段在文档中的位置信息JSON'; +COMMENT ON COLUMN leaudit_rule_results.rule_meta IS '规则元数据JSON(risk, score, messages等快照)'; +COMMENT ON COLUMN leaudit_rule_results.remediation IS '修正建议JSON,结构: {suggestions: [...], actions: [...]}'; +COMMENT ON COLUMN leaudit_rule_results.rescue_applied IS '是否已应用补救流程'; +COMMENT ON COLUMN leaudit_rule_results.rescue_passed IS '补救后是否通过'; +COMMENT ON COLUMN leaudit_rule_results.result_payload IS '原始结果JSON(完整保留leaudit引擎输出)'; +COMMENT ON COLUMN leaudit_rule_results.created_at IS '记录创建时间'; +COMMENT ON COLUMN leaudit_rule_results.updated_at IS '记录更新时间'; + + +-- -------------------------------------------------------------------------- +-- 5.7 leaudit_field_results +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_field_results IS '字段抽取结果表 — 评查中每个字段的抽取值和置信度信息'; + +COMMENT ON COLUMN leaudit_field_results.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_field_results.run_id IS '所属评查运行ID,外键引用 leaudit_audit_runs.id'; +COMMENT ON COLUMN leaudit_field_results.document_id IS '所属文档ID,外键引用 leaudit_documents.id'; +COMMENT ON COLUMN leaudit_field_results.sub_doc_id IS '所属子文档ID(案卷/多实体场景)'; +COMMENT ON COLUMN leaudit_field_results.field_name IS '字段名(对应DSL field.name)'; +COMMENT ON COLUMN leaudit_field_results.field_type IS '字段类型(对应DSL field.type,如 verbatim/string/money/date/enum)'; +COMMENT ON COLUMN leaudit_field_results.value_text IS '抽取的文本值'; +COMMENT ON COLUMN leaudit_field_results.raw_value_json IS '原始抽取结果JSON(含所有候选值)'; +COMMENT ON COLUMN leaudit_field_results.confidence IS '综合置信度(0-1),由logprob/grounding/rule加权计算'; +COMMENT ON COLUMN leaudit_field_results.logprob_score IS 'Logprob置信分(语言模型token概率)'; +COMMENT ON COLUMN leaudit_field_results.grounding_score IS '文本落地置信分(抽取值在原文中的可追溯性)'; +COMMENT ON COLUMN leaudit_field_results.grounding_method IS '落地验证方法: exact(精确匹配) | fuzzy(模糊匹配) | text_search(文本搜索) | none(未验证)'; +COMMENT ON COLUMN leaudit_field_results.rule_score IS '规则置信分(业务规则校验)'; +COMMENT ON COLUMN leaudit_field_results.hard_failed IS '是否硬失败(落在置信阈值以下且无兜底值)'; +COMMENT ON COLUMN leaudit_field_results.fallback_value IS '兜底/替代值(置信不足时使用)'; +COMMENT ON COLUMN leaudit_field_results.meta_json IS '扩展元数据JSON(phase信息、field位置、分组等)'; +COMMENT ON COLUMN leaudit_field_results.created_at IS '记录创建时间'; + + +-- -------------------------------------------------------------------------- +-- 5.8 leaudit_run_metrics +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_run_metrics IS '评查运行指标表 — 每次运行的性能统计和耗时分解'; + +COMMENT ON COLUMN leaudit_run_metrics.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_run_metrics.run_id IS '所属评查运行ID,外键引用 leaudit_audit_runs.id'; +COMMENT ON COLUMN leaudit_run_metrics.ocr_seconds IS 'OCR阶段耗时(秒)'; +COMMENT ON COLUMN leaudit_run_metrics.normalize_seconds IS '文档归一化阶段耗时(秒)'; +COMMENT ON COLUMN leaudit_run_metrics.extract_seconds IS '字段抽取阶段耗时(秒)'; +COMMENT ON COLUMN leaudit_run_metrics.evaluate_seconds IS '规则评查阶段耗时(秒)'; +COMMENT ON COLUMN leaudit_run_metrics.rescue_seconds IS '补救阶段耗时(秒)'; +COMMENT ON COLUMN leaudit_run_metrics.total_seconds IS '总耗时(秒)'; +COMMENT ON COLUMN leaudit_run_metrics.page_count IS '文档总页数'; +COMMENT ON COLUMN leaudit_run_metrics.sub_document_count IS '子文档数量(案卷拆分的子文档数)'; +COMMENT ON COLUMN leaudit_run_metrics.field_count IS '抽取的字段总数'; +COMMENT ON COLUMN leaudit_run_metrics.rule_count IS '执行的规则总数'; +COMMENT ON COLUMN leaudit_run_metrics.llm_call_count IS 'LLM调用次数'; +COMMENT ON COLUMN leaudit_run_metrics.vlm_call_count IS 'VLM调用次数'; +COMMENT ON COLUMN leaudit_run_metrics.rescue_rule_count IS '补救规则数(触发rescue的规则数量)'; +COMMENT ON COLUMN leaudit_run_metrics.artifact_count IS '产出的产物文件总数'; +COMMENT ON COLUMN leaudit_run_metrics.created_at IS '记录创建时间'; + + +-- -------------------------------------------------------------------------- +-- 5.9 leaudit_run_errors +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_run_errors IS '评查运行错误表 — 记录流水线各阶段的异常和错误详情'; + +COMMENT ON COLUMN leaudit_run_errors.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_run_errors.run_id IS '所属评查运行ID,外键引用 leaudit_audit_runs.id'; +COMMENT ON COLUMN leaudit_run_errors.document_id IS '所属文档ID,外键引用 leaudit_documents.id'; +COMMENT ON COLUMN leaudit_run_errors.stage IS '发生错误的阶段: ocr | normalize | extract | evaluate | rescue | persist'; +COMMENT ON COLUMN leaudit_run_errors.level IS '错误级别: fatal(致命) | error(错误) | warning(警告) | info(信息)'; +COMMENT ON COLUMN leaudit_run_errors.error_code IS '错误码(标准化标识,如 OCR_TIMEOUT / LLM_API_ERROR)'; +COMMENT ON COLUMN leaudit_run_errors.message IS '错误描述信息'; +COMMENT ON COLUMN leaudit_run_errors.detail_json IS '错误详情JSON(堆栈、上下文、请求参数等)'; +COMMENT ON COLUMN leaudit_run_errors.created_at IS '记录创建时间'; + + +-- -------------------------------------------------------------------------- +-- 5.10 leaudit_rescue_outcomes +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_rescue_outcomes IS '补救结果表 — 记录每条失败规则的补救诊断和处理结果'; + +COMMENT ON COLUMN leaudit_rescue_outcomes.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_rescue_outcomes.run_id IS '所属评查运行ID,外键引用 leaudit_audit_runs.id'; +COMMENT ON COLUMN leaudit_rescue_outcomes.document_id IS '所属文档ID,外键引用 leaudit_documents.id'; +COMMENT ON COLUMN leaudit_rescue_outcomes.rule_id IS '被补救的规则ID(DSL rule_id)'; +COMMENT ON COLUMN leaudit_rescue_outcomes.status IS '补救状态: pending | diagnosing | fixing | retrying | resolved | failed | escalated'; +COMMENT ON COLUMN leaudit_rescue_outcomes.diagnosis IS '诊断结果 — AI分析出的失败根因'; +COMMENT ON COLUMN leaudit_rescue_outcomes.diagnosis_confidence IS '诊断置信度(0-1)'; +COMMENT ON COLUMN leaudit_rescue_outcomes.final_status IS '补救后最终状态: pass | fail | review'; +COMMENT ON COLUMN leaudit_rescue_outcomes.failure_reason IS '补救失败原因(最终仍失败时记录)'; +COMMENT ON COLUMN leaudit_rescue_outcomes.llm_calls IS '补救过程LLM调用次数'; +COMMENT ON COLUMN leaudit_rescue_outcomes.vlm_calls IS '补救过程VLM调用次数'; +COMMENT ON COLUMN leaudit_rescue_outcomes.duration_ms IS '补救总耗时(毫秒)'; +COMMENT ON COLUMN leaudit_rescue_outcomes.requires_human_review IS '是否需要人工复核'; +COMMENT ON COLUMN leaudit_rescue_outcomes.payload IS '补救过程完整数据JSON(含每层rescue的输入输出)'; +COMMENT ON COLUMN leaudit_rescue_outcomes.created_at IS '记录创建时间'; +COMMENT ON COLUMN leaudit_rescue_outcomes.updated_at IS '记录更新时间'; + + +-- -------------------------------------------------------------------------- +-- 5.11 leaudit_rule_sets +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_rule_sets IS '规则集表 — 管理DSL规则集(一个规则集=一套type_id对应的YAML规则文件)'; + +COMMENT ON COLUMN leaudit_rule_sets.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_rule_sets.rule_type IS '规则类型ID(对应DSL metadata.type_id,如 contract.entrust)'; +COMMENT ON COLUMN leaudit_rule_sets.rule_name IS '规则集名称(对应DSL metadata.name,如 通用委托合同)'; +COMMENT ON COLUMN leaudit_rule_sets.domain_type IS '领域类型: contract(合同) | admin_license(行政许可) | legal_doc(法律文书)'; +COMMENT ON COLUMN leaudit_rule_sets.description IS '规则集描述(对应DSL metadata.description)'; +COMMENT ON COLUMN leaudit_rule_sets.entry_module IS '所属入口模块标识'; +COMMENT ON COLUMN leaudit_rule_sets.current_version_id IS '当前生效版本ID,外键引用 leaudit_rule_versions.id'; +COMMENT ON COLUMN leaudit_rule_sets.status IS '状态: draft(草稿) | active(生效) | deprecated(废弃) | archived(归档)'; +COMMENT ON COLUMN leaudit_rule_sets.is_builtin IS '是否为系统内置规则(内置规则不可删除)'; +COMMENT ON COLUMN leaudit_rule_sets.owner_user_id IS '负责人用户ID,外键引用 sso_users.id'; +COMMENT ON COLUMN leaudit_rule_sets.created_at IS '记录创建时间'; +COMMENT ON COLUMN leaudit_rule_sets.updated_at IS '记录更新时间'; +COMMENT ON COLUMN leaudit_rule_sets.deleted_at IS '软删除时间,NULL表示未删除'; + + +-- -------------------------------------------------------------------------- +-- 5.12 leaudit_rule_versions +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_rule_versions IS '规则版本表 — 规则集每次发布生成一个版本快照,记录YAML文件OSS地址和元数据'; + +COMMENT ON COLUMN leaudit_rule_versions.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_rule_versions.rule_set_id IS '所属规则集ID,外键引用 leaudit_rule_sets.id'; +COMMENT ON COLUMN leaudit_rule_versions.version_no IS '版本号(语义化版本,如 1.0 / 2.3)'; +COMMENT ON COLUMN leaudit_rule_versions.version_seq IS '版本序号(自增整数,rule_set_id内递增)'; +COMMENT ON COLUMN leaudit_rule_versions.status IS '状态: draft(草稿) | published(已发布) | deprecated(废弃) | rollback(已回滚)'; +COMMENT ON COLUMN leaudit_rule_versions.source_type IS '规则源类型: oss_yaml(OSS上的YAML) | local_yaml(本地YAML) | db_snippet(数据库片段)'; +COMMENT ON COLUMN leaudit_rule_versions.dsl_format IS 'DSL格式: yaml(新版YAML DSL) | json(旧版JSON格式)'; +COMMENT ON COLUMN leaudit_rule_versions.oss_url IS '规则YAML文件的OSS存储URL'; +COMMENT ON COLUMN leaudit_rule_versions.file_sha256 IS '规则文件SHA256哈希值'; +COMMENT ON COLUMN leaudit_rule_versions.file_size IS '规则文件大小(字节)'; +COMMENT ON COLUMN leaudit_rule_versions.local_cache_path IS '规则文件本地缓存路径'; +COMMENT ON COLUMN leaudit_rule_versions.metadata_type_id IS 'DSL metadata.type_id 快照'; +COMMENT ON COLUMN leaudit_rule_versions.metadata_name IS 'DSL metadata.name 快照'; +COMMENT ON COLUMN leaudit_rule_versions.metadata_version IS 'DSL metadata.version 快照'; +COMMENT ON COLUMN leaudit_rule_versions.change_note IS '版本变更说明'; +COMMENT ON COLUMN leaudit_rule_versions.editor_user_id IS '编辑者用户ID,外键引用 sso_users.id'; +COMMENT ON COLUMN leaudit_rule_versions.publisher_user_id IS '发布者用户ID,外键引用 sso_users.id'; +COMMENT ON COLUMN leaudit_rule_versions.published_at IS '发布时间'; +COMMENT ON COLUMN leaudit_rule_versions.created_at IS '记录创建时间'; +COMMENT ON COLUMN leaudit_rule_versions.updated_at IS '记录更新时间'; + + +-- -------------------------------------------------------------------------- +-- 5.13 leaudit_rule_type_bindings +-- -------------------------------------------------------------------------- +COMMENT ON TABLE leaudit_rule_type_bindings IS '规则类型绑定表 — 定义文档类型与规则集的匹配关系,支持显式绑定和通配符绑定'; + +COMMENT ON COLUMN leaudit_rule_type_bindings.id IS '主键,自增'; +COMMENT ON COLUMN leaudit_rule_type_bindings.doc_type_id IS '文档类型ID,外键引用 leaudit_document_types.id'; +COMMENT ON COLUMN leaudit_rule_type_bindings.doc_type_code IS '文档类型编码(冗余字段,用于快速匹配)'; +COMMENT ON COLUMN leaudit_rule_type_bindings.rule_set_id IS '规则集ID,外键引用 leaudit_rule_sets.id'; +COMMENT ON COLUMN leaudit_rule_type_bindings.binding_mode IS '绑定模式: explicit(显式指定) | wildcard(通配符) | fallback(兜底默认)'; +COMMENT ON COLUMN leaudit_rule_type_bindings.priority IS '优先级(数值越大优先级越高),通配符绑定通常优先级较低'; +COMMENT ON COLUMN leaudit_rule_type_bindings.is_active IS '是否激活'; +COMMENT ON COLUMN leaudit_rule_type_bindings.note IS '备注说明'; +COMMENT ON COLUMN leaudit_rule_type_bindings.created_at IS '记录创建时间'; +COMMENT ON COLUMN leaudit_rule_type_bindings.updated_at IS '记录更新时间'; + + +-- ============================================================================ +-- 6. 外键约束 (新表) +-- ============================================================================ + +-- leaudit_evaluation_point_groups 自引用 (pid → id) +ALTER TABLE leaudit_evaluation_point_groups + ADD CONSTRAINT fk_eval_point_groups_pid + FOREIGN KEY (pid) REFERENCES leaudit_evaluation_point_groups(id) + ON UPDATE CASCADE ON DELETE SET NULL; + +-- leaudit_evaluation_point_groups → leaudit_rule_sets +ALTER TABLE leaudit_evaluation_point_groups + ADD CONSTRAINT fk_eval_point_groups_rule_set + FOREIGN KEY (rule_set_id) REFERENCES leaudit_rule_sets(id) + ON UPDATE CASCADE ON DELETE SET NULL; + +-- leaudit_evaluation_points → leaudit_evaluation_point_groups +ALTER TABLE leaudit_evaluation_points + ADD CONSTRAINT fk_eval_points_group + FOREIGN KEY (group_id) REFERENCES leaudit_evaluation_point_groups(id) + ON UPDATE CASCADE ON DELETE CASCADE; + +-- leaudit_evaluation_points → leaudit_rule_sets +ALTER TABLE leaudit_evaluation_points + ADD CONSTRAINT fk_eval_points_rule_set + FOREIGN KEY (rule_set_id) REFERENCES leaudit_rule_sets(id) + ON UPDATE CASCADE ON DELETE SET NULL; + +-- leaudit_document_types → leaudit_entry_modules +ALTER TABLE leaudit_document_types + ADD CONSTRAINT fk_doc_types_entry_module + FOREIGN KEY (entry_module_id) REFERENCES leaudit_entry_modules(id) + ON UPDATE CASCADE ON DELETE SET NULL; + +-- leaudit_rule_type_bindings → leaudit_document_types +ALTER TABLE leaudit_rule_type_bindings + ADD CONSTRAINT fk_rule_type_bindings_doc_type + FOREIGN KEY (doc_type_id) REFERENCES leaudit_document_types(id) + ON UPDATE CASCADE ON DELETE CASCADE; + +-- leaudit_documents → leaudit_document_types +ALTER TABLE leaudit_documents + ADD CONSTRAINT fk_documents_type + FOREIGN KEY (type_id) REFERENCES leaudit_document_types(id) + ON UPDATE CASCADE ON DELETE SET NULL; + + +-- ============================================================================ +-- 7. 索引 +-- ============================================================================ + +-- 入口模块 +CREATE INDEX IF NOT EXISTS idx_entry_modules_sort ON leaudit_entry_modules(sort_order, is_enabled); + +-- 文档类型 +CREATE INDEX IF NOT EXISTS idx_doc_types_code ON leaudit_document_types(code); +CREATE INDEX IF NOT EXISTS idx_doc_types_entry ON leaudit_document_types(entry_module_id); + +-- 评查点规则组 +CREATE INDEX IF NOT EXISTS idx_eval_point_groups_pid ON leaudit_evaluation_point_groups(pid); +CREATE INDEX IF NOT EXISTS idx_eval_point_groups_code ON leaudit_evaluation_point_groups(code); +CREATE INDEX IF NOT EXISTS idx_eval_point_groups_rule_set ON leaudit_evaluation_point_groups(rule_set_id); +CREATE INDEX IF NOT EXISTS idx_eval_point_groups_sort ON leaudit_evaluation_point_groups(pid, sort_order); + +-- 评查点 +CREATE INDEX IF NOT EXISTS idx_eval_points_code ON leaudit_evaluation_points(code); +CREATE INDEX IF NOT EXISTS idx_eval_points_group ON leaudit_evaluation_points(group_id); +CREATE INDEX IF NOT EXISTS idx_eval_points_rule_set ON leaudit_evaluation_points(rule_set_id); +CREATE INDEX IF NOT EXISTS idx_eval_points_rule_id ON leaudit_evaluation_points(rule_id); +CREATE INDEX IF NOT EXISTS idx_eval_points_enabled ON leaudit_evaluation_points(group_id, is_enabled); +CREATE INDEX IF NOT EXISTS idx_eval_points_risk ON leaudit_evaluation_points(risk); + +COMMIT;