Jelajahi Sumber

v0.0.3-lq异构模型接入
- qwen3-8b
- qwen3-4b

WangXuMing 2 bulan lalu
induk
melakukan
5c87b467e7

+ 8 - 8
config/config.ini

@@ -1,7 +1,7 @@
 
 
 [model]
-MODEL_TYPE=gemini
+MODEL_TYPE=lq_qwen3_8b
 
 
 
@@ -29,7 +29,7 @@ QWEN_API_KEY=ms-9ad4a379-d592-4acd-b92c-8bac08a4a045
 
 [ai_review]
 # 调试模式配置
-MAX_REVIEW_UNITS=10
+MAX_REVIEW_UNITS=5
 REVIEW_MODE=random
 # REVIEW_MODE=all/random/first
 
@@ -67,14 +67,14 @@ SLCF_REANKER_MODEL_ID=BAAI/bge-reranker-v2-m3
 SLCF_VL_CHAT_MODEL_ID=THUDM/GLM-4.1V-9B-Thinking
 
 [lq_qwen3_8b]
-QWEN_LOCAL_1_5B_SERVER_URL=http://192.168.91.253:9000/v1
-QWEN_LOCAL_1_5B_MODEL_ID=/mnt/Qwen3-8B
+QWEN_LOCAL_1_5B_SERVER_URL=http://192.168.91.253:9002/v1
+QWEN_LOCAL_1_5B_MODEL_ID=Qwen3-8B
 QWEN_LOCAL_1_5B_API_KEY=dummy
 
-[qwen_local_14b]
-QWEN_LOCAL_14B_SERVER_URL=http://172.16.35.50:8003/v1
-QWEN_LOCAL_14B_MODEL_ID=Qwen3-14B
-QWEN_LOCAL_14B_API_KEY=sk-dummy
+[lq_qwen3_4b]
+QWEN_LOCAL_1_5B_SERVER_URL=http://192.168.91.253:9001/v1
+QWEN_LOCAL_1_5B_MODEL_ID=Qwen3-4B
+QWEN_LOCAL_1_5B_API_KEY=dummy
 
 
 [mysql]

+ 0 - 104
config/response_parsing_config.yaml

@@ -1,104 +0,0 @@
-# AI审查响应解析配置模板
-
-# JSON解析规则配置
-json_parsing_rules:
-  # 直接JSON检测规则
-  direct_json_patterns:
-    # 单行对象模式
-    - pattern: "^{.*}$"
-      type: "single_object"
-      description: "直接JSON对象"
-    # 多行对象模式
-    - pattern: "^\\{[\\s\\S]*\\}$"
-      type: "multiline_object"
-      description: "多行JSON对象"
-    # JSON数组模式(新增)
-    - pattern: "^\\[[\\s\\S]*\\]$"
-      type: "json_array"
-      description: "JSON数组"
-
-  # 代码块模式
-  code_block_patterns:
-    - pattern: "```json\\s*([\\s\\S]*?)\\s*```"
-      type: "json_code_block"
-      description: "标准JSON代码块"
-    - pattern: "```JSON\\s*([\\s\\S]*?)\\s*```"
-      type: "json_code_block_upper"
-      description: "大写JSON代码块"
-    - pattern: "```\s*([\\s\\S]*?)\s*```"
-      type: "generic_code_block"
-      description: "通用代码块"
-
-  # 特殊格式模式
-  special_patterns:
-    - pattern: '"check_result":\s*"[^"]*\[[\s\S]*?\]"'
-      type: "embedded_array"
-      description: "嵌入式JSON数组"
-
-# 必需关键字验证
-required_keywords:
-  # 标准检查项关键字
-  standard:
-    - "issue_point"
-    - "location"
-    - "suggestion"
-    - "reason"
-    - "risk_level"
-
-  # 可选关键字(有则提取,无则跳过)
-  optional:
-    - "check_item"
-    - "status"
-    - "severity"
-    - "category"
-
-# JSON内容验证规则
-content_validation:
-  # 最小字段数量
-  min_fields: 3
-  # 必需字段
-  required_fields: ["issue_point", "suggestion"]
-  # 字段长度限制
-  max_field_length: 1000
-  # 字符编码验证
-  encoding_check: true
-
-# 解析优先级
-parsing_priority:
-  1: "direct_json_patterns"
-  2: "code_block_patterns"
-  3: "special_patterns"
-  4: "text_fallback"
-
-# 风险等级映射
-risk_level_mapping:
-  high_risk:
-    - "高风险"
-    - "high"
-    - "严重"
-    - "critical"
-  medium_risk:
-    - "中风险"
-    - "medium"
-    - "中等"
-    - "一般"
-  low_risk:
-    - "低风险"
-    - "low"
-    - "轻微"
-    - "minor"
-  default: "medium_risk"
-
-# 错误处理策略
-error_handling:
-  # JSON解析失败时的策略
-  json_parse_failed:
-    - "try_next_pattern"
-    - "extract_keywords_manually"
-    - "fallback_to_text"
-
-  # 关键字缺失时的策略
-  missing_keywords:
-    - "extract_from_text"
-    - "use_default_values"
-    - "log_warning"

+ 48 - 5
core/construction_review/workflows/ai_review_workflow.py

@@ -195,8 +195,8 @@ class AIReviewWorkflow:
             }
 
             logger.info(f"保存审查结果")
-            with open('temp/AI审查结果.json', "w",encoding='utf-8') as f:
-                json.dump(result, f, ensure_ascii=False, indent=2, default=str)
+            # with open('temp/AI审查结果.json', "w",encoding='utf-8') as f:
+            #     json.dump(result, f, ensure_ascii=False, indent=2, default=str)
 
             return review_results
 
@@ -850,26 +850,69 @@ class AIReviewCoreFun:
 
             # 如果直接解析失败,查找JSON代码块
             if json_data is None:
-                json_pattern = r'```json\s*(.*?)\s*```'
-                json_matches = re.findall(json_pattern, response, re.DOTALL)
+                # 改进的正则表达式:正确处理多行JSON和转义字符
+                json_pattern = r'```json\s*(\[[\s\S]*?\]|\{[\s\S]*?\})\s*```'
+                json_matches = re.findall(json_pattern, response)
+
+                # 如果改进的正则仍然匹配不到,使用更宽松的模式
+                if not json_matches:
+                    json_pattern = r'```json\s*(.*?)\s*```'
+                    json_matches = re.findall(json_pattern, response, re.DOTALL)
+
             else:
                 json_matches = [response_stripped]  # 使用整个响应作为JSON
 
+            # 如果所有方法都失败,尝试最后的JSON提取策略
+            if not json_matches:
+                logger.warning("标准JSON提取失败,尝试智能JSON提取策略")
+
+                # 策略1: 查找被JSON数组/对象包围的内容
+                array_pattern = r'\[\s*\{.*?\}\s*\]'
+                object_pattern = r'\{[^{}]*"issue_point"[^{}]*\}'
+
+                array_matches = re.findall(array_pattern, response, re.DOTALL)
+                if array_matches:
+                    json_matches = array_matches
+                    logger.info(f"数组模式匹配成功,找到 {len(array_matches)} 个JSON数组")
+                else:
+                    object_matches = re.findall(object_pattern, response, re.DOTALL)
+                    if object_matches:
+                        json_matches = object_matches
+                        logger.info(f"对象模式匹配成功,找到 {len(object_matches)} 个JSON对象")
+
+            # 最后的备选方案:查找包含关键JSON字段的内容
+            if not json_matches:
+                logger.warning("所有JSON提取策略失败,查找包含关键字段的内容")
+                key_pattern = r'[^`]*["\']issue_point["\'][^`]*["\']location["\'][^`]*'
+                key_matches = re.findall(key_pattern, response, re.DOTALL)
+                if key_matches:
+                    # 尝试将匹配内容包装为有效JSON
+                    for match in key_matches:
+                        # 简单包装,可能需要更复杂的逻辑
+                        wrapped_match = f'[{match}]' if not match.strip().startswith('[') else match
+                        json_matches.append(wrapped_match)
+                    logger.info(f"关键字段模式匹配成功,生成 {len(json_matches)} 个JSON候选")
+
             if json_matches:
+                logger.info(f"成功匹配到 {len(json_matches)} 个JSON代码块")
                 # 解析找到的JSON
-                for json_str in json_matches:
+                for i, json_str in enumerate(json_matches):
                     try:
                         # 如果是直接解析的JSON,不需要重新解析
                         if json_str == response_stripped and json_data is not None:
                             issue_data = json_data
+                            logger.debug(f"使用直接解析的JSON数据 (第{i+1}个)")
                         else:
                             # 清理JSON字符串
                             json_str = json_str.strip()
                             if not json_str:
+                                logger.warning(f"第{i+1}个JSON代码块为空,跳过")
                                 continue
 
+                            logger.debug(f"尝试解析第{i+1}个JSON: {json_str[:100]}...")
                             # 解析JSON
                             issue_data = json.loads(json_str)
+                            logger.info(f"第{i+1}个JSON解析成功,包含 {len(issue_data) if isinstance(issue_data, (list, dict)) else 0} 个元素")
 
                         risk_level = issue_data.get("risk_level", "")
 

+ 1 - 1
foundation/base/celery_app.py

@@ -40,7 +40,7 @@ app.conf.update(
     enable_utc=True,
 
     # Worker配置
-    worker_prefetch_multiplier=2,  # 每个worker一次只取一个任务
+    worker_prefetch_multiplier=1,  # 每个worker一次只取一个任务
     task_acks_late=True,           # 任务完成后再确认
 
     # 并发控制

+ 16 - 12
foundation/utils/utils.py

@@ -23,6 +23,7 @@
 ├── _get_deepseek_model()        # 获取DeepSeek模型
 ├── _get_gemini_model()          # 获取Gemini模型
 ├── _get_lq_qwen3_8b_model()     # 获取本地Qwen3-8B模型
+├── _get_lq_qwen3_4b_model()     # 获取本地Qwen3-4B模型
 └── _get_qwen_local_14b_model()  # 获取本地Qwen3-14B模型
 '''
 
@@ -43,6 +44,7 @@ class ModelHandler:
     - deepseek: DeepSeek模型
     - gemini: Gemini模型
     - lq_qwen3_8b: 本地Qwen3-8B模型
+    - lq_qwen3_4b: 本地Qwen3-4B模型
     - qwen_local_14b: 本地Qwen3-14B模型
     """
 
@@ -63,7 +65,7 @@ class ModelHandler:
 
         Note:
             根据配置文件中的MODEL_TYPE参数选择对应模型
-            支持的模型类型:doubao, qwen, deepseek, lq_qwen3_8b, qwen_local_14b
+            支持的模型类型:doubao, qwen, deepseek, lq_qwen3_8b, lq_qwen3_4b, qwen_local_14b
             默认返回豆包模型
         """
         model_type = self.config.get("model", "MODEL_TYPE")
@@ -71,7 +73,7 @@ class ModelHandler:
 
         if model_type == "doubao":
             model = self._get_doubao_model()
-        if model_type == "gemini":
+        elif model_type == "gemini":
             model = self._get_gemini_model()
         elif model_type == "qwen":
             model = self._get_qwen_model()
@@ -79,12 +81,14 @@ class ModelHandler:
             model = self._get_deepseek_model()
         elif model_type == "lq_qwen3_8b":
             model = self._get_lq_qwen3_8b_model()
+        elif model_type == "lq_qwen3_4b":
+            model = self._get_lq_qwen3_4b_model()
         elif model_type == "qwen_local_14b":
             model = self._get_qwen_local_14b_model()
         else:
-            # 默认返回豆包
+            # 默认返回gemini
             logger.warning(f"未知的模型类型 '{model_type}',使用默认gemini模型")
-            model = model = self._get_gemini_model()
+            model = self._get_gemini_model()
 
         logger.info(f"AI模型初始化完成: {model_type}")
         return model
@@ -189,25 +193,25 @@ class ModelHandler:
             ChatOpenAI: 配置好的本地Qwen3-8B模型实例
         """
         llm = ChatOpenAI(
-            base_url="http://192.168.91.253:9000/v1",
-            model="/mnt/Qwen3-8B",
+            base_url="http://192.168.91.253:9002/v1",
+            model="Qwen3-8B",
             api_key="dummy",  # 本地模型使用虚拟API key
             temperature=0.7,
         )
 
         return llm
 
-    def _get_qwen_local_14b_model(self):
+    def _get_lq_qwen3_4b_model(self):
         """
-        获取本地Qwen3-14B模型
+        获取本地Qwen3-4B-Instruct模型
 
         Returns:
-            ChatOpenAI: 配置好的本地Qwen3-14B模型实例
+            ChatOpenAI: 配置好的本地Qwen3-4B模型实例
         """
         llm = ChatOpenAI(
-            base_url="http://172.16.35.50:8003/v1",
-            model="Qwen3-14B",
-            api_key="sk-dummy",  # 本地模型使用虚拟API key
+            base_url="http://192.168.91.253:9001/v1",
+            model="Qwen3-4B",
+            api_key="dummy",  # 本地模型使用虚拟API key
             temperature=0.7,
         )
 

File diff ditekan karena terlalu besar
+ 1 - 1
temp/AI审查结果.json


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini