14 Комити aa58c429df ... 66f746d6ef

Аутор SHA1 Порука Датум
  lingmin_package@163.com 66f746d6ef fix(sgsc-目录审查):目录审查修改字段名称 пре 2 недеља
  WangXuMing 03b2a3f506 Merge branch 'dev_sgsc_wxm' of CRBC-MaaS-Platform-Project/LQAgentPlatform into dev пре 2 недеља
  WangXuMing f969c861f4 refactor: 重构目录审查逻辑,移除旧版代码,优化YOLO依赖检测 пре 2 недеља
  WangXuMing 76d6acb87d Merge branch 'dev_sgsc_wxm' of CRBC-MaaS-Platform-Project/LQAgentPlatform into dev пре 2 недеља
  WangXuMing 712cf27ff8 refactor(pdf_extractor): 移除 toc_detector 导入保护,强制依赖生效 пре 2 недеља
  WangXuMing 6384c768ac Merge branch 'dev_sgsc_wxm' of CRBC-MaaS-Platform-Project/LQAgentPlatform into dev пре 2 недеља
  WangXuMing 26179c2cb8 refactor(toc_detector): 移除 YOLO 降级保护,强制依赖生效 пре 2 недеља
  WangXuMing 8743a0c8c2 Merge branch 'dev_sgsc_wxm' of CRBC-MaaS-Platform-Project/LQAgentPlatform into dev пре 2 недеља
  WangXuMing 1a6f9c01fd feat(catalog): 目录完整性审查模块支持思考模式 пре 2 недеља
  LingMin 799016e47d Merge branch 'dev_sgsc_lpl' of CRBC-MaaS-Platform-Project/LQAgentPlatform into dev пре 2 недеља
  suhua31 6d44ae8265 fix(sgsc-时效性审查模型-xth): 修复特殊字符未处理bug пре 2 недеља
  WangXuMing 4fbdee6a4a Merge branch 'dev_sgsc_wxm' of CRBC-MaaS-Platform-Project/LQAgentPlatform into dev пре 2 недеља
  WangXuMing 6e4807d82e fix(catalog): 修复目录完整性检查,直接使用分类代码对比 пре 2 недеља
  LingMin 4dd0db1fe3 Merge branch 'dev_lingmin' of CRBC-MaaS-Platform-Project/LQAgentPlatform into dev пре 2 недеља

+ 3 - 1
config/config.ini.template

@@ -242,5 +242,7 @@ MAX_CELERY_TASKS=1
 # 时效性审查中用于匹配前需要去除的符号(第二轮处理)
 # 这些符号会在基础规范化(去除空白、书名号、括号、HTML标签)之后去除
 # 包含各种连接符:半角连字符(-)、全角连接号(-)、全角破折号(—)
-REMOVE_SYMBOLS=),-,.,/,,:,[,],【,】,〔,〕,(,),-,—
+# 包含各种连接符:半角连字符(-)、全角连接号(-)、全角破折号(—)、水平线(―)、
+# 连字符(‐)、不换行连字符(‑)、数字线(‒)、短破折号(–)、减号(−)
+REMOVE_SYMBOLS=),-,.,/,,:,[,],【,】,〔,〕,(,),-,—,―,‐,‑,‒,–,−
 

+ 6 - 0
config/model_setting.yaml

@@ -118,6 +118,12 @@ model_settings:
     enable_thinking: false
     description: "时效规范审查抽取(目录提取),蜀天35B"
 
+  # 目录完整性审查(对比实际目录与标准目录)
+  catalog_integrity_review:
+    model: shutian_qwen3_5_122b
+    enable_thinking: true
+    description: "目录完整性审查,对比OCR提取目录与标准目录,找出缺失项,蜀天35B"
+
   # Embedding 模型(用于相似度计算)
   embedding:
     model: shutian_qwen3_embed # 或 lq_qwen3_8b_emd 

+ 106 - 307
core/construction_review/component/ai_review_engine.py

@@ -728,19 +728,14 @@ class AIReviewEngine(BaseReviewer):
             # 转换为字典
             result_dict = result_to_dict_lightweight(result)
 
-            # ========== 新增:目录一二级缺失检查 ==========
-            # 只在全文档检查或 catalogue 章节时执行,避免重复
-            outline_issues = []
-            if chapter_code in ["all", "catalogue"]:
-                try:
-                    outline_result = await self._check_outline_for_completeness(
-                        state=state,
-                        trace_id_idx=trace_id_idx
-                    )
-                    outline_issues = outline_result.get("issues", [])
-                except Exception as e:
-                    logger.warning(f"目录缺失检查失败: {str(e)}")
-            # =============================================
+            # 加载 first_code -> first_seq 映射
+            first_seq_map = {}
+            try:
+                df_map = pd.read_csv(csv_path, usecols=['first_code', 'first_seq'])
+                first_seq_map = dict(df_map.drop_duplicates(subset=['first_code']).set_index('first_code')['first_seq'])
+            except Exception:
+                pass
+            current_first_seq = int(first_seq_map[chapter_code]) if chapter_code != "all" and chapter_code in first_seq_map else ""
 
             # 使用 recommendations 构建 response_items
             # recommendations 已按 一级→二级→三级 层级判断,用 continue 阻断级联:
@@ -770,6 +765,7 @@ class AIReviewEngine(BaseReviewer):
                 response_items.append({
                     "check_item": "completeness_check",
                     "chapter_code": chapter_code if chapter_code != "all" else "unknown",
+                    "first_seq": current_first_seq,
                     "check_item_code": f"{chapter_code if chapter_code != 'all' else 'unknown'}_completeness_check",
                     "check_result": {
                         "issue_point": issue_point,
@@ -782,16 +778,13 @@ class AIReviewEngine(BaseReviewer):
                     "risk_info": {"risk_level": risk_level_en}
                 })
             
-            # 合并目录缺失检查的问题(目录缺失作为完整性的一部分)
-            if outline_issues:
-                response_items.extend(outline_issues)
-            
             # 如果没有缺失项,显示完整度
             if not response_items:
                 completeness_rate = result_dict.get('tertiary_completeness', {}).get('completeness_rate', '0%')
                 response_items.append({
                     "check_item": "completeness_check",
                     "chapter_code": chapter_code if chapter_code != "all" else "all",
+                    "first_seq": current_first_seq,
                     "check_item_code": f"{chapter_code if chapter_code != 'all' else 'all'}_completeness_check",
                     "check_result": {
                         "issue_point": f"【内容完整】三级分类覆盖完整",
@@ -872,125 +865,6 @@ class AIReviewEngine(BaseReviewer):
             }
             return error_result, trace_id_idx
 
-    async def _check_outline_for_completeness(
-        self,
-        state: Dict[str, Any],
-        trace_id_idx: str
-    ) -> Dict[str, Any]:
-        """
-        为完整性检查提供目录一二级缺失结果
-        复用 check_outline_catalogue 方法,返回标准 issue 格式列表
-        
-        Args:
-            state: AI审查状态,包含 structured_content
-            trace_id_idx: 追踪ID索引
-            
-        Returns:
-            Dict: {"issues": [...]} 标准格式的 issue 列表
-        """
-        try:
-            # 调用现有目录缺失检查方法
-            outline_data = state.get("structured_content", {})
-            result = await self.check_outline_catalogue(
-                trace_id_idx=trace_id_idx,
-                outline_data=outline_data,
-                state=state,
-                stage_name="completeness_check"
-            )
-            
-            if not result.get("success"):
-                return {"issues": []}
-            
-            # 转换为 completeness_check 格式的 issues
-            issues = []
-            details = result.get("details", {})
-            missing_first = details.get("missing_first", [])
-            missing_second = details.get("missing_second", [])
-            missing_first_count = len(missing_first)
-            missing_second_count = len(missing_second)
-            
-            # 如果有缺失目录,先添加汇总统计 issue(放在最前面)
-            if missing_first or missing_second:
-                total_missing = missing_first_count + missing_second_count
-                
-                # 构建缺失目录名称列表
-                missing_first_names = [item.get('first_name', '未知') for item in missing_first if isinstance(item, dict)]
-                missing_second_names = [f"{item.get('first_name', '')}.{item.get('secondary_name', '未知')}" for item in missing_second if isinstance(item, dict)]
-                
-                # 构建建议文本
-                suggestion_parts = []
-                if missing_first_names:
-                    suggestion_parts.append(f"一级目录({missing_first_count}个):{', '.join(missing_first_names)}")
-                if missing_second_names:
-                    suggestion_parts.append(f"二级目录({missing_second_count}个):{', '.join(missing_second_names[:10])}")  # 最多显示10个
-                    if len(missing_second_names) > 10:
-                        suggestion_parts.append(f"... 及其他 {len(missing_second_names) - 10} 个二级目录")
-                
-                suggestion_text = "建议补充以下缺失目录:\n" + "\n".join(suggestion_parts)
-                
-                # 添加汇总统计 issue
-                issues.append({
-                    "check_item": "completeness_check",
-                    "chapter_code": "catalogue",  # 汇总 issue 归属到 catalogue 章节
-                    "check_item_code": "catalogue_completeness_check",
-                    "check_result": {
-                        "issue_point": f"【目录缺失汇总】共缺失 {total_missing} 个目录(一级{missing_first_count}个,二级{missing_second_count}个)",
-                        "location": "整篇文档",
-                        "suggestion": suggestion_text,
-                        "reason": f"根据标准分类表对比,文档目录结构不完整,共发现 {total_missing} 个缺失目录",
-                        "risk_level": "中风险",
-                        "summary": {
-                            "missing_first_count": missing_first_count,
-                            "missing_second_count": missing_second_count,
-                            "missing_total": total_missing,
-                            "missing_first_names": missing_first_names,
-                            "missing_second_names": missing_second_names
-                        }
-                    },
-                    "exist_issue": True,
-                    "risk_info": {"risk_level": "medium"}
-                })
-            
-            # 缺失一级目录 → 每个生成 issue(统一归属到 catalogue 章节)
-            for item in missing_first:
-                issues.append({
-                    "check_item": "completeness_check",
-                    "chapter_code": "catalogue",
-                    "check_item_code": "catalogue_completeness_check",
-                    "check_result": {
-                        "issue_point": f"【目录缺失】缺失一级目录:{item.get('first_name', '')}",
-                        "location": f"{item.get('first_seq', '')}. {item.get('first_name', '')}",
-                        "suggestion": f"补充一级目录:{item.get('first_name', '')}",
-                        "reason": "根据标准分类表,该一级目录应当出现",
-                        "risk_level": "高风险"
-                    },
-                    "exist_issue": True,
-                    "risk_info": {"risk_level": "high"}
-                })
-            
-            # 缺失二级目录 → 统一归属到 catalogue 章节
-            for item in missing_second:
-                issues.append({
-                    "check_item": "completeness_check",
-                    "chapter_code": "catalogue",
-                    "check_item_code": "catalogue_completeness_check",
-                    "check_result": {
-                        "issue_point": f"【目录缺失】缺失二级目录:{item.get('secondary_name', '')}",
-                        "location": f"{item.get('first_seq', '')}.{item.get('second_seq', '')} {item.get('first_name', '')} > {item.get('secondary_name', '')}",
-                        "suggestion": f"补充二级目录:{item.get('secondary_name', '')}",
-                        "reason": f"在'{item.get('first_name', '')}'章节下,该二级目录应当出现",
-                        "risk_level": "中风险"
-                    },
-                    "exist_issue": True,
-                    "risk_info": {"risk_level": "medium"}
-                })
-            
-            return {"issues": issues}
-            
-        except Exception as e:
-            logger.warning(f"目录缺失检查异常: {str(e)}")
-            return {"issues": []}
-
     async def check_outline_catalogue(
         self,
         trace_id_idx: str,
@@ -999,207 +873,132 @@ class AIReviewEngine(BaseReviewer):
         stage_name: str
     ) -> Dict[str, Any]:
         """
-        基于文档目录(outline)的一二级分类缺失检查。
-
-        使用模糊匹配算法,支持基于名称相似度的目录匹配。
+        基于LLM的目录完整性检查。
+        使用 catalog_reviewer 模块进行标准格式对比。
 
         Args:
             trace_id_idx: 追踪ID索引
-            outline_data: 包含 outline 的字典(通常来自 structured_content)
-            state: 状态字典,可从中回退获取 structured_content.outline
+            outline_data: 包含 catalog 的字典
+            state: 状态字典
             stage_name: 阶段名称
 
         Returns:
-            Dict[str, Any]: 包含缺失一级、二级目录统计结果
+            Dict[str, Any]: 缺失目录统计结果(对齐 check_completeness 格式)
         """
-        from .outline_catalogue_matcher import OutlineCatalogueMatcher
+        from .minimal_pipeline.catalog_reviewer import CatalogReviewer
 
-        start_time = time.time()
         name = "outline_catalogue_check"
+        logger.info(f"[{name}] 开始LLM目录完整性检查")
 
         try:
-            logger.info(f"[{name}] 开始目录一二级缺失检查")
-
-            # CSV路径
-            csv_path = str(
-                Path(__file__).parent / 'doc_worker' / 'config' /
-                'StandardCategoryTable.csv'
-            )
-            raw_content_csv = str(
-                Path(__file__).parent / 'doc_worker' / 'config' /
-                'construction_plan_standards.csv'
-            )
-
-            # 获取 catalog(YOLO+OCR提取的原始目录)和 outline(分类后的结构)
-            catalog_chapters = []
-            outline_chapters = []
+            # 获取 catalog 的标准格式文本
+            formatted_text = ""
 
+            # 优先从 catalog.formatted_text 获取
             if outline_data and isinstance(outline_data, dict):
-                # 从 outline_data 获取 catalog(优先)
                 catalog_raw = outline_data.get('catalog')
                 if catalog_raw and isinstance(catalog_raw, dict):
-                    catalog_chapters = catalog_raw.get('chapters', [])
-                # 获取 outline(用于分类代码映射)
-                outline_raw = outline_data.get('outline')
-                if isinstance(outline_raw, dict):
-                    outline_chapters = outline_raw.get('chapters', [])
-                elif isinstance(outline_raw, list):
-                    outline_chapters = outline_raw
-
-            # 从 state 回退获取
-            if state and isinstance(state, dict):
+                    formatted_text = catalog_raw.get('formatted_text', '')
+
+            # 回退到从 state 获取
+            if not formatted_text and state and isinstance(state, dict):
                 structured = state.get('structured_content', {})
+                catalog_raw = structured.get('catalog')
+                if catalog_raw and isinstance(catalog_raw, dict):
+                    formatted_text = catalog_raw.get('formatted_text', '')
+
+            # 如果没有标准格式,从 chapters 构建
+            if not formatted_text:
+                catalog_chapters = []
+                if outline_data and isinstance(outline_data, dict):
+                    catalog_raw = outline_data.get('catalog')
+                    if catalog_raw:
+                        catalog_chapters = catalog_raw.get('chapters', [])
 
-                # 获取 catalog
-                if not catalog_chapters:
+                if not catalog_chapters and state and isinstance(state, dict):
+                    structured = state.get('structured_content', {})
                     catalog_raw = structured.get('catalog')
-                    if catalog_raw and isinstance(catalog_raw, dict):
+                    if catalog_raw:
                         catalog_chapters = catalog_raw.get('chapters', [])
 
-                # 获取 outline
-                if not outline_chapters:
-                    outline_raw = structured.get('outline', {})
-                    if isinstance(outline_raw, dict):
-                        outline_chapters = outline_raw.get('chapters', [])
-                    elif isinstance(outline_raw, list):
-                        outline_chapters = outline_raw
-
-            logger.info(f"[{name}] catalog: {len(catalog_chapters)} 章, outline: {len(outline_chapters)} 章")
-
-            # 使用模糊匹配器
-            matcher = OutlineCatalogueMatcher(csv_path, raw_content_csv)
-
-            # 构建 outline 标题到分类代码的映射
-            # outline: [{"chapter_classification": "basis", "title": "第一章 编制依据", "subsections": [...]}]
-            outline_first_map = {}  # title -> chapter_classification
-            outline_second_map = {}  # (first_title, sub_title) -> secondary_category_code
-
-            for chapter in outline_chapters:
-                if not isinstance(chapter, dict):
-                    continue
-                first_code = chapter.get('chapter_classification', '')
-                first_title = chapter.get('title', '')
-                if first_code and first_title:
-                    outline_first_map[first_title] = first_code
-
-                for sub in chapter.get('subsections', []):
-                    if isinstance(sub, dict):
+                # 构建标准格式文本
+                lines = []
+                for ch in catalog_chapters:
+                    ch_title = ch.get('title', '')
+                    if ch_title:
+                        lines.append(ch_title)
+                    for sub in ch.get('subsections', []):
                         sub_title = sub.get('title', '')
-                        second_code = sub.get('secondary_category_code', '')
-                        if first_title and sub_title and second_code:
-                            outline_second_map[(first_title, sub_title)] = second_code
+                        if sub_title:
+                            lines.append(f"  {sub_title}")
+                formatted_text = '\n'.join(lines)
 
-            # 使用 catalog 的标题,匹配 outline 的分类代码
-            outline_first = set()
-            outline_secondary = {}
-
-            for chapter in catalog_chapters:
-                if not isinstance(chapter, dict):
-                    continue
+            if not formatted_text:
+                logger.warning(f"[{name}] 未获取到目录内容")
+                return {
+                    "details": {
+                        "name": name,
+                        "response": [{
+                            "check_item": "catalog_check",
+                            "chapter_code": "catalog",
+                            "check_item_code": "catalog_check",
+                            "check_result": {
+                                "issue_point": "【无目录】未能提取到文档目录",
+                                "location": "目录页",
+                                "suggestion": "请检查文档是否包含目录页,或尝试手动上传目录",
+                                "reason": "OCR未能识别到目录内容",
+                                "risk_level": "中风险"
+                            },
+                            "exist_issue": True,
+                            "risk_info": {"risk_level": "medium"}
+                        }],
+                        "review_location_label": "目录完整性审查",
+                        "chapter_code": "catalog",
+                        "original_content": "未获取到目录内容"
+                    },
+                    "success": False,
+                    "execution_time": 0
+                }
 
-                catalog_title = chapter.get('title', '')
-                if not catalog_title:
-                    continue
+            logger.info(f"[DEBUG][{name}] 开始使用 CatalogReviewer 审查")
+            logger.info(f"[DEBUG][{name}] formatted_text length: {len(formatted_text)}")
+            logger.info(f"[DEBUG][{name}] formatted_text preview:\n{formatted_text[:200]}...")
 
-                # 尝试从 outline 匹配一级分类代码
-                first_code = outline_first_map.get(catalog_title)
-
-                # 如果精确匹配失败,尝试模糊匹配
-                if not first_code:
-                    for outline_title, code in outline_first_map.items():
-                        if matcher._calculate_similarity(catalog_title, outline_title) > 0.7:
-                            first_code = code
-                            break
-
-                if first_code:
-                    outline_first.add(first_code)
-
-                # 匹配二级分类
-                for sub in chapter.get('subsections', []):
-                    if not isinstance(sub, dict):
-                        continue
-                    sub_title = sub.get('title', '')
-                    if not sub_title:
-                        continue
-
-                    # 尝试精确匹配
-                    second_code = outline_second_map.get((catalog_title, sub_title))
-
-                    # 模糊匹配
-                    if not second_code and first_code:
-                        for (outline_first, outline_sub), code in outline_second_map.items():
-                            if matcher._calculate_similarity(catalog_title, outline_first) > 0.7 and \
-                               matcher._calculate_similarity(sub_title, outline_sub) > 0.7:
-                                second_code = code
-                                break
-
-                    if first_code and second_code:
-                        outline_secondary[(first_code, second_code)] = sub_title
-
-            logger.info(f"[{name}] 匹配到 {len(outline_first)} 个一级, {len(outline_secondary)} 个二级")
-
-            # 执行标准目录匹配检查
-            match_result = matcher.match_catalogue(
-                outline_first=outline_first,
-                outline_secondary=outline_secondary,
-                threshold=0.6
-            )
-            
-            catalogue_result = {
-                "level": "primary_and_secondary",
-                "is_complete": match_result['missing_first_count'] == 0 and match_result['missing_second_count'] == 0,
-                "first_level": {
-                    "total_required": len(matcher.first_names),
-                    "actual_present": len(match_result['matched_first']),
-                    "missing_count": match_result['missing_first_count'],
-                    "missing": match_result['missing_first']
-                },
-                "second_level": {
-                    "total_required": len(matcher.second_names),
-                    "actual_present": len(match_result['matched_second']),
-                    "missing_count": match_result['missing_second_count'],
-                    "missing": match_result['missing_second']
-                },
-                "match_details": match_result['match_details']
-            }
+            # 使用 CatalogReviewer 进行审查
+            reviewer = CatalogReviewer()
+            result = await reviewer.review(formatted_text, trace_id_idx)
 
-            execution_time = time.time() - start_time
-            logger.info(
-                f"[{name}] 检查完成,耗时: {execution_time:.2f}s, "
-                f"缺失一级: {match_result['missing_first_count']} 个, "
-                f"缺失二级: {match_result['missing_second_count']} 个"
-            )
-
-            return {
-                "success": True,
-                "execution_time": execution_time,
-                "details": {
-                    "name": name,
-                    "missing_first_count": match_result['missing_first_count'],
-                    "missing_second_count": match_result['missing_second_count'],
-                    "missing_first": match_result['missing_first'],
-                    "missing_second": match_result['missing_second'],
-                    "catalogue_check": catalogue_result
-                }
-            }
+            logger.info(f"[DEBUG][{name}] 检查完成,返回结果")
+            logger.info(f"[DEBUG][{name}] result type: {type(result)}")
+            logger.info(f"[DEBUG][{name}] result success: {result.get('success')}")
+            return result
 
         except Exception as e:
-            execution_time = time.time() - start_time
-            error_msg = f"[{name}] 检查失败: {str(e)}"
-            logger.error(error_msg, exc_info=True)
-
+            logger.error(f"[{name}] 检查失败: {e}", exc_info=True)
+            import time
             return {
-                "success": False,
-                "execution_time": execution_time,
-                "error": str(e),
                 "details": {
                     "name": name,
-                    "missing_first_count": 0,
-                    "missing_second_count": 0,
-                    "missing_first": [],
-                    "missing_second": [],
-                    "catalogue_check": {}
-                }
+                    "response": [{
+                        "check_item": "catalog_check",
+                        "chapter_code": "catalog",
+                        "check_item_code": "catalog_check",
+                        "check_result": {
+                            "issue_point": "目录审查失败",
+                            "location": "目录页",
+                            "suggestion": "请检查OCR识别结果或手动确认目录",
+                            "reason": str(e),
+                            "risk_level": "中风险"
+                        },
+                        "exist_issue": True,
+                        "risk_info": {"risk_level": "medium"}
+                    }],
+                    "review_location_label": "目录完整性审查",
+                    "chapter_code": "catalog",
+                    "original_content": f"审查失败: {str(e)}"
+                },
+                "success": False,
+                "execution_time": 0
             }
 
     async def check_sensitive(self, trace_id_idx: str, review_content: str,

+ 20 - 143
core/construction_review/component/doc_worker/classification/chunk_classifier.py

@@ -22,101 +22,6 @@ from ..config.provider import default_config_provider
 from ..utils.prompt_loader import PromptLoader
 
 
-# ==================== 二级分类本地规则 ====================
-# 结构: {一级代码: [(关键词模式, 二级代码, 二级中文名), ...]}
-SECONDARY_CLASSIFICATION_RULES: Dict[str, List[Tuple[str, str, str]]] = {
-    "basis": [
-        (r"法律|法规|规章|政策|条文", "LawsAndRegulations", "法律法规"),
-        (r"标准|规范|GB|JTG|CJJ|Q/CR", "StandardsAndSpecifications", "标准规范"),
-        (r"文件|制度|程序|办法|规定|路桥|集团|公司", "DocumentSystems", "文件制度"),
-        (r"编制.*原则|原则|程序|功能|合同|力量", "CompilationPrinciples", "编制原则"),
-        (r"编制.*范围|范围|施工.*工艺", "CompilationScope", "编制范围"),
-    ],
-    "overview": [
-        (r"设计.*概况|概况|简介|介绍|工程.*说明", "DesignSummary", "设计概况"),
-        (r"地质|水文|气象|气候|地下.*水", "GeologyWeather", "工程地质与水文气象"),
-        (r"周边.*环境|环境|位置.*关系|相邻|距离|管线|高压", "Surroundings", "周边环境"),
-        (r"平面.*布置|立面|临时.*设施|拌和|材料|便道|水电", "LayoutPlan", "施工平面及立面布置"),
-        (r"工期|质量.*目标|安全.*目标|环境.*目标|目标", "RequirementsTech", "施工要求和技术保证条件"),
-        (r"风险|危险源|危害|隐患|风险.*辨识|分级", "RiskLevel", "风险辨别与分级"),
-        (r"参建.*单位|建设.*单位|设计.*单位|监理|施工.*单位", "Stakeholders", "参建各方责任主体单位"),
-    ],
-    "plan": [
-        (r"进度.*计划|进度|横道图|甘特图|节点|工期", "Schedule", "施工进度计划"),
-        (r"材料.*计划|材料|物资|钢筋|混凝土|水泥", "Materials", "施工材料计划"),
-        (r"设备.*计划|设备|机械|机具|吊装|起重|泵车", "Equipment", "施工设备计划"),
-        (r"劳动力|人员|工种|工人|班组|劳务", "Workforce", "劳动力计划"),
-        (r"安全.*费用|安全.*投入|安全.*经费", "SafetyCost", "安全生产费用使用计划"),
-    ],
-    "technology": [
-        (r"施工.*方法|工艺.*选择|主要.*方法", "MethodsOverview", "主要施工方法概述"),
-        (r"技术.*参数|材料.*规格|设备.*名称", "TechParams", "技术参数"),
-        (r"工艺.*流程|施工.*流程|工序|流程.*图", "ProcessFlow", "工艺流程"),
-        (r"操作.*要点|施工.*要点|注意.*事项", "OperationPoints", "操作要点"),
-        (r"检查.*要求|质量.*检查|验收.*标准", "InspectionRequirements", "检查要求"),
-    ],
-    "safety": [
-        (r"安全.*目标|目标", "SafetyGoals", "安全目标"),
-        (r"危险源|危害|风险|LEC|辨识", "SafetyHazards", "危险源辨识"),
-        (r"组织.*保证|安全.*组织|管理.*机构|领导小组", "Organization", "组织保证措施"),
-        (r"技术.*措施|安全.*技术|防护|防护.*措施", "SafetyTech", "技术措施"),
-        (r"监测|监控|量测|观测|预警", "Monitoring", "监测监控"),
-        (r"应急|预案|救援|抢险|处置", "Emergency", "应急处置措施"),
-    ],
-    "quality": [
-        (r"质量.*目标|目标|质量.*标准", "QualityGoals", "质量目标"),
-        (r"质量.*组织|组织.*保证|管理.*机构|质量.*体系", "QualityOrg", "质量组织保证措施"),
-        (r"技术.*措施|质量.*技术|控制.*措施|质量保证.*措施", "QualityTech", "技术措施"),
-        (r"检查.*验收|验收.*程序|质量.*检查|三检", "QualityInspection", "检查验收"),
-        (r"质量.*保修|保修.*期|缺陷.*责任", "Warranty", "质量保修"),
-    ],
-    "environment": [
-        (r"环境.*目标|环保.*目标|文明.*施工|绿色.*施工", "EnvGoals", "环境目标"),
-        (r"环保.*组织|环境.*组织|管理.*机构", "EnvOrg", "环境保护组织机构"),
-        (r"环保.*措施|环境.*技术|扬尘|噪声|污水|废弃物", "EnvTech", "技术措施"),
-        (r"节能|减排|资源.*利用|绿色.*建材", "GreenConstruction", "绿色施工措施"),
-    ],
-    "management": [
-        (r"管理.*人员|施工.*管理.*人员|项目.*经理|项目.*总工|名单", "Managers", "施工管理人员"),
-        (r"专职.*安全|安全.*总监|安全员|C证|考核.*合格", "SafetyStaff", "专职安全生产管理人员"),
-        (r"特种.*作业|特种.*人员|电工|焊工|架子工|起重", "SpecialWorkers", "特种作业人员"),
-        (r"其他.*作业|工种.*数量|作业.*人员|分包.*人员", "OtherWorkers", "其它作业人员"),
-    ],
-    "acceptance": [
-        (r"验收.*标准|标准|规范|依据", "Standards", "验收标准"),
-        (r"验收.*程序|程序|流程|步骤", "Procedures", "验收程序"),
-        (r"验收.*人员|人员|组织|验收.*组|专家", "Personnel", "验收人员"),
-        (r"验收.*条件|条件|前提|要求", "Conditions", "验收条件"),
-    ],
-    "other": [
-        (r"计算|验算|受力|稳定性|强度|刚度", "Calculations", "计算书"),
-        (r"图纸|附图|附表|平面.*图|立面.*图|剖面.*图", "Drawings", "图纸"),
-    ],
-}
-
-
-def classify_secondary_local(section_title: str, first_category_code: str) -> Optional[Tuple[str, str, float]]:
-    """
-    本地规则分类二级标题
-
-    返回: (二级代码, 二级中文名, 置信度) 或 None
-    """
-    if not section_title or not first_category_code:
-        return None
-
-    rules = SECONDARY_CLASSIFICATION_RULES.get(first_category_code, [])
-    if not rules:
-        return None
-
-    title = section_title.strip()
-
-    for pattern, code, cn in rules:
-        if re.search(pattern, title, re.IGNORECASE):
-            logger.debug(f"[二级本地分类] '{title}' -> {cn} ({code})")
-            return code, cn, 0.85
-
-    return None
-
 # 延迟导入新的三级分类器(避免循环导入)
 _LLM_CONTENT_CLASSIFIER = None
 
@@ -349,7 +254,7 @@ class ChunkClassifier:
 
     async def classify_chunks_secondary_async(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
         """
-        异步对chunks进行二级分类
+        异步对chunks进行二级分类(全部走LLM,移除本地规则)
 
         参数:
             chunks: 已完成一级分类的chunk列表
@@ -357,7 +262,7 @@ class ChunkClassifier:
         返回:
             添加了二级分类字段的chunk列表
         """
-        logger.info(f"正在对 {len(chunks)} 个内容块进行二级分类...")
+        logger.info(f"正在对 {len(chunks)} 个内容块进行二级分类(LLM全量)...")
 
         # 准备LLM请求
         llm_requests = []
@@ -401,56 +306,28 @@ class ChunkClassifier:
             logger.info("所有内容块都没有二级分类标准,跳过二级分类")
             return chunks
 
-        # === 阶段1: 本地规则分类 ===
-        local_classified = []  # (chunk, code, cn) 或 None
-        need_llm_indices = []  # 需要LLM的索引
+        # 全部走LLM分类
+        logger.info(f"[二级分类] 全部 {len(valid_chunks)} 个内容块走LLM分类")
 
-        for idx, chunk in enumerate(valid_chunks):
-            first_code = chunk.get("chapter_classification", "")
-            section_title = chunk.get("section_label", "")
+        llm_results = await self._batch_call_llm(llm_requests, model_name=self.SECONDARY_MODEL)
 
-            # 尝试本地分类
-            local_result = classify_secondary_local(section_title, first_code)
+        # 处理LLM结果
+        for chunk, llm_result, index_mapping in zip(valid_chunks, llm_results, index_mappings):
+            if llm_result and isinstance(llm_result, dict):
+                category_index = llm_result.get("category_index")
 
-            if local_result:
-                code, cn, confidence = local_result
-                local_classified.append((chunk, code, cn, confidence, "local"))
-                logger.debug(f"[二级本地分类] '{section_title}' -> {cn}")
-            else:
-                local_classified.append((chunk, None, None, 0.0, "need_llm"))
-                need_llm_indices.append(idx)
-
-        logger.info(f"[二级分类] 本地规则分类 {len(local_classified) - len(need_llm_indices)} 个, 需要LLM {len(need_llm_indices)} 个")
-
-        # === 阶段2: LLM分类(仅对需要的)===
-        if need_llm_indices:
-            llm_requests_filtered = [llm_requests[i] for i in need_llm_indices]
-            # 二级分类使用轻量级35B模型以提高速度
-            llm_results = await self._batch_call_llm(llm_requests_filtered, model_name=self.SECONDARY_MODEL)
-
-            # 映射回结果
-            for i, idx in enumerate(need_llm_indices):
-                llm_result = llm_results[i] if i < len(llm_results) else None
-                chunk = valid_chunks[idx]
-                index_mapping = index_mappings[idx]
-
-                if llm_result and isinstance(llm_result, dict):
-                    category_index = llm_result.get("category_index")
-
-                    if isinstance(category_index, int) and category_index in index_mapping:
-                        secondary_cn, secondary_code = index_mapping[category_index]
-                        local_classified[idx] = (chunk, secondary_code, secondary_cn, 0.8, "llm")
-                    else:
-                        # LLM返回无效,使用非标准项
-                        local_classified[idx] = (chunk, "non_standard", "非标准项", 0.0, "llm_failed")
+                if isinstance(category_index, int) and category_index in index_mapping:
+                    secondary_cn, secondary_code = index_mapping[category_index]
+                    chunk["secondary_category_code"] = secondary_code
+                    chunk["secondary_category_cn"] = secondary_cn
                 else:
-                    # LLM调用失败
-                    local_classified[idx] = (chunk, "non_standard", "非标准项", 0.0, "llm_failed")
-
-        # === 阶段3: 写入结果 ===
-        for chunk, code, cn, confidence, source in local_classified:
-            chunk["secondary_category_code"] = code
-            chunk["secondary_category_cn"] = cn
+                    # LLM返回无效,使用非标准项
+                    chunk["secondary_category_code"] = "non_standard"
+                    chunk["secondary_category_cn"] = "非标准项"
+            else:
+                # LLM调用失败
+                chunk["secondary_category_code"] = "non_standard"
+                chunk["secondary_category_cn"] = "非标准项"
 
         logger.info("二级分类完成!")
         return chunks

+ 160 - 0
core/construction_review/component/doc_worker/config/StandardCatalogTemplate.yaml

@@ -0,0 +1,160 @@
+# 施工方案标准目录结构
+# 格式:第X章 一级标题
+#       一、二级标题
+
+catalog:
+  - chapter_num: 1
+    chapter_title: 编制依据
+    sections:
+      - 一、法律法规
+      - 二、标准规范
+      - 三、文件制度
+      - 四、编制原则
+      - 五、编制范围
+
+  - chapter_num: 2
+    chapter_title: 工程概况
+    sections:
+      - 一、设计概况
+      - 二、工程地质与水文气象
+      - 三、周边环境
+      - 四、施工平面及立面布置
+      - 五、施工要求和技术保证条件
+      - 六、风险辨识与分级
+      - 七、参建各方责任主体单位
+
+  - chapter_num: 3
+    chapter_title: 施工计划
+    sections:
+      - 一、施工进度计划
+      - 二、施工材料计划
+      - 三、施工设备计划
+      - 四、劳动力计划
+      - 五、安全生产费用使用计划
+
+  - chapter_num: 4
+    chapter_title: 施工工艺技术
+    sections:
+      - 一、主要施工方法概述
+      - 二、技术参数
+      - 三、工艺流程
+      - 四、施工准备
+      - 五、施工方法及操作要求
+      - 六、检查要求
+
+  - chapter_num: 5
+    chapter_title: 安全保证措施
+    sections:
+      - 一、安全保证体系
+      - 二、组织保证措施
+      - 三、技术保证措施
+      - 四、监测监控措施
+      - 五、应急处置措施
+
+  - chapter_num: 6
+    chapter_title: 质量保证措施
+    sections:
+      - 一、质量保证体系
+      - 二、质量目标
+      - 三、工程创优规划
+      - 四、质量控制程序与具体措施
+
+  - chapter_num: 7
+    chapter_title: 环境保证措施
+    sections:
+      - 一、环境保证体系
+      - 二、环境保护组织机构
+      - 三、环境保护及文明施工措施
+
+  - chapter_num: 8
+    chapter_title: 施工管理及作业人员配备与分工
+    sections:
+      - 一、施工管理人员
+      - 二、专职安全生产管理人员
+      - 三、其他作业人员
+
+  - chapter_num: 9
+    chapter_title: 验收要求
+    sections:
+      - 一、验收标准
+      - 二、验收程序
+      - 三、验收内容
+      - 四、验收时间
+      - 五、验收人员
+
+  - chapter_num: 10
+    chapter_title: 其他资料
+    sections:
+      - 一、计算书
+      - 二、相关施工图纸
+      - 三、附图附表
+      - 四、编制及审核人员情况
+
+# 纯文本格式(用于LLM对比)
+text_template: |
+  第一章 编制依据
+  一、法律法规
+  二、标准规范
+  三、文件制度
+  四、编制原则
+  五、编制范围
+
+  第二章 工程概况
+  一、设计概况
+  二、工程地质与水文气象
+  三、周边环境
+  四、施工平面及立面布置
+  五、施工要求和技术保证条件
+  六、风险辨识与分级
+  七、参建各方责任主体单位
+
+  第三章 施工计划
+  一、施工进度计划
+  二、施工材料计划
+  三、施工设备计划
+  四、劳动力计划
+  五、安全生产费用使用计划
+
+  第四章 施工工艺技术
+  一、主要施工方法概述
+  二、技术参数
+  三、工艺流程
+  四、施工准备
+  五、施工方法及操作要求
+  六、检查要求
+
+  第五章 安全保证措施
+  一、安全保证体系
+  二、组织保证措施
+  三、技术保证措施
+  四、监测监控措施
+  五、应急处置措施
+
+  第六章 质量保证措施
+  一、质量保证体系
+  二、质量目标
+  三、工程创优规划
+  四、质量控制程序与具体措施
+
+  第七章 环境保证措施
+  一、环境保证体系
+  二、环境保护组织机构
+  三、环境保护及文明施工措施
+
+  第八章 施工管理及作业人员配备与分工
+  一、施工管理人员
+  二、专职安全生产管理人员
+  三、其他作业人员
+
+  第九章 验收要求
+  一、验收标准
+  二、验收程序
+  三、验收内容
+  四、验收时间
+  五、验收人员
+
+  第十章 其他资料
+  一、计算书
+  二、相关施工图纸
+  三、附图附表
+  四、编制及审核人员情况

+ 44 - 68
core/construction_review/component/doc_worker/config/StandardCategoryTable.csv

@@ -1,16 +1,12 @@
-first_seq,first_code,first_name,second_seq,second_code,second_name,second_focus,third_seq,third_code,third_name,third_focus,keywords,extra_prompt
-1,basis,编制依据,1,LawsAndRegulations,法律法规,NULL,1,NationalLawsAndRegulations,国家政府发布的法律法规与规章制度,国家级、法律、法规、规章、强制力、普遍适用、基础框架、顶层设计、行业准则、合规性、统一标准、权威性、强制性条文、基本要求。,国家法律;法规;规章;强制性条文;国务院令;住房城乡建设部;中华人民共和国,
-1,basis,编制依据,1,LawsAndRegulations,法律法规,NULL,2,ProvincialLawsAndRegulationsOfProjectLocation,工程所在地省级政府发布的法律法规与规章制度,地方性、区域性、细化补充、因地制宜、执行细则、地方特色、适应性要求、属地管理、动态调整、配套政策、本地化实施。,省级;地方法规;省政府;地方规章;属地管理;四川省;省人民政府,
-1,basis,编制依据,2,StandardsAndSpecifications,标准规范,NULL,1,IndustryStandards,行业标准,需符合国家/行业强制或推荐性标准(如GB/T、JTG等)、时效性强(需跟踪最新版)、覆盖全生命周期(设计→施工→运维)、是定义工程项目的最低技术要求、质量验收准则、安全红线。,GB/T;JTG;CJJ;行业标准;国家标准;推荐性标准;GB 5;TB;HJ;DL,
-1,basis,编制依据,3,DocumentSystems,文件制度,NULL,1,SichuanRoadAndBridgeDocumentSystemsAndmanagementProcedures,四川路桥下发的文件制度和管理程序文件,四川路桥下发的文件制度和管理程序文件,与四川路桥相关的文件制度和管理程序文件,视为符合,包含四川公路桥梁建设集团;四川公路桥梁;SCQJ;SCQJT;四川路桥总公司;四川路桥等关键字视为符合,四川公路桥梁建设集团;四川公路桥梁;SCQJ;SCQJT;四川路桥总公司,
-1,basis,编制依据,3,DocumentSystems,文件制度,NULL,2,RoadAndBridgeGroupDocumentSystemsAndmanagementProcedures,路桥集团下发的文件制度和管理程序文件,路桥集团下发的文件制度和管理程序文件,与路桥集团相关的文件制度和管理程序文件,视为符合,包含路桥集团;路桥股份;四川路桥集团有限公司;四川路桥集团;四川路桥集团超危大;川路桥〔;路桥〔;集团下发;集团公司文件等关键字视为符合,路桥集团;路桥股份;四川路桥集团有限公司;四川路桥集团;四川路桥集团超危大;川路桥〔;路桥〔;集团下发;集团公司文件,
-1,basis,编制依据,3,DocumentSystems,文件制度,NULL,3,BridgeCompanyDocumentSystemsAndmanagementProcedures,桥梁公司下发的文件制度和管理程序文件,桥梁公司下发的文件制度和管理程序文件,与桥梁公司相关的文件制度和管理程序文件,视为符合,包含桥梁公司;桥梁分公司;桥梁工程公司;四川路桥桥梁公司;公司下发;公司管理制度等关键字视为符合,桥梁公司;桥梁分公司;桥梁工程公司;四川路桥桥梁公司;公司下发;公司管理制度,
-1,basis,编制依据,3,DocumentSystems,文件制度,NULL,4,ConstructionUnitDocumentSystemsAndmanagementProcedures,建设单位下发的文件制度和管理程序文件,建设单位下发的文件制度和管理程序文件,与建设单位相关的文件制度和管理程序文件,视为符合,包含建设单位;业主;甲方文件;建设方;建设单位下发;业主要求等关键字视为符合,建设单位;业主;甲方文件;建设方;建设单位下发;业主要求,
-1,basis,编制依据,4,CompilationPrinciples,编制原则,NULL,1,NationalPoliciesStandardsAndDesignDocument,编制原则细则,"编制原则应认真贯彻执行国家方针、政策、标准和设计文件,严格执行基本建
+first_seq,first_code,first_name,second_seq,second_code,second_name,second_focus,third_seq,third_code,third_name,third_focus,keywords,extra_prompt
+1,basis,编制依据,1,LawsAndRegulations,法律法规,,1,NationalLawsAndRegulations,国家政府发布的法律法规与规章制度,国家级、法律、法规、规章、强制力、普遍适用、基础框架、顶层设计、行业准则、合规性、统一标准、权威性、强制性条文、基本要求。,国家法律;法规;规章;强制性条文;国务院令;住房城乡建设部;中华人民共和国,
+1,basis,编制依据,1,LawsAndRegulations,法律法规,,2,ProvincialLawsAndRegulationsOfProjectLocation,工程所在地省级政府发布的法律法规与规章制度,地方性、区域性、细化补充、因地制宜、执行细则、地方特色、适应性要求、属地管理、动态调整、配套政策、本地化实施。,省级;地方法规;省政府;地方规章;属地管理;四川省;省人民政府,
+1,basis,编制依据,2,StandardsAndSpecifications,标准规范,,1,IndustryStandards,行业标准,需符合国家/行业强制或推荐性标准(如GB/T、JTG等)、时效性强(需跟踪最新版)、覆盖全生命周期(设计→施工→运维)、是定义工程项目的最低技术要求、质量验收准则、安全红线。,GB/T;JTG;CJJ;行业标准;国家标准;推荐性标准;GB 5;TB;HJ;DL,
+1,basis,编制依据,3,DocumentSystems,文件制度,,1,SichuanRoadAndBridgeDocumentSystemsAndmanagementProcedures,四川路桥下发的文件制度和管理程序文件,四川路桥下发的文件制度和管理程序文件,与四川路桥相关的文件制度和管理程序文件,视为符合,包含四川公路桥梁建设集团;四川公路桥梁;SCQJ;SCQJT;四川路桥总公司;四川路桥等关键字视为符合,四川公路桥梁建设集团;四川公路桥梁;SCQJ;SCQJT;四川路桥总公司,
+1,basis,编制依据,3,DocumentSystems,文件制度,,2,ConstructionUnitDocumentSystemsAndmanagementProcedures,建设单位下发的文件制度和管理程序文件,需明确引用建设单位(即“蜀道集团”或“蜀道投资集团”)下发的文件制度或管理程序。请重点识别带有该集团名称的《XX管理办法》、明确表述“遵照蜀道集团规定”,或包含类似“蜀道司发〔20XX〕XXX号”特征的文件编号。,建设单位;业主;甲方文件;建设方;建设单位下发;业主要求,
+1,basis,编制依据,4,CompilationPrinciples,编制原则,,1,NationalPoliciesStandardsAndDesignDocument,编制原则细则,"编制原则应认真贯彻执行国家方针、政策、标准和设计文件,严格执行基本建
 设程序,实现工程项目的全部功能;全面履行工程合同,满足建设单位要求,有效
 地集中施工力量,按期完成;按照工序关系,合理安排施工顺序,统筹考虑。",国家方针;政策;设计文件;国家政策;设计规范;设计图纸;施工图,
-1,basis,编制依据,5,CompilationScope,编制范围,NULL,1,ProjectCoverage,填写完整涵盖本方案包含的所有工程,"编制范围应填写完整,涵盖本方案包含的所有工程,部分工程可简要说明采取
-的施工工艺。",编制范围;工程范围;施工范围;工程内容;本方案涵盖;方案范围,
 2,overview,工程概况,1,DesignSummary,设计概况,关注名称类、具体数值类、量化单位类、技术标准需引用国家或行业规范、关注标准号数字类、各类年限、等级数值、量化单位。,1,ProjectIntroduction,工程简介,工程名称、工程类型(如住宅、桥梁、隧道)、建设规模(如建筑面积、长度、高度)、工程地址、投资额、工程性质(新建/改建/扩建)、设计单位、设计依据(如合同编号)、工程范围(如施工边界坐标)。,工程名称;工程概况;工程简介;工程性质;建设规模;工程类型;项目名称,
 2,overview,工程概况,1,DesignSummary,设计概况,关注名称类、具体数值类、量化单位类、技术标准需引用国家或行业规范、关注标准号数字类、各类年限、等级数值、量化单位。,2,MainTechnicalStandards,主要技术标准,技术规范编号、设计使用年限、荷载标准(如活荷载、恒荷载)、抗震设防烈度、防火等级、环保标准(如绿色建筑认证)、材料标准(如混凝土强度等级C30)、施工工艺标准。,技术标准;设计使用年限;荷载等级;抗震设防;防火等级;混凝土强度;技术规范编号,
 2,overview,工程概况,2,GeologyWeather,工程地质与水文气象,关注地名类、具体水位数值类、量化单位类、关注记录降雨量、水位、气温等数值量化单位类。,1,HydrologicalConditions,水文状况,地下水位(历史最高水位、当前水位)、含水层类型(孔隙水、裂隙水、承压水)、隔水层厚度、渗透系数(K值)、给水度、水质腐蚀性(如pH值、氯离子含量)、补径排条件(补给源、径流方向)、水文地质参数(如越流系数)、地下水动态监测数据。,水文;地下水;水位;地下水位;含水层;渗透系数;水文地质;补径排,
@@ -18,21 +14,20 @@
 2,overview,工程概况,3,Surroundings,周边环境,周边环境需分析地形地貌名词、建筑分布名词及交通状况道路名词、相关量化单位、相关数字数值、各类专业性名词、建筑物名词、米或毫米等单位类。,1,PositionalRelationship,周边环境,"周边环境主要包括与该工程有关的主要建(构)筑物、山体、边坡、河谷、深
 基坑、道路、高压电、地下管线的位置关系、结构尺寸等情况,并在《施工平面布
 置图》中绘制,标注距离和尺寸。",位置关系;周边环境;相邻建筑;距离;管线;高压线;河道;构筑物;方位,
-2,overview,工程概况,4,LayoutPlan,施工平面及立面布置,场地名词、数值类、量化单位类、名称类、数值类、量化单位类。,1,TemporaryFacilityLocation,临时设施位置,拌和站坐标(如X、Y)、钢筋加工场距工程距离(米)、材料堆码区域面积(㎡)、临时占地红线、与工程最近点距离、场地利用率(%)。,拌和站;钢筋加工;材料堆放;临时设施;临时占地;材料堆场,
-2,overview,工程概况,4,LayoutPlan,施工平面及立面布置,场地名词、数值类、量化单位类、名称类、数值类、量化单位类。,2,ConstructionWorkPlatform,施工作业平台与便道参数,作业平台尺寸(长×宽、米)、地面形式(混凝土硬化、砂石铺垫)、施工便道长度(米)、宽度(米)、路面形式(沥青、碎石)、最小弯曲半径(米)、坡度(%)、承载力(kPa)。,施工平台;作业平台;施工便道;便道长度;平台尺寸;通道宽度,
-2,overview,工程概况,4,LayoutPlan,施工平面及立面布置,场地名词、数值类、量化单位类、名称类、数值类、量化单位类。,3,TemporaryWaterAndElectricityArrangement,临时水电布置,临时用水源(市政管网、地下水井)、管径(如DN100)、管线布置图(走向、节点距离)、供水压力(MPa)、变压器容量(kVA)、配电箱位置、线路走向(架空/埋地)、敷设方式(直埋、穿管)、电缆规格(如YJV22)。,临时用水;临时用电;供水管径;配电箱;水电布置;临时电缆,
+2,overview,工程概况,4,LayoutPlan,施工平面及立面布置,场地名词、数值类、量化单位类、名称类、数值类、量化单位类。,1,ConstructionWorkPlatform,施工作业平台与便道参数,作业平台尺寸(长×宽、米)、地面形式(混凝土硬化、砂石铺垫)、施工便道长度(米)、宽度(米)、路面形式(沥青、碎石)、最小弯曲半径(米)、坡度(%)、承载力(kPa)。,施工平台;作业平台;施工便道;便道长度;平台尺寸;通道宽度,
+2,overview,工程概况,4,LayoutPlan,施工平面及立面布置,场地名词、数值类、量化单位类、名称类、数值类、量化单位类。,2,TemporaryWaterAndElectricityArrangement,临时水电布置,临时用水源(市政管网、地下水井)、管径(如DN100)、管线布置图(走向、节点距离)、供水压力(MPa)、变压器容量(kVA)、配电箱位置、线路走向(架空/埋地)、敷设方式(直埋、穿管)、电缆规格(如YJV22)。,临时用水;临时用电;供水管径;配电箱;水电布置;临时电缆,
 2,overview,工程概况,5,RequirementsTech,施工要求和技术保证条件,名称类、日期类。名称类、量化单位类、数值类。,1,DurationTarget,工期目标,工期目标包括本项目的总体工期和本工程的工期,仅需说明起止时间和持续时间,工期;开工日期;竣工日期;总工期;工期目标;关键节点;工期保证,
 2,overview,工程概况,5,RequirementsTech,施工要求和技术保证条件,名称类、日期类。名称类、量化单位类、数值类。,2,QualityTarget,质量目标,质量目标、合同条款编号、业主具体要求(如绿色施工认证)。,质量目标;合格率;质量标准;鲁班奖;优质工程;质量等级,
 2,overview,工程概况,5,RequirementsTech,施工要求和技术保证条件,名称类、日期类。名称类、量化单位类、数值类。,3,SecurityGoals,安全目标,安全目标(如零死亡事故、隐患整改率)、合同条款编号、业主具体要求(如绿色施工认证)。,安全目标;零伤亡;安全事故;安全指标;安全生产目标,
 2,overview,工程概况,5,RequirementsTech,施工要求和技术保证条件,名称类、日期类。名称类、量化单位类、数值类。,4,EnvironmentalGoals,环境目标,环境目标(如扬尘控制、噪声限值)或业主具体要求(如绿色施工认证)。,环境目标;扬尘控制;噪声限值;绿色施工指标;文明施工目标,
-2,overview,工程概况,6,RiskLevel,风险辨识与分级,危害隐患性词汇类、法规名称类、标准编号类。风险等级相关专业性词汇、属于、标准编号或其它编号、部门名称类、数值类、量化单位类。名称类、数值类。,1,DangerSource,危险源,"风险辨识与分级包含在施工过程中所有的危险源,并按照法律法规的要求对其
-进行分级,并说明其应对措施。如果页面采用横向布置,本章保留标题,",危险源;风险源;危害因素;安全隐患;事故隐患;危险因素;风险点,
-2,overview,工程概况,6,RiskLevel,风险辨识与分级,危害隐患性词汇类、法规名称类、标准编号类。风险等级相关专业性词汇、属于、标准编号或其它编号、部门名称类、数值类、量化单位类。名称类、数值类。,2,ClassificationAndResponseMeasures,分级与应对措施,"风险辨识与分级包含在施工过程中所有的危险源,并按照法律法规的要求对其
-进行分级,并说明其应对措施。如果页面采用横向布置,本章保留标题,",风险等级;重大风险;较大风险;一般风险;应对措施;LEC;风险分级;风险评估,
+2,overview,工程概况,6,RiskLevel,风险辨识与分级,危害隐患性词汇类、法规名称类、标准编号类。风险等级相关专业性词汇、属于、标准编号或其它编号、部门名称类、数值类、量化单位类。名称类、数值类。,1,DangerSource,危险源,"第一优先级(引用识别): 若文本中出现如“见表XX”、“见附件XX”、“相关表格放置于第十章(或某章)”等明确指向外部表格或附件的表述,直接视为满足当前审查要求。
+第二优先级(要素审查): 若文本中没有指向外部的引用,请审查正文是否同时包含了以下核心要素:列出具体的危险源。",危险源;风险源;危害因素;安全隐患;事故隐患;危险因素;风险点,
+2,overview,工程概况,6,RiskLevel,风险辨识与分级,危害隐患性词汇类、法规名称类、标准编号类。风险等级相关专业性词汇、属于、标准编号或其它编号、部门名称类、数值类、量化单位类。名称类、数值类。,2,ClassificationAndResponseMeasures,分级与应对措施,"第一优先级(引用识别): 若文本中出现如“见表XX”、“见附件XX”、“相关表格放置于第十章(或某章)”等明确指向外部表格或附件的表述,直接视为满足当前审查要求。
+第二优先级(要素审查): 若文本中没有指向外部的引用,请审查正文是否同时包含了以下核心要素:① 对危险源进行分级;;② 明确对应的应对措施。",风险等级;重大风险;较大风险;一般风险;应对措施;LEC;风险分级;风险评估,
 2,overview,工程概况,7,Stakeholders,参建各方责任主体单位,名称类、数值类。,1,UnitType,单位类型,"参建各方责任主体单位主要描述该项目的建设单位、设计单位、监理单位、施
 工单位、监控单位、专业分包单位的名称。",建设单位;设计单位;监理单位;施工单位;参建单位;总承包;社会信用代码,
-3,plan,施工计划,1,Schedule,施工进度计划,关键工程节点安排、施工进度计划横道图、进度控制点、里程碑事件、工序搭接关系、工期延误风险、进度调整机制、施工流水节拍、网络计划技术(如双代号网络图),2,KeyProjectNodeArrangement,关键工程(工序)节点安排,主要工程(工序)节点的起止时间和持续时间、聚焦影响总工期的关键工序(如基础浇筑、主体封顶)、是进度控制的核心;,关键节点;里程碑;关键工序;主要节点;节点工期;关键线路,
-3,plan,施工计划,1,Schedule,施工进度计划,、关键工程节点安排、施工进度计划横道图、进度控制点、里程碑事件、工序搭接关系、工期延误风险、进度调整机制、施工流水节拍、网络计划技术(如双代号网络图),3,ConstructionScheduleGanttChart,施工进度计划横道图等,施工进度计划横道图,包含施工进度计划横道图相关名词视为符合,直观展示进度安排的标准工具、需包含主要工序名称、起始时间、截止时间、持续时间、时间横道、责任人等信息;,横道图;进度横道;施工进度计划;甘特图;进度安排;时间计划,
+3,plan,施工计划,1,Schedule,施工进度计划,关键工程节点安排、施工进度计划横道图、进度控制点、里程碑事件、工序搭接关系、工期延误风险、进度调整机制、施工流水节拍、网络计划技术(如双代号网络图),1,KeyProjectNodeArrangement,关键工程(工序)节点安排,主要工程(工序)节点的起止时间和持续时间、聚焦影响总工期的关键工序(如基础浇筑、主体封顶)、是进度控制的核心;,关键节点;里程碑;关键工序;主要节点;节点工期;关键线路,
+3,plan,施工计划,1,Schedule,施工进度计划,、关键工程节点安排、施工进度计划横道图、进度控制点、里程碑事件、工序搭接关系、工期延误风险、进度调整机制、施工流水节拍、网络计划技术(如双代号网络图),2,ConstructionScheduleGanttChart,施工进度计划横道图等,施工进度计划横道图,包含施工进度计划横道图相关名词视为符合,直观展示进度安排的标准工具、需包含主要工序名称、起始时间、截止时间、持续时间、时间横道、责任人等信息;,横道图;进度横道;施工进度计划;甘特图;进度安排;时间计划,
 3,plan,施工计划,2,Materials,施工材料计划,名称类、规格类、数值类、数值单位类,1,ListOfConstructionMeasuresAndMaterials,施工措施材料清单,排除主题工程材料、施工措施材料应包含如临时支撑结构材料、辅助施工材料、非主体工程的挡防措施、作业平台处理、模板配置、人员上下通道、安全防护措施和安全防护用品等、详细列出材料名称、规格、数量、重量及来源(如厂家、经销商)、是材料计划的核心输出,措施材料;临时支撑材料;辅助材料;安全防护材料;模板;脚手架材料,
 3,plan,施工计划,3,Equipment,施工设备计划,设备名称类、规格类、数值类、数值单位类、时间日期类,1,MainConstructionMachineryAndEquipment,主要施工机械设备,列出关键设备(如起重吊装设备、混凝土浇筑设备、张拉压浆设备、人员升降设备、钻孔设备、隧道专用设备、监测监控设备、质量检查验收设备等)、明确其设备名称、规格(如额定功率)、数量及来源(自有或租赁);,施工机械;机械设备;起重机;泵车;钻机;吊装设备;设备清单;主要机械,
 3,plan,施工计划,4,Workforce,劳动力计划,工种名称类、时间日期类、数值类、数值单位类,1,WorkforceAllocationPlan,劳动力配置计划,【工种与人数维度】:文本或表格中必须按不同的技术工种(如操作手、电工、普工等)列出对应的人员数量。,劳动力;工种投入;工人配置;班组;劳动力计划;人员配置计划,
@@ -45,16 +40,15 @@
 3,plan,施工计划,5,SafetyCost,安全生产费用使用计划,名称类、金额类、货币数值类、货币单位类、不能将项目总的安全生产费用列入,3,SingleInvestmentAmount,单项投入金额,单项投入金额即每项费用的具体数值(如“临时防护栏杆采购:5万元”)、确保费用可量化;,单项金额;费用金额;万元;单项投入;单项安全费,
 3,plan,施工计划,5,SafetyCost,安全生产费用使用计划,名称类、金额类、货币数值类、货币单位类、不能将项目总的安全生产费用列入,4,TotalSafetyProductionExpenses,安全生产费用总额,根据工程规模、风险等级计算、确保足额投入,安全费用总额;总金额;安全投入合计;安全费总计,
 4,technology,施工工艺技术,1,MethodsOverview,主要施工方法概述,工艺名称类、施工专业词汇类、规格类、数值类、数值单位类,1,ConstructionTechnologySelection,施工工艺选择,主要施工方法概述应简要说明采取的主要施工工艺和施工方法,或为见附表,见附录,见详情类似表述视为符合,工艺选择;施工工艺;核心工艺;施工方法选择;工法,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-4,technology,施工工艺技术,1,MethodsOverview,主要施工方法概述,工艺名称类、施工专业词汇类、规格类、数值类、数值单位类,2,MainConstructionMethods,主要施工方法,"主要施工方法概述应简要说明采取的主要施工工艺和施工方法,或为见附表,见附录,见详情类似表述视为符合",施工方法;主要施工方法;关键做法;灌注桩;现浇;装配式;施工工法,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-4,technology,施工工艺技术,2,TechParams,技术参数,工程材料类名词、规格类、数值类、数值单位类、时间日期类、重量单位类,1,MaterialType,材料类型规格,术参数主要包含使用材料的类型、规格,材料类型;钢筋;混凝土;防水材料;钢材;主要材料,
-4,technology,施工工艺技术,2,TechParams,技术参数,工程材料类名词、规格类、数值类、数值单位类、时间日期类、重量单位类,2,MaterialSpecifications,主要设备名称,本参数主要设备的名称、型号、出厂时间、性能参数、自重等。,材料规格;型号;HRB400;C30;规格型号;材料尺寸,
+4,technology,施工工艺技术,1,MethodsOverview,主要施工方法概述,工艺名称类、施工专业词汇类、规格类、数值类、数值单位类,2,MainConstructionMethods,主要施工方法,"主要施工方法概述应简要说明采取的主要施工工艺和施工方法,或为见附表,见附录,见详情类似表述视为符合",材料类型;钢筋;混凝土;防水材料;钢材;主要材料;材料规格;型号;HRB400;C30;规格型号;材料尺寸,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
+4,technology,施工工艺技术,2,TechParams,技术参数,工程材料类名词、规格类、数值类、数值单位类、时间日期类、重量单位类,1,MaterialType,"材料类型规格,主要设备名称",本参数主要包含使用材料的类型、规格或本参数主要设备的名称、型号、出厂时间、性能参数、自重等。,材料类型;钢筋;混凝土;防水材料;钢材;主要材料,
 4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,1,MeasurementAndStakeout,测量放样,需明确测量的基准点、控制网设置、是施工定位的关键;,测量放样;控制网;轴线;基准点;放线;测量基准;坐标,
 4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,2,TemporaryWaterAndElectricityConsumption,临时水电用量,需计算施工期间的用水、用电量、,临时用水量;临时用电量;用水量;用电量;水电用量,
-4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,4,Staffing,人员,需列出各岗位的人员数量、是劳动力管理的核心;,人员配置;岗位人员;项目经理;施工员;人员配备;人员分工,
-4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,5,SafetyProtectionFacilities,安全防护措施,需列出现场的安全设施、是安全保障的基础;,安全防护;安全网;防护栏杆;消防设施;安全设施;防护措施,
+4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,3,Staffing,人员,需列出各岗位的人员数量、是劳动力管理的核心;,人员配置;岗位人员;项目经理;施工员;人员配备;人员分工,
+4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,4,SafetyProtectionFacilities,安全防护措施,需列出现场的安全设施、是安全保障的基础;,安全防护;安全网;防护栏杆;消防设施;安全设施;防护措施,
 4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,5,Area,场地,需列出施工场地等介绍;,安全防护;安全网;防护栏杆;消防设施;安全设施;防护措施,
-4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,5,Equipment,设备,需列出施工设备等介绍;,安全防护;安全网;防护栏杆;消防设施;安全设施;防护措施,
-4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,6,PersonnelAccess,人员上下通道,需明确通道的形式、位置、是人员通行的安全保障。,人员通道;上下通道;楼梯通道;斜道;人员上下;通道布置,
+4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,6,Equipment,设备,需列出施工设备等介绍;,安全防护;安全网;防护栏杆;消防设施;安全设施;防护措施,
+4,technology,施工工艺技术,3,PrepWork,施工准备,名称类、数值类、规格类、数值单位类、岗位名称类、时间日期类、工程设备类,7,PersonnelAccess,人员上下通道,需明确通道的形式、位置、是人员通行的安全保障。,人员通道;上下通道;楼梯通道;斜道;人员上下;通道布置,
 4,technology,施工工艺技术,4,Process,工艺流程,工序专业名称类、工程名称类、数值类、数值单位类,1,ConstructionProcess,工艺流程,"工艺流程包含整个方案的主要施工工序,按照施工的先后顺序,建议采用金山
 软件流程图或微软Visio进行绘制,工艺流程图采用无颜色填充,字体为五号或小
 五号。",施工工序;主要工序;工序流程;施工顺序;工艺步骤,
@@ -62,8 +56,8 @@
 4,technology,施工工艺技术,5,Operations,施工方法及操作要求,施工流程名称类、数值类、数值单位类,2,ConstructionPoints,施工要点,需明确工序的关键要求、是质量控制的关键;,施工要点;关键要求;质量关键;工艺要点;控制要点,
 4,technology,施工工艺技术,5,Operations,施工方法及操作要求,施工流程名称类、数值类、数值单位类,3,FAQPrevention,常见问题及预防,需列出工序的常见问题及预防措施、是风险防控的重点 ,常见问题;质量通病;预防措施;防治措施;常见缺陷;预防对策,
 4,technology,施工工艺技术,5,Operations,施工方法及操作要求,施工流程名称类、数值类、数值单位类,4,ProblemSolvingMeasures,问题处理措施,需明确问题的解决方法、是问题解决的指南;,问题处理;处理措施;整改措施;修复方法;缺陷处理,
-4,technology,施工工艺技术,6,Inspection,检查要求,工序检查内容、工序检查标准,3,ProcessInspectionContent,工序检查内容,【施工工序检查维度】:文本必须涵盖该方案主要施工步骤(如安装、浇筑、张拉等)的过程检查内容。,工序检查;检查内容;检查项目;工序检验;检查清单,
-4,technology,施工工艺技术,6,Inspection,检查要求,工序检查内容、工序检查标准,4,ProcessInspectionStandards,工序检查标准,【量化标准有效性(红线)】:针对上述检查内容,文本必须提供具体的“检查标准”。特征表现为明确的量化允许偏差(如±Xmm)、强度指标(如100%)、或明确引用的国家/行业验收规范条款编号。,检查标准;验收标准;允许偏差;检查合格;偏差限值,
+4,technology,施工工艺技术,6,Inspection,检查要求,工序检查内容、工序检查标准,1,ProcessInspectionContent,工序检查内容,【施工工序检查维度】:文本必须涵盖该方案主要施工步骤(如安装、浇筑、张拉等)的过程检查内容。,工序检查;检查内容;检查项目;工序检验;检查清单,
+4,technology,施工工艺技术,6,Inspection,检查要求,工序检查内容、工序检查标准,2,ProcessInspectionStandards,工序检查标准,【量化标准有效性(红线)】:针对上述检查内容,文本必须提供具体的“检查标准”。特征表现为明确的量化允许偏差(如±Xmm)、强度指标(如100%)、或明确引用的国家/行业验收规范条款编号。,检查标准;验收标准;允许偏差;检查合格;偏差限值,
 5,safety,安全保证措施,1,SafetySystem,安全保证体系,流程体系类名词、标准文书类、标标准编号编码数字类,1,SafetyProductionAssuranceSystemFrameworkDiagram,安全生产保证体系框图,含安全生产保证体系框图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,安全保证体系;安全体系框图;安全管理体系框图;安全组织体系,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
 5,safety,安全保证措施,2,Organization,组织保证措施,名词类、人名类、岗位名称类、制度名词类,1,SafetymanagementOrganization,安全管理组织机构,基于项目经理为组长的安全工作领导小组、关注岗位组织架构名称类、部门名称类、关系结构类名词;,安全管理组织;安全领导小组;安全管理机构;安全管理组织机构,
 5,safety,安全保证措施,2,Organization,组织保证措施,名词类、人名类、岗位名称类、制度名词类,2,PersonnelSafetyResponsibilities,人员安全职责,关注岗位名称类、人名类、责任制度名词类、岗位职责名词类、安全制度名词类;,安全职责;人员安全责任;岗位安全;安全责任制,
@@ -85,16 +79,15 @@
 5,safety,安全保证措施,5,Emergency,应急处置措施,事故名称类、救援器材类、机构名称类、数字类、数值单位类。,3,EmergencySuppliesAndEquipmentSupport,应急物资及设备保障,应根据事故的不同、以表格的形式说明救援的物品名称、规格型号、单位、数量、监管人、联系电话等内容、应急处置的物质基础、需明确物资的名称(如灭火器、急救箱、千斤顶)、数量(如每100平方米配备2个灭火器)、存放位置(如施工现场入口处)及维护要求(如每月检查一次灭火器压力)、确保物资随时可用;,应急物资;应急设备;救援器材;灭火器;急救箱;应急保障,
 5,safety,安全保证措施,5,Emergency,应急处置措施,事故名称类、救援器材类、机构名称类、数字类、数值单位类。,4,TrafficmanagementAndMedicalRescue,交通疏导与医疗救援,应以表格的形式明确施工工点附近的医疗救援机构名称、联系电话、距离等、并附应急救援线路图;,医疗救援;交通疏导;救援线路;医院联系;急救电话;应急救援路线,
 5,safety,安全保证措施,5,Emergency,应急处置措施,事故名称类、救援器材类、机构名称类、数字类、数值单位类。,5,PostDisposal,后期处置,包括善后处理、调查与评估、恢复生产等三个方面、事故后的恢复工作、需明确善后处理(如伤亡人员家属安抚、财产损失统计)、事故调查(如原因分析、责任认定评估)及整改措施(如完善安全制度、加强培训)、避免事故重复发生;,后期处置;善后处理;事故调查;恢复生产;善后工作;事故评估,
-6,quality,质量保证措施,1,QualitySystem,质量保证体系,组织机构名称类、岗位名称类、岗位职责词汇类。,2,QualitymanagementOrganization,人员职责,基于项目经理为组长的工作领导小组、小组中包括项目经理、项目总工、质量总监、工程部门、质检部门、专业分包单位(协作队伍)项目负责人和项目技术负责人等、需明确层级(如公司级、项目级、班组级)及组成部门(如质量部、工程部、技术部)、形成“横向到边、纵向到底”的管理网络;,质量管理组织;质量领导小组;质检人员;质量总监;质量体系组织,
-6,quality,质量保证措施,1,QualitySystem,质量保证体系,组织机构名称类、岗位名称类、岗位职责词汇类。,3,PersonnelResponsibilities,质量保证体系框图,含质量保证体系框图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,质量职责;质量责任制;岗位质量责任;质量保证体系框图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
+6,quality,质量保证措施,1,QualitySystem,质量保证体系,组织机构名称类、岗位名称类、岗位职责词汇类。,1,QualitymanagementOrganization,人员职责,基于项目经理为组长的工作领导小组、小组中包括项目经理、项目总工、质量总监、工程部门、质检部门、专业分包单位(协作队伍)项目负责人和项目技术负责人等、需明确层级(如公司级、项目级、班组级)及组成部门(如质量部、工程部、技术部)、形成“横向到边、纵向到底”的管理网络;,质量管理组织;质量领导小组;质检人员;质量总监;质量体系组织,
+6,quality,质量保证措施,1,QualitySystem,质量保证体系,组织机构名称类、岗位名称类、岗位职责词汇类。,2,PersonnelResponsibilities,质量保证体系框图,含质量保证体系框图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,质量职责;质量责任制;岗位质量责任;质量保证体系框图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
 6,quality,质量保证措施,2,QualityGoals,质量目标,目标标准词汇类、合同条款类、具体工程名称类、量化数值类、数值单位类。,1,DecompositionOfQualityObjectives,质量目标分解,根据施工合同和业主要求填写、需将总目标拆解为分部(基础、主体、装饰)、分项工程的具体目标(如“主体结构混凝土强度合格率100%”)、是目标落地的关键;,质量目标分解;分项质量;质量指标;质量目标分项,
-6,quality,质量保证措施,3,Excellence,工程创优规划,工程创优总体计划、技术准备(BIM/新技术应用)、过程控制(关键工序精品打造)、细部处理(节点优化)、精品工程创建、新技术推广(四新技术)、申报资料编制、工程资料归档、创优考核机制,7,EngineeringDataArchiving,工程创优规划要求,"1、广泛开展QC小组及创优质样板工程活动,通过广泛的论证、分析和研究,确保工程质量得到有效控制。 
+6,quality,质量保证措施,3,Excellence,工程创优规划,工程创优总体计划、技术准备(BIM/新技术应用)、过程控制(关键工序精品打造)、细部处理(节点优化)、精品工程创建、新技术推广(四新技术)、申报资料编制、工程资料归档、创优考核机制,1,EngineeringDataArchiving,工程创优规划要求,"1、广泛开展QC小组及创优质样板工程活动,通过广泛的论证、分析和研究,确保工程质量得到有效控制。 
 2、在施工前,组织有关人员认真学习新技术、新工艺、新材料、新设备、新测试方法的技术要点,并认真进行技术交底,确保在施工中正确应用,提高工程质量。
 3、施工后总结评比。使广大技术人员熟悉和掌握有关的施工规范、规程和质量标准。在施工中,加强质量监督和技术指导,确保工程质量。",工程资料归档;档案管理;竣工资料;资料归档,
-6,quality,质量保证措施,4,QualityControl,质量控制程序与具体措施,原材料检查验收(三证一检)、实体工程质量验收(分项/分部工程验收)、质量通病防治(墙面空鼓/屋面渗漏)、季节性施工质量控制(冬期混凝土保温/雨期防水)、工序质量控制点、质量检查程序(自检/互检/专检)、质量问题整改(闭环管理),1,RawMaterialInspection,原材料检查验收,需执行“三证一检”(合格证、质检报告、生产许可证+进场复检)、确保材料质量;,原材料进场;三证一检;材料检验;复检报告;进场材料质量,
-6,quality,质量保证措施,4,QualityControl,质量控制程序与具体措施,原材料检查验收(三证一检)、实体工程质量验收(分项/分部工程验收)、质量通病防治(墙面空鼓/屋面渗漏)、季节性施工质量控制(冬期混凝土保温/雨期防水)、工序质量控制点、质量检查程序(自检/互检/专检)、质量问题整改(闭环管理),2,PhysicalProjectQualityAcceptance,实体工程质量验收,需按分项(如“钢筋绑扎”)、分部工程(如“基础工程”)进行验收、符合规范要求;,实体验收;分项验收;分部验收;实体工程验收;工程质量验收,
-6,quality,质量保证措施,4,QualityControl,质量控制程序与具体措施,原材料检查验收(三证一检)、实体工程质量验收(分项/分部工程验收)、质量通病防治(墙面空鼓/屋面渗漏)、季节性施工质量控制(冬期混凝土保温/雨期防水)、工序质量控制点、质量检查程序(自检/互检/专检)、质量问题整改(闭环管理),3,PreventionAndControlOfCommonQualityDefectsInProcesses,工序质量通病防治,需针对常见问题(如“墙面空鼓”“屋面渗漏”)制定专项措施(如“抹灰前基层凿毛”“防水附加层施工”)、减少质量缺陷;,质量通病;空鼓;渗漏;裂缝;蜂窝麻面;防治措施;通病防治,
-6,quality,质量保证措施,4,QualityControl,质量控制程序与具体措施,原材料检查验收(三证一检)、实体工程质量验收(分项/分部工程验收)、质量通病防治(墙面空鼓/屋面渗漏)、季节性施工质量控制(冬期混凝土保温/雨期防水)、工序质量控制点、质量检查程序(自检/互检/专检)、质量问题整改(闭环管理),4,SeasonalConstructionQualityAssuranceMeasures,季节性施工质量保证措施,需针对冬期(混凝土保温)、雨期(防水加强)、高温(混凝土保湿)制定专项措施、确保施工质量;,季节性施工;冬期施工;雨期施工;高温施工;夏季施工;冬季混凝土,
+6,quality,质量保证措施,4,QualityControl,质量控制程序与具体措施,原材料检查验收(三证一检)、实体工程质量验收(分项/分部工程验收)、质量通病防治(墙面空鼓/屋面渗漏)、季节性施工质量控制(冬期混凝土保温/雨期防水)、工序质量控制点、质量检查程序(自检/互检/专检)、质量问题整改(闭环管理),1,PhysicalProjectQualityAcceptance,实体工程质量验收,需按分项(如“钢筋绑扎”)、分部工程(如“基础工程”)进行验收、符合规范要求;,实体验收;分项验收;分部验收;实体工程验收;工程质量验收,
+6,quality,质量保证措施,4,QualityControl,质量控制程序与具体措施,原材料检查验收(三证一检)、实体工程质量验收(分项/分部工程验收)、质量通病防治(墙面空鼓/屋面渗漏)、季节性施工质量控制(冬期混凝土保温/雨期防水)、工序质量控制点、质量检查程序(自检/互检/专检)、质量问题整改(闭环管理),2,PreventionAndControlOfCommonQualityDefectsInProcesses,工序质量通病防治,需针对常见问题(如“墙面空鼓”“屋面渗漏”)制定专项措施(如“抹灰前基层凿毛”“防水附加层施工”)、减少质量缺陷;,质量通病;空鼓;渗漏;裂缝;蜂窝麻面;防治措施;通病防治,
+6,quality,质量保证措施,4,QualityControl,质量控制程序与具体措施,原材料检查验收(三证一检)、实体工程质量验收(分项/分部工程验收)、质量通病防治(墙面空鼓/屋面渗漏)、季节性施工质量控制(冬期混凝土保温/雨期防水)、工序质量控制点、质量检查程序(自检/互检/专检)、质量问题整改(闭环管理),3,SeasonalConstructionQualityAssuranceMeasures,季节性施工质量保证措施,需针对冬期(混凝土保温)、雨期(防水加强)、高温(混凝土保湿)制定专项措施、确保施工质量;,季节性施工;冬期施工;雨期施工;高温施工;夏季施工;冬季混凝土,
 7,environment,环境保证措施,1,EnvSystem,环境保证体系,环境保证体系框图、公司标准体系引用,1,BlockDiagramOfEnvironmentalAssuranceSystem,环境保证体系框图,含环境保证体系框图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,环境保证体系;环境管理体系框图;环境保证体系框图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
 7,environment,环境保证措施,2,EnvOrg,环境保护组织机构,环境保护组织架构、管理人员姓名、管理人员职务、管理人员职责、环境管理岗位责任、责任考核机制、环境管理职责分工、环境管理人员资质、环境管理沟通机制,1,EnvironmentalAssuranceSystemFramework,环境保护组织架构,"环境保护组织机构包含管理人员姓名、职务、职责。环境管理组织机构基于项
 目经理为组长的工作领导小组,小组中包括项目经理、项目副经理、项目总工、工
@@ -115,35 +108,18 @@
 8,management,施工管理及作业人员配备与分工,1,Managers,施工管理人员,施工管理人员名单、岗位职责清单、管理职责分解、管理权限划分、管理流程衔接。,2,JobResponsibilitiesList,施工管理人员岗位职责,需细化每个管理岗位的职责(如项目经理的“项目全面管理”职责、技术负责人的“技术方案审核”职责)、避免职责模糊导致的管理漏洞;,岗位职责;职责清单;管理岗位职责;岗位分工;职责分解,
 8,management,施工管理及作业人员配备与分工,2,SafetyStaff,专职安全生产管理人员,专职安全生产管理人员名单、安全生产考核合格证书、证书编号、证书有效期、安全岗位职责、安全责任追究。,1,ListOfFullTimeSafetyProductionmanagementPersonnel,专职安全生产管理人员名单,专职安全生产管理人员、特种作业人员均以表格的形式说明人员姓名、证书类型、证书编号、有效期、岗位职责等内容,,专职安全员;专职安全管理人员;安全员名单;安全管理人员名单,
 8,management,施工管理及作业人员配备与分工,3,SpecialWorkers,特种作业人员,特种作业人员名单、特种作业操作资格证书、证书编号、证书有效期、特种作业工种、岗位职责、证书延期复核、违章作业记录。,1,ListOfSecialOperationsPersonnel,特种作业人员名单,需以表格形式明确特种作业人员(如建筑电工、建筑架子工、建筑起重机械司机等)的姓名、工种及联系方式、是特种作业管理的基础台账;,特种作业人员;特种作业;电工;架子工;起重机司机;焊工;特种人员名单,
-8,management,施工管理及作业人员配备与分工,4,OtherWorkers,其它作业人员,专业分包单位管理人员数量、不同工种作业人员数量、作业人员台账、工种分类统计。,3,WorkersLlog,其它作业人员名单,其他作业人员包含专业分包单位(协作队伍)管理人员数量,不同工种(班组、区域)的作业人员数量等。,作业人员台账;工人信息;人员档案;实名制;人员登记,
-9,acceptance,验收要求,3,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),1,SafetyProductionConditionAcceptance,安全生产条件验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需细化具体内容(如“安全防护设施验收”包括“安全网张挂验收”“防护栏杆安装验收”)、避免“安全生产验收”等泛化表述;,安全生产条件验收;安全验收;安全防护验收;临时用电验收,
-9,acceptance,验收要求,3,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),2,ResourceAllocationAcceptance,资源配置验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需关联资源类型(如“人员配置验收”包括“特种作业人员资质验收”“管理人员到位验收”)、体现资源的针对性;,资源配置验收;人员配置验收;设备配置验收;资源验收,
-9,acceptance,验收要求,3,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),3,ConstructionProcessAcceptance,施工工艺验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需明确工艺环节(如“模板安装工艺验收”包括“模板垂直度验收”“模板拼接缝验收”)、强调工艺的标准化;,施工工艺验收;模板安装验收;工艺验收;施工技术验收,
-9,acceptance,验收要求,3,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),4,AcceptanceOfMechanicalEquipment,机械设备验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需指向具体设备(如“塔式起重机验收”包括“设备型号验收”“安全装置验收”)、确保设备符合施工要求。,机械设备验收;设备验收;起重机验收;机械验收,
-9,acceptance,验收要求,3,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),5,TemporarySupportStructure,临时支撑结构验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、专项施工方案及审批记录、技术交底记录、构配件质量证明文件(合格证/检测报告)、地基承载力报告、搭设过程检查记录、荷载试验报告(高支模/大跨度)、验收记录表(含实测数据/影像资料)、整改复查记录。,临时支撑验收;脚手架验收;满堂支架验收;支架验收;临时结构验收,
-9,acceptance,验收要求,3,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),6,PersonnelOperationPlatform,人员操作平台验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、架体材质(如钢管无裂纹、弯曲、型钢无开焊);架体构造(立杆间距、剪刀撑设置、连墙件固定);稳定性(移动式平台刹车装置、落地式平台基础坚实度);荷载限制(平台荷载不超过设计值、悬挂限载标志);防护栏杆(高度≥1.2m、竖向栏杆间距≤1.5m、底部设挡脚板);平台铺板(满铺、固定、无空隙);登高扶梯(防滑、固定、与平台连接牢固);安全网(平台周边设置密目网或安全平网)。,操作平台验收;人员平台;高空作业平台验收;施工平台验收,
-9,acceptance,验收要求,3,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),7,SafetyProtectionFacilities,安全防护措施验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需结合场景需求(如建筑施工中的基坑临边防护、电梯井防护门)、功能定位(如预防事故的防护栏杆、减少事故影响的安全网)、技术要求(如材质、构造、固定方式)。其核心逻辑是“隔离危险、承接冲击、提醒注意”,安全防护验收;防护设施验收;安全网验收;防护栏杆验收,
-9,acceptance,验收要求,5,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),1,AcceptancePersonnelOfTheConstructionUnit,建设单位验收人员,需明确具体角色(如“建设单位项目负责人”)、避免“建设单位人员”等泛化表述;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,建设单位验收人员;业主验收;建设单位项目负责人;甲方验收,
-9,acceptance,验收要求,5,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),2,DesignUnitAcceptancePersonnel,设计单位验收人员,需明确验收人员姓名、关联专业(如“设计单位专业工程师”)、体现设计的专业性;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,设计单位验收;设计单位人员;设计师验收;设计验收,
-9,acceptance,验收要求,5,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),3,ConstructionUnitAcceptancePersonnel,施工单位验收人员,需明确验收人员姓名、指向管理岗位(如“施工单位项目经理”“施工单位技术负责人”)、强调施工单位的主体责任;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,施工单位验收;施工方验收;施工单位项目经理;施工验收人员,
-9,acceptance,验收要求,5,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),4,InspectionPersonnelOfTheSupervisionUnit,监理单位验收人员,需明确验收人员姓名、监理角色(如“总监理工程师”“专业监理工程师”)、体现监理的监督职责;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,监理单位验收;总监理工程师;监理人员;监理验收,
-9,acceptance,验收要求,5,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),5,MonitoringUnitAcceptancePersonnel,监测单位验收人员,需明确验收人员姓名、关联监测内容(如“监测项目负责人”“监测技术员”)、确保监测数据的准确性;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,监测单位验收;监测人员;监测项目负责人;监测验收,
-10,other,其它资料,1,Calculations,计算书,编制依据、工程简况、方案简述、设计参数、主要工况计算、局部计算、结论及建议、应力分析结果、变形分析结果、反力分析结果、屈曲分析结果,1,ContentRequirements,内容要求,专项施工方案中包含承重结构、重要临时设施、设备选型、吊绳吊具受力计算;地基承载力等工作内容编制的专项计算书、内容应包含编制依据、工程简况、方案简述、设计参数、主要工况计算、局部计算、结论及建议。,计算书;编制依据;设计参数;主要工况;计算内容;结构计算,
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,1,OverallLayoutPlan,总体平面布置图,含总体平面布置图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,总体平面布置图;总平面图;施工布局;总体布置,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,2,ConstructionSiteLayoutPlan,施工工点平面布置图,含施工工点平面布置图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,施工工点平面布置图;工点布置;场地布置图;施工场地平面,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,3,LongitudinalElevationLayoutOfSupportingStructure,支撑结构纵立面布置图,含支撑结构纵立面布置图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,支撑结构纵立面;纵立面布置;桩长;纵断面图;支撑纵立面,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,4,CrossSectionalLayoutDiagram,支横断面布置图,含支横断面布置图图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,横断面图;断面布置图;横断面布置;截面图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,5,FloorPlan,平面布置图,含平面布置图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,平面布置图;功能分区;施工区域划分;平面图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,6,DetailedStructuralDiagram,细部构造图,含细部构造图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,细部构造图;节点详图;构造详图;节点图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,7,FormworkLayoutDrawing,模板布置图,含模板布置图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,模板布置图;模板平面图;模板位置,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,2,Drawings,相关施工图纸,工程专业名词类、设备设施类、量化数值类、数值单位类、结构组件名称类、施工区域名称类,8,TemplateConstructionDiagram,模板构造图,含模板构造图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,模板构造图;模板体系图;支撑系统图;模板结构图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,3,Tables,附图附表,工序名称类、施工危险因素词汇类、安全设备设施类、资质证照名称类、标准文书类、数值类、时间时期类、数值单位类,1,ConstructionScheduleNetworkDiagram,施工进度计划网络图,含施工进度计划网络图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,网络图;施工进度网络图;工序网络;双代号网络图,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,3,Tables,附图附表,工序名称类、施工危险因素词汇类、安全设备设施类、资质证照名称类、标准文书类、数值类、时间时期类、数值单位类,2,ConstructionScheduleGanttChart,施工进度计划横道图,含施工进度计划横道图关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,施工进度横道图;横道图附表;进度计划横道;甘特图附表,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,3,Tables,附图附表,工序名称类、施工危险因素词汇类、安全设备设施类、资质证照名称类、标准文书类、数值类、时间时期类、数值单位类,3,HazardAnalysisAndResponseMeasuresTable,危险源分析和应对措施表,含危险源分析和应对措施表关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,危险源分析表;应对措施表;危险源表;风险分析表,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,3,Tables,附图附表,工序名称类、施工危险因素词汇类、安全设备设施类、资质证照名称类、标准文书类、数值类、时间时期类、数值单位类,4,ScannedCopyOfTheCertificateOfFulltimSafetymanagementPersonnel,专职安全管理人员证件扫描件,含专职安全管理人员证件扫描件关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,安全证件扫描;专职安全考核证;安全证书扫描件,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,3,Tables,附图附表,工序名称类、施工危险因素词汇类、安全设备设施类、资质证照名称类、标准文书类、数值类、时间时期类、数值单位类,5,ScannedCopyOfSpecialOperationsPersonnelsCertificate,特种作业人员证件扫描件,含特种作业人员证件扫描件关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,特种作业证件扫描;特种证书扫描件;操作证扫描,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,3,Tables,附图附表,工序名称类、施工危险因素词汇类、安全设备设施类、资质证照名称类、标准文书类、数值类、时间时期类、数值单位类,6,ScannedCopyOfProfessionalSubcontractorsQualifications,专业分包单位资质扫描件,含专业分包单位资质扫描件关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,分包资质扫描;营业执照扫描;资质证书扫描;分包证件,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,4,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,1,ListOfAcceptanceConditionsForSpecialConstructionSchemes,专项施工方案验收条件一览表,含专项施工方案验收条件一览表关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,验收条件一览表;专项施工方案验收条件;验收前提条件,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
-10,other,其它资料,4,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,2,PreparePersonnelInformation,编制人员信息,需包含“姓名”“职务”“职称”(如“张三 技术员 助理工程师”)、确保编制人员具备专业能力;,编制人员;编制人信息;方案编制者;编制人,
-10,other,其它资料,4,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,3,ReviewerInformation,审核人员信息,需包含“姓名”“职务”“职称”(如“李四 项目技术负责人 工程师”)、确保审核流程的严谨性;,审核人员;复核人员;审核信息;审核人;复核人,
-10,other,其它资料,4,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,4,ApprovalPersonnelInformation,审批人员信息,需包含“姓名”“职务”“职称”(如“王五 项目经理 高级工程师”)、确保方案符合项目整体要求,审批人员;批准人;审批信息;审批签字;项目经理审批,
+8,management,施工管理及作业人员配备与分工,4,OtherWorkers,其它作业人员,专业分包单位管理人员数量、不同工种作业人员数量、作业人员台账、工种分类统计。,1,WorkersLlog,其它作业人员名单,其他作业人员包含专业分包单位(协作队伍)管理人员数量,不同工种(班组、区域)的作业人员数量等。,作业人员台账;工人信息;人员档案;实名制;人员登记,
+9,acceptance,验收要求,1,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),1,SafetyProductionConditionAcceptance,安全生产条件验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需细化具体内容(如“安全防护设施验收”包括“安全网张挂验收”“防护栏杆安装验收”)、避免“安全生产验收”等泛化表述;,安全生产条件验收;安全验收;安全防护验收;临时用电验收,
+9,acceptance,验收要求,1,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),2,ResourceAllocationAcceptance,资源配置验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需关联资源类型(如“人员配置验收”包括“特种作业人员资质验收”“管理人员到位验收”)、体现资源的针对性;,资源配置验收;人员配置验收;设备配置验收;资源验收,
+9,acceptance,验收要求,1,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),3,ConstructionProcessAcceptance,施工工艺验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需明确工艺环节(如“模板安装工艺验收”包括“模板垂直度验收”“模板拼接缝验收”)、强调工艺的标准化;,施工工艺验收;模板安装验收;工艺验收;施工技术验收,
+9,acceptance,验收要求,1,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),4,AcceptanceOfMechanicalEquipment,机械设备验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需指向具体设备(如“塔式起重机验收”包括“设备型号验收”“安全装置验收”)、确保设备符合施工要求。,机械设备验收;设备验收;起重机验收;机械验收,
+9,acceptance,验收要求,1,Content,验收内容,安全生产条件验收(安全防护设施验收、临时用电验收)、资源配置验收(人员配置验收、设备配置验收)、施工工艺验收(模板安装工艺验收、混凝土浇筑工艺验收)、机械设备验收(塔式起重机验收、混凝土泵车验收)、临时支撑结构验收(脚手架验收、满堂支架验收)、人员操作平台验收(高空作业平台验收、操作脚手架验收)、安全防护设施验收(安全网验收、防护栏杆验收),5,SafetyProtectionFacilities,安全防护措施验收,验收表格中要明确项目的具体验收标准、验收标准应尽量量化到具体参数或标准、需结合场景需求(如建筑施工中的基坑临边防护、电梯井防护门)、功能定位(如预防事故的防护栏杆、减少事故影响的安全网)、技术要求(如材质、构造、固定方式)。其核心逻辑是“隔离危险、承接冲击、提醒注意”,安全防护验收;防护设施验收;安全网验收;防护栏杆验收,
+9,acceptance,验收要求,2,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),1,AcceptancePersonnelOfTheConstructionUnit,建设单位验收人员,需明确具体角色(如“建设单位项目负责人”)、避免“建设单位人员”等泛化表述;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,建设单位验收人员;业主验收;建设单位项目负责人;甲方验收,
+9,acceptance,验收要求,2,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),2,DesignUnitAcceptancePersonnel,设计单位验收人员,需明确验收人员姓名、关联专业(如“设计单位专业工程师”)、体现设计的专业性;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,设计单位验收;设计单位人员;设计师验收;设计验收,
+9,acceptance,验收要求,2,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),3,ConstructionUnitAcceptancePersonnel,施工单位验收人员,需明确验收人员姓名、指向管理岗位(如“施工单位项目经理”“施工单位技术负责人”)、强调施工单位的主体责任;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,施工单位验收;施工方验收;施工单位项目经理;施工验收人员,
+9,acceptance,验收要求,2,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),4,InspectionPersonnelOfTheSupervisionUnit,监理单位验收人员,需明确验收人员姓名、监理角色(如“总监理工程师”“专业监理工程师”)、体现监理的监督职责;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,监理单位验收;总监理工程师;监理人员;监理验收,
+9,acceptance,验收要求,2,Personnel,验收人员,建设单位验收人员(如建设单位项目负责人、建设单位技术负责人)、设计单位验收人员(如设计单位项目负责人、设计单位专业工程师)、施工单位验收人员(如施工单位项目经理、施工单位技术负责人)、监理单位验收人员(如总监理工程师、专业监理工程师)、监测单位验收人员(如监测项目负责人、监测技术员),5,MonitoringUnitAcceptancePersonnel,监测单位验收人员,需明确验收人员姓名、关联监测内容(如“监测项目负责人”“监测技术员”)、确保监测数据的准确性;由施工作业班组在施工过程中自行对照方案自检、施工完成后由方案编制负责人、项目经理、项目副经理、项目技术负责人、安全环保处、工程处、机料处、合同处、专业分包单位(协作队伍)项目负责人和项目技术负责人等部门人员参加方案验收。,监测单位验收;监测人员;监测项目负责人;监测验收,
+10,other,其它资料,1,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,1,ListOfAcceptanceConditionsForSpecialConstructionSchemes,专项施工方案验收条件一览表,含专项施工方案验收条件一览表关键字,及类似表述,视为符合,类似出现这种;见附表,详情,详见附表,专详见另册及类似描述视为符合! 这种表述视为符合,验收条件一览表;专项施工方案验收条件;验收前提条件,"当内容仅含""详见附表""、""详见另册""、""见附表""、""见另册""、""专详见另册""等通用索引说明时,视为本分类已有依据。"
+10,other,其它资料,1,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,2,PreparePersonnelInformation,编制人员信息,需包含“姓名”“职务”“职称”(如“张三 技术员 助理工程师”)、确保编制人员具备专业能力;,编制人员;编制人信息;方案编制者;编制人,
+10,other,其它资料,1,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,3,ReviewerInformation,审核人员信息,需包含“姓名”“职务”“职称”(如“李四 项目技术负责人 工程师”)、确保审核流程的严谨性;,审核人员;复核人员;审核信息;审核人;复核人,
+10,other,其它资料,1,Team,编制及审核人员情况,专项施工方案验收条件一览表、编制人员信息、复核人员信息、审核人员信息、审批人员信息、姓名、职务、职称,4,ApprovalPersonnelInformation,审批人员信息,需包含“姓名”“职务”“职称”(如“王五 项目经理 高级工程师”)、确保方案符合项目整体要求,审批人员;批准人;审批信息;审批签字;项目经理审批,

+ 9 - 2
core/construction_review/component/doc_worker/models/document_structure.py

@@ -197,6 +197,9 @@ class UnifiedDocumentStructure:
     # ========== 原始数据(可选) ==========
     raw_metadata: Dict[str, Any] = field(default_factory=dict)
 
+    # ========== 文档原始切分结果(来自 PDF 提取器) ==========
+    original_split_result: Dict[str, Any] = field(default_factory=dict)
+
     # ========== 便捷方法 ==========
 
     def get_secondary_by_code(self, second_code: str) -> Optional[SecondaryClassification]:
@@ -281,7 +284,9 @@ class UnifiedDocumentStructure:
                 }
                 for t in self.tertiary_classifications
             ],
-            "outline": self.outline.to_dict()
+            "outline": self.outline.to_dict(),
+            "catalog": self.catalog,
+            "original_split_result": self.original_split_result
         }
 
     @classmethod
@@ -349,7 +354,9 @@ class UnifiedDocumentStructure:
                 for t in data.get("tertiary_classifications", [])
             ],
             outline=Outline.from_dict(data.get("outline", [])),
-            raw_metadata=data.get("raw_metadata", {})
+            catalog=data.get("catalog"),
+            raw_metadata=data.get("raw_metadata", {}),
+            original_split_result=data.get("original_split_result", {})
         )
 
     # ========== 统计信息 ==========

+ 420 - 0
core/construction_review/component/minimal_pipeline/catalog_reviewer.py

@@ -0,0 +1,420 @@
+"""
+目录完整性审查模块
+
+使用LLM对比实际目录(OCR提取)和标准目录,找出缺失项。
+"""
+
+import json
+import re
+from pathlib import Path
+from typing import Dict, Any, List, Optional
+
+import yaml
+
+from foundation.observability.logger.loggering import review_logger as logger
+
+
+class CatalogReviewer:
+    """目录审查器"""
+
+    # 默认标准目录模板路径
+    DEFAULT_TEMPLATE_PATH = Path(__file__).parent.parent / 'doc_worker' / 'config' / 'StandardCatalogTemplate.yaml'
+
+    # JSON 格式示例(避免 f-string 嵌套问题,单独定义)
+    _JSON_EXAMPLE_TEMPLATE = '''{
+  "details": {
+    "name": "outline_check",
+    "response": [
+      {
+        "check_item": "completeness_check",
+        "chapter_code": "outline",
+        "check_item_code": "outline_completeness_check",
+        "check_result": {
+          "issue_point": "【一级缺失】第四章 施工工艺技术",
+          "location": "目录页",
+          "suggestion": "建议补充'第四章 施工工艺技术'章节",
+          "reason": "目录页缺少该章节",
+          "risk_level": "高风险"
+        },
+        "exist_issue": true,
+        "risk_info": {"risk_level": "high"}
+      },
+      {
+        "check_item": "completeness_check",
+        "chapter_code": "outline",
+        "check_item_code": "outline_completeness_check",
+        "check_result": {
+          "issue_point": "【一级缺失】第十章 其他资料",
+          "location": "目录页",
+          "suggestion": "建议补充'第十章 其他资料'章节",
+          "reason": "目录页缺少该章节",
+          "risk_level": "高风险"
+        },
+        "exist_issue": true,
+        "risk_info": {"risk_level": "high"}
+      },
+      {
+        "check_item": "completeness_check",
+        "chapter_code": "outline",
+        "check_item_code": "outline_completeness_check",
+        "check_result": {
+          "issue_point": "【二级缺失】第一章 编制依据 - 四、编制原则",
+          "location": "第一章",
+          "suggestion": "建议补充'四、编制原则'",
+          "reason": "第一章缺少该二级目录",
+          "risk_level": "中风险"
+        },
+        "exist_issue": true,
+        "risk_info": {"risk_level": "medium"}
+      }
+    ],
+    "review_location_label": "目录完整性审查",
+    "chapter_code": "outline"
+  },
+  "success": true
+}'''
+
+    def __init__(self, template_path: Optional[Path] = None):
+        self.template_path = template_path or self.DEFAULT_TEMPLATE_PATH
+        self.standard_text = self._load_standard_template()
+
+    def _load_standard_template(self) -> str:
+        """加载标准目录模板"""
+        try:
+            with open(self.template_path, 'r', encoding='utf-8') as f:
+                template = yaml.safe_load(f)
+            return template.get('text_template', '')
+        except Exception as e:
+            logger.warning(f"[CatalogReviewer] 加载标准模板失败: {e}")
+            return self._default_template()
+
+    def _default_template(self) -> str:
+        """默认标准目录模板"""
+        return """第一章 编制依据
+一、法律法规
+二、标准规范
+三、文件制度
+四、编制原则
+五、编制范围
+
+第二章 工程概况
+一、设计概况
+二、工程地质与水文气象
+三、周边环境
+四、施工平面及立面布置
+五、施工要求和技术保证条件
+六、风险辨识与分级
+七、参建各方责任主体单位
+
+第三章 施工计划
+一、施工进度计划
+二、施工材料计划
+三、施工设备计划
+四、劳动力计划
+五、安全生产费用使用计划
+
+第四章 施工工艺技术
+一、主要施工方法概述
+二、技术参数
+三、工艺流程
+四、施工准备
+五、施工方法及操作要求
+六、检查要求
+
+第五章 安全保证措施
+一、安全保证体系
+二、组织保证措施
+三、技术保证措施
+四、监测监控措施
+五、应急处置措施
+
+第六章 质量保证措施
+一、质量保证体系
+二、质量目标
+三、工程创优规划
+四、质量控制程序与具体措施
+
+第七章 环境保证措施
+一、环境保证体系
+二、环境保护组织机构
+三、环境保护及文明施工措施
+
+第八章 施工管理及作业人员配备与分工
+一、施工管理人员
+二、专职安全生产管理人员
+三、其他作业人员
+
+第九章 验收要求
+一、验收标准
+二、验收程序
+三、验收内容
+四、验收时间
+五、验收人员
+
+第十章 其他资料
+一、计算书
+二、相关施工图纸
+三、附图附表
+四、编制及审核人员情况"""
+
+    async def review(self, actual_catalog_text: str, trace_id_idx: str = "") -> Dict[str, Any]:
+        """
+        审查目录完整性
+
+        Args:
+            actual_catalog_text: 实际目录文本(标准格式)
+            trace_id_idx: 追踪ID索引
+
+        Returns:
+            对齐 completeness_check 格式的结果字典
+        """
+        import time
+        start_time = time.time()
+
+        try:
+            from foundation.ai.agent.generate.model_generate import generate_model_client
+
+            prompt = self._build_prompt(actual_catalog_text)
+
+            # 重试机制:最多3次
+            max_retries = 3
+            last_error = None
+
+            for attempt in range(max_retries):
+                try:
+                    logger.info(f"[DEBUG][CatalogReviewer] 调用模型 catalog_integrity_review,第 {attempt + 1} 次尝试")
+
+                    # 使用 generate_model_client 调用模型
+                    content = await generate_model_client.get_model_generate_invoke(
+                        trace_id=f"{trace_id_idx or 'catalog_review'}_attempt{attempt}",
+                        system_prompt="你是一位施工方案文档审查专家,负责对比实际目录和标准目录,找出缺失项。请按JSON格式输出最终结果。",
+                        user_prompt=prompt,
+                        function_name="catalog_integrity_review",
+                        timeout=120
+                    )
+
+                    logger.info(f"[DEBUG][CatalogReviewer] 模型返回,开始解析")
+                    logger.info(f"[DEBUG][CatalogReviewer] content length: {len(content)}")
+
+                    # 直接解析 LLM 返回的 completeness_check 格式
+                    result = self._extract_json(content)
+                    if result and "details" in result:
+                        logger.info(f"[DEBUG][CatalogReviewer] 成功解析 LLM 返回的格式")
+                        execution_time = time.time() - start_time
+                        return {
+                            "details": result["details"],
+                            "success": result.get("success", True),
+                            "execution_time": execution_time
+                        }
+                    else:
+                        logger.warning(f"[DEBUG][CatalogReviewer] 第 {attempt + 1} 次:LLM 返回格式不正确")
+                        last_error = "LLM 返回格式不正确"
+                        if attempt < max_retries - 1:
+                            import asyncio
+                            await asyncio.sleep(1)  # 短暂等待后重试
+
+                except Exception as e:
+                    logger.warning(f"[DEBUG][CatalogReviewer] 第 {attempt + 1} 次调用失败: {e}")
+                    last_error = str(e)
+                    if attempt < max_retries - 1:
+                        import asyncio
+                        await asyncio.sleep(1)
+
+            # 所有重试都失败
+            raise ValueError(f"重试 {max_retries} 次后仍失败: {last_error}")
+
+        except Exception as e:
+            logger.error(f"[CatalogReviewer] LLM审查失败(已重试3次): {e}")
+            execution_time = time.time() - start_time
+            return {
+                "details": {
+                    "name": "outline_check",
+                    "response": [{
+                        "check_item": "completeness_check",
+                        "chapter_code": "outline",
+                        "check_item_code": "outline_completeness_check",
+                        "check_result": {
+                            "issue_point": "目录审查失败",
+                            "location": "目录页",
+                            "suggestion": "请检查OCR识别结果或手动确认目录",
+                            "reason": str(e),
+                            "risk_level": "中风险"
+                        },
+                        "exist_issue": True,
+                        "risk_info": {"risk_level": "medium"}
+                    }],
+                    "review_location_label": "目录完整性审查",
+                    "chapter_code": "outline",
+                    "original_content": f"审查失败: {str(e)}"
+                },
+                "success": False,
+                "execution_time": execution_time
+            }
+
+    def _build_prompt(self, actual_catalog_text: str) -> str:
+        """构建审查Prompt"""
+        json_example = self._JSON_EXAMPLE_TEMPLATE
+
+        # 基础 JSON 模板(使用单引号字符串避免 f-string 转义问题)
+        base_template = '''{
+  "details": {
+    "name": "outline_check",
+    "response": [
+      {
+        "check_item": "completeness_check",
+        "chapter_code": "outline",
+        "check_item_code": "outline_completeness_check",
+        "check_result": {
+          "issue_point": "【一级缺失】xxx",
+          "location": "目录页",
+          "suggestion": "建议补充'xxx'章节",
+          "reason": "简要说明",
+          "risk_level": "高风险"
+        },
+        "exist_issue": true,
+        "risk_info": {"risk_level": "high"}
+      }
+    ],
+    "review_location_label": "目录完整性审查",
+    "chapter_code": "outline"
+  },
+  "success": true
+}'''
+
+        return f"""你是一位施工方案文档审查专家。请对比【实际目录】和【标准目录】,找出缺失项。
+
+## 审查原则
+1. **语义匹配**:实际目录与标准目录含义相同即算匹配,不要求文字完全一致
+2. **常见同义表述**(示例):
+   - "编制依据" ≈ "方案编制依据" ≈ "编制原则及依据"
+   - "工程概况" ≈ "工程基本情况" ≈ "项目概况"
+   - "施工计划" ≈ "施工进度计划" ≈ "施工安排"
+   - "法律法规" ≈ "相关法律" ≈ "法规依据"
+3. **容错范围**:
+   - 一级标题必须严格对应(如"编制依据"不能变成"引用标准")
+   - 二级标题允许一定变通,但核心含义必须一致
+
+## 实际目录(来自OCR识别)
+```
+{actual_catalog_text}
+```
+
+## 标准目录(必须包含的完整结构)
+```
+{self.standard_text}
+```
+
+## 输出规则
+1. **一级缺失判定**:实际目录中完全没有对应的章,或章节标题完全不匹配
+2. **二级缺失判定**:只有当父级一级目录**存在**时,才检查其下的二级目录是否缺失
+3. **重要**:如果某个一级目录缺失,**不要报告**该章节下的二级目录缺失(避免重复提醒)
+
+## 输出要求
+**重要:最终答案只输出 JSON,不要添加 markdown 代码块标记(```json)。**
+
+请直接输出 completeness_check 格式的 JSON 结果:
+{base_template}
+
+**重要输出规则**:
+1. **每个缺失项必须单独输出**:一级缺失和二级缺失要分开,不同的缺失项也要分开
+2. **禁止合并**:不要将多个缺失项写在一个 `issue_point` 里
+3. **列表格式**:`response` 必须是一个列表,每个缺失项是列表中的一个独立对象
+
+**正确示例**(多个缺失项分开):
+```json
+{json_example}
+```
+
+**风险等级规则**:
+- 一级缺失:risk_level 为 "高风险", risk_info.risk_level 为 "high"
+- 二级缺失:risk_level 为 "中风险", risk_info.risk_level 为 "medium"
+- 如无缺失,response 中放一条 "issue_point": "【目录完整】一二级目录结构完整", "exist_issue": false
+"""
+
+    def _extract_json(self, content: str) -> Optional[Dict[str, Any]]:
+        """从LLM响应中提取JSON,增强健壮性(支持思考模式输出)"""
+        try:
+            # 清理内容:移除 markdown 代码块标记
+            content = content.strip()
+            original_preview = content[:500]
+
+            # 移除 markdown 代码块
+            content = re.sub(r'^```json\s*', '', content, flags=re.IGNORECASE | re.MULTILINE)
+            content = re.sub(r'\s*```\s*$', '', content, flags=re.MULTILINE)
+            content = re.sub(r'^```\s*', '', content, flags=re.MULTILINE)
+
+            # 处理思考模式输出:跳过思考部分,提取最终答案
+            # 检查 <think>...</think> 标签 (Qwen3.5 思考模式标准格式)
+            think_end = content.find("</think>")
+            if think_end != -1:
+                # 提取 </think> 之后的内容
+                content = content[think_end + len("</think>"):].strip()
+                logger.debug(f"[CatalogReviewer] 检测到 <think> 标签,从 </think> 后提取内容,长度: {len(content)}")
+
+            # 找到第一个 { 开始的位置
+            json_start = content.find('{')
+            if json_start == -1:
+                logger.warning(f"[CatalogReviewer] 未找到 JSON 开始标记 '{{'")
+                return None
+            content = content[json_start:]
+
+            # 找到最后一个 } 结束的位置
+            json_end = content.rfind('}')
+            if json_end == -1:
+                logger.warning(f"[CatalogReviewer] 未找到 JSON 结束标记 '}}'")
+                return None
+            content = content[:json_end + 1]
+
+            # 尝试直接解析
+            try:
+                return json.loads(content)
+            except json.JSONDecodeError as e:
+                logger.debug(f"[CatalogReviewer] 直接解析失败: {e}")
+
+            # 尝试修复常见问题后重新解析
+            fixed_content = self._fix_json_content(content)
+            try:
+                return json.loads(fixed_content)
+            except json.JSONDecodeError as e:
+                logger.debug(f"[CatalogReviewer] 修复后解析失败: {e}")
+
+            logger.error(f"[CatalogReviewer] JSON解析失败")
+            logger.error(f"[CatalogReviewer] 原始内容: {original_preview}")
+            return None
+
+        except Exception as e:
+            logger.error(f"[CatalogReviewer] JSON解析异常: {e}")
+            logger.error(f"[CatalogReviewer] 内容前500字: {content[:500]}")
+            return None
+
+    def _fix_json_content(self, content: str) -> str:
+        """尝试修复常见的 JSON 格式问题"""
+        # 1. 移除多余的空白和换行
+        content = content.strip()
+
+        # 2. 修复属性名未加引号的问题(简单情况)
+        # 将 { key: value } 转换为 { "key": value }
+        content = re.sub(r'(\{|,)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:', r'\1"\2":', content)
+
+        # 3. 修复尾随逗号
+        content = re.sub(r',\s*([}\]])', r'\1', content)
+
+        # 4. 修复单引号为双引号
+        content = content.replace("'", '"')
+
+        return content
+
+
+async def review_catalog_integrity(actual_catalog_text: str, template_path: Optional[Path] = None) -> Dict[str, Any]:
+    """
+    便捷函数:审查目录完整性
+
+    Args:
+        actual_catalog_text: 实际目录文本(标准格式)
+        template_path: 可选的自定义模板路径
+
+    Returns:
+        审查结果字典
+    """
+    reviewer = CatalogReviewer(template_path)
+    return await reviewer.review(actual_catalog_text)

+ 2 - 6
core/construction_review/component/minimal_pipeline/pdf_extractor.py

@@ -148,12 +148,8 @@ class PdfStructureExtractor:
         Returns:
             {"chapters": [...], "total_chapters": N} 或 None
         """
-        # 延迟导入避免循环依赖
-        try:
-            from .toc_detector import TOCCatalogExtractor
-        except ImportError:
-            logger.warning("[PDF提取] toc_detector 模块未找到,跳过目录检测")
-            return None
+        # 延迟导入避免循环依赖(YOLO依赖必须存在,否则报错)
+        from .toc_detector import TOCCatalogExtractor
 
         if self._toc_extractor is None:
             self._toc_extractor = TOCCatalogExtractor(

+ 131 - 1
core/construction_review/component/minimal_pipeline/simple_processor.py

@@ -122,6 +122,18 @@ class SimpleDocumentProcessor:
 
         structure = self.pdf_extractor.extract(file_content, progress_callback=_extraction_progress)
         catalog = structure.get("catalog")  # 获取YOLO检测+OCR提取的目录
+
+        # 对 catalog 进行分类(如果存在)
+        if catalog and catalog.get("chapters"):
+            try:
+                catalog = await self._classify_catalog(catalog)
+                logger.info(f"[SimpleProcessor] Catalog分类完成")
+                # 验证一级分类是否写入
+                for ch in catalog.get("chapters", [])[:2]:
+                    logger.info(f"[SimpleProcessor] Catalog章节验证: '{ch.get('title')}' -> code={ch.get('chapter_classification')}")
+            except Exception as e:
+                logger.warning(f"[SimpleProcessor] Catalog分类失败: {e}")
+
         await self._emit_progress(progress_callback, "文档提取", 10, "PDF结构提取完成")
 
         # 2. 一级分类
@@ -139,7 +151,7 @@ class SimpleDocumentProcessor:
         chunks = assemble_chunks(structure, primary_result, secondary_result)
         if not chunks:
             logger.warning("[SimpleProcessor] 无可用的 chunks")
-            return structure, primary_result, secondary_result, chunks
+            return structure, primary_result, secondary_result, chunks, catalog
         await self._emit_progress(progress_callback, "文档切分", 50, f"组装 {len(chunks)} 个内容块")
 
         # 5. 三级分类
@@ -158,6 +170,12 @@ class SimpleDocumentProcessor:
         logger.info("[SimpleProcessor] 三级分类完成")
         await self._emit_progress(progress_callback, "文档分类", 90, "三级分类完成")
 
+        # 验证返回前的catalog
+        if catalog:
+            logger.info(f"[SimpleProcessor] 返回前Catalog验证: {len(catalog.get('chapters', []))} 章")
+            for ch in catalog.get("chapters", [])[:2]:
+                logger.info(f"[SimpleProcessor] 返回前章节: '{ch.get('title')}' -> code={ch.get('chapter_classification')}")
+
         return structure, primary_result, secondary_result, chunks, catalog
 
     async def _emit_progress(
@@ -226,8 +244,15 @@ class SimpleDocumentProcessor:
         }
 
         # 设置目录结构(YOLO检测+OCR提取)
+        if catalog:
+            logger.info(f"[_build_unified_doc] 设置catalog: {len(catalog.get('chapters', []))} 章")
+            for ch in catalog.get("chapters", [])[:2]:
+                logger.info(f"[_build_unified_doc] catalog章节: '{ch.get('title')}' -> code={ch.get('chapter_classification')}")
         unified.catalog = catalog
 
+        # 设置原始切分结果(来自 PDF 提取器)
+        unified.original_split_result = structure.get("chapters", {})
+
         return unified
 
     def _merge_tertiary_to_unified(
@@ -317,3 +342,108 @@ class SimpleDocumentProcessor:
             total_pages=total_pages,
             secondary_classifications=[],
         )
+
+    async def _classify_catalog(self, catalog: Dict[str, Any]) -> Dict[str, Any]:
+        """
+        使用 HierarchyClassifier 对 catalog 进行一二级分类
+        """
+        from ..doc_worker.classification.hierarchy_classifier import HierarchyClassifier
+
+        # 转换为 toc_items 格式
+        toc_items = []
+        for idx, chapter in enumerate(catalog.get("chapters", [])):
+            # 一级目录
+            toc_items.append({
+                "title": chapter.get("title", ""),
+                "page": str(chapter.get("page", "0")),
+                "level": 1,
+                "original": chapter.get("original", "")
+            })
+            # 二级目录
+            for sub in chapter.get("subsections", []):
+                toc_items.append({
+                    "title": sub.get("title", ""),
+                    "page": str(sub.get("page", "0")),
+                    "level": 2,
+                    "original": sub.get("original", "")
+                })
+
+        if not toc_items:
+            return catalog
+
+        # 调用分类器
+        classifier = HierarchyClassifier()
+
+        # 一级分类
+        primary_result = await classifier.classify_async(toc_items, target_level=1)
+
+        # 二级分类
+        secondary_result = await classifier.classify_secondary_async(primary_result)
+
+        # 将分类结果写回 catalog
+        primary_items = primary_result.get("items", [])
+        secondary_items = secondary_result.get("items", [])
+
+        # 一级分类结果映射 (normalized_title -> code/name)
+        first_classification = {}
+        for item in primary_items:
+            title = item.get("title", "").strip()
+            first_classification[title] = {
+                "code": item.get("category_code", ""),
+                "name": item.get("category", "")
+            }
+
+        # 二级分类结果映射 ((first_title, sub_title) -> code)
+        second_classification = {}
+        for first_item in secondary_items:
+            first_title = (first_item.get("original_title", "") or first_item.get("first_category", "")).strip()
+            classifications = first_item.get("classifications", [])
+            for cls in classifications:
+                sub_title = cls.get("title", "").strip()
+                key = (first_title, sub_title)
+                second_classification[key] = cls.get("category_code", "")
+
+        logger.info(f"[_classify_catalog] 一级分类映射: {first_classification}")
+        logger.info(f"[_classify_catalog] 二级分类映射: {list(second_classification.keys())}")
+
+        # 写回 catalog,并调整格式与 outline 一致
+        for chapter in catalog.get("chapters", []):
+            ch_title = chapter.get("title", "").strip()
+            logger.info(f"[_classify_catalog] 处理章节: '{ch_title}'")
+            logger.info(f"[_classify_catalog] 查找一级分类, keys={list(first_classification.keys())}")
+
+            if ch_title in first_classification:
+                chapter["chapter_classification"] = first_classification[ch_title]["code"]
+                chapter["first_name"] = first_classification[ch_title]["name"]
+                logger.info(f"[_classify_catalog] 精确匹配成功: {ch_title} -> {first_classification[ch_title]}")
+            else:
+                # 尝试模糊匹配
+                matched = False
+                for cls_title, cls_data in first_classification.items():
+                    if cls_title in ch_title or ch_title in cls_title:
+                        chapter["chapter_classification"] = cls_data["code"]
+                        chapter["first_name"] = cls_data["name"]
+                        logger.info(f"[_classify_catalog] 模糊匹配成功: '{ch_title}' ~ '{cls_title}' -> {cls_data}")
+                        matched = True
+                        break
+                if not matched:
+                    logger.warning(f"[_classify_catalog] 未找到匹配: '{ch_title}' 不在 {list(first_classification.keys())}")
+
+            # 调整 original 格式:只保留 "第X章"
+            chapter["original"] = f"第{chapter.get('index', 1)}章"
+
+            # 二级
+            for sub in chapter.get("subsections", []):
+                sub_title = sub.get("title", "").strip()
+                key = (ch_title, sub_title)
+                if key in second_classification:
+                    sub["secondary_category_code"] = second_classification[key]
+                else:
+                    # 尝试模糊匹配
+                    for (ft, st), code in second_classification.items():
+                        if (ft in ch_title or ch_title in ft) and (st in sub_title or sub_title in st):
+                            sub["secondary_category_code"] = code
+                            break
+                # 不再修改 sub["original"],保持其标准格式(如"一、法律法规")
+
+        return catalog

+ 80 - 55
core/construction_review/component/minimal_pipeline/toc_detector.py

@@ -17,18 +17,8 @@ import numpy as np
 
 from foundation.observability.logger.loggering import review_logger as logger
 
-# 尝试导入 YOLO 相关库
-try:
-    from ultralytics import YOLO
-    YOLO_AVAILABLE = True
-except ImportError:
-    YOLO_AVAILABLE = False
-
-try:
-    from PIL import Image
-    PIL_AVAILABLE = True
-except ImportError:
-    PIL_AVAILABLE = False
+from ultralytics import YOLO
+from PIL import Image
 
 
 @dataclass
@@ -94,26 +84,15 @@ class TOCCatalogExtractor:
         self.ocr_timeout = ocr_timeout
 
         self._model = None
-        self._yolo_available = YOLO_AVAILABLE and PIL_AVAILABLE
 
     def _load_model(self) -> bool:
-        """加载 YOLO 模型"""
-        if not self._yolo_available:
-            logger.debug("[TOC检测] YOLO库未安装,跳过目录检测")
-            return False
-
+        """加载 YOLO 模型,缺少依赖或模型文件直接报错"""
         if not os.path.exists(self.model_path):
-            logger.debug(f"[TOC检测] 模型文件不存在: {self.model_path}")
-            return False
+            raise FileNotFoundError(f"[TOC检测] YOLO模型文件不存在: {self.model_path}")
 
         if self._model is None:
-            try:
-                logger.info(f"[TOC检测] 正在加载YOLO模型: {self.model_path}")
-                self._model = YOLO(self.model_path)
-                return True
-            except Exception as e:
-                logger.warning(f"[TOC检测] 模型加载失败: {e}")
-                return False
+            logger.info(f"[TOC检测] 正在加载YOLO模型: {self.model_path}")
+            self._model = YOLO(self.model_path)
         return True
 
     def detect_and_extract(
@@ -361,7 +340,6 @@ class TOCCatalogExtractor:
             force_smaller: 是否强制更小的尺寸(用于处理过大的图片)
         """
         try:
-            from PIL import Image
             img = Image.open(io.BytesIO(img_bytes))
 
             if img.mode in ('RGBA', 'LA', 'P'):
@@ -396,15 +374,20 @@ class TOCCatalogExtractor:
 
     def _parse_toc_text(self, text: str) -> Dict[str, Any]:
         """
-        解析目录文本为结构化数据
+        解析目录文本为结构化数据,输出标准格式
 
-        支持格式:
-        - 第一章 XXX...................1
-        - 一、XXX......................2
-        - 1. XXX ......................3
+        标准格式:
+        第X章 XXX
+        一、XXX
+        二、XXX
 
         Returns:
-            {"chapters": [...], "total_chapters": N}
+            {
+                "chapters": [...],
+                "total_chapters": N,
+                "raw_ocr_text": "原始OCR文本",
+                "formatted_text": "标准格式文本"
+            }
         """
         lines = text.strip().split('\n')
         chapters = []
@@ -422,6 +405,13 @@ class TOCCatalogExtractor:
             r'([0-9]+)[\.\s]+(.+?)\s*[\.\s]+(\d+)\s*$'
         )
 
+        # 中文数字映射
+        chinese_nums = {
+            '一': 1, '二': 2, '三': 3, '四': 4, '五': 5,
+            '六': 6, '七': 7, '八': 8, '九': 9, '十': 10,
+            '十一': 11, '十二': 12, '十三': 13, '十四': 14, '十五': 15
+        }
+
         for line in lines:
             line = line.strip()
             if not line or len(line) < 3:
@@ -442,24 +432,37 @@ class TOCCatalogExtractor:
                 if current_chapter:
                     chapters.append(current_chapter)
 
+                # 标准化为阿拉伯数字
+                if chapter_num.isdigit():
+                    idx = int(chapter_num)
+                else:
+                    idx = chinese_nums.get(chapter_num, len(chapters) + 1)
+
                 current_chapter = {
-                    "index": self._chinese_to_number(chapter_num) if not chapter_num.isdigit() else int(chapter_num),
-                    "title": f"第{chapter_num}章 {title}",
+                    "index": idx,
+                    "title": f"第{idx}章 {title}",
                     "page": page,
                     "original": line,
                     "subsections": []
                 }
                 continue
 
-            # 尝试匹配节(二级)
+            # 尝试匹配节(二级)- 标准化为一、二、三格式
             section_match = section_pattern.search(line)
             if section_match and current_chapter:
                 section_num = section_match.group(1)
                 title = section_match.group(2).strip()
                 page = section_match.group(3).strip()
 
+                # 标准化节编号
+                if section_num.isdigit():
+                    section_idx = int(section_num)
+                    section_cn = self._number_to_chinese(section_idx)
+                else:
+                    section_cn = section_num
+
                 current_chapter["subsections"].append({
-                    "title": f"{section_num}、{title}",
+                    "title": f"{section_cn}、{title}",
                     "page": page,
                     "level": 2,
                     "original": line
@@ -472,23 +475,25 @@ class TOCCatalogExtractor:
                 title = generic_match.group(2).strip()
                 page = generic_match.group(3).strip()
 
-                # 判断是章还是节(根据缩进或内容特征)
+                # 判断是章还是节(根据内容特征)
                 if any(kw in title for kw in ['编制依据', '工程概况', '施工计划', '施工工艺',
                                                '安全保证', '质量保证', '环境保证', '人员配备',
                                                '验收要求']):
-                    # 可能是章标题(没有"第X章"前缀的变体)
                     chapters.append(current_chapter)
+                    idx = len(chapters) + 1
                     current_chapter = {
-                        "index": len(chapters) + 1,
-                        "title": title,
+                        "index": idx,
+                        "title": f"第{idx}章 {title}",
                         "page": page,
                         "original": line,
                         "subsections": []
                     }
                 else:
-                    # 作为节
+                    # 作为节,自动编号
+                    section_idx = len(current_chapter["subsections"]) + 1
+                    section_cn = self._number_to_chinese(section_idx)
                     current_chapter["subsections"].append({
-                        "title": title,
+                        "title": f"{section_cn}、{title}",
                         "page": page,
                         "level": 2,
                         "original": line
@@ -502,17 +507,33 @@ class TOCCatalogExtractor:
         if not chapters and lines:
             chapters = self._fallback_parse(lines)
 
+        # 构建标准格式文本
+        formatted_lines = []
+        for ch in chapters:
+            formatted_lines.append(ch["title"])
+            for sub in ch.get("subsections", []):
+                formatted_lines.append(f"  {sub['title']}")
+
+        formatted_text = "\n".join(formatted_lines)
+
+        # 日志输出完整的目录解析结果
+        logger.info(f"[TOC解析] 共 {len(chapters)} 章,标准格式文本:\n{formatted_text}")
+
         return {
             "chapters": chapters,
-            "total_chapters": len(chapters)
+            "total_chapters": len(chapters),
+            "raw_ocr_text": text,
+            "formatted_text": formatted_text
         }
 
     def _fallback_parse(self, lines: List[str]) -> List[Dict[str, Any]]:
         """
         降级解析策略:当正则无法匹配时使用启发式方法
+        输出标准格式:第X章 XXX / 一、XXX
         """
         chapters = []
         idx = 0
+        section_idx = 0
 
         for line in lines:
             line = line.strip()
@@ -530,22 +551,26 @@ class TOCCatalogExtractor:
             # 根据内容特征判断层级
             is_chapter = any(kw in title for kw in ['编制依据', '工程概况', '施工计划',
                                                        '施工工艺', '安全保证', '质量保证',
-                                                       '环境保证', '人员配备', '验收'])
+                                                       '环境保证', '人员配备', '验收',
+                                                       '其他资料'])
 
             if is_chapter or len(chapters) == 0:
                 idx += 1
+                section_idx = 0  # 重置节计数
                 chapters.append({
                     "index": idx,
-                    "title": title,
+                    "title": f"第{idx}章 {title}",
                     "page": page,
                     "original": line,
                     "subsections": []
                 })
             else:
-                # 作为上一章的节
+                # 作为上一章的节,使用标准格式 一、二、三
                 if chapters:
+                    section_idx += 1
+                    section_cn = self._number_to_chinese(section_idx)
                     chapters[-1]["subsections"].append({
-                        "title": title,
+                        "title": f"{section_cn}、{title}",
                         "page": page,
                         "level": 2,
                         "original": line
@@ -553,14 +578,14 @@ class TOCCatalogExtractor:
 
         return chapters
 
-    def _chinese_to_number(self, chinese: str) -> int:
-        """中文数字转阿拉伯数字"""
+    def _number_to_chinese(self, num: int) -> str:
+        """阿拉伯数字转中文数字"""
         chinese_nums = {
-            '一': 1, '二': 2, '三': 3, '四': 4, '五': 5,
-            '六': 6, '七': 7, '八': 8, '九': 9, '十': 10,
-            '十一': 11, '十二': 12
+            1: '一', 2: '二', 3: '三', 4: '四', 5: '五',
+            6: '六', 7: '七', 8: '八', 9: '九', 10: '十',
+            11: '十一', 12: '十二', 13: '十三', 14: '十四', 15: '十五'
         }
-        return chinese_nums.get(chinese, 0)
+        return chinese_nums.get(num, str(num))
 
 
 def extract_catalog_from_pdf(

+ 3 - 1
core/construction_review/component/reviewers/standard_timeliness_reviewer.py

@@ -320,7 +320,9 @@ class StandardTimelinessReviewer:
         text = text.replace('《', '').replace('》', '').replace('(', '').replace(')', '').replace('(', '').replace(')', '')
 
         # 第二轮:从 config.ini 读取并去除指定符号
-        default_symbols = '),-,.,/,,:,[,],【,】,〔,〕,(,),-,—'
+        # 包含各种连接符:半角连字符(-)、全角连接号(-)、全角破折号(—)、水平线(―)、
+        # 连字符(‐)、不换行连字符(‑)、数字线(‒)、短破折号(–)、减号(−)
+        default_symbols = '),-,.,/,,:,[,],【,】,〔,〕,(,),-,—,―,‐,‑,‒,–,−'
 
         # 尝试从配置读取
         symbols_str = default_symbols

+ 9 - 18
core/construction_review/component/standard_matching/standard_service.py

@@ -221,7 +221,9 @@ class StandardRepository:
         # ========== 第二轮:从配置读取并去除指定符号 ==========
         # 读取配置中的符号列表,默认使用常见符号
         # 包含各种连接符:半角连字符(-)、全角连接号(-)、全角破折号(—)
-        default_symbols = '),-,.,/,,:,[,],【,】,〔,〕,(,),-,—'
+        # 包含各种连接符:半角连字符(-)、全角连接号(-)、全角破折号(—)、水平线(―)、
+        # 连字符(‐)、不换行连字符(‑)、数字线(‒)、短破折号(–)、减号(−)
+        default_symbols = '),-,.,/,,:,[,],【,】,〔,〕,(,),-,—,―,‐,‑,‒,–,−'
 
         if _CONFIG_AVAILABLE and config_handler:
             try:
@@ -362,26 +364,15 @@ class StandardMatcher:
             # 名称规范化后匹配成功,按完全匹配处理
             return self._handle_full_match(result, db_record)
 
-        # 尝试用规范化名称模糊匹配
-        name_matches = self.repo.find_by_normalized_name(result.normalized_name)
-
-        # 查找精确名称匹配(使用规范化名称)
-        exact_match = self._find_exact_name_match(name_matches, result.normalized_name)
-
-        if exact_match:
-            # 找到名称匹配的记录,检查标准号是否一致
-            if result.normalized_number == exact_match.normalized_number:
-                # 标准号实质一致,按完全匹配处理
-                return self._handle_full_match(result, exact_match)
-            else:
-                # 名称匹配但标准号不一致 = 标准号错误
-                return self._set_mismatch_result(result, exact_match)
-
-        # 名称完全不匹配,但标准号已匹配成功
-        # 说明该标准存在于库中,应返回不匹配而非不存在
+        # 【关键修复】标准号已匹配成功,即使名称不完全匹配,
+        # 也不应该再通过名称去查找其他版本的记录。
+        # 因为这会导致:2017版(现行)→ 通过名称找到 → 2012版(废止)
+        # 应直接基于已匹配的记录返回结果。
         if db_record.validity in [ValidityStatus.CURRENT.value, ValidityStatus.TRIAL.value]:
+            # 现行/试行版本,返回不匹配,建议改为当前匹配的标准号
             return self._set_mismatch_result(result, db_record)
         elif db_record.validity == ValidityStatus.ABOLISHED.value:
+            # 废止版本,查找同名现行版本作为替代
             return self._handle_abolished(result, db_record)
 
         return self._set_not_found_result(result)

+ 71 - 44
core/construction_review/workflows/ai_review_workflow.py

@@ -298,7 +298,8 @@ class AIReviewWorkflow:
                 'reference_check': 'reference_basis_reviewer',
                 'sensitive_check': 'check_sensitive',
                 'non_parameter_compliance_check': 'check_non_parameter_compliance',
-                'parameter_compliance_check': 'check_parameter_compliance'
+                'parameter_compliance_check': 'check_parameter_compliance',
+                'catalogue_completeness_check': 'check_outline_catalogue'  # 目录完整性检查
             }
 
             # 获取审查项配置
@@ -328,11 +329,14 @@ class AIReviewWorkflow:
 
             # 根据标准配置对review_item_config进行排序
             review_item_dict_sorted = self.core_fun._check_item_mapping_order(review_item_config)
-            logger.info(f"审查项配置解析完成: {review_item_dict_sorted}")
+            logger.info(f"[DEBUG] 审查项配置解析完成: {review_item_dict_sorted}")
+            logger.info(f"[DEBUG] 是否包含 catalogue: {'catalogue' in review_item_dict_sorted}")
+            if 'catalogue' in review_item_dict_sorted:
+                logger.info(f"[DEBUG] catalogue 审查函数: {review_item_dict_sorted['catalogue']}")
             
             # 3️⃣ 获取结构化内容
             original_chunks = state.get("structured_content", {}).get("chunks", [])
-            
+
             # 安全获取 outline - 兼容无目录的情况(如某些DOCX文档)
             outline_data = state.get("structured_content", {}).get("outline", {})
             if isinstance(outline_data, dict):
@@ -341,33 +345,46 @@ class AIReviewWorkflow:
                 # outline 不是字典(可能是列表或None),视为无目录
                 original_outline = []
                 logger.warning("文档 outline 格式异常或非字典类型,视为无目录结构")
-            
+
             # 如果没有目录,记录警告并继续(跳过目录审查)
             if not original_outline:
                 logger.warning("文档未检测到目录结构,将跳过目录完整性审查")
-            
-            outline_content_list = []
-            
-            def extract_original_recursive(content):
-                """递归提取 original 字段,包括主目录和所有子目录"""
-                result = []
-                if isinstance(content, dict):
-                    # 提取当前层级的 original
-                    if "original" in content:
-                        result.append(content["original"])
-                    # 递归提取 subsections
-                    if "subsections" in content and isinstance(content["subsections"], list):
-                        for subsection in content["subsections"]:
-                            result.extend(extract_original_recursive(subsection))
-                return result
-
-            for content in original_outline:
-                # 递归提取主目录和子目录的 original 字段
-                originals = extract_original_recursive(content)
-                outline_content_list.extend(originals)
-
-            # 4. 最终拼接成字符串(列表join效率远高于str+=)
-            outline_content_str = "".join(outline_content_list)
+
+            # 优先使用 catalog.formatted_text(标准格式)
+            catalog_data = state.get("structured_content", {}).get("catalog", {})
+            if isinstance(catalog_data, dict) and catalog_data.get("formatted_text"):
+                outline_content_str = catalog_data["formatted_text"]
+                logger.info(f"使用 catalog.formatted_text,长度: {len(outline_content_str)}")
+            else:
+                # 回退:从 outline 构建(修复格式)
+                outline_content_list = []
+
+                def extract_title_recursive(content, parent_title=""):
+                    """递归提取 title 字段,构建标准格式"""
+                    result = []
+                    if isinstance(content, dict):
+                        # 提取当前层级的 title
+                        title = content.get("title", "")
+                        if title:
+                            if parent_title:
+                                # 二级标题缩进
+                                result.append(f"  {title}")
+                            else:
+                                # 一级标题
+                                result.append(title)
+                        # 递归提取 subsections
+                        subsections = content.get("subsections", [])
+                        if isinstance(subsections, list):
+                            for subsection in subsections:
+                                result.extend(extract_title_recursive(subsection, title))
+                    return result
+
+                for content in original_outline:
+                    titles = extract_title_recursive(content)
+                    outline_content_list.extend(titles)
+
+                outline_content_str = "\n".join(outline_content_list)
+                logger.info(f"使用 outline 构建目录文本,长度: {len(outline_content_str)}")
             
             # 预处理:根据 review_item_dict_sorted 中的 key 对 structured_content 进行筛选
             filtered_chunks = [
@@ -399,8 +416,11 @@ class AIReviewWorkflow:
                 all_check_items.extend(check_list)  # 把每个分类的检查项加入总列表
 
             # 统计所有 filtered_chunks 作为总块数(与实际处理的块数保持一致)
-            # 注意:+1 为目录审查单元(系统强制添加,不在用户配置的 review_item_config 中)
-            total_chunks = len(filtered_chunks) + 1
+            # 如果配置了 catalogue_completeness_check,+1 计入目录审查单元
+            has_catalogue = "catalogue" in review_item_dict_sorted
+            total_chunks = len(filtered_chunks) + (1 if has_catalogue else 0)
+            if has_catalogue:
+                logger.info(f"检测到 catalogue_completeness_check 配置,目录审查计入总任务数")
 
             # 初始化issues列表
             all_issues = []
@@ -454,21 +474,28 @@ class AIReviewWorkflow:
 
                 logger.info(f"章节 {chapter_code} 处理完成")
 
-            # 主流程完成后,串行处理 catalogue(目录审查)
-            # 注意:catalogue 是系统强制添加的审查单元,已计入 total_chunks
-            logger.info("开始处理目录审查(catalogue)")
-            # 目录审查只执行完整性检查(目录缺失统计已整合到 check_completeness 中)
-            chunks_completed, all_issues = await self.core_fun._process_chapter_item(
-                "catalogue",                 # chapter_code
-                catalogue,                   # chapter_content
-                ["check_completeness"],      # 只执行完整性检查(包含目录缺失统计)
-                state,
-                all_issues,
-                completed_chunks,
-                total_chunks
-            )
-            completed_chunks += chunks_completed  # 更新已完成块数
-            logger.info("目录审查处理完成")
+            # 主流程完成后,处理 catalogue(目录审查)
+            # 只有配置了 catalogue_completeness_check 才执行
+            logger.info(f"[DEBUG] 检查是否需要目录审查: catalogue in dict = {'catalogue' in review_item_dict_sorted}")
+            if "catalogue" in review_item_dict_sorted:
+                logger.info("[DEBUG] 开始处理目录审查(catalogue)")
+                logger.info(f"[DEBUG] catalogue chapter_content: {len(catalogue)} 个块")
+                logger.info(f"[DEBUG] catalogue 第一个块 keys: {catalogue[0].keys() if catalogue else 'N/A'}")
+                # 目录审查只执行目录结构检查(一二级缺失检查)
+                chunks_completed, all_issues = await self.core_fun._process_chapter_item(
+                    "catalogue",                 # chapter_code
+                    catalogue,                   # chapter_content
+                    ["check_outline_catalogue"],  # 只执行目录结构检查
+                    state,
+                    all_issues,
+                    completed_chunks,
+                    total_chunks
+                )
+                completed_chunks += chunks_completed  # 更新已完成块数
+                logger.info("[DEBUG] 目录审查处理完成")
+                logger.info(f"[DEBUG] 目录审查完成后 all_issues 数量: {len(all_issues)}")
+            else:
+                logger.info("[DEBUG] 未配置 catalogue_completeness_check,跳过目录审查")
 
             logger.info(f"all_issues_结果调试: {len(all_issues)} 个问题")
             # 7️ 汇总结果

+ 33 - 0
core/construction_review/workflows/core_functions/ai_review_core_fun.py

@@ -436,6 +436,39 @@ class AIReviewCoreFun:
                 overall_risk=self._calculate_single_result_risk(completeness_result),
                 is_sse_push=True
             )
+
+        elif func_name == "check_outline_catalogue":
+            # 目录结构完整性检查(一二级缺失检查)
+            # 从 state 获取 catalog 数据
+            outline_data = state.get("structured_content", {}).get("catalog", {})
+
+            logger.info(f"[DEBUG][check_outline_catalogue] 开始目录结构审查")
+            logger.info(f"[DEBUG][check_outline_catalogue] outline_data type: {type(outline_data)}")
+            logger.info(f"[DEBUG][check_outline_catalogue] outline_data keys: {outline_data.keys() if isinstance(outline_data, dict) else 'N/A'}")
+
+            logger.info(f"[DEBUG][check_outline_catalogue] 调用 ai_review_engine.check_outline_catalogue")
+            outline_result = await method(trace_id, outline_data, state, stage_name)
+
+            logger.info(f"[DEBUG][check_outline_catalogue] 返回结果 type: {type(outline_result)}")
+            logger.info(f"[DEBUG][check_outline_catalogue] 返回结果 keys: {outline_result.keys() if isinstance(outline_result, dict) else 'N/A'}")
+            if isinstance(outline_result, dict):
+                logger.info(f"[DEBUG][check_outline_catalogue] success: {outline_result.get('success')}")
+                details = outline_result.get('details', {})
+                logger.info(f"[DEBUG][check_outline_catalogue] details name: {details.get('name')}")
+                logger.info(f"[DEBUG][check_outline_catalogue] response count: {len(details.get('response', []))}")
+            logger.info(f"[check_outline_catalogue完成] 结果: {outline_result.get('details', {}).get('summary', '')}")
+
+            return UnitReviewResult(
+                unit_index=chunk_index,
+                unit_content=chunk,
+                basic_compliance={
+                    "check_outline_catalogue": outline_result
+                },
+                technical_compliance={},
+                rag_enhanced={},
+                overall_risk=self._calculate_single_result_risk(outline_result),
+                is_sse_push=True
+            )
         elif func_name == "check_non_parameter_compliance" and not is_complete_field:
             # 技术审查方法需要从 RAG 检索结果中获取 references
             raw_result = await self._execute_technical_review(

+ 554 - 0
utils_test/Model_Test/test_thinking_vs_nonthinking.py

@@ -0,0 +1,554 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+测试 qwen3.5 模型在思考模式与非思考模式下的输出区别
+
+测试场景:目录完整性审查(catalog_integrity_review)
+模型:shutian_qwen3_5_122b
+
+运行方式:
+    cd D:/wx_work/sichuan_luqiao/LQAgentPlatform
+    python utils_test/Model_Test/test_thinking_vs_nonthinking.py
+"""
+
+import asyncio
+import time
+import sys
+import json
+from pathlib import Path
+from datetime import datetime
+
+# 添加项目根目录到 Python 路径
+project_root = Path(__file__).parent.parent.parent
+sys.path.insert(0, str(project_root))
+
+from foundation.ai.agent.generate.model_generate import generate_model_client
+from foundation.observability.logger.loggering import review_logger as logger
+
+
+# 测试用的实际目录文本(模拟OCR识别结果)
+TEST_ACTUAL_CATALOG = """第一章 编制依据
+一、法律法规
+二、标准规范
+三、文件制度
+
+第二章 工程概况
+一、设计概况
+二、工程地质与水文气象
+三、周边环境
+
+第三章 施工计划
+一、施工进度计划
+二、施工材料计划
+
+第四章 施工工艺技术
+一、主要施工方法概述
+二、技术参数
+三、工艺流程
+
+第五章 安全保证措施
+一、安全保证体系
+二、组织保证措施
+
+第六章 质量保证措施
+一、质量保证体系
+
+第七章 施工管理及作业人员配备与分工
+一、施工管理人员
+
+第八章 验收要求
+一、验收标准"""
+
+# 标准目录模板
+STANDARD_CATALOG = """第一章 编制依据
+一、法律法规
+二、标准规范
+三、文件制度
+四、编制原则
+五、编制范围
+
+第二章 工程概况
+一、设计概况
+二、工程地质与水文气象
+三、周边环境
+四、施工平面及立面布置
+五、施工要求和技术保证条件
+六、风险辨识与分级
+七、参建各方责任主体单位
+
+第三章 施工计划
+一、施工进度计划
+二、施工材料计划
+三、施工设备计划
+四、劳动力计划
+五、安全生产费用使用计划
+
+第四章 施工工艺技术
+一、主要施工方法概述
+二、技术参数
+三、工艺流程
+四、施工准备
+五、施工方法及操作要求
+六、检查要求
+
+第五章 安全保证措施
+一、安全保证体系
+二、组织保证措施
+三、技术保证措施
+四、监测监控措施
+五、应急处置措施
+
+第六章 质量保证措施
+一、质量保证体系
+二、质量目标
+三、工程创优规划
+四、质量控制程序与具体措施
+
+第七章 环境保证措施
+一、环境保证体系
+二、环境保护组织机构
+三、环境保护及文明施工措施
+
+第八章 施工管理及作业人员配备与分工
+一、施工管理人员
+二、专职安全生产管理人员
+三、其他作业人员
+
+第九章 验收要求
+一、验收标准
+二、验收程序
+三、验收内容
+四、验收时间
+五、验收人员
+
+第十章 其他资料
+一、计算书
+二、相关施工图纸
+三、附图附表
+四、编制及审核人员情况"""
+
+# System Prompt(更新后,允许思考)
+SYSTEM_PROMPT = "你是一位施工方案文档审查专家,负责对比实际目录和标准目录,找出缺失项。请按JSON格式输出最终结果。"
+
+# User Prompt(更新后,允许思考)
+USER_PROMPT_TEMPLATE = """你是一位施工方案文档审查专家。请对比【实际目录】和【标准目录】,找出缺失项。
+
+## 审查原则
+1. **语义匹配**:实际目录与标准目录含义相同即算匹配,不要求文字完全一致
+2. **常见同义表述**(示例):
+   - "编制依据" ≈ "方案编制依据" ≈ "编制原则及依据"
+   - "工程概况" ≈ "工程基本情况" ≈ "项目概况"
+   - "施工计划" ≈ "施工进度计划" ≈ "施工安排"
+   - "法律法规" ≈ "相关法律" ≈ "法规依据"
+3. **容错范围**:
+   - 一级标题必须严格对应(如"编制依据"不能变成"引用标准")
+   - 二级标题允许一定变通,但核心含义必须一致
+
+## 实际目录(来自OCR识别)
+```
+{actual_catalog}
+```
+
+## 标准目录(必须包含的完整结构)
+```
+{standard_catalog}
+```
+
+## 输出规则
+1. **一级缺失判定**:实际目录中完全没有对应的章,或章节标题完全不匹配
+2. **二级缺失判定**:只有当父级一级目录**存在**时,才检查其下的二级目录是否缺失
+3. **重要**:如果某个一级目录缺失,**不要报告**该章节下的二级目录缺失(避免重复提醒)
+
+## 输出要求
+**重要:最终答案只输出 JSON,不要添加 markdown 代码块标记(```json)。**
+
+请直接输出 check_completeness 格式的 JSON 结果:
+{{
+  "details": {{
+    "name": "catalog_check",
+    "response": [
+      {{
+        "check_item": "check_completeness",
+        "chapter_code": "catalog",
+        "check_item_code": "catalog_check_completeness",
+        "check_result": {{
+          "issue_point": "【一级缺失】xxx",
+          "location": "目录页",
+          "suggestion": "建议补充'xxx'章节",
+          "reason": "简要说明",
+          "risk_level": "高风险"
+        }},
+        "exist_issue": true,
+        "risk_info": {{"risk_level": "high"}}
+      }}
+    ],
+    "review_location_label": "目录完整性审查",
+    "chapter_code": "catalog"
+  }},
+  "success": true
+}}
+
+**注意**:
+- 一级缺失:risk_level 为 "高风险", risk_info.risk_level 为 "high"
+- 二级缺失:risk_level 为 "中风险", risk_info.risk_level 为 "medium"
+- 如无缺失,response 中放一条 "issue_point": "【目录完整】一二级目录结构完整", "exist_issue": false
+"""
+
+
+def build_prompt(actual_catalog: str, standard_catalog: str) -> str:
+    """构建测试用的 prompt"""
+    return USER_PROMPT_TEMPLATE.format(
+        actual_catalog=actual_catalog,
+        standard_catalog=standard_catalog
+    )
+
+
+async def test_with_mode(mode_name: str, enable_thinking: bool, output_dir: Path) -> dict:
+    """
+    测试指定模式
+
+    Args:
+        mode_name: 模式名称(用于输出)
+        enable_thinking: 是否启用思考模式
+        output_dir: 输出目录
+
+    Returns:
+        测试结果字典
+    """
+    print(f"\n{'='*70}")
+    print(f" 测试模式: {mode_name} (enable_thinking={enable_thinking})")
+    print(f"{'='*70}")
+
+    model_name = "shutian_qwen3_5_122b"
+    trace_id = f"test_{mode_name}_{int(time.time())}"
+
+    # 构建 prompt
+    user_prompt = build_prompt(TEST_ACTUAL_CATALOG, STANDARD_CATALOG)
+
+    # 记录开始时间
+    start_time = time.time()
+
+    try:
+        # 调用模型
+        print(f"⏳ 正在调用模型 {model_name}...")
+        print(f"   enable_thinking={enable_thinking}")
+        print(f"   trace_id={trace_id}")
+
+        response = await generate_model_client.get_model_generate_invoke(
+            trace_id=trace_id,
+            system_prompt=SYSTEM_PROMPT,
+            user_prompt=user_prompt,
+            model_name=model_name,
+            enable_thinking=enable_thinking,
+            timeout=180
+        )
+
+        elapsed_time = time.time() - start_time
+
+        print(f"✅ 调用成功")
+        print(f"   响应时间: {elapsed_time:.2f}s")
+        print(f"   响应长度: {len(response)} 字符")
+
+        # 保存完整响应到文件
+        output_file = output_dir / f"{mode_name}_response.txt"
+        with open(output_file, 'w', encoding='utf-8') as f:
+            f.write(f"模式: {mode_name}\n")
+            f.write(f"enable_thinking: {enable_thinking}\n")
+            f.write(f"模型: {model_name}\n")
+            f.write(f"响应时间: {elapsed_time:.2f}s\n")
+            f.write(f"响应长度: {len(response)} 字符\n")
+            f.write(f"trace_id: {trace_id}\n")
+            f.write("="*70 + "\n")
+            f.write("原始响应内容:\n")
+            f.write(response)
+
+        print(f"   完整响应已保存: {output_file}")
+
+        # 分析响应特征
+        analysis = analyze_response(response)
+
+        # 保存分析结果
+        analysis_file = output_dir / f"{mode_name}_analysis.json"
+        with open(analysis_file, 'w', encoding='utf-8') as f:
+            json.dump({
+                "mode": mode_name,
+                "enable_thinking": enable_thinking,
+                "model": model_name,
+                "elapsed_time": elapsed_time,
+                "response_length": len(response),
+                "trace_id": trace_id,
+                "analysis": analysis
+            }, f, ensure_ascii=False, indent=2)
+
+        print(f"   分析结果已保存: {analysis_file}")
+
+        return {
+            "success": True,
+            "mode": mode_name,
+            "enable_thinking": enable_thinking,
+            "elapsed_time": elapsed_time,
+            "response_length": len(response),
+            "analysis": analysis,
+            "response_preview": response[:500] + "..." if len(response) > 500 else response
+        }
+
+    except Exception as e:
+        elapsed_time = time.time() - start_time
+        print(f"❌ 调用失败: {e}")
+
+        # 保存错误信息
+        error_file = output_dir / f"{mode_name}_error.txt"
+        with open(error_file, 'w', encoding='utf-8') as f:
+            f.write(f"模式: {mode_name}\n")
+            f.write(f"enable_thinking: {enable_thinking}\n")
+            f.write(f"错误信息: {str(e)}\n")
+            f.write(f"响应时间: {elapsed_time:.2f}s\n")
+
+        return {
+            "success": False,
+            "mode": mode_name,
+            "enable_thinking": enable_thinking,
+            "elapsed_time": elapsed_time,
+            "error": str(e)
+        }
+
+
+def analyze_response(response: str) -> dict:
+    """分析响应内容的特征"""
+    analysis = {
+        "has_thinking_process": False,
+        "has_answer_marker": False,
+        "has_json_structure": False,
+        "thinking_length": 0,
+        "json_start_index": -1,
+        "detected_patterns": []
+    }
+
+    # 检测思考过程标记
+    thinking_markers = [
+        "Thinking Process:",
+        "思考过程",
+        "1.  **Analyze",
+        "1. **分析",
+        "让我",
+        "我需要",
+        "第一步",
+        "首先",
+    ]
+
+    for marker in thinking_markers:
+        if marker in response:
+            analysis["detected_patterns"].append(f"包含标记: {marker}")
+            analysis["has_thinking_process"] = True
+            break
+
+    # 检测答案标记
+    answer_markers = [
+        "Answer:\n",
+        "Final Answer:\n",
+        "**Answer:**\n",
+        "**Final Answer:**\n",
+    ]
+
+    for marker in answer_markers:
+        if marker in response:
+            analysis["has_answer_marker"] = True
+            analysis["detected_patterns"].append(f"答案标记: {marker}")
+            break
+
+    # 检测 JSON 结构
+    json_start = response.find('{')
+    json_end = response.rfind('}')
+
+    if json_start != -1 and json_end != -1 and json_end > json_start:
+        analysis["has_json_structure"] = True
+        analysis["json_start_index"] = json_start
+
+        # 尝试计算思考部分长度
+        if json_start > 0:
+            analysis["thinking_length"] = json_start
+
+    # 检测响应结构特征
+    lines = response.split('\n')
+    analysis["total_lines"] = len(lines)
+
+    # 检测是否有明显的思考/答案分隔
+    for i, line in enumerate(lines):
+        if line.strip() in ["Answer:", "Final Answer:", "**Answer:**", "**Final Answer:**"]:
+            analysis["answer_line_number"] = i + 1
+            break
+
+    return analysis
+
+
+def print_comparison(result_thinking: dict, result_non_thinking: dict):
+    """打印两种模式的对比结果"""
+    print(f"\n{'='*70}")
+    print(" 对比分析结果")
+    print(f"{'='*70}")
+
+    # 基本信息对比
+    print("\n【基本信息对比】")
+    print(f"{'指标':<30} {'思考模式':>15} {'非思考模式':>15}")
+    print("-" * 70)
+    print(f"{'响应时间':<30} {result_thinking['elapsed_time']:>14.2f}s {result_non_thinking['elapsed_time']:>14.2f}s")
+    print(f"{'响应长度':<30} {result_thinking['response_length']:>14,} {result_non_thinking['response_length']:>14,}")
+
+    if result_thinking['success'] and result_non_thinking['success']:
+        time_diff = result_thinking['elapsed_time'] - result_non_thinking['elapsed_time']
+        length_diff = result_thinking['response_length'] - result_non_thinking['response_length']
+
+        print(f"{'时间差异':<30} {f'+{time_diff:.2f}s' if time_diff > 0 else f'{time_diff:.2f}s':>15}")
+        print(f"{'长度差异':<30} {f'+{length_diff:,}' if length_diff > 0 else f'{length_diff:,}':>15,}")
+
+        # 特征对比
+        print("\n【内容特征对比】")
+        analysis_t = result_thinking['analysis']
+        analysis_nt = result_non_thinking['analysis']
+
+        print(f"{'指标':<30} {'思考模式':>15} {'非思考模式':>15}")
+        print("-" * 70)
+        print(f"{'包含思考过程':<30} {'是' if analysis_t['has_thinking_process'] else '否':>15} {'是' if analysis_nt['has_thinking_process'] else '否':>15}")
+        print(f"{'包含答案标记':<30} {'是' if analysis_t['has_answer_marker'] else '否':>15} {'是' if analysis_nt['has_answer_marker'] else '否':>15}")
+        print(f"{'包含JSON结构':<30} {'是' if analysis_t['has_json_structure'] else '否':>15} {'是' if analysis_nt['has_json_structure'] else '否':>15}")
+        print(f"{'思考部分长度':<30} {analysis_t['thinking_length']:>14,} {analysis_nt['thinking_length']:>14,}")
+        print(f"{'总行数':<30} {analysis_t.get('total_lines', 0):>14,} {analysis_nt.get('total_lines', 0):>14,}")
+
+        # 检测到的模式
+        print("\n【思考模式 - 检测到的特征】")
+        for pattern in analysis_t.get('detected_patterns', []):
+            print(f"  - {pattern}")
+
+        print("\n【非思考模式 - 检测到的特征】")
+        for pattern in analysis_nt.get('detected_patterns', []):
+            print(f"  - {pattern}")
+
+        # 内容预览
+        print("\n【思考模式 - 响应预览】")
+        print(result_thinking.get('response_preview', 'N/A')[:300])
+
+        print("\n【非思考模式 - 响应预览】")
+        print(result_non_thinking.get('response_preview', 'N/A')[:300])
+
+    else:
+        print("\n⚠️ 部分测试失败,无法完成完整对比")
+
+
+def save_summary_report(result_thinking: dict, result_non_thinking: dict, output_dir: Path):
+    """保存汇总报告"""
+    report_file = output_dir / "comparison_report.md"
+
+    with open(report_file, 'w', encoding='utf-8') as f:
+        f.write("# Qwen3.5 思考模式 vs 非思考模式 测试报告\n\n")
+        f.write(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
+
+        f.write("## 测试配置\n\n")
+        f.write(f"- 模型: `shutian_qwen3_5_122b`\n")
+        f.write(f"- 测试场景: 目录完整性审查 (catalog_integrity_review)\n")
+        f.write(f"- Prompt: 允许思考,要求最终输出 JSON\n\n")
+
+        f.write("## 性能对比\n\n")
+        f.write("| 指标 | 思考模式 | 非思考模式 | 差异 |\n")
+        f.write("|------|----------|------------|------|\n")
+
+        if result_thinking['success'] and result_non_thinking['success']:
+            time_t = result_thinking['elapsed_time']
+            time_nt = result_non_thinking['elapsed_time']
+            len_t = result_thinking['response_length']
+            len_nt = result_non_thinking['response_length']
+
+            f.write(f"| 响应时间 | {time_t:.2f}s | {time_nt:.2f}s | {time_t - time_nt:+.2f}s |\n")
+            f.write(f"| 响应长度 | {len_t:,} | {len_nt:,} | {len_t - len_nt:+,} |\n")
+
+        f.write("\n## 内容特征对比\n\n")
+
+        if result_thinking['success'] and result_non_thinking['success']:
+            analysis_t = result_thinking['analysis']
+            analysis_nt = result_non_thinking['analysis']
+
+            f.write("| 特征 | 思考模式 | 非思考模式 |\n")
+            f.write("|------|----------|------------|\n")
+            f.write(f"| 包含思考过程 | {'✅ 是' if analysis_t['has_thinking_process'] else '❌ 否'} | {'✅ 是' if analysis_nt['has_thinking_process'] else '❌ 否'} |\n")
+            f.write(f"| 包含答案标记 | {'✅ 是' if analysis_t['has_answer_marker'] else '❌ 否'} | {'✅ 是' if analysis_nt['has_answer_marker'] else '❌ 否'} |\n")
+            f.write(f"| 包含JSON结构 | {'✅ 是' if analysis_t['has_json_structure'] else '❌ 否'} | {'✅ 是' if analysis_nt['has_json_structure'] else '❌ 否'} |\n")
+            f.write(f"| 思考部分长度 | {analysis_t['thinking_length']:,} | {analysis_nt['thinking_length']:,} |\n")
+
+            f.write("\n### 思考模式检测到的特征\n\n")
+            for pattern in analysis_t.get('detected_patterns', []):
+                f.write(f"- {pattern}\n")
+
+            f.write("\n### 非思考模式检测到的特征\n\n")
+            for pattern in analysis_nt.get('detected_patterns', []):
+                f.write(f"- {pattern}\n")
+
+        f.write("\n## 结论\n\n")
+
+        if result_thinking['success'] and result_non_thinking['success']:
+            analysis_t = result_thinking['analysis']
+
+            if analysis_t['has_thinking_process']:
+                f.write("✅ **思考模式生效**: 模型输出了明显的思考过程,然后通过 `Answer:` 标记分隔最终答案。\n\n")
+            else:
+                f.write("⚠️ **思考模式未生效**: 模型未输出明显的思考过程。\n\n")
+
+            f.write("### 建议\n\n")
+            f.write("- 思考模式下响应时间更长,但可能获得更好的推理质量\n")
+            f.write("- 非思考模式下响应更快,适合对延迟敏感的场景\n")
+            f.write("- 当前 `_extract_json` 增强逻辑可以正确处理思考模式的输出\n")
+        else:
+            f.write("⚠️ 部分测试失败,请检查日志。\n")
+
+    print(f"\n📄 汇总报告已保存: {report_file}")
+
+
+async def main():
+    """主函数"""
+    print("="*70)
+    print(" Qwen3.5 思考模式 vs 非思考模式 输出对比测试")
+    print("="*70)
+    print(f"\n测试场景: 目录完整性审查 (catalog_integrity_review)")
+    print(f"模型: shutian_qwen3_5_122b")
+    print(f"Prompt: 允许思考,最终输出 JSON")
+
+    # 创建输出目录
+    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+    output_dir = Path(project_root) / "utils_test" / "Model_Test" / "output" / f"thinking_test_{timestamp}"
+    output_dir.mkdir(parents=True, exist_ok=True)
+
+    print(f"\n输出目录: {output_dir}")
+
+    # 测试思考模式
+    result_thinking = await test_with_mode("thinking_enabled", True, output_dir)
+
+    # 等待一小段时间,避免 trace_id 冲突
+    await asyncio.sleep(1)
+
+    # 测试非思考模式
+    result_non_thinking = await test_with_mode("thinking_disabled", False, output_dir)
+
+    # 打印对比结果
+    print_comparison(result_thinking, result_non_thinking)
+
+    # 保存汇总报告
+    save_summary_report(result_thinking, result_non_thinking, output_dir)
+
+    print(f"\n{'='*70}")
+    print(" 测试完成")
+    print(f"{'='*70}")
+    print(f"\n所有结果已保存到: {output_dir}")
+
+    return result_thinking['success'] and result_non_thinking['success']
+
+
+if __name__ == "__main__":
+    try:
+        success = asyncio.run(main())
+        sys.exit(0 if success else 1)
+    except KeyboardInterrupt:
+        print("\n\n测试被用户中断")
+        sys.exit(1)
+    except Exception as e:
+        print(f"\n\n测试运行出错: {e}")
+        import traceback
+        traceback.print_exc()
+        sys.exit(1)