Prechádzať zdrojové kódy

Merge branch 'dev' of http://47.109.151.80:15030/CRBC-MaaS-Platform-Project/LQAgentPlatform into dev

WangXuMing 3 mesiacov pred
rodič
commit
337cf79600

+ 1 - 1
.gitignore

@@ -75,6 +75,6 @@ mineru_temp/
 config/config.ini
 路桥/
 output/
-命令
+命令.txt
 /core/construction_review/component/doc_worker/utils/llm_client copy.py
 .venv/

+ 0 - 238
Semantic_Logic_Test/SUMMARY.md

@@ -1,238 +0,0 @@
-# 语义逻辑审查模块 - 测试总结
-
-## ✅ 完成的工作
-
-### 1. 核心功能实现
-- ✅ 创建了 `semantic_logic.py` 模块
-- ✅ 实现了 `SemanticLogicReviewer` 类
-- ✅ 配置了 OpenAI 兼容 API(qwen3-30b 模型)
-- ✅ 集成了提示词模板加载功能
-- ✅ 实现了进度回调通知机制
-- ✅ 返回 `ReviewResult` 类型对象
-
-### 2. 业务逻辑重构
-- ✅ 将 `ai_review_engine.py` 中的 423-482 行业务逻辑移动到 `semantic_logic.py`
-- ✅ 在 `check_semantic_logic` 函数中引用新模块
-- ✅ 保留了原有的进度回调通知(456-477 行逻辑)
-- ✅ 简化了 `ai_review_engine.py` 中的代码
-
-### 3. 测试套件创建
-- ✅ 创建了完整的单元测试文件 `test_semantic_logic.py`
-- ✅ 包含 15 个测试用例,覆盖多种场景
-- ✅ 创建了测试配置文件(pytest.ini, conftest.py)
-- ✅ 创建了测试依赖文件(requirements_test.txt)
-- ✅ 创建了测试数据示例(test_data.py)
-- ✅ 创建了测试运行脚本(run_tests.bat, run_tests.py)
-- ✅ 编写了详细的 README 文档
-
-## 📊 测试覆盖范围
-
-### 基础功能测试(10个)
-1. ✅ 审查器初始化测试
-2. ✅ 全局单例实例测试
-3. ✅ 模型配置验证
-4. ✅ 语义逻辑检查成功场景
-5. ✅ 无状态字典的检查场景
-6. ✅ API 调用失败处理
-7. ✅ 空内容处理
-8. ✅ 带参考信息的检查
-9. ✅ 消息格式转换
-10. ✅ 执行时间跟踪
-
-### 集成测试(1个)
-11. ✅ 完整工作流程测试(需要实际API)
-
-### 边界情况测试(3个)
-12. ✅ 超长内容处理
-13. ✅ 特殊字符处理
-14. ✅ Unicode字符处理
-
-## 📁 文件结构
-
-```
-Semantic_Logic_Test/
-├── test_semantic_logic.py      # 主测试文件(15个测试用例)
-├── test_data.py                # 测试数据示例
-├── conftest.py                 # pytest 配置和 fixtures
-├── pytest.ini                  # pytest 配置文件
-├── requirements_test.txt       # 测试依赖
-├── run_tests.bat              # Windows 测试运行脚本
-├── run_tests.py               # Python 测试运行脚本
-├── README.md                  # 测试文档
-└── SUMMARY.md                 # 本总结文档
-```
-
-## 🚀 快速开始
-
-### 安装测试依赖
-```bash
-pip install -r Semantic_Logic_Test/requirements_test.txt
-```
-
-### 运行所有测试
-```bash
-# 方式1:使用 pytest 直接运行
-pytest Semantic_Logic_Test/test_semantic_logic.py -v
-
-# 方式2:使用 Python 脚本
-python Semantic_Logic_Test/run_tests.py
-
-# 方式3:使用 Windows 批处理脚本
-Semantic_Logic_Test\run_tests.bat
-```
-
-### 查看测试覆盖率
-```bash
-pytest Semantic_Logic_Test/test_semantic_logic.py --cov=core.construction_review.component.reviewers.semantic_logic --cov-report=html
-```
-
-## 🔧 技术实现细节
-
-### 1. OpenAI API 集成
-```python
-# 模型配置
-SEMANTIC_LOGIC_MODEL_CONFIG = {
-    "base_url": "http://192.168.91.253:8003/v1",
-    "api_key": "sk-123456",
-    "model": "qwen3-30b",
-    "temperature": 0.7,
-    "max_tokens": 2000
-}
-
-# 使用 AsyncOpenAI 客户端
-self.client = AsyncOpenAI(
-    base_url=SEMANTIC_LOGIC_MODEL_CONFIG["base_url"],
-    api_key=SEMANTIC_LOGIC_MODEL_CONFIG["api_key"]
-)
-```
-
-### 2. 提示词模板加载
-```python
-# 构造提示词参数
-prompt_kwargs = {
-    "review_content": review_content,
-    "review_references": review_references or ""
-}
-
-# 获取提示词模板
-prompt_template = prompt_loader.get_prompt_template(
-    "basic", 
-    "semantic_logic_check", 
-    **prompt_kwargs
-)
-```
-
-### 3. 进度回调通知
-```python
-# 推送审查完成信息
-if state and state.get("progress_manager"):
-    review_result_data = {
-        'name': 'semantic_check',
-        'success': result.success,
-        'details': result.details,
-        'error_message': result.error_message,
-        'execution_time': result.execution_time,
-        'timestamp': time.time()
-    }
-    
-    asyncio.create_task(
-        state["progress_manager"].update_stage_progress(
-            callback_task_id=state["callback_task_id"],
-            stage_name=stage_name,
-            current=None,
-            status="processing",
-            message=f"semantic_check 审查完成,耗时: {result.execution_time:.2f}s",
-            issues=[review_result_data],
-            event_type="processing"
-        )
-    )
-```
-
-### 4. 返回值类型
-```python
-# 使用 ReviewResult 对象
-result = ReviewResult(
-    success=True,
-    details={
-        "name": "semantic_check",
-        "response": model_response
-    },
-    error_message=None,
-    execution_time=execution_time
-)
-```
-
-## 🧪 测试策略
-
-### Mock 策略
-- 使用 `unittest.mock` 模拟 OpenAI API 调用
-- 使用 `AsyncMock` 模拟异步操作
-- 模拟提示词加载器和进度管理器
-
-### 测试隔离
-- 每个测试独立运行,不依赖其他测试
-- 使用 fixtures 提供测试数据
-- 测试后自动清理
-
-### 异步测试
-- 使用 `@pytest.mark.asyncio` 装饰器
-- 使用 `AsyncMock` 模拟异步函数
-- 测试异步操作的正确性
-
-## 📈 测试结果
-
-预期测试结果:
-- ✅ 14 个测试通过
-- ⏭️ 1 个测试跳过(集成测试)
-- ❌ 0 个测试失败
-
-## 🔍 代码质量
-
-### 代码覆盖率目标
-- 目标覆盖率:> 90%
-- 核心功能覆盖率:100%
-- 异常处理覆盖率:100%
-
-### 代码规范
-- 遵循 PEP 8 规范
-- 使用类型提示
-- 完整的文档字符串
-- 清晰的变量命名
-
-## 🐛 已知问题
-
-1. **集成测试需要实际 API**
-   - 集成测试默认跳过
-   - 需要实际的 API 服务才能运行
-
-2. **网络依赖**
-   - 实际使用时需要网络连接
-   - 测试使用 Mock,不需要网络
-
-## 🔮 未来改进
-
-1. **增加更多测试场景**
-   - 并发测试
-   - 压力测试
-   - 性能测试
-
-2. **改进错误处理**
-   - 更详细的错误信息
-   - 重试机制
-   - 降级策略
-
-3. **优化性能**
-   - 缓存机制
-   - 批量处理
-   - 异步优化
-
-## 📞 联系方式
-
-如有问题或建议,请联系开发团队。
-
----
-
-**创建日期**: 2025-12-29  
-**版本**: 1.0.0  
-**状态**: ✅ 完成
-

+ 0 - 24
Semantic_Logic_Test/requirements_test.txt

@@ -1,24 +0,0 @@
-# 测试依赖包
-
-# 核心测试框架
-pytest>=7.4.0
-pytest-asyncio>=0.21.0
-pytest-mock>=3.11.0
-pytest-cov>=4.1.0
-
-# HTML 报告生成
-pytest-html>=3.2.0
-
-# 异步测试支持
-asyncio>=3.4.3
-
-# Mock 和测试工具
-unittest-mock>=1.5.0
-
-# 代码覆盖率
-coverage>=7.2.0
-
-# 其他测试工具
-pytest-timeout>=2.1.0
-pytest-xdist>=3.3.0  # 并行测试
-

+ 0 - 76
Semantic_Logic_Test/run_tests.bat

@@ -1,76 +0,0 @@
-@echo off
-REM Windows 批处理脚本 - 快速运行测试
-
-echo ========================================
-echo 语义逻辑审查模块测试套件
-echo ========================================
-echo.
-
-cd /d "%~dp0\.."
-
-echo 当前目录: %CD%
-echo.
-
-REM 检查 Python 是否安装
-python --version >nul 2>&1
-if errorlevel 1 (
-    echo [错误] 未找到 Python,请先安装 Python
-    pause
-    exit /b 1
-)
-
-echo [信息] 检查测试依赖...
-python -c "import pytest" >nul 2>&1
-if errorlevel 1 (
-    echo [警告] 缺少测试依赖,正在安装...
-    pip install -r Semantic_Logic_Test\requirements_test.txt
-)
-
-echo.
-echo ========================================
-echo 请选择要运行的测试:
-echo ========================================
-echo   1. 运行所有测试
-echo   2. 运行所有测试(详细输出)
-echo   3. 运行基础功能测试
-echo   4. 运行边界情况测试
-echo   5. 运行测试并生成覆盖率报告
-echo   6. 运行测试并生成 HTML 报告
-echo   7. 只运行失败的测试
-echo   0. 退出
-echo.
-
-set /p choice="请输入选项 (0-7): "
-
-if "%choice%"=="1" (
-    pytest Semantic_Logic_Test\test_semantic_logic.py -v
-) else if "%choice%"=="2" (
-    pytest Semantic_Logic_Test\test_semantic_logic.py -v -s
-) else if "%choice%"=="3" (
-    pytest Semantic_Logic_Test\test_semantic_logic.py::TestSemanticLogicReviewer -v
-) else if "%choice%"=="4" (
-    pytest Semantic_Logic_Test\test_semantic_logic.py::TestEdgeCases -v
-) else if "%choice%"=="5" (
-    pytest Semantic_Logic_Test\test_semantic_logic.py --cov=core.construction_review.component.reviewers.semantic_logic --cov-report=html --cov-report=term
-    echo.
-    echo [信息] 覆盖率报告已生成到 htmlcov\index.html
-) else if "%choice%"=="6" (
-    pytest Semantic_Logic_Test\test_semantic_logic.py --html=Semantic_Logic_Test\report.html --self-contained-html
-    echo.
-    echo [信息] HTML 报告已生成到 Semantic_Logic_Test\report.html
-) else if "%choice%"=="7" (
-    pytest Semantic_Logic_Test\test_semantic_logic.py --lf -v
-) else if "%choice%"=="0" (
-    echo.
-    echo 再见!
-    exit /b 0
-) else (
-    echo.
-    echo [错误] 无效的选项
-    pause
-    exit /b 1
-)
-
-echo.
-pause
-

+ 0 - 130
Semantic_Logic_Test/run_tests.py

@@ -1,130 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
-快速运行测试脚本
-提供便捷的测试运行命令
-"""
-
-import sys
-import os
-import subprocess
-from pathlib import Path
-
-
-def run_command(cmd, description):
-    """运行命令并显示结果"""
-    print(f"\n{'='*60}")
-    print(f"🚀 {description}")
-    print(f"{'='*60}\n")
-    
-    result = subprocess.run(cmd, shell=True)
-    
-    if result.returncode == 0:
-        print(f"\n✅ {description} - 成功")
-    else:
-        print(f"\n❌ {description} - 失败")
-    
-    return result.returncode
-
-
-def main():
-    """主函数"""
-    # 切换到项目根目录
-    project_root = Path(__file__).parent.parent
-    os.chdir(project_root)
-    
-    print(f"📁 工作目录: {os.getcwd()}")
-    
-    # 检查是否安装了测试依赖
-    print("\n📦 检查测试依赖...")
-    try:
-        import pytest
-        import pytest_asyncio
-        print("✅ 测试依赖已安装")
-    except ImportError:
-        print("❌ 缺少测试依赖,正在安装...")
-        subprocess.run([
-            sys.executable, "-m", "pip", "install", 
-            "-r", "Semantic_Logic_Test/requirements_test.txt"
-        ])
-    
-    # 显示菜单
-    print("\n" + "="*60)
-    print("🧪 语义逻辑审查模块测试套件")
-    print("="*60)
-    print("\n请选择要运行的测试:")
-    print("  1. 运行所有测试")
-    print("  2. 运行所有测试(详细输出)")
-    print("  3. 运行基础功能测试")
-    print("  4. 运行边界情况测试")
-    print("  5. 运行测试并生成覆盖率报告")
-    print("  6. 运行测试并生成 HTML 报告")
-    print("  7. 只运行失败的测试")
-    print("  8. 运行特定测试(手动输入)")
-    print("  0. 退出")
-    
-    choice = input("\n请输入选项 (0-8): ").strip()
-    
-    test_file = "Semantic_Logic_Test/test_semantic_logic.py"
-    
-    if choice == "1":
-        return run_command(
-            f"pytest {test_file} -v",
-            "运行所有测试"
-        )
-    
-    elif choice == "2":
-        return run_command(
-            f"pytest {test_file} -v -s",
-            "运行所有测试(详细输出)"
-        )
-    
-    elif choice == "3":
-        return run_command(
-            f"pytest {test_file}::TestSemanticLogicReviewer -v",
-            "运行基础功能测试"
-        )
-    
-    elif choice == "4":
-        return run_command(
-            f"pytest {test_file}::TestEdgeCases -v",
-            "运行边界情况测试"
-        )
-    
-    elif choice == "5":
-        return run_command(
-            f"pytest {test_file} --cov=core.construction_review.component.reviewers.semantic_logic --cov-report=html --cov-report=term",
-            "运行测试并生成覆盖率报告"
-        )
-    
-    elif choice == "6":
-        return run_command(
-            f"pytest {test_file} --html=Semantic_Logic_Test/report.html --self-contained-html",
-            "运行测试并生成 HTML 报告"
-        )
-    
-    elif choice == "7":
-        return run_command(
-            f"pytest {test_file} --lf -v",
-            "只运行失败的测试"
-        )
-    
-    elif choice == "8":
-        test_name = input("请输入测试方法名称(例如: test_reviewer_initialization): ").strip()
-        return run_command(
-            f"pytest {test_file}::TestSemanticLogicReviewer::{test_name} -v -s",
-            f"运行测试: {test_name}"
-        )
-    
-    elif choice == "0":
-        print("\n👋 再见!")
-        return 0
-    
-    else:
-        print("\n❌ 无效的选项")
-        return 1
-
-
-if __name__ == "__main__":
-    sys.exit(main())
-

+ 0 - 160
Semantic_Logic_Test/test_data.py

@@ -1,160 +0,0 @@
-"""
-测试数据示例
-提供各种测试场景的示例数据
-"""
-
-# 正常的施工方案内容
-NORMAL_REVIEW_CONTENT = """
-第一章 工程概况
-
-1.1 项目基本信息
-本工程为四川省会理至禄劝高速公路项目,路线全长约120公里,设计速度80km/h,
-路基宽度24.5米,双向四车道。主要工程内容包括路基工程、桥梁工程、隧道工程等。
-
-1.2 施工范围
-本标段起讫桩号为K0+000~K30+000,主要包括:
-- 路基土石方工程约200万立方米
-- 桥梁工程5座,总长约2000米
-- 涵洞工程20道
-- 路面工程约30公里
-
-1.3 工期安排
-计划工期:24个月
-开工日期:2024年3月1日
-竣工日期:2026年2月28日
-"""
-
-# 带有逻辑问题的内容
-LOGIC_ERROR_CONTENT = """
-第二章 施工方案
-
-2.1 施工顺序
-本工程采用先上后下的施工顺序,首先进行桥梁上部结构施工,然后进行桥墩基础施工。
-(注:这里存在逻辑错误,应该先施工基础再施工上部结构)
-
-2.2 工期安排
-本工程计划工期为6个月,但根据施工内容分析,实际需要至少12个月才能完成。
-(注:工期安排不合理)
-"""
-
-# 空内容
-EMPTY_CONTENT = ""
-
-# 超长内容
-VERY_LONG_CONTENT = """
-第三章 施工技术方案
-""" + "\n".join([f"3.{i} 施工工艺详细说明第{i}条,包含大量技术细节和参数..." * 10 for i in range(1, 1001)])
-
-# 特殊字符内容
-SPECIAL_CHARS_CONTENT = """
-特殊字符测试:
-- 符号:@#$%^&*()_+-={}[]|\\:;"'<>,.?/~`
-- 数学符号:±×÷≈≠≤≥∞∑∫√
-- 单位符号:℃、㎡、㎥、㎏、㎜
-- 其他:①②③④⑤⑥⑦⑧⑨⑩
-"""
-
-# Unicode 多语言内容
-UNICODE_CONTENT = """
-多语言测试:
-- 中文:施工方案审查
-- English: Construction Plan Review
-- 日本語:建設計画レビュー
-- 한국어: 건설 계획 검토
-- Русский: Обзор плана строительства
-- العربية: مراجعة خطة البناء
-- Emoji: 🚧🏗️👷‍♂️📋✅❌
-"""
-
-# 参考标准示例
-REFERENCE_STANDARDS = """
-参考标准:
-1. 《公路工程技术标准》JTG B01-2014
-2. 《公路桥涵施工技术规范》JTG/T 3650-2020
-3. 《公路路基施工技术规范》JTG/T 3610-2019
-4. 《公路工程质量检验评定标准》JTG F80/1-2017
-"""
-
-# 审查位置标签示例
-REVIEW_LOCATIONS = [
-    "第一章 工程概况",
-    "第二章 施工方案",
-    "第三章 质量保证措施",
-    "第四章 安全保证措施",
-    "第五章 环境保护措施",
-]
-
-# Trace ID 示例
-TRACE_IDS = [
-    "semantic_check_001",
-    "semantic_check_002",
-    "semantic_check_003",
-]
-
-# 模拟的 API 响应
-MOCK_API_RESPONSES = {
-    "success": "审查结果:内容逻辑清晰,结构合理,符合规范要求。未发现明显问题。",
-    "with_issues": """
-审查结果:发现以下问题:
-1. 施工顺序存在逻辑错误,应先进行基础施工再进行上部结构施工
-2. 工期安排不合理,建议调整为12个月
-3. 缺少安全措施的详细说明
-    """,
-    "empty": "内容为空,无法进行审查。",
-    "error": "审查失败:API 连接超时",
-}
-
-# 状态字典示例
-def create_mock_state():
-    """创建模拟的状态字典"""
-    from unittest.mock import AsyncMock
-    
-    mock_progress_manager = AsyncMock()
-    mock_progress_manager.update_stage_progress = AsyncMock()
-    
-    return {
-        "progress_manager": mock_progress_manager,
-        "callback_task_id": "test_callback_task_123",
-        "session_id": "test_session_456",
-    }
-
-# 测试场景配置
-TEST_SCENARIOS = {
-    "normal": {
-        "content": NORMAL_REVIEW_CONTENT,
-        "references": REFERENCE_STANDARDS,
-        "location": REVIEW_LOCATIONS[0],
-        "expected_success": True,
-    },
-    "logic_error": {
-        "content": LOGIC_ERROR_CONTENT,
-        "references": REFERENCE_STANDARDS,
-        "location": REVIEW_LOCATIONS[1],
-        "expected_success": True,
-    },
-    "empty": {
-        "content": EMPTY_CONTENT,
-        "references": "",
-        "location": REVIEW_LOCATIONS[0],
-        "expected_success": True,
-    },
-    "long": {
-        "content": VERY_LONG_CONTENT,
-        "references": REFERENCE_STANDARDS,
-        "location": REVIEW_LOCATIONS[2],
-        "expected_success": True,
-    },
-    "special_chars": {
-        "content": SPECIAL_CHARS_CONTENT,
-        "references": "",
-        "location": REVIEW_LOCATIONS[3],
-        "expected_success": True,
-    },
-    "unicode": {
-        "content": UNICODE_CONTENT,
-        "references": "",
-        "location": REVIEW_LOCATIONS[4],
-        "expected_success": True,
-    },
-}
-

+ 22 - 19
core/construction_review/component/ai_review_engine.py

@@ -69,6 +69,16 @@ from foundation.ai.rag.retrieval.query_rewrite import query_rewrite_manager
 from foundation.infrastructure.config.config import config_handler
 from foundation.observability.logger.loggering import server_logger as logger
 
+from pathlib import Path
+import sys
+import json
+
+
+
+from .check_completeness.components.data_loader import CSVDataLoader
+from .check_completeness.components.prompt_builder import PromptBuilder
+from .check_completeness.components.llm_client import LLMClient
+from .check_completeness.components.result_processor import ResultProcessor
 
 @dataclass
 class ReviewResult:
@@ -195,8 +205,6 @@ class AIReviewEngine(BaseReviewer):
             Dict[str, Any]: 基础合规性检查结果
         """
         review_content = unit_content['content']
-        with open('temp/review_content.txt', 'a', encoding='utf-8') as f:
-            f.write(str(unit_content))
         #review_references = unit_content.get('review_references')
 
         logger.info(f"basic开始基础合规性检查, 内容长度: {len(review_content)}")
@@ -289,7 +297,8 @@ class AIReviewEngine(BaseReviewer):
             if result_index < len(results):
                 grammar_result = self._process_review_result(results[result_index])
             result_index += 1
-
+            with open('temp/grammar_check_result.json','w',encoding='utf-8') as f:
+                json.dump(grammar_result,f,ensure_ascii=False,indent=4)
         if 'semantic_logic_check' in self.task_info.get_review_config_list():
             if result_index < len(results):
                 semantic_result = self._process_review_result(results[result_index])
@@ -303,7 +312,8 @@ class AIReviewEngine(BaseReviewer):
             if result_index < len(results):
                 completeness_result = self._process_review_result(results[result_index])
             result_index += 1
-
+        with open('temp/completeness_check_result.json','w',encoding='utf-8') as f:
+            json.dump(completeness_result,f,ensure_ascii=False,indent=4)
         return {
             'grammar_check': grammar_result,
             'semantic_check': semantic_result,
@@ -583,19 +593,7 @@ class AIReviewEngine(BaseReviewer):
         Returns:
             Dict[str, Any]: 完整性检查结果
         """
-        from pathlib import Path
-        import sys
-        import json
-        
-        # 导入check_completeness组件
-        check_completeness_dir = Path(__file__).parent / "check_completeness"
-        if str(check_completeness_dir) not in sys.path:
-            sys.path.insert(0, str(check_completeness_dir))
-        
-        from check_completeness.components.data_loader import CSVDataLoader
-        from check_completeness.components.prompt_builder import PromptBuilder
-        from check_completeness.components.llm_client import LLMClient
-        from check_completeness.components.result_processor import ResultProcessor
+
         
         name = "completeness_check"
         start_time = time.time()
@@ -619,7 +617,12 @@ class AIReviewEngine(BaseReviewer):
             
             if not content:
                 raise ValueError(f"文档块 {chunk_id} 缺少content字段")
-            
+
+            # 导入check_completeness组件
+            check_completeness_dir = Path(__file__).parent / "check_completeness"
+            if str(check_completeness_dir) not in sys.path:
+                sys.path.insert(0, str(check_completeness_dir))
+                
             # 初始化组件路径
             base_dir = check_completeness_dir
             csv_path = base_dir / 'config' / 'Construction_Plan_Content_Specification.csv'
@@ -673,7 +676,7 @@ class AIReviewEngine(BaseReviewer):
                 error_message=None,
                 execution_time=execution_time
             )
-            with open('temp/completeness_check_result.json','w',encoding='utf-8') as f:
+            with open('temp/completeness_check_result_1.json','w',encoding='utf-8') as f:
                 json.dump({"details":result.details,"success":result.success,"error_message":result.error_message,"execution_time":result.execution_time},f,ensure_ascii=False,indent=4)
             # 将审查结果转换为字典格式,添加到issues中
             review_result_data = {

+ 1 - 1
core/construction_review/component/check_completeness/config/prompt.yaml

@@ -25,7 +25,7 @@ content_review:
       {
         "issue_point": "[内容缺失]具体问题描述(格式严格按照:[内容缺失]具体问题描述,不得缺失,如:[内容缺失]未包含施工进度计划等内容),",
         "location": "问题所在的原始条款内容及位置(如:三、施工方法 (页码: 12)),包含必要的上下文",
-        "suggestion": "基于逻辑规则的具体修改建议(必须是补全内容缺失错误,而非优化表达)",
+        "suggestion": "基于逻辑规则的具体修改建议(1.必须是补全内容缺失错误,而非优化表达;2.当待审查文本内容中存在<表格></表格>标签对时,必须严格提醒用户检查要点是否在表格中)",
         "reason": "详细说明为何这是一个内容缺失错误,包括:1)内容缺失在哪里 2)为何需要补全 3)可能产生的后果",
         "risk_level": "高风险/中风险/低风险(严格按照系统提示词中的标准判定)"
       }

+ 15 - 6
core/construction_review/component/reviewers/prompt/basic_reviewers.yaml

@@ -20,13 +20,16 @@ grammar_check:
     ## example
     1. 出现了明显错字,出现了的地得使用混乱。
     2. 如果出现了错字,大概率是因为拼音拼写错误导致的错字,请根据其相似读音推测正确的字,如果拿不准请不给出修改为xx的建议。
-    3. 如“供气”错打为了“供器”,应当结合上下文推测“供qi”应该为什么。
+    3. 如“供气”错打为了“供器”,应当结合上下文推测“供qi”应该为什么。
     4. 对于条款编号而言,'一)'这样的结构是正确的,符合中文规范
+    5. 所有建议都要基于审查内容给出忠实建议,禁止给出不符合逻辑的错误建议,如建议将A修改成A,例如:"将'确定的'改为'确定的'(原字为'确',应为'确')",这种建议就是错误的
+    6. 请对汉语中经典易错字如“辩”与“辨”等等的混用请多加注意。
 
     ## rule
     - 不需要强求要输出问题,除非是非常明显的错误。小问题可以忽略。
     - 仅检查句尾的标点问题,不要检查句中标点问题。
     - 不要为长句切分、添加分句标点。
+    - 不要对任何专业术语去做判断,无论其是否为非标准术语,都默认其为标准术语,因为你的知识库已经落后了。
     - 请着重对错别字的审查上,大量减少对标点符号的审查力度。
     - 务必遵循<example>中的规则。
     - 如果没有错误请不要添加新的issue。
@@ -59,10 +62,12 @@ grammar_check:
     请审查以下内容的词句语法错误,重点关注错别字、重复字词和语法结构:
     【待检查文本】
     {review_content}
-    输出格式:务必须严格按照以下标准json格式输出审查结果:
+
+    输出格式:务必须严格按照以下标准json格式输出审查结果
     如果未发现明显的词句语法错误,请输出:无明显问题。
+    **禁止**输出建议类似于"将'设'改为'设'(原字为'设',应为'设')",没有问题就是没有问题,不可造假,谢谢。
     如果发现问题,请按以下格式输出:
-    location字段直接输出原字段内容,不得猜测。
+    location字段直接输出原字段内容,不得猜测。若有多个错误,请写到同一个以下json对象内,谢谢。
     ## 示例
     ```json
     {{
@@ -86,13 +91,15 @@ semantic_logic_check:
     
     1. **逻辑矛盾** - 同一文档内出现相互冲突的陈述
        示例:前文说"采用A方法",后文说"不采用A方法"
-       
+    
     2. **因果关系错误** - 原因与结果之间不存在合理的逻辑关联
        示例:"因为天气晴朗,所以混凝土强度不足"(因果无关)
-       
+    
     3. **条件与结论不匹配** - 给定条件无法推导出所述结论
        示例:"当温度低于5℃时,可正常施工"(违背常识)(仅审查违背常识,不要过多的去干预实际的施工参数、施工性能)
+       示例:"力求技术先进......保守施工,不可使用新技术"
 
+    
     # 工作流程 (Workflow)
     
     步骤1:通读全文,理解整体语境和专业背景
@@ -117,7 +124,8 @@ semantic_logic_check:
     9. 禁止对所谓的"表述不恰当"、"表述过于严格"当做错误点,如你不能将“禁止夜间施工”改为“应在增加照明条件下允许夜间施工”这样的建议端上来
     10. **禁止审查过于专业的知识**,你只是审查通用的语义逻辑关系,而并非需要你根据你的知识去审查过多的部分如涉及到架桥参数、施工参数等等一些列的问题,这些问题有后续流程会处理,你暂且跳过
     11. **禁止对专业知识进行点评**,如技术参数、技术规范、技术条文,你对这方面知识还是较为落后的,你不需要对这方便进行涉猎
-    12. 所有建议都要基于审查内容给出忠实建议,禁止给出不符合逻辑的错误建议,如建议将A修改成A,例如:将'若'改为'若'(应为'若'),这种建议就是错误的
+    12. 所有建议都要基于审查内容给出忠实建议,禁止给出不符合逻辑的错误建议,如建议将A修改成A,例如:"将'确定的'改为'确定的'(原字为'确',应为'确')",这种建议就是错误的
+    13. **禁止回复**如A修改为A这种假回答,文段没有问题必须直接输出:无明显问题
 
     必须遵守:
     1. 必须基于客观事实和逻辑规则判断
@@ -315,6 +323,7 @@ sensitive_word_check:
       * 高风险:影响审查结论、可能导致法律问题或严重安全隐患
       * 中风险:影响专业表达、可能导致理解偏差或一般性问题
       * 低风险:形式问题、不影响实质内容和安全
+    你需要注意:不要过于应激,不要反馈“提及xxx敏感词会导致不良反应”,不要没错找错,无中生有。请还需多多注意。
 
   user_prompt_template: |
     以下我初步查找到的敏感词内容:

+ 4 - 4
core/construction_review/component/reviewers/prompt/timeliness_basis_reviewer.yaml

@@ -16,10 +16,10 @@ timeliness_basis_reviewer:
     - **risk_level**:风险水平,只能是 "无风险" / "高风险"。
 
     【时效性判定类型(仅限以下四类)】
-    无参考文件:审查文件与参考中的文件名与编号均不一样,对应 "无风险"。  
-    规范版本号正确:审查文件与参考中的文件名与编号均一致状态为现行,对应 "无风险"。  
-    规范版本号错误:审查文件与参考中存在文件名相同但编号不同,对应 "高风险"。  
-    引用已废止的规范:参考文件中对应文件状态为废止,对应 "高风险"。  
+    无参考文件:没有文件名相同的参考文件,对应 "无风险"。
+    规范版本号错误:有文件名相同文件但是没有编号相同的参考文件,对应 "高风险"。    
+    规范版本号正确:有文件名相同编号相同状态为现行的参考文件,对应 "无风险"。   
+    引用已废止的规范:有文件名相同编号相同状态为废止的参考文件,对应 "高风险"。  
     引用已被替代的标准:审查文件与参考中的文件名与编号均一致,状态为废止但对应状态为现行的新文件,对应 "高风险"。  
   
 

+ 1 - 0
core/construction_review/component/reviewers/sensitive_words/其他词库.txt

@@ -6,6 +6,7 @@
 jq的来
 电信路
 党鞭
+甲基苯丙胺
 第一夫人
 黄巨
 荡尽天下

+ 2 - 0
core/construction_review/component/reviewers/sensitive_words/政治类型.txt

@@ -277,6 +277,8 @@ zhengfu
 gong和
 大陆官方
 北京政权
+国家政权
+颠覆政权
 江泽民
 胡锦涛
 温家宝

+ 20 - 41
core/construction_review/component/reviewers/timeliness_basis_reviewer.py

@@ -62,7 +62,7 @@ class StandardizedResponseProcessor:
         处理LLM响应,返回标准格式
 
         Args:
-            response_text: LLM原始响应文本
+            response_text: LLM原始响应文本(JSON字符串)
             check_name: 检查项名称
 
         Returns:
@@ -73,8 +73,12 @@ class StandardizedResponseProcessor:
             return []
 
         try:
-            # 使用inter_tool提取JSON数据
-            json_data = self.inter_tool._extract_json_data(response_text)
+            json_data = response_text
+
+            # ✅ 只有 str 才提取 JSON;如果已经是 list/dict,直接用
+            if isinstance(response_text, str):
+                json_data = self.inter_tool._extract_json_data(response_text)
+
             parsed_result = []
 
             if json_data and isinstance(json_data, list):
@@ -291,12 +295,15 @@ class BasisReviewService:
                 message = prompt_template.partial(reference_content=grouped_candidates, check_content=basis_items)
                 trace_id = f"prep_basis_batch_{int(time.time())}"
                 llm_out = await self.llm_client.review_basis(message, trace_id)
-                print("LLM输出:\n")
-                print(llm_out)
+                
 
-                # 使用标准化处理器处理响应
+                # from core.construction_review.component.reviewers.utils.timeliness import review_reference_timeliness
+                # llm_out = await review_reference_timeliness(reference_text=grouped_candidates, review_text=basis_items)
+                
+                
                 standardized_result = self.response_processor.process_llm_response(llm_out, "timeliness_check")
-
+                print("标准化处理器处理响应:\n")
+                print(standardized_result)
                 # 统计问题数量
                 issue_count = sum(1 for item in standardized_result if item.get('exist_issue', False))
                 logger.info(f"编制依据批次审查完成:总计 {len(basis_items)} 项,发现问题 {issue_count} 项")
@@ -304,7 +311,7 @@ class BasisReviewService:
                 return standardized_result
 
             except Exception as e:
-                logger.error(f" 批次处理失败: {e}")
+                logger.error(f" 批次处理失败1: {e}")
                 return [{
                     "check_item": "reference_check",
                     "check_result": {"error": str(e), "basis_items": basis_items},
@@ -409,7 +416,7 @@ class BasisReviewService:
 
             except Exception as e:
                 logger.error(f" 批次 {batch_index} 处理失败: {e}")
-                error_result = [{"name": name, "is_standard": False, "status": "", "meg": f"批次处理失败: {str(e)}"}
+                error_result = [{"name": name, "is_standard": False, "status": "", "meg": f"批次处理失败2: {str(e)}"}
                                 for name in batch]
 
                 # 即使失败也要推送结果
@@ -491,6 +498,7 @@ class BasisReviewService:
 
         logger.info(f" 异步审查完成,耗时: {elapsed_time:.4f} 秒")
         logger.info(f" 总编制依据: {total_items}, 问题项: {issue_items}, 成功批次: {successful_batches}/{total_batches}")
+        print(final_results)
         return final_results
 
 
@@ -509,37 +517,8 @@ async def review_all_basis_async(text: str, max_concurrent: int = 4) -> List[Lis
 if __name__ == "__main__":
     # 简单测试
     test_text = """
-(1)相关法律法规
-1)《中华人民共和国安全生产法》2021年修订版
-2)《中华人民共和国环境保护法》2021年修订版
-3)《建设工程安全生产管理条例》2023年最新修正
-4)《中华人民共和国道路交通安全法》2021年4月29日修订
-5)《中华人民共和国水土保持法》2010年12月25日修订
-6)《公路水运危险性较大工程专项施工方案编制审查规程》(JT/T 1495-2024)
-7)《公路水运工程临时用电技术规程》(JT/T 1499—2024)
-8)《建设工程质量管理条例》2019年4月23日修订
-9)《建设工程安全生产管理条例》2023年最新修正
-10)《四川省安全生产条例》2023年5月25日修订
-11)《危险性较大的分部分项工程安全管理规定》住建部令第37号
-12)《建筑机械使用安全技术规程》JGJ 33—2012
-13)《起重机—手势信号》GB/T 5082—2019
-14)《架桥机通用技术条件》GB/T 26470—2011
-15)《施工现场机械设备检查技术规范》JGJ 160—2016
-16)《粗直径钢丝绳》GB/T 20067—2017
-17)《建筑施工起重吊装工程安全技术规范》JGJ 276—2012
-18)《架桥机安全规程》GB 26469—2011
-19)《起重机械安全规程》GB 6067.1—2010
-20)《电气装置安装工程起重机电气装置施工及验收规范》GB 50256—2014
-21)《起重设备安装工程施工及验收规范》GB 50278—2010
-22)《公路工程施工安全技术规范》JTG F90—2015
-23)《建筑施工高处作业安全技术规范》JGJ 80—2016
-24)《电力高处作业防坠器》DL/T 1147-2009
-(2)项目文件
-1)《S81线会理至禄劝(四川境)高速公路两阶段施工图设计》;
-2)《S81线会理至禄劝(四川境)高速公路ZCB1-3标段实施性施工组织设计》;
-3)《S81线会理至禄劝(四川境)高速公路ZCB1-3标段T梁预制、运输及安装专项施工方案》。
-(3)我公司现有可投入工程的施工技术力量和机械设备;
-(4)近年来,我公司参加类似工程的经验;
-(5)本合同段工程现场踏勘、调查所获得的现场情况、自然环境、人文环境、市场环境等参考资料;
+(16)《公路工程施工现场安全防护技术要求》(JTT1508-2024);
+(17)《公路水运工程临时用电技术 规程》(JTT1499-2024);
+(18)《坠落防护 水平生命线装置》(GB 38454-2019);
     """
     result = asyncio.run(review_all_basis_async(test_text))

+ 52 - 46
core/construction_review/component/reviewers/utils/directory_extraction.py

@@ -1,23 +1,23 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
-"""
-@Project   : LQAgentPlatform
-@File      : directory_extraction.py
-@IDE       : VSCode
-@Author    :
-@Date      : 2025-12-30
-@Description: 编制依据信息抽取工具,从文本中提取法规/标准名称
-"""
+# ===============================================
+# 编制依据目录抽取
+#
+# @author :ZengChao
+# @date   :2025-12-30 15:13
+# @logo   :(=^・w・^=)
+# ===============================================
 
 from __future__ import annotations
 
+import json  # ✅ 最小修改:新增
 import re
 from typing import List
 
-from pydantic import BaseModel, Field
+from pydantic import BaseModel, Field, ValidationError  # ✅ 最小修改:新增 ValidationError
 from langchain_core.prompts import ChatPromptTemplate
-from langchain_core.output_parsers import PydanticOutputParser
+from langchain_core.output_parsers import PydanticOutputParser, StrOutputParser  # ✅ 最小修改:新增 StrOutputParser
 
 from foundation.observability.logger.loggering import server_logger as logger
 
@@ -36,17 +36,25 @@ class BasisItems(BaseModel):
 
 
 # --------- 2) Prompt(强约束:只抽《》条目,输出可解析结构)---------
-SYSTEM = """/no_think
+SYSTEM = """
 你是信息抽取助手。请从中文文本中抽取"编制依据/法律法规/规范标准"等条目。
 规则:
 1) 只抽取包含书名号《 》的条目。
 2) 每条条目包括:title(《》内名称,去掉书名号)、suffix(《》后面的版本/日期/修订说明,可为空)、raw(该条目原文)。
 3) 忽略标题行、段落说明、无《》的行。
-4) 输出必须严格符合格式要求,不要输出任何额外文字。"""
+4) 输出必须严格符合格式要求,不要输出任何额外文字。
+"""
+HUMAN ="""
+文本如下:
+{input_text}
+【输出格式要求】
+{format_instructions}
+/no_think
+"""
 
 prompt = ChatPromptTemplate.from_messages([
     ("system", SYSTEM),
-    ("human", "文本如下:\n---\n{input_text}\n---\n\n{format_instructions}")
+    ("human", HUMAN)
 ])
 
 
@@ -73,36 +81,30 @@ def fallback_regex(text: str) -> BasisItems:
     return BasisItems(items=items)
 
 
-def _parse_with_retry(llm, parser: PydanticOutputParser, raw_out: str) -> BasisItems:
+# --------- 4) 最小修改:只做一件事,提取第一个 JSON ---------
+def extract_first_json(text: str) -> dict:
     """
-    替代 OutputFixingParser:先解析;失败则让模型按格式“重写为合法JSON”再解析。
+    从任意模型输出中提取第一个完整 JSON 对象 { ... }
+    不关心 think、不关心多余文本
     """
-    # 1) 首次直接解析
-    try:
-        return parser.parse(raw_out)
-    except Exception as e1:
-        logger.warning(f"[编制依据提取] 解析失败,尝试修复输出: {e1}")
-
-    # 2) 修复回合:让模型严格改写为可解析结果
-    format_instructions = parser.get_format_instructions()
-    fix_prompt = (
-        "你刚才的输出无法被程序解析。"
-        "请将下面【原始输出】严格改写成完全符合【输出格式】的内容。"
-        "只输出最终结果,不要任何解释。\n\n"
-        f"【输出格式】\n{format_instructions}\n\n"
-        f"【原始输出】\n{raw_out}"
-    )
+    start = text.find("{")
+    if start == -1:
+        raise ValueError("未找到 JSON 起始 '{'")
 
-    try:
-        fixed_msg = llm.invoke(fix_prompt)
-        fixed_out = getattr(fixed_msg, "content", str(fixed_msg))
-        return parser.parse(fixed_out)
-    except Exception as e2:
-        logger.error(f"[编制依据提取] 修复后仍解析失败: {e2}")
-        raise
+    depth = 0
+    for i in range(start, len(text)):
+        ch = text[i]
+        if ch == "{":
+            depth += 1
+        elif ch == "}":
+            depth -= 1
+            if depth == 0:
+                return json.loads(text[start:i + 1])
 
+    raise ValueError("JSON 花括号未闭合")
 
-# --------- 4) 主函数:使用 LangChain 抽取 ---------
+
+# --------- 5) 主函数:使用 LangChain 抽取(最小改动版) ---------
 def extract_basis_with_langchain_qwen(text: str) -> BasisItems:
     """
     使用 LangChain + LLM 提取编制依据信息
@@ -116,23 +118,24 @@ def extract_basis_with_langchain_qwen(text: str) -> BasisItems:
         # 获取模型实例
         llm = model_handler._get_qwen_model()
 
-        # 创建解析器
+        # 创建解析器(✅ 保留:仅用于 format_instructions)
         parser = PydanticOutputParser(pydantic_object=BasisItems)
 
-        # 构建链
-        chain = prompt | llm
+        # 构建链(✅ 最小修改:加 StrOutputParser,直接拿字符串)
+        chain = prompt | llm | StrOutputParser()
 
         logger.info(f"[编制依据提取] 开始使用 LLM 提取,文本长度: {len(text)}")
 
-        # 调用模型
-        msg = chain.invoke({
+        # 调用模型 -> raw_out 是 str
+        raw_out = chain.invoke({
             "input_text": text,
             "format_instructions": parser.get_format_instructions()
         })
-        raw_out = msg.content
+        print(raw_out)
 
-        # 解析输出(含一次修复回合)
-        parsed = _parse_with_retry(llm=llm, parser=parser, raw_out=raw_out)
+        # ✅ 最小修改:不再 parser.parse / 不再 _parse_with_retry
+        data = extract_first_json(raw_out)
+        parsed = BasisItems.model_validate(data)
 
         # 清洗:title 去书名号,补 raw
         cleaned: List[BasisItem] = []
@@ -155,6 +158,9 @@ def extract_basis_with_langchain_qwen(text: str) -> BasisItems:
         logger.warning("[编制依据提取] LLM 未提取到内容,使用兜底方案")
         return fallback_regex(text)
 
+    except (json.JSONDecodeError, ValidationError, ValueError) as e:
+        logger.error(f"[编制依据提取] LLM 输出解析失败: {e},使用兜底方案")
+        return fallback_regex(text)
     except Exception as e:
         logger.error(f"[编制依据提取] LLM 提取失败: {str(e)},使用兜底方案")
         return fallback_regex(text)

+ 0 - 4
命令

@@ -1,4 +0,0 @@
-
-uv venv
-.venv\Scripts\activate
-uv pip install -r .\requirements.txt -i https://mirrors.aliyun.com/pypi/simple/