|
|
@@ -0,0 +1,383 @@
|
|
|
+"""
|
|
|
+测试提示词脚本
|
|
|
+使用requests库测试语法审查API
|
|
|
+支持本地模型和在线模型两种调用方式
|
|
|
+"""
|
|
|
+import requests
|
|
|
+import json
|
|
|
+from openai import OpenAI
|
|
|
+
|
|
|
+
|
|
|
+class PromptTester:
|
|
|
+ """提示词测试类"""
|
|
|
+
|
|
|
+ def __init__(self, api_url, api_key=None, is_local=True):
|
|
|
+ """
|
|
|
+ 初始化测试器
|
|
|
+
|
|
|
+ Args:
|
|
|
+ api_url: API地址
|
|
|
+ api_key: API密钥(在线模型需要)
|
|
|
+ is_local: 是否使用本地模型(True: 本地模型使用requests, False: 在线模型使用OpenAI SDK)
|
|
|
+ """
|
|
|
+ self.api_url = api_url
|
|
|
+ self.api_key = api_key
|
|
|
+ self.is_local = is_local
|
|
|
+
|
|
|
+ # 如果是在线模型,初始化OpenAI客户端
|
|
|
+ if not is_local and api_key:
|
|
|
+ self.client = OpenAI(
|
|
|
+ base_url=api_url.replace('/chat/completions', ''), # 移除末尾的路径
|
|
|
+ api_key=api_key
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ self.client = None
|
|
|
+ self.system_prompt = """
|
|
|
+# 角色定位 (Role)
|
|
|
+你是建筑施工方案语义逻辑审查专家,专注于识别文本中的逻辑矛盾、语义冲突和表述混乱问题。
|
|
|
+你的职责是发现真实存在的逻辑错误,而非挑剔文字表达或提出主观性建议。
|
|
|
+
|
|
|
+# 审查范围 (Scope)
|
|
|
+仅审查以下三类明确的语义逻辑问题:
|
|
|
+
|
|
|
+1. **逻辑矛盾** - 同一文档内出现相互冲突的陈述
|
|
|
+ 示例:前文说"采用A方法",后文说"不采用A方法"
|
|
|
+
|
|
|
+2. **因果关系错误** - 原因与结果之间不存在合理的逻辑关联
|
|
|
+ 示例:"因为天气晴朗,所以混凝土强度不足"(因果无关)
|
|
|
+
|
|
|
+3. **条件与结论不匹配** - 给定条件无法推导出所述结论
|
|
|
+ 示例:"当温度低于5℃时,可正常施工"(违背常识)
|
|
|
+# 工作流程 (Workflow)
|
|
|
+
|
|
|
+步骤1:通读全文,理解整体语境和专业背景
|
|
|
+步骤2:识别关键陈述、条件判断、因果关系
|
|
|
+步骤3:检查是否存在上述三类明确的逻辑问题
|
|
|
+步骤4:对于疑似问题,进行二次验证:
|
|
|
+ - 是否确实存在逻辑冲突?
|
|
|
+ - 是否可能是专业术语的正常表达?
|
|
|
+ - 是否可能是上下文理解不足导致的误判?
|
|
|
+ - 如果你的上文中的内容是另外一个板块的规则,不可用于下一个板块的逻辑判断。
|
|
|
+步骤5:仅输出确认无误的问题
|
|
|
+# 严格规则 (Strict Rules)
|
|
|
+
|
|
|
+禁止行为:
|
|
|
+1. 禁止对正确内容提出修改建议
|
|
|
+2. 禁止对专业术语的标准表达提出质疑
|
|
|
+3. 禁止对文字风格、表达习惯提出意见
|
|
|
+4. 禁止对表格格式、制表符进行检查
|
|
|
+5. 禁止对同一问题重复输出
|
|
|
+6. 禁止在没有明确逻辑错误时输出问题
|
|
|
+7. 禁止将"表达不够完美"当作"逻辑错误"
|
|
|
+8. 禁止将"可以优化"当作"必须修改"
|
|
|
+9. 禁止在无上下文的情况猜测规则,禁止臆想规则。你的无上下文的规则不应该作为评判的依据。
|
|
|
+
|
|
|
+必须遵守:
|
|
|
+1. 必须基于客观事实和逻辑规则判断
|
|
|
+2. 必须确保问题的真实性和严重性
|
|
|
+3. 必须结合建筑施工专业知识理解内容
|
|
|
+4. 必须区分"逻辑错误"与"表达习惯"
|
|
|
+5. 必须在不确定时选择"无明显问题"
|
|
|
+6. 必须保持高标准:宁缺毋滥
|
|
|
+
|
|
|
+# 风险等级判定标准 (Risk Level)
|
|
|
+
|
|
|
+- **高风险**:存在明显逻辑矛盾,可能导致施工错误或安全隐患
|
|
|
+ 示例:安全措施前后矛盾、施工顺序逻辑错误
|
|
|
+
|
|
|
+- **中风险**:存在因果关系错误,可能导致理解偏差
|
|
|
+ 示例:原因分析不合理、条件判断不准确
|
|
|
+
|
|
|
+- **低风险**:存在轻微的表述不一致,不影响实质理解
|
|
|
+ 示例:用词前后略有差异但不影响理解
|
|
|
+
|
|
|
+# 判断原则 (Principles)
|
|
|
+
|
|
|
+1. **疑罪从无原则**:当无法确定是否为错误时,判定为无问题
|
|
|
+2. **专业优先原则**:尊重建筑施工行业的专业术语和表达习惯
|
|
|
+3. **语境理解原则**:必须在完整语境中理解句子含义
|
|
|
+4. **实质审查原则**:关注实质性逻辑错误,忽略形式问题
|
|
|
+5. **严格证据原则**:必须有明确证据证明存在逻辑错误
|
|
|
+6. **上下章节隔离原则**: 上下不同章节之间的信息不应该一同参考,即使有冲突也不应该一同讨论,章节条例应当独立
|
|
|
+审查参考:
|
|
|
+{review_references}
|
|
|
+"""
|
|
|
+ self.user_prompt_template = """
|
|
|
+# 审查任务
|
|
|
+请对以下施工方案内容进行语义逻辑审查,严格按照系统提示词中的三类问题范围进行检查。
|
|
|
+
|
|
|
+## 待审查内容:
|
|
|
+{review_content}
|
|
|
+
|
|
|
+
|
|
|
+## 审查要求:
|
|
|
+1. 仅识别明确的逻辑矛盾、因果错误、条件结论不匹配问题
|
|
|
+2. 必须确保问题的真实性,不得对正确内容提出修改
|
|
|
+3. 不确定是否为问题时,必须输出"无明显问题"
|
|
|
+4. 必须结合建筑施工专业知识和完整语境判断
|
|
|
+
|
|
|
+## 输出格式:
|
|
|
+
|
|
|
+**情况1:未发现明确的语义逻辑问题**
|
|
|
+直接输出:“无明显问题”,不需要解释。
|
|
|
+
|
|
|
+**情况2:发现明确的语义逻辑问题**
|
|
|
+严格按照以下JSON格式输出(仅输出确认无误的问题):
|
|
|
+```json
|
|
|
+{{
|
|
|
+ "issue_point": "[问题类型]具体问题描述(问题类型必须是:逻辑矛盾/因果关系错误/条件结论不匹配之一)",
|
|
|
+ "location": "问题所在的原始条款内容及位置(如:三、施工方法 (页码: 12)),包含必要的上下文",
|
|
|
+ "suggestion": "基于逻辑规则的具体修改建议(必须是纠正逻辑错误,而非优化表达)",
|
|
|
+ "reason": "详细说明为何这是一个逻辑错误,包括:1)矛盾点在哪里 2)为何不符合逻辑 3)可能产生的后果",
|
|
|
+ "risk_level": "高风险/中风险/低风险(严格按照系统提示词中的标准判定)"
|
|
|
+}}
|
|
|
+```
|
|
|
+
|
|
|
+## 特别提醒:
|
|
|
+- 如果内容表达虽不完美但逻辑正确,输出"无明显问题"
|
|
|
+- 如果是专业术语的标准表达,输出"无明显问题"
|
|
|
+- 如果只是表达习惯差异,输出"无明显问题"
|
|
|
+- 保持高标准:宁可漏报,不可误报
|
|
|
+- 上下章节隔离: 上下不同章节之间的信息不应该一同参考,即使有冲突也不应该一同讨论,章节条例应当独立
|
|
|
+"""
|
|
|
+
|
|
|
+ def test_prompt(self, review_content, model="Qwen3-8B", temperature=0.3, max_tokens=2000):
|
|
|
+ """
|
|
|
+ 测试提示词
|
|
|
+
|
|
|
+ Args:
|
|
|
+ review_content: 待审查的文本内容
|
|
|
+ model: 模型名称
|
|
|
+ temperature: 温度参数
|
|
|
+ max_tokens: 最大token数
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ API响应结果
|
|
|
+ """
|
|
|
+ # 填充用户提示词
|
|
|
+ user_prompt = self.user_prompt_template.format(review_content=review_content)
|
|
|
+
|
|
|
+ # 打印请求信息
|
|
|
+ print("=" * 80)
|
|
|
+ print(f"调用方式: {'本地模型 (requests)' if self.is_local else '在线模型 (OpenAI SDK)'}")
|
|
|
+ print("发送请求到:", self.api_url)
|
|
|
+ print("=" * 80)
|
|
|
+ print("System Prompt:")
|
|
|
+ print("-" * 80)
|
|
|
+ print(self.system_prompt)
|
|
|
+ print("=" * 80)
|
|
|
+ print("User Prompt:")
|
|
|
+ print("-" * 80)
|
|
|
+ print(user_prompt)
|
|
|
+ print("=" * 80)
|
|
|
+
|
|
|
+ # 根据is_local选择不同的调用方式
|
|
|
+ if self.is_local:
|
|
|
+ # 本地模型:使用requests
|
|
|
+ return self._call_with_requests(user_prompt, model, temperature, max_tokens)
|
|
|
+ else:
|
|
|
+ # 在线模型:使用OpenAI SDK
|
|
|
+ return self._call_with_openai(user_prompt, model, temperature, max_tokens)
|
|
|
+
|
|
|
+ def _call_with_requests(self, user_prompt, model, temperature, max_tokens):
|
|
|
+ """使用requests库调用本地模型"""
|
|
|
+ # 构建请求数据
|
|
|
+ payload = {
|
|
|
+ "model": model,
|
|
|
+ "messages": [
|
|
|
+ {
|
|
|
+ "role": "system",
|
|
|
+ "content": self.system_prompt
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "role": "user",
|
|
|
+ "content": user_prompt
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "temperature": temperature,
|
|
|
+ "max_tokens": max_tokens
|
|
|
+ }
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 构建请求头
|
|
|
+ headers = {"Content-Type": "application/json"}
|
|
|
+ if self.api_key:
|
|
|
+ headers["Authorization"] = f"Bearer {self.api_key}"
|
|
|
+
|
|
|
+ # 发送POST请求
|
|
|
+ response = requests.post(
|
|
|
+ self.api_url,
|
|
|
+ headers=headers,
|
|
|
+ json=payload,
|
|
|
+ timeout=60
|
|
|
+ )
|
|
|
+
|
|
|
+ # 检查响应状态
|
|
|
+ response.raise_for_status()
|
|
|
+
|
|
|
+ # 解析响应
|
|
|
+ result = response.json()
|
|
|
+
|
|
|
+ print("响应状态码:", response.status_code)
|
|
|
+ print("=" * 80)
|
|
|
+ print("API响应结果:")
|
|
|
+ print("-" * 80)
|
|
|
+ print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
|
+ print("=" * 80)
|
|
|
+
|
|
|
+ # 提取AI回复内容
|
|
|
+ if "choices" in result and len(result["choices"]) > 0:
|
|
|
+ ai_response = result["choices"][0].get("message", {}).get("content", "")
|
|
|
+ print("AI回复内容:")
|
|
|
+ print("-" * 80)
|
|
|
+ print(ai_response)
|
|
|
+ print("=" * 80)
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+ except requests.exceptions.RequestException as e:
|
|
|
+ print(f"请求失败: {e}")
|
|
|
+ return None
|
|
|
+ except json.JSONDecodeError as e:
|
|
|
+ print(f"JSON解析失败: {e}")
|
|
|
+ print("原始响应:", response.text)
|
|
|
+ return None
|
|
|
+
|
|
|
+ def _call_with_openai(self, user_prompt, model, temperature, max_tokens):
|
|
|
+ """使用OpenAI SDK调用在线模型"""
|
|
|
+ if not self.client:
|
|
|
+ print("错误: OpenAI客户端未初始化")
|
|
|
+ return None
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 使用OpenAI SDK调用
|
|
|
+ extra_body = {
|
|
|
+ # enable thinking, set to False to disable test
|
|
|
+ "enable_thinking": False,
|
|
|
+ # use thinking_budget to contorl num of tokens used for thinking
|
|
|
+ # "thinking_budget": 4096
|
|
|
+ }
|
|
|
+ response = self.client.chat.completions.create(
|
|
|
+ model=model,
|
|
|
+ messages=[
|
|
|
+ {
|
|
|
+ "role": "system",
|
|
|
+ "content": self.system_prompt
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "role": "user",
|
|
|
+ "content": user_prompt
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ temperature=temperature,
|
|
|
+ max_tokens=max_tokens,
|
|
|
+ extra_body=extra_body
|
|
|
+ )
|
|
|
+
|
|
|
+ # 转换为字典格式
|
|
|
+ result = {
|
|
|
+ "id": response.id,
|
|
|
+ "object": response.object,
|
|
|
+ "created": response.created,
|
|
|
+ "model": response.model,
|
|
|
+ "choices": [
|
|
|
+ {
|
|
|
+ "index": choice.index,
|
|
|
+ "message": {
|
|
|
+ "role": choice.message.role,
|
|
|
+ "content": choice.message.content
|
|
|
+ },
|
|
|
+ "finish_reason": choice.finish_reason
|
|
|
+ }
|
|
|
+ for choice in response.choices
|
|
|
+ ],
|
|
|
+ "usage": {
|
|
|
+ "prompt_tokens": response.usage.prompt_tokens,
|
|
|
+ "completion_tokens": response.usage.completion_tokens,
|
|
|
+ "total_tokens": response.usage.total_tokens
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ print("=" * 80)
|
|
|
+ print("API响应结果:")
|
|
|
+ print("-" * 80)
|
|
|
+ print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
|
+ print("=" * 80)
|
|
|
+
|
|
|
+ # 提取AI回复内容
|
|
|
+ if result["choices"] and len(result["choices"]) > 0:
|
|
|
+ ai_response = result["choices"][0]["message"]["content"]
|
|
|
+ print("AI回复内容:")
|
|
|
+ print("-" * 80)
|
|
|
+ print(ai_response)
|
|
|
+ print("=" * 80)
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ print(f"OpenAI SDK调用失败: {e}")
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def main():
|
|
|
+ """主函数"""
|
|
|
+
|
|
|
+ # ==================== 配置区域 ====================
|
|
|
+ # 是否使用本地模型(True: 本地模型, False: 在线模型)
|
|
|
+ is_local = True
|
|
|
+
|
|
|
+ # 本地模型配置
|
|
|
+ local_config = {
|
|
|
+ "api_url": "http://192.168.91.253:8003/v1/chat/completions",
|
|
|
+ "api_key": "sk-123456",
|
|
|
+ "model": "qwen3-30b",
|
|
|
+ "temperature": 0.7,
|
|
|
+ "max_tokens": 2000
|
|
|
+ }
|
|
|
+
|
|
|
+ # 在线模型配置(ModelScope)
|
|
|
+ online_config = {
|
|
|
+ "api_url": "https://api-inference.modelscope.cn/v1",
|
|
|
+ "api_key": "ms-c0349a0a-8f15-466b-96be-4f96d001d8f2", # ModelScope Token
|
|
|
+ "model": "Qwen/Qwen3-14B",
|
|
|
+ "temperature": 0.7,
|
|
|
+ "max_tokens": 2000
|
|
|
+ }
|
|
|
+ # ==================== 配置区域结束 ====================
|
|
|
+
|
|
|
+ # 根据is_local选择配置
|
|
|
+ config = local_config if is_local else online_config
|
|
|
+
|
|
|
+ print("=" * 80)
|
|
|
+ print(f"当前使用: {'本地模型' if is_local else '在线模型'}")
|
|
|
+ print(f"API地址: {config['api_url']}")
|
|
|
+ print(f"模型名称: {config['model']}")
|
|
|
+ print("=" * 80)
|
|
|
+
|
|
|
+ # 创建测试器
|
|
|
+ tester = PromptTester(config["api_url"], config["api_key"], is_local)
|
|
|
+
|
|
|
+ custom_content = """
|
|
|
+1、验收程序
|
|
|
+(1)建立完整的质量保证体系,按施工合同约定的质量要求与质量管理程序进行作业,保证施工质量。
|
|
|
+(2)每道工序开工前施工单位进行施工技术交底,重要工序或分部工程其内容须书面报送监理工程师审查。
|
|
|
+(3)工序施工完毕,实行各道工序的操作人员“自检”、“互检”和专职质量管理人员“专检”相结合的“三检”程序,并签署有完整的检验记录。不合格,则自行返工。
|
|
|
+(4)在“自检”、“互检”和“专检”合格基础上,备齐自检资料和报验申请表,提前申请验收。
|
|
|
+(5)工程监理采用巡视、旁站、平行检查方式,及平常的工地例行检查,不能作为对施工方的施工质量的检查验收。
|
|
|
+(6)施工工序属于隐蔽工程,需提前通知监理单位验收,未经监理工程师批准,任何工程工序均不能擅自隐蔽。隐蔽验收须按施工工序步骤逐步进行,并按工序步骤记录在验收表上,验收合格后才准许隐蔽。
|
|
|
+(7)监理方接到施工方验收申请,积极组织监理方人员检查,对工程中存在的质量问题和安全隐患问题以书面的形式,要求施工单位进行整改回复、检查、再申请验收。
|
|
|
+(8)监理方按设计和施工验收规范检查,确认无质量、安全问题,组织业主、施工单位联合检验。
|
|
|
+(9)为确保工程质量,为设计和施工验收提供可靠依据,施工过程中各项试验,应严格按国家相关标准的规定进行见证抽样送检。未经监理见证送检的材料,一律不准用于工程实体。
|
|
|
+图7-1 验收程序
|
|
|
+"""
|
|
|
+ tester.test_prompt(
|
|
|
+ custom_content,
|
|
|
+ model=config["model"],
|
|
|
+ temperature=config["temperature"],
|
|
|
+ max_tokens=config["max_tokens"]
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ main()
|
|
|
+
|