Pārlūkot izejas kodu

v0.0.5-功能优化
# 优化项
## 文档切分功能
1.优化文件切分模块的目录校对与分类功能
2.增加第十一个模型分类收容项
## 完整性审查功能
1.重构完整性审查模块的数据构造与处理功能逻辑;
2. 实现完整性审查,按章审查逻辑
3. 优化完整性审查可读性
## 专业性审查功能
4. 优化专业性审查提示词

## 编制依据功能
1. 重构规范性审查逻辑,
2. 规范性审查增加搜索判断,过滤未收录的规范
3. 优化规范性审查解释,减少语义逻辑冲突
4. 优化编制编号判断标准

# 完成项
1. 完成审查工作流审查项新流程全功能接入
2. 完成大纲完整性审查框架主体与核心功能
3. 完成正文编制依据联库判断功能

WangXuMing 1 mēnesi atpakaļ
vecāks
revīzija
60f4d2d632

+ 14 - 0
core/construction_review/component/ai_review_engine.py

@@ -227,6 +227,20 @@ class AIReviewEngine(BaseReviewer):
 
         # Step 2: 构建查询对
         query_pairs = query_rewrite_manager.query_extract(unit_content)
+
+        # 检查 query_pairs 是否为 None(模型调用失败时的防护)
+        if query_pairs is None:
+            logger.warning("[RAG增强] Query提取失败,返回空结果")
+            return {
+                'vector_search': [],
+                'retrieval_status': 'query_extract_failed',
+                'file_name': '',
+                'text_content': '',
+                'metadata': {},
+                'entity_results': [],        # 保持结构一致
+                'total_entities': 0          # 保持结构一致
+            }
+
         logger.info(f"[RAG增强] 提取到 {len(query_pairs)} 个查询对")
 
         # Step 3: 根据查询对主实体、辅助实体,进行实体增强召回

+ 59 - 45
core/construction_review/component/reviewers/prompt/technical_reviewers.yaml

@@ -3,94 +3,108 @@
 # 非参数合规性检查功能 - 审查 安全相关/强制性条文相关知识库
 non_parameter_compliance_check:
   system_prompt: |
-    你是施工方案非参数合规性审查专家,专门负责检查安全相关条文和强制性标准的符合性。
+    # 角色: 
+    你是施工方案非参数合规性审查专家,专门负责检查安全相关条文和非参数的强制性标准的符合性。
 
-    审查参考:
+    ## 审查参考:
     {review_references}
 
-    审查要求:
-    - 重点检查安全相关强制性条文符合性
+    ## 审查要求:
+    - 重点检查安全相关非参数性的条文内容
     - 识别违反安全标准和强制规范的问题
     - 关注安全防护措施、安全风险评估、安全管理要求
     - 简明扼要指出违规内容和整改要求
     - 风险等级分类:
-      * 高风险:影响审查结论、可能导致法律问题或严重安全隐患
-      * 中风险:影响专业表达、可能导致理解偏差或一般性问题
-      * 低风险:形式问题、不影响实质内容和安全
-
-    注意事项:
-    1. 务必结合语境进行分析检查
-    2. 对于表格制表符、不需要检查
-    3. 对于术语概念不得曲解
-    4. 没有明显安全合规问题的内容不予检查,输出无明显问题
-    5. 已检查出的问题项仅输出一次检查结果,禁止对同一内容重复检查
-    6. 若审查参考与审查内容相关性过低,不予检查,输出无明显问题
-    7. 务必注意,只有在审查参考与审查内容相关时才能依据审查参考的内容进行问题检查,否则输出无明显问题
-    8. 审查依据务必是基于审查参考,如果审查参考不足以对审查内容提供参考时,不予检查,输出无明显问题,不得自行编造审查依据
+      * 高风险: 影响审查结论、可能导致法律问题或严重安全隐患
+      * 中风险: 影响专业表达、可能导致理解偏差或一般性问题
+      * 低风险: 形式问题、不影响实质内容和安全
 
   user_prompt_template: |
-    请审查以下内容的安全合规性和强制性标准符合性:
+    请审查以下内容的安全合规性和非参数性内容(不含数字):
 
-    {review_content}
 
-    输出格式:务必须严格按照以下标准JSON格式输出审查结果:
-    如果未发现问题,请输出:无明显问题
-    如果发现问题,请按以下格式输出:
-    location字段直接输出原字段内容,不得猜测
+    ## 待审查内容:
+    {review_content}  
+
+    ## 强制标准:
+    1. 审查结果必须基于<审查参考>,如果审查参考不足以对审查内容提供参考时,不予检查,输出无明显问题,不得自行编造审查依据
+    2. 审查依据必须使用<审查参考>中的文件信息不得引用其他外部信息,如果无文件信息,不予检查,输出无明显问题
+    3. 对于表格制表符不需要检查
+    4. 对于术语概念不得曲解
+    5. 没有明显参数问题的内容不予检查,输出无明显问题
+    6. 已检查出的问题项仅输出一次检查结果,禁止对同一内容重复检查
+    7. 若审查参考与审查内容相关性过低,不予检查,输出无明显问题
+    8. 务必注意,只有在审查参考与审查内容相关时才能依据审查参考的内容进行问题检查,否则输出无明显问题
+    
+    ## rules:
+    - 输出格式:务必须严格按照以下标准JSON格式输出审查结果:
+    - 如果未发现问题,请输出:无明显问题
+    - 如果发现问题,请按以下格式输出:
+    - location字段直接输出原字段内容,不得猜测
+    - 务必遵循<强制标准>进行审查
+    - 尤其要注意<强制标准>中的第1条
     ```json
     {{
       "issue_point": "问题标题描述",
       "location": "当前问题对应的原始条款内容及位置,如六、验收标准 (页码: 85),以及其语境上下文",
       "suggestion": "具体的修改建议内容",
       "reason": "问题的原因分析和依据说明",
-      "risk_level": ""
+      "risk_level": "高风险/中风险/低风险"
     }}
     ```
 
+
 # 参数合规性检查功能 - 审查 实体概念/工程术语相关知识库
 parameter_compliance_check:
   system_prompt: |
+    # 角色: 
     你是施工方案参数合规性审查专家,专门负责检查技术参数、实体概念和工程术语的准确性和合理性。
 
-    审查参考:
+    ## 审查参考:
     {review_references}
 
-    审查要求:
+    ## 审查要求:
     - 重点检查技术参数的准确性和合理性
     - 识别参数错误或不合理设置
     - 检查实体概念和工程术语的参数是否正确使用
     - 验证设计值与标准的符合性
     - 简明扼要指出参数问题和修正建议
     - 风险等级分类:
-      * 高风险:影响审查结论、可能导致法律问题或严重安全隐患
-      * 中风险:影响专业表达、可能导致理解偏差或一般性问题
-      * 低风险:形式问题、不影响实质内容和安全
-
-    注意事项:
-    1. 务必结合语境进行分析检查
-    2. 对于表格制表符、不需要检查
-    3. 对于术语概念不得曲解
-    4. 没有明显参数问题的内容不予检查,输出无明显问题
-    5. 已检查出的问题项仅输出一次检查结果,禁止对同一内容重复检查
-    6. 若审查参考与审查内容相关性过低,不予检查,输出无明显问题
-    7. 务必注意,只有在审查参考与审查内容相关时才能依据审查参考的内容进行问题检查,否则输出无明显问题
-    8. 审查依据务必是基于审查参考,如果审查参考不足以对审查内容提供参考时,不予检查,输出无明显问题,不得自行编造审查依据
+      * 高风险: 影响审查结论、可能导致法律问题或严重安全隐患
+      * 中风险: 影响专业表达、可能导致理解偏差或一般性问题
+      * 低风险: 形式问题、不影响实质内容和安全
+
+
 
   user_prompt_template: |
     请审查以下内容的技术参数精确性、实体概念和工程术语的正确性:
 
-    {review_content}
+    ## 待审查内容:
+    {review_content}  
+
+    ## 强制标准:
+    1. 审查结果必须基于<审查参考>,如果审查参考不足以对审查内容提供参考时,不予检查,输出无明显问题,不得自行编造审查依据
+    2. 审查依据必须使用<审查参考>中的文件信息不得引用其他外部信息,如果无文件信息,不予检查,输出无明显问题
+    3. 对于表格制表符不需要检查
+    4. 对于术语概念不得曲解
+    5. 没有明显参数问题的内容不予检查,输出无明显问题
+    6. 已检查出的问题项仅输出一次检查结果,禁止对同一内容重复检查
+    7. 若审查参考与审查内容相关性过低,不予检查,输出无明显问题
+    8. 务必注意,只有在审查参考与审查内容相关时才能依据审查参考的内容进行问题检查,否则输出无明显问题
 
-    输出格式:务必须严格按照以下标准JSON格式输出审查结果:
-    如果未发现问题,请输出:无明显问题
-    如果发现问题,请按以下格式输出:
-    location字段直接输出原字段内容,不得猜测
+    ## rules:
+    - 输出格式:务必须严格按照以下标准JSON格式输出审查结果:
+    - 如果未发现问题,请输出:无明显问题
+    - 如果发现问题,请按以下格式输出:
+    - location字段直接输出原字段内容,不得猜测
+    - 务必遵循<强制标准>进行审查
+    - 尤其要注意<强制标准>中的第1条
     ```json
     {{
       "issue_point": "问题标题描述",
       "location": "当前问题对应的原始条款内容及位置,如六、验收标准 (页码: 85),以及其语境上下文",
       "suggestion": "具体的修改建议内容",
       "reason": "问题的原因分析和依据说明",
-      "risk_level": ""
+      "risk_level": "高风险/中风险/低风险"
     }}
     ```

+ 1 - 1
core/construction_review/component/reviewers/timeliness_basis_reviewer.py

@@ -447,7 +447,7 @@ async def review_all_basis_async(basis_items: BasisItems, max_concurrent: int =
 if __name__ == "__main__":
     # 直接构造 BasisItems 测试 review_all
     test_basis_items = BasisItems(items=[
-        BasisItem(title="坠落防护水平生命线装置", suffix="GB 38454", raw="《坠落防护水平生命线装置》GB 38454"),
+        BasisItem(title="坠落防护水平生命线装置", suffix="GB 38454", raw="《预应力混凝土用钢绞线》(GB/T5224-2023);"),
         BasisItem(title="电力高处作业防坠器", suffix="DL/T 1147", raw="《电力高处作业防坠器》DL/T 1147"),
         BasisItem(title="坠落防护挂点装置", suffix="GB 30862", raw="《坠落防护挂点装置》GB 30862"),
         BasisItem(title="混凝土结构设计规范", suffix="GB 50010-2010", raw="《混凝土结构设计规范》GB 50010-2010"),

+ 56 - 4
core/construction_review/component/reviewers/utils/directory_extraction.py

@@ -83,6 +83,46 @@ def fallback_regex(text: str) -> BasisItems:
     return BasisItems(items=items)
 
 
+# --------- 3.5) 根据chapter_code过滤,避免LLM误抽 ---------
+def _filter_by_chapter_code(items: List[BasisItem], chapter_code: str) -> List[BasisItem]:
+    """
+    根据章节代码过滤编制依据条目
+
+    规则:
+    - 如果 chapter_code == "basis":编制依据章节,不过滤,返回所有条目
+    - 如果 chapter_code != "basis":非编制依据章节,过滤掉raw中没有书名号的条目
+
+    Args:
+        items: 待过滤的条目列表
+        chapter_code: 章节代码("basis" 表示编制依据章节)
+
+    Returns:
+        过滤后的条目列表
+    """
+    # 编制依据章节,不过滤
+    if chapter_code == "basis":
+        logger.debug(f"[编制依据提取] 当前为编制依据章节(basis),不过滤,共 {len(items)} 条")
+        return items
+
+    # 非编制依据章节,过滤掉没有书名号的条目(避免LLM误抽)
+    before_count = len(items)
+    filtered_items = [
+        item for item in items
+        if "《" in item.raw and "》" in item.raw
+    ]
+    after_count = len(filtered_items)
+
+    # 如果有过滤,记录日志
+    if before_count != after_count:
+        logger.info(
+            f"[编制依据提取] 非编制依据章节(chapter_code={chapter_code}),"
+            f"过滤掉无书名号条目: {before_count} -> {after_count} "
+            f"(过滤 {before_count - after_count} 条)"
+        )
+
+    return filtered_items
+
+
 # --------- 4) 最小修改:只做一件事,提取第一个 JSON ---------
 def extract_first_json(text: str) -> dict:
     """
@@ -107,7 +147,7 @@ def extract_first_json(text: str) -> dict:
 
 
 # --------- 5) 主函数:使用 LangChain 抽取(最小改动版) ---------
-async def extract_basis_with_langchain_qwen(progress_manager,callback_task_id,text: str) -> BasisItems:
+async def extract_basis_with_langchain_qwen(progress_manager,callback_task_id:str,text: str,chapter_code: str) -> BasisItems:
     """
     使用 LangChain + LLM 提取编制依据信息(流式输出版本)
     """
@@ -199,19 +239,31 @@ async def extract_basis_with_langchain_qwen(progress_manager,callback_task_id,te
 
             cleaned.append(BasisItem(title=title, suffix=suffix, raw=raw))
 
+        # ✅ 新增:根据chapter_code过滤,避免LLM在非编制依据章节误抽
+        cleaned = _filter_by_chapter_code(cleaned, chapter_code)
+
         if cleaned:
             logger.info(f"[编制依据提取] LLM 提取成功,共 {len(cleaned)} 条")
             return BasisItems(items=cleaned)
 
         logger.warning("[编制依据提取] LLM 未提取到内容,使用兜底方案")
-        return fallback_regex(text)
+        # ✅ 修改:兜底方案也要经过过滤
+        fallback_result = fallback_regex(text)
+        filtered_items = _filter_by_chapter_code(fallback_result.items, chapter_code)
+        return BasisItems(items=filtered_items)
 
     except (json.JSONDecodeError, ValidationError, ValueError) as e:
         logger.error(f"[编制依据提取] LLM 输出解析失败: {e},使用兜底方案")
-        return fallback_regex(text)
+        # ✅ 修改:兜底方案也要经过过滤
+        fallback_result = fallback_regex(text)
+        filtered_items = _filter_by_chapter_code(fallback_result.items, chapter_code)
+        return BasisItems(items=filtered_items)
     except Exception as e:
         logger.error(f"[编制依据提取] LLM 提取失败: {str(e)},使用兜底方案")
-        return fallback_regex(text)
+        # ✅ 修改:兜底方案也要经过过滤
+        fallback_result = fallback_regex(text)
+        filtered_items = _filter_by_chapter_code(fallback_result.items, chapter_code)
+        return BasisItems(items=filtered_items)
 
 
 

+ 7 - 4
core/construction_review/workflows/core_functions/ai_review_core_fun.py

@@ -245,18 +245,21 @@ class AIReviewCoreFun:
         semaphore = asyncio.Semaphore(5)  # 单个块内限制并发数为5
         rag_enhanced_content = None  # 初始化变量,避免作用域错误
         basis_content = None  # 初始化变量,避免作用域错误
-
-        if 'check_parameter_compliance' in func_names or 'check_non_parameter_compliance' in func_names:
+        is_complete_field = chunk.get('is_complete_field', False)
+        logger.info(f"检查is_complete_field值是否正常: {is_complete_field}")
+        # 只有非完整性审查的chunk才执行RAG检索(注意括号位置,确保运算符优先级正确)
+        if ('check_parameter_compliance' in func_names or 'check_non_parameter_compliance' in func_names) and not is_complete_field:
             logger.debug("开始执行RAG检索增强")
             rag_enhanced_content = self.ai_review_engine.rag_enhanced_check(chunk.get('content', ''))
 
-        if 'reference_basis_reviewer' in func_names or 'timeliness_basis_reviewer' in func_names:
+        if ('reference_basis_reviewer' in func_names or 'timeliness_basis_reviewer' in func_names) and not is_complete_field:
             logger.debug("开始执行编制依据/时效性预处理")
             # 预处理编制依据/时效性审查所需内容
             basis_content = await directory_extraction.extract_basis_with_langchain_qwen(
                 state['progress_manager'],
                 state["callback_task_id"],
-                chunk.get('content', '')
+                chunk.get('content', ''),
+                chapter_code
             )
         async def execute_with_semaphore(func_name):
             async with semaphore:

+ 1 - 0
data_pipeline/RAG_recall/rag_miluvs/foundation/ai/rag/retrieval/retrieval.py

@@ -42,6 +42,7 @@ class RetrievalManager:
             self.logger.info(f"开始混合检索")
 
             param = {'collection_name': collection_name}
+            self.logger.info(f"开始向量检索")
             results = self.vector_manager.hybrid_search(
                 param=param,
                 query_text=query_text,

+ 1 - 1
foundation/database/base/vector/milvus_vector.py

@@ -453,7 +453,7 @@ class MilvusVectorManager(BaseVectorDB):
         """
         try:
             collection_name = param.get('collection_name')
-
+            logger.info(f"开始 hybrid_search, collection_name: {collection_name}")
             # 使用预创建的连接,避免运行时竞争
             if collection_name in self._vectorstore_cache:
                 vectorstore = self._vectorstore_cache[collection_name]