Bläddra i källkod

v0.0.2-AI审查模型测试

WangXuMing 3 månader sedan
förälder
incheckning
40c34354ce
32 ändrade filer med 1171 tillägg och 1656 borttagningar
  1. 2 1
      .gitignore
  2. 34 13
      config/config.ini
  3. 0 10
      config/prompt/common_model_query.yaml
  4. 0 22
      config/prompt/intent_prompt.yaml
  5. 0 19
      config/prompt/system_prompt.yaml
  6. 30 2
      core/base/workflow_manager.py
  7. 125 47
      core/construction_review/component/ai_review_engine.py
  8. 44 20
      core/construction_review/component/document_processor.py
  9. 1 7
      core/construction_review/component/reviewers/__init__.py
  10. 45 91
      core/construction_review/component/reviewers/base_reviewer.py
  11. 0 233
      core/construction_review/component/reviewers/basic_reviewers.py
  12. 89 0
      core/construction_review/component/reviewers/prompt/ai_suggestion.yaml
  13. 121 0
      core/construction_review/component/reviewers/prompt/basic_reviewers.yaml
  14. 79 0
      core/construction_review/component/reviewers/prompt/rag_reviewers.yaml
  15. 78 0
      core/construction_review/component/reviewers/prompt/technical_reviewers.yaml
  16. 0 282
      core/construction_review/component/reviewers/technical_reviewers.py
  17. 1 3
      core/construction_review/component/reviewers/utils/__init__.py
  18. 195 67
      core/construction_review/component/reviewers/utils/prompt_loader.py
  19. 0 116
      core/construction_review/prompt/basic_reviewers.yaml
  20. 0 167
      core/construction_review/prompt/rag_reviewers.yaml
  21. 0 165
      core/construction_review/prompt/technical_reviewers.yaml
  22. 106 60
      core/construction_review/workflows/ai_review_workflow.py
  23. 19 80
      foundation/agent/generate/model_generate.py
  24. 0 0
      foundation/agent/monitor/__init__.py
  25. 11 0
      foundation/agent/monitor/ai_trace_monitor.py
  26. 2 2
      foundation/agent/workflow/test_workflow_node.py
  27. 1 1
      foundation/base/tasks.py
  28. 174 197
      foundation/utils/utils.py
  29. 7 47
      temp/AI审查结果.json
  30. 3 0
      test/test_enumerate.py
  31. 1 1
      views/construction_review/file_upload.py
  32. 3 3
      views/test_views.py

+ 2 - 1
.gitignore

@@ -60,4 +60,5 @@ target/
 
 todo.md
 .design
-.claude
+.claude
+.R&D

+ 34 - 13
config/config.ini

@@ -1,23 +1,37 @@
 
 
 [model]
-MODEL_TYPE=qwen
+MODEL_TYPE=qwen_local_14b
+
+
+
+[gemini]
+GEMINI_SERVER_URL=https://generativelanguage.googleapis.com
+GEMINI_MODEL_ID=gemini-2.5-flash
+GEMINI_API_KEY=AIzaSyDcL1AZS4u9N-8OyE7q7M25wvYZhj2okJc
 
 [deepseek]
 DEEPSEEK_SERVER_URL=https://api.deepseek.com
 DEEPSEEK_MODEL_ID=deepseek-chat
-DEEPSEEK_API_KEY=
+DEEPSEEK_API_KEY=sk-9fe722389bac47e9ab30cf45b32eb736
+
+[doubao]
+DOUBAO_SERVER_URL=https://ark.cn-beijing.volces.com/api/v3/
+DOUBAO_MODEL_ID=doubao-seed-1-6-flash-250715
+DOUBAO_API_KEY=c98686df-506f-432c-98de-32e571a8e916
 
 
 [qwen]
-MODEL_SERVER_URL=https://api-inference.modelscope.cn/v1/
-CHAT_MODEL_ID=Qwen/Qwen3-30B-A3B
-API_KEY=ms-61bf873e-7536-42a9-b830-b12dca656e1f
+QWEN_SERVER_URL=https://api-inference.modelscope.cn/v1/
+QWEN_MODEL_ID=Qwen/Qwen3-30B-A3B
+QWEN_API_KEY=ms-9ad4a379-d592-4acd-b92c-8bac08a4a045
 
 
-[api_key]
-DASHSCOPE_API_KEY=sk-9fca4fca37ce4f509ec9ead71ccdd542
-EMBED_MODEL_ID=text-embedding-v4
+[ai_review]
+# 调试模式配置
+MAX_REVIEW_UNITS=1
+REVIEW_MODE=random
+# REVIEW_MODE=all/random/first
 
 
 
@@ -40,12 +54,9 @@ LOG_FILE_MAX_MB=10
 LOG_BACKUP_COUNT=5
 CONSOLE_OUTPUT=True
 
-
-<<<<<<< HEAD
-
 [user_lists]
 USERS=['user-001']
-=======
+
 [siliconflow]
 SLCF_MODEL_SERVER_URL=https://api.siliconflow.cn/v1
 SLCF_API_KEY=sk-npqfinszhdvnwvensnjmlqtihgevehqiyfwunedxnefkmrud
@@ -53,4 +64,14 @@ SLCF_CHAT_MODEL_ID=test-model
 SLCF_EMBED_MODEL_ID=netease-youdao/bce-embedding-base_v1
 SLCF_REANKER_MODEL_ID=BAAI/bge-reranker-v2-m3
 SLCF_VL_CHAT_MODEL_ID=THUDM/GLM-4.1V-9B-Thinking
->>>>>>> 55a5de5dac64be4c91d083a1d1b9bb6e647ad1b5
+
+[qwen_local_1.5b]
+QWEN_LOCAL_1_5B_SERVER_URL=http://172.16.35.50:8000/v1
+QWEN_LOCAL_1_5B_MODEL_ID=Qwen2.5-1.5B-Instruct
+QWEN_LOCAL_1_5B_API_KEY=sk-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
+

+ 0 - 10
config/prompt/common_model_query.yaml

@@ -1,10 +0,0 @@
-
-# 任务提示词
-task_prompt: |
-  你是一个智能助手,根据提供的信息回答问题。
-
-
-
-# test
-template: |
-  ## 测试内容

+ 0 - 22
config/prompt/intent_prompt.yaml

@@ -1,22 +0,0 @@
-
-# 系统提示词
-system_prompt: |
-  基于提供的样例,结合用户最近的对话历史上下文进行意图识别,精准匹配对应的业务场景指令。
-  必须优先参考最近的上下文语义及用户意图演变,若问题与样例中的任一业务场景相符,则返回对应指令;若无法匹配任何已定义场景,则返回 chat_box_generate。
-  严格遵守:仅输出指令字符串,不附加任何解释、说明或格式。
-  用户目前历史上下文信息:
-  {history}
-
-
-
-
-# 意图案例 准备few-shot样例;
-intent_examples: 
-  - inn: 你好;咨询.
-    out: chat_box_generate
-
-  - inn: 执行;操作;查询;处理;
-    out: common_agent
-
-
-           

+ 0 - 19
config/prompt/system_prompt.yaml

@@ -1,19 +0,0 @@
-
-
-# 系统提示词
-system_prompt: |
-  分析专家于一身的AI助手,提供全方位的智能化指导。
-        你的建议要务实、经济、易操作,并能基于物联网数据提供精准预警和具体解决方案。
-            
-
-    
-# 用户上下文会话记录 摘要提示词
-summary_system_prompt: |
-  请总结以下对话内容,保留关键信息:
-  {history}
-
-
-
-# test
-template: |
-  ## 测试内容

+ 30 - 2
core/base/workflow_manager.py

@@ -145,12 +145,26 @@ class WorkflowManager:
 
             structured_content = doc_result['structured_content']
 
+            # 读取AI审查配置
+            import configparser
+            config = configparser.ConfigParser()
+            config.read('config/config.ini', encoding='utf-8')
+
+            max_review_units = config.getint('ai_review', 'MAX_REVIEW_UNITS', fallback=None)
+            if max_review_units == 0:  # 如果配置为0,表示审查所有
+                max_review_units = None
+            review_mode = config.get('ai_review', 'REVIEW_MODE', fallback='all')
+
+            logger.info(f"AI审查配置: 最大审查条文数量={max_review_units}, 审查模式={review_mode}")
+
             ai_workflow = AIReviewWorkflow(
                 file_id=task_chain.file_id,
                 callback_task_id=task_chain.callback_task_id,
                 user_id=task_chain.user_id,
                 structured_content=structured_content,
-                progress_manager=self.progress_manager
+                progress_manager=self.progress_manager,
+                max_review_units=max_review_units,
+                review_mode=review_mode
             )
 
             ai_result = await ai_workflow.execute()
@@ -223,12 +237,26 @@ class WorkflowManager:
 
             structured_content = doc_result['structured_content']
 
+            # 读取AI审查配置
+            import configparser
+            config = configparser.ConfigParser()
+            config.read('config/config.ini', encoding='utf-8')
+
+            max_review_units = config.getint('ai_review', 'MAX_REVIEW_UNITS', fallback=None)
+            if max_review_units == 0:  # 如果配置为0,表示审查所有
+                max_review_units = None
+            review_mode = config.get('ai_review', 'REVIEW_MODE', fallback='all')
+
+            logger.info(f"AI审查配置: 最大审查数量={max_review_units}, 审查模式={review_mode}")
+
             ai_workflow = AIReviewWorkflow(
                 file_id=task_chain.file_id,
                 callback_task_id=task_chain.callback_task_id,
                 user_id=task_chain.user_id,
                 structured_content=structured_content,
-                progress_manager=self.progress_manager
+                progress_manager=self.progress_manager,
+                max_review_units=max_review_units,
+                review_mode=review_mode
             )
 
             # 同步执行AI审查

+ 125 - 47
core/construction_review/component/ai_review_engine.py

@@ -4,13 +4,11 @@ AI审查引擎
 """
 
 import asyncio
-import time
-from typing import Dict, List, Any, Optional, Callable
+from enum import Enum
 from dataclasses import dataclass
-from datetime import datetime
-
+from typing import Dict, List, Any
 from foundation.logger.loggering import server_logger as logger
-
+from core.construction_review.component.reviewers.base_reviewer import BaseReviewer,BaseRAGReviewer
 @dataclass
 class ReviewResult:
     """审查结果"""
@@ -21,24 +19,76 @@ class ReviewResult:
     rag_enhanced: Dict[str, Any]
     overall_risk: str
 
-class AIReviewEngine:
+class Stage(Enum):
+    """工作流状态"""
+    BASIC = {
+        'reviewer_type':'basic',
+        'sensitive': 'sensitive_word_check',
+        'semantic': 'semantic_logic_check',
+        'completeness': 'completeness_check',
+        'timeliness': 'timeliness_check',
+        'reference': 'reference_check'
+    }
+    TECHNICAL = {
+        'reviewer_type':'technical',
+        'mandatory': 'mandatory_standards_check',
+        'technical': 'technical_parameters_check',
+        'design': 'design_values_check'
+    }
+    RAG = {
+        'reviewer_type':'rag',
+        'rag': 'rag_enhanced_review',
+        'vector': 'vector_search_review',
+        'hybrid': 'hybrid_search_review'
+    }
+    AI = {
+        'reviewer_type':'ai',
+        'professional': 'professional_suggestion',
+        'standardization': 'standardization_suggestion',
+        'completeness': 'completeness_suggestion',
+        'readability': 'readability_suggestion'
+    }
+
+
+class AIReviewEngine(BaseReviewer):
     """AI审查引擎 - 支持审查条目并发"""
 
-    def __init__(self, max_concurrent_reviews: int = 20):
+    def __init__(self, max_concurrent_reviews: int = 8):
+        super().__init__()  
         self.max_concurrent_reviews = max_concurrent_reviews
         self.semaphore = asyncio.Semaphore(max_concurrent_reviews)
 
+
+
     
-    async def basic_compliance_check(self, unit_content: Dict[str, Any]) -> Dict[str, Any]:
+    async def basic_compliance_check(self,trace_id_idx: str, unit_content: Dict[str, Any]) -> Dict[str, Any]:
         """基础合规性检查"""
-        # 词句语法检查
-        grammar_result = await self.check_grammar(unit_content['content'])
+        review_content = unit_content['content']
+        review_references = unit_content.get('review_references')
+
+        logger.info(f"开始基础合规性检查, 内容长度: {len(review_content)}")
+
+        async def check_with_semaphore(check_func, *args):
+            async with self.semaphore:
+                return await check_func(*args)
+
+        basic_tasks = [
+            check_with_semaphore(self.check_grammar, trace_id_idx, review_content, review_references),
+            check_with_semaphore(self.check_semantic_logic, trace_id_idx, review_content, review_references),
+            check_with_semaphore(self.check_completeness, trace_id_idx, review_content, review_references)
+        ]
+
+
+        grammar_result, semantic_result, completeness_result = await asyncio.gather(*basic_tasks, return_exceptions=True)
 
-        # 语义逻辑检查
-        semantic_result = await self.check_semantic_logic(unit_content['content'])
 
-        # 条文完整性检查
-        completeness_result = await self.check_completeness(unit_content['content'])
+
+        if isinstance(grammar_result, Exception):
+            grammar_result = {"error": str(grammar_result), "success": False}
+        if isinstance(semantic_result, Exception):
+            semantic_result = {"error": str(semantic_result), "success": False}
+        if isinstance(completeness_result, Exception):
+            completeness_result = {"error": str(completeness_result), "success": False}
 
         return {
             'grammar_check': grammar_result,
@@ -47,16 +97,30 @@ class AIReviewEngine:
             'overall_score': self._calculate_basic_score(grammar_result, semantic_result, completeness_result)
         }
 
-    async def technical_compliance_check(self, unit_content: Dict[str, Any]) -> Dict[str, Any]:
+    async def technical_compliance_check(self, trace_id_idx: str, unit_content: Dict[str, Any]) -> Dict[str, Any]:
         """技术性合规检查"""
-        # 强制性标准符合性检查
-        mandatory_result = await self.check_mandatory_standards(unit_content['content'])
-
-        # 设计值符合性检查
-        design_value_result = await self.check_design_values(unit_content['content'])
-
-        # 技术参数精确检查
-        technical_param_result = await self.check_technical_parameters(unit_content['content'])
+        review_content = unit_content['content']
+        review_references = unit_content.get('review_references')
+        logger.info(f"开始技术性合规检查,内容长度: {len(review_content)}")
+        async def check_with_semaphore(check_func, *args):
+            async with self.semaphore:
+                return await check_func(*args)
+
+        technical_tasks = [
+            check_with_semaphore(self.check_mandatory_standards, trace_id_idx, review_content,review_references),
+            check_with_semaphore(self.check_design_values, trace_id_idx, review_content,review_references),
+            check_with_semaphore(self.check_technical_parameters, trace_id_idx, review_content,review_references)
+        ]
+
+        mandatory_result, design_value_result, technical_param_result = await asyncio.gather(*technical_tasks, return_exceptions=True)
+
+        # 处理异常结果
+        if isinstance(mandatory_result, Exception):
+            mandatory_result = {"error": str(mandatory_result), "success": False}
+        if isinstance(design_value_result, Exception):
+            design_value_result = {"error": str(design_value_result), "success": False}
+        if isinstance(technical_param_result, Exception):
+            technical_param_result = {"error": str(technical_param_result), "success": False}
 
         return {
             'mandatory_standards': mandatory_result,
@@ -83,41 +147,50 @@ class AIReviewEngine:
             'enhanced_suggestions': self.generate_enhanced_suggestions(reranked_results)
         }
 
-    # 基础合规性审查 - 原子化组件方法
-    async def check_grammar(self, content: str) -> Dict[str, Any]:
+
+    async def check_grammar(self, trace_id_idx: str, review_content: str = None, review_references: str = None) -> Dict[str, Any]:
         """语法检查"""
-        await asyncio.sleep(0.1)  # 模拟处理时间
-        return {"score": 85, "issues": []}
+        reviewer_type = Stage.BASIC.value['reviewer_type']
+        prompt_name = Stage.BASIC.value['sensitive']
+        trace_id = prompt_name+trace_id_idx
+        return await self.review("语法检查", trace_id, reviewer_type, prompt_name, review_content,review_references)
 
-    async def check_semantic_logic(self, content: str) -> Dict[str, Any]:
+    async def check_semantic_logic(self, trace_id_idx: str, review_content: str = None, review_references: str = None) -> Dict[str, Any]:
         """语义逻辑检查"""
-        logger.info(f"开始执行语法检查,内容:{content}")
-        await asyncio.sleep(0.1)
-        return {"score": 90, "logic_issues": []}
+        reviewer_type = Stage.BASIC.value['reviewer_type']
+        prompt_name = Stage.BASIC.value['semantic']
+        trace_id = prompt_name+trace_id_idx
+        return await self.review("语义逻辑检查", trace_id, reviewer_type, prompt_name, review_content,review_references)
 
-    async def check_completeness(self, content: str) -> Dict[str, Any]:
+    async def check_completeness(self, trace_id_idx: str, review_content: str = None, review_references: str = None) -> Dict[str, Any]:
         """完整性检查"""
-        logger.info(f"开始执行完整性检查,内容:{content}")
-        await asyncio.sleep(0.1)
-        return {"score": 88, "missing_items": []}
+        reviewer_type = Stage.BASIC.value['reviewer_type']
+        prompt_name = Stage.BASIC.value['completeness']
+        trace_id = prompt_name+trace_id_idx
+        return await self.review("完整性检查", trace_id, reviewer_type, prompt_name, review_content,review_references)
 
-    async def check_mandatory_standards(self, content: str) -> Dict[str, Any]:
+    async def check_mandatory_standards(self, trace_id_idx: str, review_content: str = None, review_references: str = None) -> Dict[str, Any]:
         """强制性标准检查"""
-        logger.info(f"开始执行强制性标准检查,内容:{content}")
-        await asyncio.sleep(0.3)
-        return {"compliance_rate": 92, "violations": []}
+        reviewer_type = Stage.TECHNICAL.value['reviewer_type']
+        prompt_name = Stage.TECHNICAL.value['mandatory']
+        trace_id = prompt_name+trace_id_idx
+        return await self.review("强制性标准检查", trace_id, reviewer_type, prompt_name, review_content,review_references)
 
-    async def check_design_values(self, content: str) -> Dict[str, Any]:
+    async def check_design_values(self, trace_id_idx: str, review_content: str = None, review_references: str = None) -> Dict[str, Any]:
         """设计值检查"""
-        await asyncio.sleep(0.2)
-        return {"accuracy": 87, "deviations": []}
+        reviewer_type = Stage.TECHNICAL.value['reviewer_type']
+        prompt_name = Stage.TECHNICAL.value['design']
+        trace_id = prompt_name+trace_id_idx
+        return await self.review("设计值检查", trace_id, reviewer_type, prompt_name, review_content,review_references)
 
-    async def check_technical_parameters(self, content: str) -> Dict[str, Any]:
+    async def check_technical_parameters(self, trace_id_idx: str, review_content: str = None, review_references: str = None) -> Dict[str, Any]:
         """技术参数检查"""
-        await asyncio.sleep(0.2)
-        return {"precision": 90, "errors": []}
+        reviewer_type = Stage.TECHNICAL.value['reviewer_type']
+        prompt_name = Stage.TECHNICAL.value['technical']
+        trace_id = prompt_name+trace_id_idx
+        return await self.review("技术参数检查", trace_id, reviewer_type, prompt_name, review_content,review_references)
 
-    # RAG检索增强 - 原子化组件方法
+    # RAG检索增强
     async def vector_search(self, content: str) -> List[Dict[str, Any]]:
         """向量检索"""
         await asyncio.sleep(0.1)
@@ -153,7 +226,12 @@ class AIReviewEngine:
         basic_score = basic.get('overall_score', 0)
         technical_score = technical.get('overall_score', 0)
 
-        avg_score = (basic_score + technical_score) / 2
+        # 如果RAG被禁用或有错误,忽略它
+        if 'error' in rag:
+            avg_score = (basic_score + technical_score) / 2
+        else:
+            rag_score = rag.get('overall_score', 0)
+            avg_score = (basic_score + technical_score + rag_score) / 3
 
         if avg_score >= 90:
             return "low"

+ 44 - 20
core/construction_review/component/document_processor.py

@@ -75,8 +75,18 @@ class DocumentProcessor:
                 separators=["\n\n", "\n", " ", ""]
             )
             splits = text_splitter.split_documents(documents)
+            original_count = len(splits)  # 记录原始分块数量
 
-            logger.info(f"PDF解析完成,分块数量: {len(splits)}")
+            # 过滤空内容切块,确保每个切块内容不为空
+            valid_splits = []
+            for split in splits:
+                content = split.page_content.strip()
+                if content:  # 确保内容不为空
+                    split.page_content = content  # 更新清理后的内容
+                    valid_splits.append(split)
+
+            splits = valid_splits  # 使用过滤后的切块
+            logger.info(f"PDF解析完成,过滤前分块数量: {original_count},过滤后有效分块数量: {len(splits)}")
 
             return {
                 'document_type': 'pdf',
@@ -113,18 +123,21 @@ class DocumentProcessor:
             doc = Document(io.BytesIO(file_content))
             full_text = '\n'.join([paragraph.text for paragraph in doc.paragraphs])
 
-            # 简单分块
+            # 简单分块,并过滤空内容
             chunks = []
             chunk_size = 1000
+            chunk_index = 1
             for i in range(0, len(full_text), chunk_size):
-                chunk_text = full_text[i:i+chunk_size]
-                chunks.append({
-                    'chunk_id': f'chunk_{i+1}',
-                    'content': chunk_text,
-                    'metadata': {'chunk_index': i+1}
-                })
+                chunk_text = full_text[i:i+chunk_size].strip()
+                if chunk_text:  # 确保切块内容不为空
+                    chunks.append({
+                        'chunk_id': f'chunk_{chunk_index}',
+                        'content': chunk_text,
+                        'metadata': {'chunk_index': chunk_index}
+                    })
+                    chunk_index += 1
 
-            logger.info(f"DOCX解析完成,分块数量: {len(chunks)}")
+            logger.info(f"DOCX解析完成,有效分块数量: {len(chunks)}")
 
             return {
                 'document_type': 'docx',
@@ -148,22 +161,33 @@ class DocumentProcessor:
                 # PDF结构化
                 chunks = []
                 for i, chunk in enumerate(raw_content['chunks']):
-                    chunks.append({
-                        'chunk_id': f'chunk_{i+1}',
-                        'page': chunk['page'],
-                        'content': chunk['content'],
-                        'chapter': f'第{chunk["page"]}页',
-                        'title': f'内容块{i+1}',
-                        'original_content': chunk['content'][:100] + '...' if len(chunk['content']) > 100 else chunk['content']
-                    })
+                    content = chunk['content'].strip()
+                    if content:  # 确保内容不为空
+                        chunks.append({
+                            'chunk_id': f'chunk_{i+1}',
+                            'page': chunk['page'],
+                            'content': content,
+                            'chapter': f'第{chunk["page"]}页',
+                            'title': f'内容块{i+1}',
+                            'original_content': content[:100] + '...' if len(content) > 100 else content
+                        })
             else:
-                # DOCX结构化
-                chunks = raw_content.get('chunks', [])
+                # DOCX结构化 - 也进行空内容检查
+                all_chunks = raw_content.get('chunks', [])
+                chunks = []
+                for chunk in all_chunks:
+                    content = chunk.get('content', '').strip()
+                    if content:  # 确保内容不为空
+                        chunks.append({
+                            'chunk_id': chunk.get('chunk_id', f'chunk_{len(chunks)+1}'),
+                            'content': content,
+                            'metadata': chunk.get('metadata', {})
+                        })
 
             return {
                 'document_name': f"施工方案文档_{raw_content.get('document_type', 'unknown')}",
                 'document_type': raw_content['document_type'],
-                'total_chunks': raw_content.get('total_chunks', 0),
+                'total_chunks': len(chunks),  # 使用实际的切块数量
                 'chunks': chunks,
                 'metadata': raw_content.get('metadata', {})
             }

+ 1 - 7
core/construction_review/component/reviewers/__init__.py

@@ -4,13 +4,7 @@
 """
 
 from .base_reviewer import BaseReviewer
-from .basic_reviewers import BasicComplianceReviewer
-from .technical_reviewers import TechnicalComplianceReviewer
-from .rag_reviewers import RAGEnhancedReviewer
 
 __all__ = [
-    'BaseReviewer',
-    'BasicComplianceReviewer',
-    'TechnicalComplianceReviewer',
-    'RAGEnhancedReviewer'
+    'BaseReviewer'
 ]

+ 45 - 91
core/construction_review/component/reviewers/base_reviewer.py

@@ -3,12 +3,16 @@
 定义模型调用、提示词设定的基础接口
 """
 
-from abc import ABC, abstractmethod
+
+import uuid
+import time
+from abc import ABC
 from typing import Dict, Any, Optional
 from dataclasses import dataclass
-import uuid
-
-from foundation.agent.generate.model_generate import test_generate_model_client
+from langfuse import obverse
+from foundation.agent.monitor.ai_trace_monitor import lf
+from foundation.agent.generate.model_generate import generate_model_client
+from core.construction_review.component.reviewers.utils.prompt_loader import prompt_loader
 from foundation.logger.loggering import server_logger as logger
 
 
@@ -16,9 +20,7 @@ from foundation.logger.loggering import server_logger as logger
 class ReviewResult:
     """审查结果基类"""
     success: bool
-    score: float
     details: Dict[str, Any]
-    suggestions: list
     error_message: Optional[str] = None
     execution_time: Optional[float] = None
 
@@ -26,126 +28,78 @@ class ReviewResult:
 class BaseReviewer(ABC):
     """审查器基类"""
 
-    def __init__(self, name: str):
-        self.name = name
-        self.model_client = test_generate_model_client
-
-    @abstractmethod
-    def get_system_prompt(self) -> str:
-        """获取系统提示词"""
-        pass
-
-    @abstractmethod
-    def get_user_prompt_template(self) -> str:
-        """获取用户提示词模板"""
-        pass
-
-    @abstractmethod
-    def format_result(self, model_response: str, **kwargs) -> ReviewResult:
-        """格式化模型返回结果"""
-        pass
-
-    async def review(self, content: str, context: Optional[Dict[str, Any]] = None) -> ReviewResult:
+    def __init__(self):
+        self.model_client = generate_model_client
+        self.prompt_loader = prompt_loader
+    
+    @obverse
+    async def review(self, name: str, trace_id: str, reviewer_type: str, prompt_name: str, review_content: str,review_references: str = None) -> ReviewResult:
         """
         执行审查
 
         Args:
-            content: 待审查内容
-            context: 额外的上下文信息
+            name: 审查器名称 (必填)
+            trace_id: 追踪ID (必填)
+            reviewer_type: 审查器类型 (basic, technical, rag, ai) (必填)
+            prompt_name: 提示词名称 (必填)
+                - basic: semantic_logic_check, completeness_check, timeliness_check, reference_check, sensitive_word_check
+                - technical: mandatory_standards_check, technical_parameters_check, design_values_check
+                - rag: rag_enhanced_review, vector_search_review, hybrid_search_review
+                - ai: professional_suggestion, standardization_suggestion, completeness_suggestion, readability_suggestion
+            review_content: 待审查内容 (必填)
+
+            review_references: 审查参考内容 (可选)
 
         Returns:
             ReviewResult: 审查结果
         """
-        import time
         start_time = time.time()
-        trace_id = str(uuid.uuid4())
-
+        name = prompt_name
         try:
-            logger.info(f"开始执行 {self.name} 审查,trace_id: {trace_id}")
-
-            # 构建任务提示信息
+            logger.info(f"开始执行 {name} 审查,trace_id: {trace_id},内容长度: {len(review_content)}")
+            prompt_kwargs = {}
+            prompt_kwargs["content"] = review_content
+            prompt_kwargs["review_content"] = review_content
+            prompt_kwargs["review_references"] = review_references or ""
             task_prompt_info = {
-                "task_prompt": self.get_system_prompt(),
-                "task_name": self.name
+                "task_prompt": self.prompt_loader.get_prompt_template(reviewer_type, prompt_name, **prompt_kwargs),
+                "task_name": name
             }
 
-            # 构建用户提示词
-            user_prompt = self.get_user_prompt_template().format(
-                content=content,
-                context=context or {}
-            )
-
             # 调用模型
-            model_response = self.model_client.get_model_generate_invoke(
+            model_response = await self.model_client.get_model_generate_invoke(
                 trace_id=trace_id,
-                task_prompt_info=task_prompt_info,
-                input_query=user_prompt,
-                context=str(context) if context else None
+                task_prompt_info=task_prompt_info
             )
 
             # 格式化结果
-            result = self.format_result(model_response, content=content, context=context)
+            result = self.format_result(model_response)
             result.execution_time = time.time() - start_time
 
-            logger.info(f"{self.name} 审查完成,score: {result.score}, 耗时: {result.execution_time:.2f}s")
+            logger.info(f"{name} 审查完成, 耗时: {result.execution_time:.2f}s")
             return result
 
         except Exception as e:
             execution_time = time.time() - start_time
-            error_msg = f"{self.name} 审查失败: {str(e)}"
+            error_msg = f"{name} 审查失败: {str(e)}"
             logger.error(error_msg, exc_info=True)
 
             return ReviewResult(
                 success=False,
-                score=0.0,
                 details={},
-                suggestions=[],
                 error_message=error_msg,
                 execution_time=execution_time
             )
 
-    def validate_input(self, content: str) -> bool:
-        """验证输入内容"""
-        if not content or not content.strip():
-            return False
-        return len(content.strip()) > 10  # 至少10个字符
-
-    def get_model_config(self) -> Dict[str, Any]:
-        """获取模型配置(可被子类重写)"""
-        return {
-            "temperature": 0.1,  # 审查任务要求低温度
-            "max_tokens": 2000,
-            "top_p": 0.9
-        }
-
-
-class BaseComplianceReviewer(BaseReviewer):
-    """合规性审查器基类"""
-
-    def format_result(self, model_response: str, **kwargs) -> ReviewResult:
+    def format_result(self, model_response: str) -> ReviewResult:
         """
-        格式化合规性审查结果
-        子类可以根据需要重写此方法
+        格式化模型返回结果为ReviewResult对象
         """
-        try:
-            # 尝试解析JSON响应
-            import json
-            response_data = json.loads(model_response)
-
-            return ReviewResult(
-                success=True,
-                score=response_data.get('score', 0.0),
-                details=response_data.get('details', {}),
-                suggestions=response_data.get('suggestions', [])
-            )
-        except (json.JSONDecodeError, KeyError):
-            # 如果解析失败,使用简单格式
-            return ReviewResult(
-                success=True,
-                score=75.0,  # 默认分数
-                details={"raw_response": model_response},
-                suggestions=["需要进一步人工审查"]
-            )
+        return ReviewResult(
+            success=True,
+            details={"response": model_response},
+            error_message=None
+        )
 
 
 class BaseRAGReviewer(BaseReviewer):

+ 0 - 233
core/construction_review/component/reviewers/basic_reviewers.py

@@ -1,233 +0,0 @@
-"""
-基础合规性审查器
-负责语法检查、语义逻辑检查、完整性检查等基础审查功能
-"""
-
-import json
-from typing import Dict, Any, Optional
-from .base_reviewer import BaseComplianceReviewer, ReviewResult
-
-
-class GrammarCheckReviewer(BaseComplianceReviewer):
-    """语法检查审查器"""
-
-    def __init__(self):
-        super().__init__("语法检查")
-
-    def get_system_prompt(self) -> str:
-        return """你是一个专业的中文语法检查专家,专门负责检查施工方案文档中的语法问题。
-
-你的任务是:
-1. 检查语法错误、标点符号使用
-2. 识别语句不通顺的地方
-3. 发现用词不当的问题
-4. 检查专业术语使用是否规范
-
-请对给定的施工方案内容进行语法检查,并以JSON格式返回结果:
-{
-    "score": 85.5,
-    "details": {
-        "grammar_errors": [{"text": "错误内容", "position": "位置", "suggestion": "修改建议"}],
-        "punctuation_errors": [{"text": "错误内容", "position": "位置", "suggestion": "修改建议"}],
-        "word_choice_issues": [{"text": "用词问题", "position": "位置", "suggestion": "修改建议"}],
-        "total_errors": 3
-    },
-    "suggestions": ["建议1", "建议2"]
-}
-
-评分标准:
-- 90-100分:语法优秀,基本无错误
-- 80-89分:语法良好,少量小错误
-- 70-79分:语法一般,有一些错误
-- 60-69分:语法较差,错误较多
-- 0-59分:语法很差,需要重写
-"""
-
-    def get_user_prompt_template(self) -> str:
-        return """请对以下施工方案内容进行语法检查:
-
-待检查内容:
-{content}
-
-请仔细检查上述内容的语法、标点符号和用词,并以JSON格式返回检查结果。"""
-
-
-class SemanticLogicReviewer(BaseComplianceReviewer):
-    """语义逻辑检查审查器"""
-
-    def __init__(self):
-        super().__init__("语义逻辑检查")
-
-    def get_system_prompt(self) -> str:
-        return """你是一个专业的施工方案语义逻辑检查专家,负责检查施工方案中的逻辑一致性和语义合理性。
-
-你的任务是:
-1. 检查前后内容是否矛盾
-2. 验证技术参数的逻辑一致性
-3. 检查施工流程的合理性
-4. 识别语义不清晰或歧义的表达
-5. 验证数据之间的逻辑关系
-
-请对给定的施工方案内容进行语义逻辑检查,并以JSON格式返回结果:
-{
-    "score": 88.0,
-    "details": {
-        "logic_conflicts": [{"issue": "逻辑冲突描述", "location": "位置", "suggestion": "修改建议"}],
-        "parameter_inconsistencies": [{"issue": "参数不一致描述", "location": "位置", "suggestion": "修改建议"}],
-        "semantic_ambiguities": [{"issue": "语义歧义描述", "location": "位置", "suggestion": "修改建议"}],
-        "data_logic_issues": [{"issue": "数据逻辑问题", "location": "位置", "suggestion": "修改建议"}],
-        "total_issues": 2
-    },
-    "suggestions": ["建议1", "建议2"]
-}
-
-评分标准:
-- 90-100分:逻辑清晰,无矛盾
-- 80-89分:逻辑基本清晰,轻微问题
-- 70-79分:逻辑一般,有一些问题
-- 60-69分:逻辑较差,问题较多
-- 0-59分:逻辑混乱,需要重写
-"""
-
-    def get_user_prompt_template(self) -> str:
-        return """请对以下施工方案内容进行语义逻辑检查:
-
-待检查内容:
-{content}
-
-请仔细检查上述内容的逻辑一致性、参数合理性和语义清晰度,并以JSON格式返回检查结果。"""
-
-
-class CompletenessReviewer(BaseComplianceReviewer):
-    """完整性检查审查器"""
-
-    def __init__(self):
-        super().__init__("完整性检查")
-
-    def get_system_prompt(self) -> str:
-        return """你是一个专业的施工方案完整性检查专家,负责检查施工方案的完整性和规范性。
-
-你的任务是:
-1. 检查必要的章节和内容是否齐全
-2. 验证技术参数是否完整
-3. 检查是否缺少关键信息
-4. 验证表格和图表的完整性
-5. 检查引用和参考文献是否完整
-
-请对给定的施工方案内容进行完整性检查,并以JSON格式返回结果:
-{
-    "score": 82.5,
-    "details": {
-        "missing_sections": [{"section": "缺失章节名称", "importance": "高/中/低", "suggestion": "补充建议"}],
-        "incomplete_parameters": [{"parameter": "参数名称", "location": "位置", "suggestion": "完善建议"}],
-        "missing_references": [{"reference": "缺失引用", "context": "上下文", "suggestion": "补充建议"}],
-        "incomplete_tables": [{"table": "表格标识", "missing_info": "缺失信息", "suggestion": "完善建议"}],
-        "total_missing_items": 4
-    },
-    "suggestions": ["建议1", "建议2"]
-}
-
-评分标准:
-- 90-100分:内容完整,基本无缺失
-- 80-89分:内容较完整,少量缺失
-- 70-79分:内容一般,有一些缺失
-- 60-69分:内容不完整,缺失较多
-- 0-59分:内容严重不完整,需要补充大量信息
-"""
-
-    def get_user_prompt_template(self) -> str:
-        return """请对以下施工方案内容进行完整性检查:
-
-待检查内容:
-{content}
-
-请仔细检查上述内容的完整性,包括章节、参数、引用等方面,并以JSON格式返回检查结果。"""
-
-
-class BasicComplianceReviewer(BaseComplianceReviewer):
-    """基础合规性综合审查器"""
-
-    def __init__(self):
-        super().__init__("基础合规性审查")
-
-        # 初始化各个子审查器
-        self.grammar_reviewer = GrammarCheckReviewer()
-        self.semantic_reviewer = SemanticLogicReviewer()
-        self.completeness_reviewer = CompletenessReviewer()
-
-    async def comprehensive_check(self, content: str, context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
-        """
-        综合基础合规性检查
-        """
-        results = {}
-
-        try:
-            # 并行执行各项检查
-            import asyncio
-
-            tasks = [
-                self.grammar_reviewer.review(content, context),
-                self.semantic_reviewer.review(content, context),
-                self.completeness_reviewer.review(content, context)
-            ]
-
-            grammar_result, semantic_result, completeness_result = await asyncio.gather(*tasks)
-
-            results = {
-                "grammar_check": {
-                    "score": grammar_result.score,
-                    "details": grammar_result.details,
-                    "suggestions": grammar_result.suggestions,
-                    "execution_time": grammar_result.execution_time
-                },
-                "semantic_check": {
-                    "score": semantic_result.score,
-                    "details": semantic_result.details,
-                    "suggestions": semantic_result.suggestions,
-                    "execution_time": semantic_result.execution_time
-                },
-                "completeness_check": {
-                    "score": completeness_result.score,
-                    "details": completeness_result.details,
-                    "suggestions": completeness_result.suggestions,
-                    "execution_time": completeness_result.execution_time
-                },
-                "overall_score": self._calculate_overall_score(
-                    grammar_result.score,
-                    semantic_result.score,
-                    completeness_result.score
-                )
-            }
-
-        except Exception as e:
-            results = {
-                "error": str(e),
-                "overall_score": 0.0
-            }
-
-        return results
-
-    def _calculate_overall_score(self, grammar_score: float, semantic_score: float, completeness_score: float) -> float:
-        """计算综合得分"""
-        # 权重配置
-        weights = {
-            "grammar": 0.2,      # 语法权重20%
-            "semantic": 0.4,     # 语义逻辑权重40%(最重要)
-            "completeness": 0.4  # 完整性权重40%
-        }
-
-        overall_score = (
-            grammar_score * weights["grammar"] +
-            semantic_score * weights["semantic"] +
-            completeness_score * weights["completeness"]
-        )
-
-        return round(overall_score, 2)
-
-    def get_system_prompt(self) -> str:
-        """这个方法在综合审查器中不会被直接调用"""
-        return ""
-
-    def get_user_prompt_template(self) -> str:
-        """这个方法在综合审查器中不会被直接调用"""
-        return ""

+ 89 - 0
core/construction_review/component/reviewers/prompt/ai_suggestion.yaml

@@ -0,0 +1,89 @@
+# 智能优化建议提示词配置
+
+# 3.1 专业性优化建议
+professional_suggestion:
+  system_prompt: |
+    你是施工方案专业性优化建议专家,负责提供专业技术改进建议。
+
+    审查要求:
+    - 重点分析技术方案的专业性和合理性
+    - 提供具体的专业改进建议
+    - 简明扼要指出优化方向和实施方法
+    - 标注建议优先级:高/中/低
+
+  user_prompt_template: |
+    请为以下施工方案提供专业性优化建议:
+
+    {review_content}
+
+    输出格式:
+    专业问题:[具体专业问题]
+    优化建议:[具体改进措施]
+    实施方法:[具体实施步骤]
+    优先级:[高/中/低]
+
+# 3.2 规范性优化建议
+standardization_suggestion:
+  system_prompt: |
+    你是施工方案规范性优化建议专家,负责提供标准化改进建议。
+
+    审查要求:
+    - 重点分析方案的规范性和标准化程度
+    - 提供具体的标准化改进建议
+    - 简明扼要指出规范化要求和实施标准
+    - 标注改进紧迫性:高/中/低
+
+  user_prompt_template: |
+    请为以下施工方案提供规范性优化建议:
+
+    {review_content}
+
+    输出格式:
+    规范问题:[具体规范性问题]
+    改进建议:[具体改进措施]
+    参考标准:[相关标准规范]
+    紧迫性:[高/中/低]
+
+# 3.3 完整性优化建议
+completeness_suggestion:
+  system_prompt: |
+    你是施工方案完整性优化建议专家,负责提供内容完整性改进建议。
+
+    审查要求:
+    - 重点分析方案内容的完整性和系统性
+    - 提供具体的内容补充建议
+    - 简明扼要指出缺失内容和补充要求
+    - 标注补充重要性:关键/重要/一般
+
+  user_prompt_template: |
+    请为以下施工方案提供完整性优化建议:
+
+    {review_content}
+
+    输出格式:
+    缺失内容:[具体缺失内容]
+    补充建议:[具体补充措施]
+    补充要求:[详细补充要求]
+    重要性:[关键/重要/一般]
+
+# 3.4 可读性优化建议
+readability_suggestion:
+  system_prompt: |
+    你是施工方案可读性优化建议专家,负责提供文档可读性改进建议。
+
+    审查要求:
+    - 重点分析方案的可读性和表达清晰度
+    - 提供具体的可读性改进建议
+    - 简明扼要指出表达问题和优化方法
+    - 标注改进效果:显著/一般/轻微
+
+  user_prompt_template: |
+    请为以下施工方案提供可读性优化建议:
+
+    {review_content}
+
+    输出格式:
+    表达问题:[具体表达问题]
+    优化建议:[具体改进措施]
+    优化方法:[具体优化方法]
+    改进效果:[显著/一般/轻微]

+ 121 - 0
core/construction_review/component/reviewers/prompt/basic_reviewers.yaml

@@ -0,0 +1,121 @@
+# 基础合规性审查提示词配置
+
+# 1.1 语义逻辑检查功能
+semantic_logic_check:
+  system_prompt: |
+    你是施工方案语义逻辑审查专家,负责检查表述一致性和逻辑清晰度。
+
+    审查要求:
+    - 重点关注语义矛盾、逻辑混乱、表述不清问题
+    - 简明扼要指出问题位置和修改建议
+    - 标注问题等级:高/中/低
+
+    审查参考:
+    {review_references}
+
+  user_prompt_template: |
+    请审查以下内容的语义逻辑:
+
+    {review_content}
+
+    输出格式:
+    逻辑问题:[具体问题描述]
+    问题位置:[章节/段落]
+    修改建议:[具体建议]
+    风险等级:[高/中/低]
+
+# 1.2 条文完整性检查功能
+completeness_check:
+  system_prompt: |
+    你是施工方案完整性审查专家,负责检查必备条文和技术要素完备性。
+
+    审查要求:
+    - 重点关注法规条文、技术要素缺失
+    - 简明扼要列出缺失内容和补充要求
+    - 标注重要性:关键/重要/一般
+
+    审查参考:
+    {review_references}
+
+  user_prompt_template: |
+    请审查以下内容的条文完整性:
+
+    {review_content}
+
+    输出格式:
+    缺失条文:[具体缺失内容]
+    重要性:[关键/重要/一般]
+    补充要求:[具体补充内容]
+    依据标准:[相关法规或标准]
+
+# 1.3 时效性检查功能
+timeliness_check:
+  system_prompt: |
+    你是施工方案时效性审查专家,负责检查引用标准和技术要求的现行有效性。
+
+    审查要求:
+    - 重点关注标准版本过时、技术要求滞后
+    - 简明扼要指出过时内容和更新要求
+    - 标注更新紧迫性:高/中/低
+
+    审查参考:
+    {review_references}
+
+  user_prompt_template: |
+    请审查以下内容的时效性:
+
+    {review_content}
+
+    输出格式:
+    过时标准:[具体标准名称及版本]
+    现行版本:[最新有效版本]
+    更新要求:[具体更新内容]
+    紧迫性:[高/中/低]
+
+# 1.4 引用规范检查功能
+reference_check:
+  system_prompt: |
+    你是施工方案引用规范审查专家,负责检查引用格式和内容准确性。
+
+    审查要求:
+    - 重点关注引用格式错误、内容不准确
+    - 简明扼要指出引用问题和修正方法
+    - 标注修正优先级:高/中/低
+
+    审查参考:
+    {review_references}
+
+  user_prompt_template: |
+    请审查以下内容的引用规范:
+
+    {review_content}
+
+    输出格式:
+    引用问题:[具体问题描述]
+    规范格式:[正确引用格式]
+    修正方法:[具体修正步骤]
+    优先级:[高/中/低]
+
+# 1.5 敏感词检查功能
+sensitive_word_check:
+  system_prompt: |
+    你是施工方案敏感词审查专家,负责检查政治敏感和表述适宜性问题。
+
+    审查要求:
+    - 重点关注政治敏感、商业机密、表述不当
+    - 简明扼要指出敏感词汇和处理建议
+    - 标注处理紧急性:高/中/低
+
+    审查参考:
+    {review_references}
+
+  user_prompt_template: |
+    请审查以下内容的敏感词:
+
+    {review_content}
+
+    输出格式:
+    敏感词汇:[具体敏感词]
+    敏感类型:[政治/商业/表述]
+    处理建议:[具体处理方法]
+    紧急性:[高/中/低]

+ 79 - 0
core/construction_review/component/reviewers/prompt/rag_reviewers.yaml

@@ -0,0 +1,79 @@
+# RAG增强审查提示词配置
+
+# RAG检索增强审查
+rag_enhanced_review:
+  system_prompt: |
+    你是施工方案RAG增强审查专家,负责基于检索到的标准文档进行深度审查。
+
+    审查要求:
+    - 结合检索到的标准文档分析施工方案合规性
+    - 重点检查方案与相关标准的符合程度
+    - 简明扼要给出合规性判断和改进建议
+    - 标注符合性等级:完全符合/基本符合/部分符合/不符合
+
+  user_prompt_template: |
+    请基于以下标准文档审查施工方案:
+
+    【施工方案内容】
+    {review_content}
+
+    【检索到的标准文档】
+    {retrieved_docs}
+
+    输出格式:
+    标准依据:[具体标准条款]
+    符合性判断:[完全符合/基本符合/部分符合/不符合]
+    偏差分析:[具体偏差描述]
+    改进建议:[具体改进措施]
+
+# 向量检索审查
+vector_search_review:
+  system_prompt: |
+    你是施工方案向量检索审查专家,负责基于语义相似度发现相关标准要求。
+
+    审查要求:
+    - 利用向量检索结果识别相关标准要求
+    - 重点发现方案中可能遗漏的标准条款
+    - 简明扼要指出标准符合性问题和补充要求
+    - 标注关联度:高/中/低
+
+  user_prompt_template: |
+    请基于向量检索结果审查施工方案:
+
+    【施工方案内容】
+    {review_content}
+
+    【向量检索结果】
+    {vector_results}
+
+    输出格式:
+    相关标准:[检索到的标准条款]
+    关联度:[高/中/低]
+    符合情况:[符合/部分符合/不符合]
+    补充要求:[需要补充的内容]
+
+# 混合检索审查
+hybrid_search_review:
+  system_prompt: |
+    你是施工方案混合检索审查专家,负责结合多种检索方式进行综合审查。
+
+    审查要求:
+    - 综合分析关键词检索和语义检索结果
+    - 全面评估施工方案的合规性和完整性
+    - 简明扼要给出综合审查意见
+    - 标注审查置信度:高/中/低
+
+  user_prompt_template: |
+    请基于混合检索结果审查施工方案:
+
+    【施工方案内容】
+    {review_content}
+
+    【混合检索结果】
+    {hybrid_results}
+
+    输出格式:
+    综合评估:[整体合规性评价]
+    关键问题:[主要不合规问题]
+    风险等级:[高/中/低]
+    整改建议:[具体整改要求]

+ 78 - 0
core/construction_review/component/reviewers/prompt/technical_reviewers.yaml

@@ -0,0 +1,78 @@
+# 技术性审查提示词配置
+
+# 2.1 强制性标准符合性检查功能
+mandatory_standards_check:
+  system_prompt: |
+    你是施工方案强制性标准审查专家,负责检查是否符合国家强制性标准。
+
+    审查参考:
+    {review_references}
+
+    审查要求:
+    - 重点检查强制性条文符合性
+    - 识别违反强标的问题
+    - 简明扼要指出违规内容和整改要求
+    - 标注违规严重性:严重/一般/轻微
+
+  user_prompt_template: |
+    请审查以下内容的强制性标准符合性:
+
+    {review_content}
+
+    输出格式:
+    强制标准:[具体强制性标准条款]
+    违规内容:[具体违规描述]
+    整改要求:[具体整改措施]
+    严重性:[严重/一般/轻微]
+
+# 2.2 技术参数精确检查功能
+technical_parameters_check:
+  system_prompt: |
+    你是施工方案技术参数审查专家,负责检查技术参数的精确性和合理性。
+
+    审查要求:
+    - 重点检查技术参数的准确性和合理性
+    - 识别参数错误或不合理设置
+    - 简明扼要指出参数问题和修正建议
+    - 标注参数风险等级:高/中/低
+
+    审查参考:
+    {review_references}
+
+  user_prompt_template: |
+    请审查以下内容的技术参数精确性:
+
+    {review_content}
+
+    输出格式:
+    技术参数:[具体参数名称]
+    参数问题:[问题描述]
+    标准要求:[正确参数范围]
+    修正建议:[具体修正方案]
+    风险等级:[高/中/低]
+
+# 2.3 设计值符合性检查功能
+design_values_check:
+  system_prompt: |
+    你是施工方案设计值审查专家,负责检查设计值的符合性和合理性。
+
+    审查要求:
+    - 重点检查设计值与标准的符合性
+    - 识别设计值超标或不合理问题
+    - 简明扼要指出设计值问题和调整建议
+    - 标注偏差程度:严重超标/轻微超标/符合要求
+
+    审查参考:
+    {review_references}
+
+  user_prompt_template: |
+    请审查以下内容的设计值符合性:
+
+    {review_content}
+
+    输出格式:
+    设计项目:[具体设计项目]
+    设计值:[当前设计值]
+    标准要求:[标准或规范要求值]
+    偏差分析:[偏差描述]
+    调整建议:[具体调整措施]

+ 0 - 282
core/construction_review/component/reviewers/technical_reviewers.py

@@ -1,282 +0,0 @@
-"""
-技术性审查器
-负责强制性标准检查、设计值检查、技术参数检查等技术性审查功能
-"""
-
-import json
-from typing import Dict, Any, Optional
-from .base_reviewer import BaseComplianceReviewer, ReviewResult
-
-
-class MandatoryStandardsReviewer(BaseComplianceReviewer):
-    """强制性标准检查审查器"""
-
-    def __init__(self):
-        super().__init__("强制性标准检查")
-
-    def get_system_prompt(self) -> str:
-        return """你是一个专业的建筑工程强制性标准检查专家,负责检查施工方案是否符合国家强制性标准。
-
-你的任务是:
-1. 检查是否符合国家强制性标准条文
-2. 验证关键指标是否满足强制性要求
-3. 检查安全措施的合规性
-4. 验证质量控制标准的执行情况
-5. 检查环保标准的符合性
-
-请对给定的施工方案内容进行强制性标准检查,并以JSON格式返回结果:
-{
-    "score": 92.0,
-    "details": {
-        "compliance_rate": 95.5,
-        "violations": [
-            {
-                "standard": "GB 50300-2013",
-                "clause": "第3.0.3条",
-                "issue": "违反强制性条文描述",
-                "risk_level": "高/中/低",
-                "suggestion": "整改建议"
-            }
-        ],
-        "compliance_items": [
-            {
-                "standard": "JGJ 18-2012",
-                "clause": "第4.1.2条",
-                "status": "符合",
-                "description": "符合描述"
-            }
-        ],
-        "total_violations": 1,
-        "high_risk_count": 1
-    },
-    "suggestions": ["建议1", "建议2"]
-}
-
-评分标准:
-- 95-100分:完全符合强制性标准
-- 85-94分:基本符合,轻微违规
-- 75-84分:部分符合,有一些违规
-- 60-74分:违规较多,需要整改
-- 0-59分:严重违规,需要重大修改
-"""
-
-    def get_user_prompt_template(self) -> str:
-        return """请对以下施工方案内容进行强制性标准检查:
-
-待检查内容:
-{content}
-
-请对照相关的国家强制性标准进行检查,重点关注安全、质量、环保等方面的强制性要求,并以JSON格式返回检查结果。"""
-
-
-class DesignValuesReviewer(BaseComplianceReviewer):
-    """设计值检查审查器"""
-
-    def __init__(self):
-        super().__init__("设计值检查")
-
-    def get_system_prompt(self) -> str:
-        return """你是一个专业的工程设计值检查专家,负责检查施工方案中的设计参数和数值是否符合规范要求。
-
-你的任务是:
-1. 检查设计参数的准确性和合理性
-2. 验证计算公式的正确性
-3. 检查单位使用是否规范
-4. 验证数值范围是否合理
-5. 检查设计值与实际情况的匹配度
-
-请对给定的施工方案内容进行设计值检查,并以JSON格式返回结果:
-{
-    "score": 87.5,
-    "details": {
-        "accuracy_rate": 89.0,
-        "deviations": [
-            {
-                "parameter": "参数名称",
-                "design_value": "设计值",
-                "suggested_value": "建议值",
-                "deviation_type": "数值偏差/单位错误/计算错误",
-                "risk_level": "高/中/低",
-                "suggestion": "修正建议"
-            }
-        ],
-        "correct_parameters": [
-            {
-                "parameter": "参数名称",
-                "value": "数值",
-                "unit": "单位",
-                "verification": "验证结果"
-            }
-        ],
-        "total_deviations": 2,
-        "critical_deviations": 1
-    },
-    "suggestions": ["建议1", "建议2"]
-}
-
-评分标准:
-- 95-100分:设计值准确无误
-- 85-94分:设计值基本准确,轻微偏差
-- 75-84分:设计值一般,有一些偏差
-- 60-74分:设计值偏差较多,需要修正
-- 0-59分:设计值严重错误,需要重新计算
-"""
-
-    def get_user_prompt_template(self) -> str:
-        return """请对以下施工方案内容进行设计值检查:
-
-待检查内容:
-{content}
-
-请仔细检查上述内容中的设计参数、计算公式、数值单位和范围,并以JSON格式返回检查结果。"""
-
-
-class TechnicalParametersReviewer(BaseComplianceReviewer):
-    """技术参数检查审查器"""
-
-    def __init__(self):
-        super().__init__("技术参数检查")
-
-    def get_system_prompt(self) -> str:
-        return """你是一个专业的工程技术参数检查专家,负责检查施工方案中的技术参数是否合理和完整。
-
-你的任务是:
-1. 检查技术参数的完整性和准确性
-2. 验证技术指标是否符合行业规范
-3. 检查施工工艺参数的合理性
-4. 验证材料规格参数的正确性
-5. 检查设备参数配置的合理性
-
-请对给定的施工方案内容进行技术参数检查,并以JSON格式返回结果:
-{
-    "score": 90.0,
-    "details": {
-        "precision_rate": 92.0,
-        "errors": [
-            {
-                "parameter": "参数名称",
-                "current_value": "当前值",
-                "correct_value": "正确值",
-                "error_type": "数值错误/单位错误/范围错误/逻辑错误",
-                "risk_level": "高/中/低",
-                "suggestion": "修正建议"
-            }
-        ],
-        "verified_parameters": [
-            {
-                "parameter": "参数名称",
-                "value": "数值",
-                "standard_reference": "参考标准",
-                "status": "符合/基本符合/不符合"
-            }
-        ],
-        "total_errors": 1,
-        "critical_errors": 0
-    },
-    "suggestions": ["建议1", "建议2"]
-}
-
-评分标准:
-- 95-100分:技术参数准确完整
-- 85-94分:技术参数基本准确,少量问题
-- 75-84分:技术参数一般,有一些问题
-- 60-74分:技术参数问题较多,需要修正
-- 0-59分:技术参数严重错误,需要重新制定
-"""
-
-    def get_user_prompt_template(self) -> str:
-        return """请对以下施工方案内容进行技术参数检查:
-
-待检查内容:
-{content}
-
-请仔细检查上述内容中的技术参数、工艺参数、材料规格等,并对照相关行业标准进行验证,以JSON格式返回检查结果。"""
-
-
-class TechnicalComplianceReviewer(BaseComplianceReviewer):
-    """技术性合规综合审查器"""
-
-    def __init__(self):
-        super().__init__("技术性合规审查")
-
-        # 初始化各个子审查器
-        self.mandards_reviewer = MandatoryStandardsReviewer()
-        self.design_reviewer = DesignValuesReviewer()
-        self.technical_reviewer = TechnicalParametersReviewer()
-
-    async def comprehensive_check(self, content: str, context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
-        """
-        综合技术性合规检查
-        """
-        results = {}
-
-        try:
-            # 并行执行各项检查
-            import asyncio
-
-            tasks = [
-                self.mandards_reviewer.review(content, context),
-                self.design_reviewer.review(content, context),
-                self.technical_reviewer.review(content, context)
-            ]
-
-            mandards_result, design_result, technical_result = await asyncio.gather(*tasks)
-
-            results = {
-                "mandatory_standards": {
-                    "compliance_rate": mandards_result.details.get('compliance_rate', 0),
-                    "details": mandards_result.details,
-                    "suggestions": mandards_result.suggestions,
-                    "execution_time": mandards_result.execution_time
-                },
-                "design_values": {
-                    "accuracy": design_result.details.get('accuracy_rate', 0),
-                    "details": design_result.details,
-                    "suggestions": design_result.suggestions,
-                    "execution_time": design_result.execution_time
-                },
-                "technical_parameters": {
-                    "precision": technical_result.details.get('precision_rate', 0),
-                    "details": technical_result.details,
-                    "suggestions": technical_result.suggestions,
-                    "execution_time": technical_result.execution_time
-                },
-                "overall_score": self._calculate_overall_score(
-                    mandards_result.score,
-                    design_result.score,
-                    technical_result.score
-                )
-            }
-
-        except Exception as e:
-            results = {
-                "error": str(e),
-                "overall_score": 0.0
-            }
-
-        return results
-
-    def _calculate_overall_score(self, mandards_score: float, design_score: float, technical_score: float) -> float:
-        """计算综合得分"""
-        # 权重配置 - 强制性标准最重要
-        weights = {
-            "mandards": 0.5,      # 强制性标准权重50%(最重要)
-            "design": 0.3,        # 设计值权重30%
-            "technical": 0.2      # 技术参数权重20%
-        }
-
-        overall_score = (
-            mandards_score * weights["mandards"] +
-            design_score * weights["design"] +
-            technical_score * weights["technical"]
-        )
-
-        return round(overall_score, 2)
-
-    def get_system_prompt(self) -> str:
-        """这个方法在综合审查器中不会被直接调用"""
-        return ""
-
-    def get_user_prompt_template(self) -> str:
-        """这个方法在综合审查器中不会被直接调用"""
-        return ""

+ 1 - 3
core/construction_review/component/reviewers/utils/__init__.py

@@ -4,9 +4,7 @@
 """
 
 from .prompt_loader import PromptLoader
-from .result_formatter import ResultFormatter
 
 __all__ = [
-    'PromptLoader',
-    'ResultFormatter'
+    'PromptLoader'
 ]

+ 195 - 67
core/construction_review/component/reviewers/utils/prompt_loader.py

@@ -1,39 +1,97 @@
 """
 提示词加载器
 从YAML配置文件中加载系统提示词和用户提示词模板
+基于新版LangChain ChatPromptTemplate实现
 """
 
 import yaml
 import os
-from typing import Dict, Any, Optional
+from typing import Dict, Any, List
 from foundation.logger.loggering import server_logger as logger
-
+from langchain_core.prompts import ChatPromptTemplate
+from langchain_core.messages import SystemMessage, HumanMessage
 
 class PromptLoader:
-    """提示词加载器"""
+    """基于LangChain的提示词管理器(单例模式)"""
+
+    _instance = None
+    _initialized = False
 
-    def __init__(self, prompt_config_dir: str = None):
+    def __new__(cls, prompt_config_dir: str = None, auto_preload: bool = True):
+        if cls._instance is None:
+            cls._instance = super().__new__(cls)
+        return cls._instance
+
+    def __init__(self, prompt_config_dir: str = None, auto_preload: bool = True):
         """
         初始化提示词加载器
 
         Args:
             prompt_config_dir: 提示词配置文件目录路径
+            auto_preload: 是否自动预加载所有提示词
         """
+        # 避免重复初始化
+        if self._initialized:
+            return
+
         if prompt_config_dir is None:
-            # 默认路径
-            current_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+            # 默认路径 - 指向prompt目录
+            current_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
             prompt_config_dir = os.path.join(current_dir, 'prompt')
 
         self.prompt_config_dir = prompt_config_dir
-        self._prompts_cache = {}  # 缓存已加载的提示词
+        self._cache = {}  # 统一缓存
+
+        # 自动预加载所有提示词
+        if auto_preload:
+            logger.info("开始预加载所有提示词...")
+            stats = self._preload_all_prompts()
+            logger.info(f"预加载完成: {stats}")
+            logger.info(f"总缓存数量: {len(self._cache)}")
+
+        # 标记已初始化
+        self._initialized = True
+
+    @classmethod
+    def reset_instance(cls):
+        """重置单例实例,用于重新初始化"""
+        cls._instance = None
+        cls._initialized = False
+
+    def list_available_prompts(self, reviewer_type: str) -> List[str]:
+        """
+        列出指定审查器类型的所有可用提示词名称
+
+        Args:
+            reviewer_type: 审查器类型 (basic, technical, rag, ai)
 
-    def load_prompt(self, reviewer_type: str, prompt_name: str) -> Dict[str, str]:
+        Returns:
+            List[str]: 可用的提示词名称列表
+        """
+        try:
+            # 构建配置文件路径
+            if reviewer_type == 'ai':
+                config_file = os.path.join(self.prompt_config_dir, "ai_suggestion.yaml")
+            else:
+                config_file = os.path.join(self.prompt_config_dir, f"{reviewer_type}_reviewers.yaml")
+
+            # 加载YAML配置
+            with open(config_file, 'r', encoding='utf-8') as f:
+                config = yaml.safe_load(f)
+
+            return list(config.keys()) if config else []
+
+        except Exception as e:
+            logger.error(f"列出可用提示词失败: {reviewer_type}, 错误: {str(e)}")
+            return []
+
+    def _load_prompt(self, reviewer_type: str, prompt_name: str) -> Dict[str, str]:
         """
         加载指定审查器的提示词
 
         Args:
-            reviewer_type: 审查器类型 (basic, technical, rag)
-            prompt_name: 提示词名称 (如 grammar_check, mandatory_standards 等)
+            reviewer_type: 审查器类型 (basic, technical, rag, ai)
+            prompt_name: 提示词名称
 
         Returns:
             Dict[str, str]: 包含 system_prompt 和 user_prompt_template 的字典
@@ -41,15 +99,15 @@ class PromptLoader:
         cache_key = f"{reviewer_type}_{prompt_name}"
 
         # 检查缓存
-        if cache_key in self._prompts_cache:
-            return self._prompts_cache[cache_key]
+        if cache_key in self._cache:
+            return self._cache[cache_key]
 
         try:
             # 构建配置文件路径
-            config_file = os.path.join(self.prompt_config_dir, f"{reviewer_type}_reviewers.yaml")
-
-            if not os.path.exists(config_file):
-                raise FileNotFoundError(f"提示词配置文件不存在: {config_file}")
+            if reviewer_type == 'ai':
+                config_file = os.path.join(self.prompt_config_dir, "ai_suggestion.yaml")
+            else:
+                config_file = os.path.join(self.prompt_config_dir, f"{reviewer_type}_reviewers.yaml")
 
             # 加载YAML配置
             with open(config_file, 'r', encoding='utf-8') as f:
@@ -62,11 +120,8 @@ class PromptLoader:
             prompt_config = config[prompt_name]
 
             # 验证必要的字段
-            if 'system_prompt' not in prompt_config:
-                raise ValueError(f"提示词配置缺少 'system_prompt' 字段: {prompt_name}")
-
-            if 'user_prompt_template' not in prompt_config:
-                raise ValueError(f"提示词配置缺少 'user_prompt_template' 字段: {prompt_name}")
+            if 'system_prompt' not in prompt_config or 'user_prompt_template' not in prompt_config:
+                raise ValueError(f"提示词配置缺少必要字段: {prompt_name}")
 
             result = {
                 'system_prompt': prompt_config['system_prompt'],
@@ -74,70 +129,143 @@ class PromptLoader:
             }
 
             # 缓存结果
-            self._prompts_cache[cache_key] = result
-
-            logger.info(f"成功加载提示词配置: {reviewer_type}/{prompt_name}")
+            self._cache[cache_key] = result
             return result
 
         except Exception as e:
             logger.error(f"加载提示词配置失败: {reviewer_type}/{prompt_name}, 错误: {str(e)}")
             # 返回默认提示词
-            return self._get_default_prompt(prompt_name)
+            return {
+                'system_prompt': f"你是专业的施工方案审查专家,负责进行{prompt_name}审查。",
+                'user_prompt_template': "请审查:{content}"
+            }
 
-    def _get_default_prompt(self, prompt_name: str) -> Dict[str, str]:
-        """
-        获取默认提示词(当加载失败时使用)
+    def get_prompt_template(self, reviewer_type: str, prompt_name: str, **kwargs) -> ChatPromptTemplate:
         """
-        return {
-            'system_prompt': f"你是一个专业的施工方案审查专家,负责进行{prompt_name}相关的审查工作。",
-            'user_prompt_template': "请对以下施工方案内容进行{prompt_name}审查:\n\n{content}\n\n请以JSON格式返回审查结果。"
-        }
+        获取ChatPromptTemplate实例(从缓存获取,避免重复I/O)
 
-    def reload_prompt(self, reviewer_type: str, prompt_name: str) -> Dict[str, str]:
-        """
-        重新加载指定的提示词(清除缓存)
+        Args:
+            reviewer_type: 审查器类型 (basic, technical, rag, ai)
+            prompt_name: 提示词名称
+            **kwargs: 模板变量,如 content, review_references, review_content 等
+
+        Returns:
+            ChatPromptTemplate: LangChain ChatPromptTemplate实例
         """
         cache_key = f"{reviewer_type}_{prompt_name}"
-        if cache_key in self._prompts_cache:
-            del self._prompts_cache[cache_key]
 
-        return self.load_prompt(reviewer_type, prompt_name)
-
-    def list_available_prompts(self, reviewer_type: str) -> list:
-        """
-        列出指定类型的所有可用提示词
-        """
         try:
-            config_file = os.path.join(self.prompt_config_dir, f"{reviewer_type}_reviewers.yaml")
+            prompt_config = self._cache[cache_key]
 
-            if not os.path.exists(config_file):
-                return []
+            # 创建ChatPromptTemplate
+            template = ChatPromptTemplate.from_messages([
+                ("system", prompt_config['system_prompt']),
+                ("user", prompt_config['user_prompt_template']+" /no_think")
+            ])
 
-            with open(config_file, 'r', encoding='utf-8') as f:
-                config = yaml.safe_load(f)
+            # 如果有变量,使用partial方法预先填充
+            if kwargs:
+                try:
+                    template = template.partial(**kwargs)
+                except Exception:
+                    # 如果partial失败,返回原始模板
+                    pass
 
-            return list(config.keys()) if config else []
+            return template
 
         except Exception as e:
-            logger.error(f"列出提示词失败: {reviewer_type}, 错误: {str(e)}")
-            return []
+            logger.error(f"创建ChatPromptTemplate失败: {reviewer_type}/{prompt_name}, 错误: {str(e)}")
+            # 返回默认模板
+            return ChatPromptTemplate.from_messages([
+                ("system", f"你是专业的施工方案审查专家,负责进行{prompt_name}审查。"),
+                ("user", "请审查:{content}")
+            ])
+  
+    def manage_cache(self, reviewer_type: str = None, prompt_name: str = None, action: str = "clear"):
+        """
+        缓存管理:清除或重新加载
 
-    def validate_prompt_config(self, reviewer_type: str, prompt_name: str) -> bool:
+        Args:
+            reviewer_type: 审查器类型
+            prompt_name: 提示词名称
+            action: "clear" 或 "reload"
         """
-        验证提示词配置是否有效
+        if action == "clear":
+            if reviewer_type is None:
+                self._cache.clear()
+                logger.info("已清除所有提示词缓存")
+            elif prompt_name is None:
+                keys_to_remove = [k for k in self._cache.keys() if k.startswith(f"{reviewer_type}_")]
+                for key in keys_to_remove:
+                    del self._cache[key]
+                logger.info(f"已清除{reviewer_type}类型的所有提示词缓存")
+            else:
+                cache_key = f"{reviewer_type}_{prompt_name}"
+                if cache_key in self._cache:
+                    del self._cache[cache_key]
+                logger.info(f"已清除提示词缓存: {reviewer_type}/{prompt_name}")
+
+        elif action == "reload" and prompt_name:
+            cache_key = f"{reviewer_type}_{prompt_name}"
+            if cache_key in self._cache:
+                del self._cache[cache_key]
+            self._load_prompt(reviewer_type, prompt_name)
+            logger.info(f"已重新加载提示词: {reviewer_type}/{prompt_name}")
+
+    def _preload_all_prompts(self, reviewer_types: List[str] = None) -> Dict[str, Any]:
         """
-        try:
-            prompt_config = self.load_prompt(reviewer_type, prompt_name)
-            return (
-                isinstance(prompt_config, dict) and
-                'system_prompt' in prompt_config and
-                'user_prompt_template' in prompt_config and
-                isinstance(prompt_config['system_prompt'], str) and
-                isinstance(prompt_config['user_prompt_template'], str)
-            )
-        except Exception:
-            return False
-
-
-# 全局提示词加载器实例
+        预加载所有提示词到缓存中(内部方法)
+
+        Args:
+            reviewer_types: 要预加载的审查器类型列表,None表示加载所有类型
+
+        Returns:
+            Dict[str, Any]: 加载结果统计
+        """
+        if reviewer_types is None:
+            reviewer_types = ['basic', 'technical', 'rag', 'ai']
+
+        stats = {
+            'loaded_types': [],
+            'total_loaded': 0,
+            'failed_items': [],
+            'by_type': {},
+            'cache_size_mb': 0
+        }
+
+        for reviewer_type in reviewer_types:
+            prompts = self.list_available_prompts(reviewer_type)
+            if not prompts:
+                logger.warning(f"未找到{reviewer_type}类型的提示词")
+                continue
+
+            type_stats = {
+                'total': len(prompts),
+                'loaded': 0,
+                'failed': []
+            }
+
+            for prompt_name in prompts:
+                try:
+                    self._load_prompt(reviewer_type, prompt_name)
+                    type_stats['loaded'] += 1
+                    stats['total_loaded'] += 1
+                except Exception as e:
+                    type_stats['failed'].append(prompt_name)
+                    stats['failed_items'].append(f"{reviewer_type}/{prompt_name}: {str(e)}")
+
+            stats['by_type'][reviewer_type] = type_stats
+            stats['loaded_types'].append(reviewer_type)
+
+        # 计算缓存大小
+        stats['cache_size_mb'] = round(
+            sum(len(str(v)) for v in self._cache.values()) / (1024 * 1024), 2
+        )
+
+        return stats
+
+
+
+
+# 全局提示词加载器实例(自动预加载)
 prompt_loader = PromptLoader()

+ 0 - 116
core/construction_review/prompt/basic_reviewers.yaml

@@ -1,116 +0,0 @@
-# 基础合规性审查器提示词配置
-
-grammar_check:
-  system_prompt: |
-    你是一个专业的中文语法检查专家,专门负责检查施工方案文档中的语法问题。
-
-    你的任务是:
-    1. 检查语法错误、标点符号使用
-    2. 识别语句不通顺的地方
-    3. 发现用词不当的问题
-    4. 检查专业术语使用是否规范
-
-    请对给定的施工方案内容进行语法检查,并以JSON格式返回结果:
-    {
-        "score": 85.5,
-        "details": {
-            "grammar_errors": [{"text": "错误内容", "position": "位置", "suggestion": "修改建议"}],
-            "punctuation_errors": [{"text": "错误内容", "position": "位置", "suggestion": "修改建议"}],
-            "word_choice_issues": [{"text": "用词问题", "position": "位置", "suggestion": "修改建议"}],
-            "total_errors": 3
-        },
-        "suggestions": ["建议1", "建议2"]
-    }
-
-    评分标准:
-    - 90-100分:语法优秀,基本无错误
-    - 80-89分:语法良好,少量小错误
-    - 70-79分:语法一般,有一些错误
-    - 60-69分:语法较差,错误较多
-    - 0-59分:语法很差,需要重写
-
-  user_prompt_template: |
-    请对以下施工方案内容进行语法检查:
-
-    待检查内容:
-    {content}
-
-    请仔细检查上述内容的语法、标点符号和用词,并以JSON格式返回检查结果。
-
-semantic_logic:
-  system_prompt: |
-    你是一个专业的施工方案语义逻辑检查专家,负责检查施工方案中的逻辑一致性和语义合理性。
-
-    你的任务是:
-    1. 检查前后内容是否矛盾
-    2. 验证技术参数的逻辑一致性
-    3. 检查施工流程的合理性
-    4. 识别语义不清晰或歧义的表达
-    5. 验证数据之间的逻辑关系
-
-    请对给定的施工方案内容进行语义逻辑检查,并以JSON格式返回结果:
-    {
-        "score": 88.0,
-        "details": {
-            "logic_conflicts": [{"issue": "逻辑冲突描述", "location": "位置", "suggestion": "修改建议"}],
-            "parameter_inconsistencies": [{"issue": "参数不一致描述", "location": "位置", "suggestion": "修改建议"}],
-            "semantic_ambiguities": [{"issue": "语义歧义描述", "location": "位置", "suggestion": "修改建议"}],
-            "data_logic_issues": [{"issue": "数据逻辑问题", "location": "位置", "suggestion": "修改建议"}],
-            "total_issues": 2
-        },
-        "suggestions": ["建议1", "建议2"]
-    }
-
-    评分标准:
-    - 90-100分:逻辑清晰,无矛盾
-    - 80-89分:逻辑基本清晰,轻微问题
-    - 70-79分:逻辑一般,有一些问题
-    - 60-69分:逻辑较差,问题较多
-    - 0-59分:逻辑混乱,需要重写
-
-  user_prompt_template: |
-    请对以下施工方案内容进行语义逻辑检查:
-
-    待检查内容:
-    {content}
-
-    请仔细检查上述内容的逻辑一致性、参数合理性和语义清晰度,并以JSON格式返回检查结果。
-
-completeness:
-  system_prompt: |
-    你是一个专业的施工方案完整性检查专家,负责检查施工方案的完整性和规范性。
-
-    你的任务是:
-    1. 检查必要的章节和内容是否齐全
-    2. 验证技术参数是否完整
-    3. 检查是否缺少关键信息
-    4. 验证表格和图表的完整性
-    5. 检查引用和参考文献是否完整
-
-    请对给定的施工方案内容进行完整性检查,并以JSON格式返回结果:
-    {
-        "score": 82.5,
-        "details": {
-            "missing_sections": [{"section": "缺失章节名称", "importance": "高/中/低", "suggestion": "补充建议"}],
-            "incomplete_parameters": [{"parameter": "参数名称", "location": "位置", "suggestion": "完善建议"}],
-            "missing_references": [{"reference": "缺失引用", "context": "上下文", "suggestion": "补充建议"}],
-            "incomplete_tables": [{"table": "表格标识", "missing_info": "缺失信息", "suggestion": "完善建议"}],
-            "total_missing_items": 4
-        },
-        "suggestions": ["建议1", "建议2"]
-    }
-
-    评分标准:
-    - 90-100分:内容完整,基本无缺失
-    - 80-89分:内容较完整,少量缺失
-    - 70-79分:内容一般,有一些缺失
-    - 60-69分:内容不完整,缺失较多
-    - 0-59分:内容严重不完整,需要补充大量信息
-
-  user_prompt_template: |
-    请对以下施工方案内容进行完整性检查:
-
-    待检查内容:
-    {content}
-
-    请仔细检查上述内容的完整性,包括章节、参数、引用等方面,并以JSON格式返回检查结果。

+ 0 - 167
core/construction_review/prompt/rag_reviewers.yaml

@@ -1,167 +0,0 @@
-# RAG增强审查器提示词配置
-
-vector_search:
-  system_prompt: |
-    你是一个专业的基于向量检索的施工方案审查专家。
-
-    你的任务是:
-    1. 基于检索到的相关标准规范进行审查
-    2. 分析施工方案与相关标准的匹配度
-    3. 识别可能存在的合规性问题
-    4. 提供基于标准的专业建议
-
-    请基于检索到的相关文档对施工方案进行审查,并以JSON格式返回结果:
-    {
-        "score": 85.0,
-        "details": {
-            "relevant_standards": [
-                {
-                    "standard": "标准名称",
-                    "relevance": 0.92,
-                    "content": "相关内容摘要",
-                    "application": "应用分析"
-                }
-            ],
-            "compliance_analysis": {
-                "matches": [{"standard": "匹配标准", "content": "匹配内容"}],
-                "gaps": [{"standard": "缺失标准", "suggestion": "补充建议"}],
-                "conflicts": [{"standard": "冲突标准", "resolution": "解决方案"}]
-            },
-            "search_effectiveness": {
-                "precision": 0.88,
-                "recall": 0.85,
-                "f1_score": 0.86
-            }
-        },
-        "suggestions": ["基于检索结果的建议1", "建议2"]
-    }
-
-    评分标准:
-    - 90-100分:检索结果精准,审查分析深入
-    - 80-89分:检索结果良好,分析较全面
-    - 70-79分:检索结果一般,分析基本到位
-    - 60-69分:检索结果较差,分析不够深入
-    - 0-59分:检索效果差,分析质量低
-
-  user_prompt_template: |
-    请基于以下检索到的相关标准规范,对施工方案进行审查:
-
-    施工方案内容:
-    {content}
-
-    相关标准规范:
-    {relevant_docs}
-
-    请分析施工方案与相关标准的符合性,并提供专业建议,以JSON格式返回结果。
-
-hybrid_search:
-  system_prompt: |
-    你是一个专业的基于混合检索的施工方案审查专家。
-
-    你的任务是:
-    1. 结合向量检索和关键词检索的优势
-    2. 提供更全面的相关标准覆盖
-    3. 基于多维检索结果进行综合审查
-    4. 提供更精准的改进建议
-
-    请基于混合检索结果对施工方案进行审查,并以JSON格式返回结果:
-    {
-        "score": 88.5,
-        "details": {
-            "search_strategy": {
-                "vector_results": 5,
-                "keyword_results": 8,
-                "merged_results": 10,
-                "fusion_method": "RRF倒排排名"
-            },
-            "relevant_standards": [
-                {
-                    "standard": "标准名称",
-                    "relevance_score": 0.91,
-                    "search_method": "vector/keyword/hybrid",
-                    "content_summary": "内容摘要",
-                    "compliance_status": "符合/不符合/部分符合"
-                }
-            ],
-            "comprehensive_analysis": {
-                "strengths": [{"aspect": "优势方面", "description": "描述"}],
-                "weaknesses": [{"aspect": "不足方面", "description": "描述"}],
-                "recommendations": [{"aspect": "改进建议", "priority": "高/中/低"}]
-            }
-        },
-        "suggestions": ["综合建议1", "建议2"]
-    }
-
-    评分标准:
-    - 90-100分:混合检索效果优秀,分析全面精准
-    - 80-89分:检索效果良好,分析较为全面
-    - 70-79分:检索效果一般,分析基本到位
-    - 60-69分:检索效果较差,分析不够深入
-    - 0-59分:检索效果差,分析质量低
-
-  user_prompt_template: |
-    请基于以下混合检索结果,对施工方案进行全面审查:
-
-    施工方案内容:
-    {content}
-
-    混合检索结果:
-    {search_results}
-
-    请综合分析检索结果,对施工方案进行全面评估,以JSON格式返回结果。
-
-rerank:
-  system_prompt: |
-    你是一个专业的基于重排序的施工方案审查专家。
-
-    你的任务是:
-    1. 对初步检索结果进行智能重排序
-    2. 提高最相关标准的权重
-    3. 基于重排序结果进行精准审查
-    4. 提供高质量的专业建议
-
-    请基于重排序后的结果对施工方案进行审查,并以JSON格式返回结果:
-    {
-        "score": 90.5,
-        "details": {
-            "reranking_analysis": {
-                "initial_results": 15,
-                "reranked_results": 8,
-                "top_improvement": 0.15,
-                "method": "cross-encoder重排序"
-            },
-            "priority_standards": [
-                {
-                    "rank": 1,
-                    "standard": "最相关标准",
-                    "relevance": 0.96,
-                    "application": "具体应用分析",
-                    "compliance_check": "合规性检查结果"
-                }
-            ],
-            "quality_assessment": {
-                "retrieval_precision": 0.94,
-                "retrieval_recall": 0.87,
-                "reranking_effectiveness": 0.91
-            }
-        },
-        "suggestions": ["基于重排序的精准建议1", "建议2"]
-    }
-
-    评分标准:
-    - 95-100分:重排序效果优秀,检索质量极高
-    - 85-94分:重排序效果良好,检索质量较高
-    - 75-84分:重排序效果一般,检索质量中等
-    - 65-74分:重排序效果较差,检索质量较低
-    - 0-64分:重排序效果差,检索质量低
-
-  user_prompt_template: |
-    请基于以下重排序后的检索结果,对施工方案进行精准审查:
-
-    施工方案内容:
-    {content}
-
-    重排序结果:
-    {reranked_results}
-
-    请重点分析排名靠前的相关标准,对施工方案进行精准评估,以JSON格式返回结果。

+ 0 - 165
core/construction_review/prompt/technical_reviewers.yaml

@@ -1,165 +0,0 @@
-# 技术性审查器提示词配置
-
-mandatory_standards:
-  system_prompt: |
-    你是一个专业的建筑工程强制性标准检查专家,负责检查施工方案是否符合国家强制性标准。
-
-    你的任务是:
-    1. 检查是否符合国家强制性标准条文
-    2. 验证关键指标是否满足强制性要求
-    3. 检查安全措施的合规性
-    4. 验证质量控制标准的执行情况
-    5. 检查环保标准的符合性
-
-    请对给定的施工方案内容进行强制性标准检查,并以JSON格式返回结果:
-    {
-        "score": 92.0,
-        "details": {
-            "compliance_rate": 95.5,
-            "violations": [
-                {
-                    "standard": "GB 50300-2013",
-                    "clause": "第3.0.3条",
-                    "issue": "违反强制性条文描述",
-                    "risk_level": "高/中/低",
-                    "suggestion": "整改建议"
-                }
-            ],
-            "compliance_items": [
-                {
-                    "standard": "JGJ 18-2012",
-                    "clause": "第4.1.2条",
-                    "status": "符合",
-                    "description": "符合描述"
-                }
-            ],
-            "total_violations": 1,
-            "high_risk_count": 1
-        },
-        "suggestions": ["建议1", "建议2"]
-    }
-
-    评分标准:
-    - 95-100分:完全符合强制性标准
-    - 85-94分:基本符合,轻微违规
-    - 75-84分:部分符合,有一些违规
-    - 60-74分:违规较多,需要整改
-    - 0-59分:严重违规,需要重大修改
-
-  user_prompt_template: |
-    请对以下施工方案内容进行强制性标准检查:
-
-    待检查内容:
-    {content}
-
-    请对照相关的国家强制性标准进行检查,重点关注安全、质量、环保等方面的强制性要求,并以JSON格式返回检查结果。
-
-design_values:
-  system_prompt: |
-    你是一个专业的工程设计值检查专家,负责检查施工方案中的设计参数和数值是否符合规范要求。
-
-    你的任务是:
-    1. 检查设计参数的准确性和合理性
-    2. 验证计算公式的正确性
-    3. 检查单位使用是否规范
-    4. 验证数值范围是否合理
-    5. 检查设计值与实际情况的匹配度
-
-    请对给定的施工方案内容进行设计值检查,并以JSON格式返回结果:
-    {
-        "score": 87.5,
-        "details": {
-            "accuracy_rate": 89.0,
-            "deviations": [
-                {
-                    "parameter": "参数名称",
-                    "design_value": "设计值",
-                    "suggested_value": "建议值",
-                    "deviation_type": "数值偏差/单位错误/计算错误",
-                    "risk_level": "高/中/低",
-                    "suggestion": "修正建议"
-                }
-            ],
-            "correct_parameters": [
-                {
-                    "parameter": "参数名称",
-                    "value": "数值",
-                    "unit": "单位",
-                    "verification": "验证结果"
-                }
-            ],
-            "total_deviations": 2,
-            "critical_deviations": 1
-        },
-        "suggestions": ["建议1", "建议2"]
-    }
-
-    评分标准:
-    - 95-100分:设计值准确无误
-    - 85-94分:设计值基本准确,轻微偏差
-    - 75-84分:设计值一般,有一些偏差
-    - 60-74分:设计值偏差较多,需要修正
-    - 0-59分:设计值严重错误,需要重新计算
-
-  user_prompt_template: |
-    请对以下施工方案内容进行设计值检查:
-
-    待检查内容:
-    {content}
-
-    请仔细检查上述内容中的设计参数、计算公式、数值单位和范围,并以JSON格式返回检查结果。
-
-technical_parameters:
-  system_prompt: |
-    你是一个专业的工程技术参数检查专家,负责检查施工方案中的技术参数是否合理和完整。
-
-    你的任务是:
-    1. 检查技术参数的完整性和准确性
-    2. 验证技术指标是否符合行业规范
-    3. 检查施工工艺参数的合理性
-    4. 验证材料规格参数的正确性
-    5. 检查设备参数配置的合理性
-
-    请对给定的施工方案内容进行技术参数检查,并以JSON格式返回结果:
-    {
-        "score": 90.0,
-        "details": {
-            "precision_rate": 92.0,
-            "errors": [
-                {
-                    "parameter": "参数名称",
-                    "current_value": "当前值",
-                    "correct_value": "正确值",
-                    "error_type": "数值错误/单位错误/范围错误/逻辑错误",
-                    "risk_level": "高/中/低",
-                    "suggestion": "修正建议"
-                }
-            ],
-            "verified_parameters": [
-                {
-                    "parameter": "参数名称",
-                    "value": "数值",
-                    "standard_reference": "参考标准",
-                    "status": "符合/基本符合/不符合"
-                }
-            ],
-            "total_errors": 1,
-            "critical_errors": 0
-        },
-        "suggestions": ["建议1", "建议2"]
-    }
-
-    评分标准:
-    - 95-100分:技术参数准确完整
-    - 85-94分:技术参数基本准确,少量问题
-    - 75-84分:技术参数一般,有一些问题
-    - 60-74分:技术参数问题较多,需要修正
-    - 0-59分:技术参数严重错误,需要重新制定
-
-  user_prompt_template: |
-    请对以下施工方案内容进行技术参数检查:
-
-    待检查内容:
-    {content}
-
-    请仔细检查上述内容中的技术参数、工艺参数、材料规格等,并对照相关行业标准进行验证,以JSON格式返回检查结果。

+ 106 - 60
core/construction_review/workflows/ai_review_workflow.py

@@ -13,7 +13,6 @@ from langgraph.graph import StateGraph, END
 from langgraph.graph.message import add_messages
 from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
 from foundation.logger.loggering import server_logger as logger
-from foundation.utils.time_statistics import track_execution_time
 from ..component import AIReviewEngine
 
 
@@ -29,23 +28,16 @@ class ReviewResult:
 
 class AIReviewState(TypedDict):
     """AI审查工作流状态"""
-    # 基本信息
+
     file_id: str
     callback_task_id: str
     user_id: str
     structured_content: Dict[str, Any]
-
-    # AI审查结果
     review_results: Optional[Dict[str, Any]]
-
-    # 状态和进度
     current_stage: str
     status: str
     error_message: Optional[str]
-
-    # 进度管理
     progress_manager: Optional[Any]
-
     # 消息日志(用于LangGraph状态追踪)
     messages: Annotated[List[BaseMessage], add_messages]
 
@@ -54,32 +46,82 @@ class AIReviewWorkflow:
     """基于LangGraph的AI审查工作流"""
 
     def __init__(self, file_id: str, callback_task_id: str, user_id: str,
-                 structured_content: Dict[str, Any], progress_manager=None):
+                 structured_content: Dict[str, Any], progress_manager=None,
+                 max_review_units: int = None, review_mode: str = "all"):
+        """
+        初始化AI审查工作流
+
+        Args:
+            file_id: 文件ID
+            callback_task_id: 回调任务ID
+            user_id: 用户ID
+            structured_content: 结构化内容
+            progress_manager: 进度管理器
+            max_review_units: 最大审查单元数量(None表示审查所有)
+            review_mode: 审查模式 ("all"=全部, "first"=前N个, "random"=随机N个)
+        """
         self.file_id = file_id
         self.callback_task_id = callback_task_id
         self.user_id = user_id
         self.structured_content = structured_content
         self.progress_manager = progress_manager
         self.ai_review_engine = AIReviewEngine()
-
-        # 构建LangGraph工作流
+        self.max_review_units = max_review_units
+        self.review_mode = review_mode
         self.graph = self._build_workflow()
 
+    def _filter_review_units(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
+        """
+        根据配置筛选要审查的单元
+
+        Args:
+            chunks: 所有审查单元
+
+        Returns:
+            List[Dict[str, Any]]: 筛选后的审查单元
+        """
+        if self.max_review_units is None or self.review_mode == "all":
+            return chunks
+
+        # 验证原始chunks不为空
+        if not chunks:
+            logger.warning("没有可用的审查单元")
+            return []
+
+        # 安全的切片操作,考虑边界情况
+        start_index = min(30, len(chunks) - 1)  # 确保start_index不超过数组边界
+        chunks = chunks[start_index:]
+
+        # 再次验证切片后的结果
+        if not chunks:
+            logger.warning(f"从索引{start_index}切片后没有可用的审查单元")
+            return []
+
+        total_chunks = len(chunks)
+        actual_review_count = min(self.max_review_units, total_chunks)
+
+        logger.info(f"审查模式: {self.review_mode}, 总单元数: {total_chunks}, 实际审查数: {actual_review_count}")
+
+        if self.review_mode == "first":
+            # 取前N个
+            return chunks[:actual_review_count]
+        elif self.review_mode == "random":
+            # 随机取N个
+            import random
+            return random.sample(chunks, actual_review_count)
+        else:
+            # 默认取前N个
+            return chunks[:actual_review_count]
+
     def _build_workflow(self) -> StateGraph:
         """构建AI审查的LangGraph工作流图"""
         workflow = StateGraph(AIReviewState)
-
-        # 添加节点
         workflow.add_node("start", self._start_node)
         workflow.add_node("initialize_progress", self._initialize_progress_node)
         workflow.add_node("ai_review", self._ai_review_node)
         workflow.add_node("complete", self._complete_node)
         workflow.add_node("error_handler", self._error_handler_node)
-
-        # 设置入口点
-        workflow.set_entry_point("start")
-
-        # 添加边(定义流程)
+        workflow.set_entry_point("start")# 设置入口节点
         workflow.add_edge("start", "initialize_progress")
         workflow.add_edge("initialize_progress", "ai_review")
         workflow.add_edge("ai_review", "complete")
@@ -105,8 +147,6 @@ class AIReviewWorkflow:
         """执行基于LangGraph的AI审查工作流"""
         try:
             logger.info(f"开始AI审查工作流,文件ID: {self.file_id}")
-
-            # 初始状态
             initial_state = AIReviewState(
                 file_id=self.file_id,
                 callback_task_id=self.callback_task_id,
@@ -144,8 +184,6 @@ class AIReviewWorkflow:
             logger.error(f"LangGraph AI审查工作流执行失败: {str(e)}")
             raise
 
-    # ========== LangGraph节点实现 ==========
-
     async def _start_node(self, state: AIReviewState) -> AIReviewState:
         """开始节点"""
         logger.info(f"AI审查工作流启动: {state['file_id']}")
@@ -177,18 +215,24 @@ class AIReviewWorkflow:
         return state
     
     async def _ai_review_node(self, state: AIReviewState) -> AIReviewState:
-        """AI审查节点 - 使用LangGraph编排原子化组件方法"""
+        """AI审查节点"""
         try:
             logger.info(f"执行AI审查: {state['file_id']}")
 
             state["current_stage"] = "ai_review"
 
-            total_units = len(state['structured_content']['chunks'])
+            # 筛选要审查的单元
+            all_chunks = state['structured_content']['chunks']
+            review_chunks = self._filter_review_units(all_chunks)
+
+            total_units = len(review_chunks)
+            total_all_units = len(all_chunks)
             completed_units = 0
 
+            logger.info(f"AI审查开始: 总单元数 {total_all_units}, 实际审查 {total_units} 个单元")
+
             # 进度回调函数
             def progress_callback(progress: int, message: str):
-                # 将AI审查的进度映射到整体进度
                 overall_progress = 50 + int(progress * 0.4)  # AI审查占整体进度的40%
                 if state["progress_manager"]:
                     asyncio.create_task(
@@ -201,16 +245,17 @@ class AIReviewWorkflow:
                         )
                     )
 
-            # 使用原子化组件方法审查单个单元
-            async def review_single_unit(unit_content: Dict[str, Any], unit_index: int) -> ReviewResult:
+            # 基本审查单元
+            async def review_single_unit(unit_content: Dict[str, Any], unit_index: int,callback_task_id) -> ReviewResult:
                 """使用LangGraph编排的原子化组件方法审查单个单元"""
-                async with self.ai_review_engine.semaphore:
-                    try:
+                try:    
+                        # 构建Trace ID
+                        trace_id_idx = "("+str(callback_task_id)+'-'+str(unit_index)+")"
                         # 并发执行各种原子化审查方法
                         review_tasks = [
-                            self.ai_review_engine.basic_compliance_check(unit_content),
-                            self.ai_review_engine.technical_compliance_check(unit_content),
-                            self.ai_review_engine.rag_enhanced_check(unit_content)
+                            self.ai_review_engine.basic_compliance_check(trace_id_idx, unit_content),
+                            self.ai_review_engine.technical_compliance_check(trace_id_idx, unit_content),
+                            # self.ai_review_engine.rag_enhanced_check(unit_content, trace_id_idx)
                         ]
 
                         # 等待所有审查完成
@@ -218,8 +263,10 @@ class AIReviewWorkflow:
 
                         # 处理异常结果
                         basic_result = review_results[0] if not isinstance(review_results[0], Exception) else {"error": str(review_results[0])}
-                        technical_result = review_results[1] if not isinstance(review_results[1], Exception) else {"error": str(review_results[1])}
-                        rag_result = review_results[2] if not isinstance(review_results[2], Exception) else {"error": str(review_results[2])}
+                        technical_result = review_results[1] if len(review_results) > 1 and not isinstance(review_results[1], Exception) else {"error": str(review_results[1]) if len(review_results) > 1 else "No result"}
+
+                        # RAG检查已注释,提供空结果
+                        rag_result = {"error": "RAG check disabled"}
 
                         # 计算总体风险等级
                         overall_risk = self._calculate_overall_risk(basic_result, technical_result, rag_result)
@@ -234,29 +281,29 @@ class AIReviewWorkflow:
                             progress_callback(progress, message)
 
                         return ReviewResult(
-                            unit_index=unit_index,
-                            unit_content=unit_content,
-                            basic_compliance=basic_result,
-                            technical_compliance=technical_result,
-                            rag_enhanced=rag_result,
-                            overall_risk=overall_risk
-                        )
+                        unit_index=unit_index,
+                        unit_content=unit_content,
+                        basic_compliance=basic_result,
+                        technical_compliance=technical_result,
+                        rag_enhanced=rag_result,
+                        overall_risk=overall_risk
+                    )
 
-                    except Exception as e:
-                        logger.error(f"审查单元 {unit_index} 失败: {str(e)}")
-                        return ReviewResult(
-                            unit_index=unit_index,
-                            unit_content=unit_content,
-                            basic_compliance={"error": str(e)},
-                            technical_compliance={"error": str(e)},
-                            rag_enhanced={"error": str(e)},
-                            overall_risk="error"
-                        )
+                except Exception as e:
+                    logger.error(f"审查单元 {unit_index} 失败: {str(e)}")
+                    return ReviewResult(
+                        unit_index=unit_index,
+                        unit_content=unit_content,
+                        basic_compliance={"error": str(e)},
+                        technical_compliance={"error": str(e)},
+                        rag_enhanced={"error": str(e)},
+                        overall_risk="error"
+                    )
 
-            # 并发审查所有单元
+            # 实现异步并发
             review_tasks = [
-                asyncio.create_task(review_single_unit(content, i))
-                for i, content in enumerate(state['structured_content']['chunks'])
+                asyncio.create_task(review_single_unit(content, i,state["callback_task_id"]))
+                for i, content in enumerate(review_chunks)
             ]
 
             # 等待所有审查完成
@@ -269,9 +316,12 @@ class AIReviewWorkflow:
             summary = self._aggregate_results(successful_results)
 
             review_results = {
-                'total_units': total_units,
+                'total_all_units': total_all_units,  # 原始总单元数
+                'total_reviewed_units': total_units,  # 实际审查的单元数
                 'successful_units': len(successful_results),
                 'failed_units': total_units - len(successful_results),
+                'review_mode': self.review_mode,
+                'max_review_units': self.max_review_units,
                 'review_results': successful_results,
                 'summary': summary
             }
@@ -333,7 +383,6 @@ class AIReviewWorkflow:
 
         return state
 
-    # ========== 辅助方法 ==========
 
     def _calculate_overall_risk(self, basic_result: Dict, technical_result: Dict, rag_result: Dict) -> str:
         """计算总体风险等级"""
@@ -379,7 +428,6 @@ class AIReviewWorkflow:
             logger.error(f"结果汇总失败: {str(e)}")
             return {}
 
-    # ========== 条件边函数 ==========
 
     def _check_ai_review_result(self, state: AIReviewState) -> str:
         """检查AI审查结果"""
@@ -393,8 +441,6 @@ class AIReviewWorkflow:
         grandalf_graph.print_ascii()
  
 
-
-
     async def _get_status(self) -> dict:
         """获取工作流状态"""
         if self.progress_manager:

+ 19 - 80
foundation/agent/generate/model_generate.py

@@ -8,14 +8,11 @@
 @Date       :2025/7/14 14:22
 '''
 
-from typing import Dict, Optional
-from langchain_core.prompts import HumanMessagePromptTemplate
 from langchain_core.prompts import ChatPromptTemplate
 from foundation.utils.utils import get_models
-from foundation.utils.yaml_utils import system_prompt_config
+from foundation.logger.loggering import server_logger as logger
 
-
-class TestGenerateModelClient:
+class GenerateModelClient:
     """
         主要是生成式模型
     """
@@ -25,90 +22,32 @@ class TestGenerateModelClient:
         llm, chat, embed = get_models()
         self.llm = llm
         self.chat = chat
-        # 固定系统提示词
-        self.system_prompt = system_prompt_config["system_prompt"]
-
 
-    def get_prompt_template(self):
-        """
-            构造普通Prompt提示词模板
+    async def get_model_generate_invoke(self, trace_id, task_prompt_info: dict):
         """
-        human_template = """
-            {system_message}
-            用户的问题为:
-                {question}  
-            答案为:
+            模型非流式生成(异步)
         """
-        human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
-        chat_prompt_template = ChatPromptTemplate.from_messages([human_message_prompt])
-        return chat_prompt_template
-    
-    
-    def get_model_generate_invoke(self, trace_id, task_prompt_info: dict, input_query, context=None):
-        """
-            模型生成链
-        """
-        # Step 1: 定义系统提示词模板 system_prompt
 
-        # Step 2: 构建完整的 prompt 模板
-        prompt_template = ChatPromptTemplate.from_messages([
-            ("system", self.system_prompt), #task_prompt_info["task_prompt"]
-            ("human", "{input}")
-        ])
-        # Step 3: 初始化模型
-        # Step 4: 使用模板格式化输入
-        messages = prompt_template.invoke({"input": input_query})
-        # Step 5: 流式调用模型
-        response = self.llm.invoke(messages)
+        prompt_template = task_prompt_info["task_prompt"]
+        # 直接格式化消息,不需要额外的invoke步骤
+        messages = prompt_template.format_messages()
+
+        # 使用异步方法调用模型,避免阻塞事件循环
+        import asyncio
+        loop = asyncio.get_event_loop()
+        response = await loop.run_in_executor(None, self.llm.invoke, messages)
+        # logger.info(f"[模型生成结果]: {response.content}")
         return response.content
 
-    def get_model_generate_stream(self, trace_id, task_prompt_info: dict, input_query, context=None):
+    async def get_model_generate_stream(self, trace_id, task_prompt_info: dict):
         """
-            模型生成链
+            模型流式生成(异步)
         """
-        # Step 1: 定义系统提示词模板 system_prompt
-
-        # Step 2: 构建完整的 prompt 模板
-        prompt_template = ChatPromptTemplate.from_messages([
-            ("system",  self.system_prompt), #task_prompt_info["task_prompt"]
-            ("human", "{input}")
-        ])
-        # Step 3: 初始化模型
-        # Step 4: 使用模板格式化输入
-        messages = prompt_template.invoke({"input": input_query})
-        # Step 5: 流式调用模型
+        prompt_template = task_prompt_info["task_prompt"]
+        # 直接格式化消息,不需要额外的invoke步骤
+        messages = prompt_template.format_messages()
         response = self.llm.stream(messages)
-        # Step 6: 逐 token 输出(打字机效果)
         for chunk in response:
             yield chunk.content
 
-
-
-    def get_input_context(
-            self,
-            trace_id: str,
-            task_prompt_info: dict,
-            input_query: str,
-            context: Optional[str] = None
-    ) -> str:
-        #server_logger.info(f"task_prompt_info: {task_prompt_info}")
-        """构建问题和上下文"""
-        context = context or "无"
-        task_prompt_info_str = task_prompt_info["task_prompt"]
-
-        # 针对场景优化的上下文提示
-        base_context_prompt = """
-            日志链路跟踪ID:{trace_id}
-            任务信息:{task_prompt_info_str}
-            相关上下文数据:{context}
-            户问题:{input}
-        """
-        return base_context_prompt.format(
-            trace_id=trace_id,
-            task_prompt_info_str=task_prompt_info_str,
-            context=context,
-            input=input_query
-        )
-
-#
-test_generate_model_client = TestGenerateModelClient()
+generate_model_client = GenerateModelClient()

+ 0 - 0
foundation/agent/monitor/__init__.py


+ 11 - 0
foundation/agent/monitor/ai_trace_monitor.py

@@ -0,0 +1,11 @@
+from langfuse import Langfuse,observe
+from typing import Dict, List
+lf = Langfuse(
+            secret_key="sk-lf-034de024-bade-4d75-9911-319aa1e4ed30",
+            public_key="pk-lf-d55b3b61-e183-42d2-9b8e-febb198dfe9d",
+            base_url="http://127.0.0.1:3000/",
+            
+)
+
+
+

+ 2 - 2
foundation/agent/workflow/test_workflow_node.py

@@ -21,7 +21,7 @@ from foundation.agent.workflow.test_cus_state import TestCusState
 from foundation.agent.generate.test_intent import intent_identify_client
 from foundation.agent.test_agent import test_agent_client
 from foundation.schemas.test_schemas import FormConfig
-from foundation.agent.generate.model_generate import test_generate_model_client
+from foundation.agent.generate.model_generate import generate_model_client
 
 
 
@@ -98,7 +98,7 @@ class TestWorkflowNode:
         user_input = state["user_input"]
         task_prompt_info = state["task_prompt_info"]
         task_prompt_info["task_prompt"] = ""
-        response_content = test_generate_model_client.get_model_generate_invoke(trace_id=trace_id , task_prompt_info=task_prompt_info, input_query=user_input)
+        response_content = generate_model_client.get_model_generate_invoke(trace_id=trace_id , task_prompt_info=task_prompt_info, input_query=user_input)
         messages = [AIMessage(content=response_content , name="chat_box_generate")]
         server_logger.info(trace_id=trace_id, msg=f"【result】: {response_content}", log_type="chat_box_generate")
         return {

+ 1 - 1
foundation/base/tasks.py

@@ -20,7 +20,7 @@ def submit_task_processing_task(self, file_info: dict):
 
     # 添加调试信息
     logger.info("=== Celery任务接收调试 ===")
-    logger.info(f"任务ID: {self.request.id}")
+    logger.info(f"队列ID: {self.request.id}")
     logger.info(f"文件ID: {file_info.get('file_id')}")
     logger.info(f"回调任务ID: {file_info.get('callback_task_id')}")
     logger.info("=== 任务接收调用栈 ===")

+ 174 - 197
foundation/utils/utils.py

@@ -1,205 +1,182 @@
-import json
-import time
-import uuid
-from datetime import datetime
-from typing import List, Dict, Optional
-
-from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
 from langchain_openai import ChatOpenAI
+from langchain_core.messages import HumanMessage
 
 from foundation.base.config import config_handler
-from foundation.logger.loggering import server_logger
-
 
-def get_models():
-    """
-    获取模型,模型类型 默认为deepseek 、qwen
-    """
-    model_type = config_handler.get("model", "MODEL_TYPE")
-    server_logger.info(f"get_models -> model_type:{model_type}")
-    if model_type.upper() == "QWEN":
-        return get_deploy_qwen_models()
-    return get_deepseek_models()
 
+class ModelHandler:
+
+	def __init__(self):
+		self.config = config_handler
+
+	def get_models(self):
+		"""
+			获取模型,默认为豆包
+		"""
+		model_type = self.config.get("model", "MODEL_TYPE")
+		if model_type == "doubao":
+			return self._get_doubao_model()
+		elif model_type == "qwen":
+			return self._get_qwen_model()
+		elif model_type == "deepseek":
+			return self._get_deepseek_model()
+		elif model_type == "qwen_local_1.5b":
+			return self._get_qwen_local_1_5b_model()
+		elif model_type == "qwen_local_14b":
+			return self._get_qwen_local_14b_model()
+		else:
+			# 默认返回豆包
+			return self._get_doubao_model()
+
+
+	def _get_doubao_model(self):
+		"""
+		获取豆包模型
+		"""
+		doubao_url = self.config.get("doubao", "DOUBAO_SERVER_URL")
+		doubao_model_id = self.config.get("doubao", "DOUBAO_MODEL_ID")
+		doubao_api_key = self.config.get("doubao", "DOUBAO_API_KEY")
+
+
+		llm = ChatOpenAI(
+			base_url=doubao_url,
+			model=doubao_model_id,
+			api_key=doubao_api_key,
+			temperature=0.7,
+			extra_body={
+				"enable_thinking": False,
+			})
+		
+		return llm
+
+	
+	def _get_qwen_model(self):
+		"""
+		获取通义千问模型
+		"""
+		qwen_url = self.config.get("qwen", "QWEN_SERVER_URL")
+		qwen_model_id = self.config.get("qwen", "QWEN_MODEL_ID")
+		qwen_api_key = self.config.get("qwen", "QWEN_API_KEY")
+
+		print(f"Debug - qwen_url: {qwen_url}")
+		print(f"Debug - qwen_model_id: {qwen_model_id}")
+		print(f"Debug - qwen_api_key: {qwen_api_key[:10]}..." if qwen_api_key else "Debug - qwen_api_key: None")
+
+		llm = ChatOpenAI(
+			base_url=qwen_url,
+			model=qwen_model_id,
+			api_key=qwen_api_key,
+			temperature=0.7,
+			extra_body={
+				"enable_thinking": False,
+			})
+
+		return llm
+	
+	def _get_deepseek_model(self):
+		"""
+		获取通义千问模型
+		"""
+		qwen_url = self.config.get("qwen", "QWEN_SERVER_URL")
+		qwen_model_id = self.config.get("qwen", "QWEN_MODEL_ID")
+		qwen_api_key = self.config.get("qwen", "QWEN_API_KEY")
+
+		print(f"Debug - qwen_url: {qwen_url}")
+		print(f"Debug - qwen_model_id: {qwen_model_id}")
+		print(f"Debug - qwen_api_key: {qwen_api_key[:10]}..." if qwen_api_key else "Debug - qwen_api_key: None")
+
+		llm = ChatOpenAI(
+			base_url=qwen_url,
+			model=qwen_model_id,
+			api_key=qwen_api_key,
+			temperature=0.7,
+			extra_body={
+				"enable_thinking": False,
+			})
+
+		return llm
+	
+	def _get_deepseek_model(self):
+		"""
+		获取通义千问模型
+		"""
+		deepseek_url = self.config.get("deepseek", "DEEPSEEK_SERVER_URL")
+		deepseek_model_id = self.config.get("deepseek", "DEEPSEEK_MODEL_ID")
+		deepseek_api_key = self.config.get("deepseek", "DEEPSEEK_API_KEY")
+
+		print(f"Debug - deepseek_url: {deepseek_url}")
+		print(f"Debug - deepseek_model_id: {deepseek_model_id}")
+		print(f"Debug - deepseek_api_key: {deepseek_api_key[:10]}..." if deepseek_api_key else "Debug - deepseek_api_key: None")
+
+		llm = ChatOpenAI(
+			base_url=deepseek_url,
+			model=deepseek_model_id,
+			api_key=deepseek_api_key,
+			temperature=0.7,
+			extra_body={
+				"enable_thinking": False,
+			})
+
+		return llm
+	
+	def _get_gemini_model(self):
+		"""
+		获取通义千问模型
+		"""
+		gemini_url = self.config.get("gemini", "GEMINI_SERVER_URL")
+		gemini_model_id = self.config.get("gemini", "GEMINI_MODEL_ID")
+		gemini_api_key = self.config.get("gemini", "GEMINI_API_KEY")
+
+		print(f"Debug - gemini_url: {gemini_url}")
+		print(f"Debug - gemini_model_id: {gemini_model_id}")
+		print(f"Debug - gemini_api_key: {gemini_api_key[:10]}..." if gemini_api_key else "Debug - gemini_api_key: None")
+
+		llm = ChatOpenAI(
+			base_url=gemini_url,
+			model=gemini_model_id,
+			api_key=gemini_api_key,
+			temperature=0.7,
+			extra_body={
+				"enable_thinking": False,
+			})
+
+		return llm
+
+	def _get_qwen_local_1_5b_model(self):
+		"""
+		获取本地Qwen2.5-1.5B-Instruct模型
+		"""
+		llm = ChatOpenAI(
+			base_url="http://172.16.35.50:8000/v1",
+			model="Qwen2.5-1.5B-Instruct",
+			api_key="sk-dummy",  # 本地模型使用虚拟API key
+			temperature=0.7,
+		)
+
+		return llm
+
+	def _get_qwen_local_14b_model(self):
+		"""
+		获取本地Qwen3-14B模型
+		"""
+		llm = ChatOpenAI(
+			base_url="http://172.16.35.50:8003/v1",
+			model="Qwen3-14B",
+			api_key="sk-dummy",  # 本地模型使用虚拟API key
+			temperature=0.7,
+		)
+
+		return llm
+
+
+# 创建全局实例
+model_handler = ModelHandler()
 
-def get_deepseek_models():
-    """
-    获取DeepSeek模型
-    """
-    deepseek_model_server_url = config_handler.get("deepseek", "DEEPSEEK_SERVER_URL")
-    deepseek_chat_model_id = config_handler.get("deepseek", "DEEPSEEK_MODEL_ID")
-    deepseek_api_key = config_handler.get("deepseek", "DEEPSEEK_API_KEY")
-    server_logger.info(f"get_deepseek_models -> chat_model_id:{deepseek_chat_model_id},api_key:{deepseek_api_key}")
-    if deepseek_model_server_url is None or deepseek_chat_model_id is None or deepseek_api_key is None:
-        server_logger.error("请设置环境变量: DEEPSEEK_SERVER_URL, DEEPSEEK_MODEL_ID, DEEPSEEK_API_KEY")
-        raise Exception("设置环境变量: DEEPSEEK_SERVER_URL, DEEPSEEK_MODEL_ID, DEEPSEEK_API_KEY")
-    # llm 大模型
-    llm = ChatOpenAI(base_url=deepseek_model_server_url,
-                     api_key=deepseek_api_key,
-                     model=deepseek_chat_model_id,
-                     max_tokens=4096,
-                     temperature=0.3,
-                     top_p=0.7,
-                     extra_body={
-                         "enable_thinking": False  # 添加这个参数以避免报错
-                     })
-    # chat 大模型
-    chat = ChatOpenAI(base_url=deepseek_model_server_url,
-                      api_key=deepseek_api_key,
-                      model=deepseek_chat_model_id,
-                      max_tokens=4096,
-                      temperature=0.3,
-                      top_p=0.2,
-                      extra_body={
-                          "enable_thinking": False  # 添加这个参数以避免报错
-                      })
-    embed = None
-    return llm, chat, embed
-
-
-# 获取千问模型
-def get_deploy_qwen_models():
+def get_models():
     """
-        加载千问系列大模型-魔搭在线Qwen3 API服务
+    获取模型的全局函数
+    返回: (llm, chat, embed)
     """
-    model_server_url = config_handler.get("qwen", "MODEL_SERVER_URL")
-    chat_model_id = config_handler.get("qwen", "CHAT_MODEL_ID")
-    api_key = config_handler.get("qwen", "API_KEY")
-    embedding_model_id = config_handler.get("qwen", "EMBED_MODEL_ID")
-    # temperature = os.getenv("CHAT_MODEL_TEMPERATURE")
-    server_logger.info(
-        f"get_qwen_chat_model -> chat_model_id:{chat_model_id},api_key:{api_key},embedding_model_id:{embedding_model_id}")
-    if model_server_url is None or chat_model_id is None or api_key is None:
-        server_logger.error("请设置环境变量: MODEL_SERVER_URL, CHAT_MODEL_ID, API_KEY")
-        raise Exception("请设置环境变量: MODEL_SERVER_URL, CHAT_MODEL_ID, API_KEY")
-
-    # llm 大模型
-    llm = ChatOpenAI(base_url=model_server_url,
-                     api_key=api_key,
-                     model=chat_model_id,
-                     max_tokens=1024,
-                     temperature=0.5,
-                     top_p=0.7,
-                     extra_body={
-                         "enable_thinking": False  # 添加这个参数以避免报错
-                     })
-    # chat 大模型
-    chat = ChatOpenAI(base_url=model_server_url,
-                      api_key=api_key,
-                      model=chat_model_id,
-                      max_tokens=1024,
-                      temperature=0.01,
-                      top_p=0.2,
-                      extra_body={
-                          "enable_thinking": False  # 添加这个参数以避免报错
-                      })
-
-    # embedding 大模型 text-embedding-v3  text-embedding-v4
-    # from langchain_community.embeddings import DashScopeEmbeddings
-    embed = None  # DashScopeEmbeddings(model=embedding_model_id)
-    return llm, chat, embed
-
-
-def test_qwen_chat_model():
-    #  获取模型
-    llm, chat, embed = get_deploy_qwen_models()
-    example_query = "你好,你是谁?"
-    result = llm.invoke(input=example_query)
-    server_logger.info(f"result={result}")
-    print(f"result={result}")
-
-
-def test_deepseek_chat_model():
-    #  获取模型
-    llm, chat, embed = get_deepseek_models()
-    example_query = "你好,你是谁?"
-    result = llm.invoke(input=example_query)
-    server_logger.info(f"result={result}")
-    print(f"result={result}")
-
-
-def serialize_messages(messages: List[Dict]) -> str:
-    """序列化消息列表为JSON字符串"""
-    return json.dumps(messages)
-
-
-def deserialize_messages(data: str) -> List[Dict]:
-    """反序列化JSON字符串为消息列表"""
-    return json.loads(data) if data else []
-
-
-def to_langchain_messages(messages: List[Dict]) -> List:
-    """将消息字典转换为LangChain消息对象"""
-    langchain_messages = []
-    for msg in messages:
-        if msg["role"] == "user":
-            langchain_messages.append(HumanMessage(content=msg["content"]))
-        elif msg["role"] == "assistant":
-            langchain_messages.append(AIMessage(content=msg["content"]))
-        elif msg["role"] == "system":
-            langchain_messages.append(SystemMessage(content=msg["content"]))
-    return langchain_messages
-
-
-def generate_session_id() -> str:
-    """生成唯一的会话ID"""
-    return f"xiwuzc-{uuid.uuid4()}"
-
-
-def get_current_timestamp() -> float:
-    """获取当前时间戳"""
-    return time.time()
-
-
-def format_timestamp(timestamp: float) -> str:
-    """格式化时间戳为可读字符串"""
-    return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
-
-
-def build_input_context(
-        trace_id: str,
-        task_prompt_info: dict,
-        input_query: str,
-        context: Optional[str] = None,
-        supplement_info: Optional[str] = None,
-        header_info: Optional[Dict] = None
-) -> str:
-    """构建场景优化的上下文提示"""
-    context = context or "无相关数据"
-    supplement_info = supplement_info or "无补充信息"
-    token = header_info.get('token', '') if header_info else ''
-    tenantId = header_info.get('tenantId', '') if header_info else ''
-    task_prompt_info_str = task_prompt_info["task_prompt"]
-
-    return f"""
-🐄 助手会话 [ID: {trace_id}] 🐖
-⏰ 时间: {format_timestamp(get_current_timestamp())}
-📌 任务: {task_prompt_info_str}
-
-📊 相关数据:
-{context}
-
-ℹ️ 补充信息:
-{supplement_info}
-
-❓ 户问题:
-{input_query}
-
-🔒 安全验证: {token}
-🏠 场ID: {tenantId}
-""".strip()
-
-
-def clean_json_output(raw_output: str) -> str:
-    """去除开头和结尾的 ```json 和 ```"""
-    cleaned = raw_output.strip()
-    if cleaned.startswith("```json"):
-        cleaned = cleaned[7:]
-    if cleaned.endswith("```"):
-        cleaned = cleaned[:-3]
-    return cleaned.strip()
-
-
-if __name__ == "__main__":
-    test_qwen_chat_model()  # 运行
-    # test_deepseek_chat_model()
+    llm = model_handler.get_models()
+    # 暂时返回相同的模型作为chat和embed
+    return llm, llm, None

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 47
temp/AI审查结果.json


+ 3 - 0
test/test_enumerate.py

@@ -0,0 +1,3 @@
+my_list = ["苹果", "香蕉", "橙子", "葡萄"]
+result = list(enumerate(my_list, start=2))
+print(result)

+ 1 - 1
views/construction_review/file_upload.py

@@ -158,7 +158,7 @@ async def file_upload(
 
 
         # 生成回调任务ID
-        callback_task_id = f"chain-{file_id}-{int(datetime.now().timestamp())}"
+        callback_task_id = f"{file_id}-{int(datetime.now().timestamp())}"
 
         # 记录文件信息
         file_info = {

+ 3 - 3
views/test_views.py

@@ -15,7 +15,7 @@ from sse_starlette import EventSourceResponse
 from starlette.responses import JSONResponse
 
 from foundation.agent.test_agent import test_agent_client
-from foundation.agent.generate.model_generate import test_generate_model_client
+from foundation.agent.generate.model_generate import generate_model_client
 from foundation.logger.loggering import server_logger
 from foundation.schemas.test_schemas import TestForm
 from foundation.utils.common import return_json, handler_err
@@ -42,7 +42,7 @@ async def generate_chat_endpoint(
         header_info = {
         }
         task_prompt_info = {"task_prompt": ""}
-        output = test_generate_model_client.get_model_generate_invoke(trace_id , task_prompt_info, 
+        output = generate_model_client.get_model_generate_invoke(trace_id , task_prompt_info, 
                                                                                  input_query, context)
         # 直接执行
         server_logger.debug(trace_id=trace_id, msg=f"【result】: {output}", log_type="agent/chat")
@@ -80,7 +80,7 @@ async def generate_stream_endpoint(
         async def event_generator():
             try:
                 # 流式处理查询 trace_id, task_prompt_info: dict, input_query, context=None
-                for chunk in test_generate_model_client.get_model_generate_stream(trace_id , task_prompt_info, 
+                for chunk in generate_model_client.get_model_generate_stream(trace_id , task_prompt_info, 
                                                                                  input_query, context):
                     # 发送数据块
                     yield {

Vissa filer visades inte eftersom för många filer har ändrats