semantic_test_prompt.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. """
  2. 测试提示词脚本
  3. 使用requests库测试语法审查API
  4. 支持本地模型和在线模型两种调用方式
  5. """
  6. import requests
  7. import json
  8. from openai import OpenAI
  9. class PromptTester:
  10. """提示词测试类"""
  11. def __init__(self, api_url, api_key=None, is_local=True):
  12. """
  13. 初始化测试器
  14. Args:
  15. api_url: API地址
  16. api_key: API密钥(在线模型需要)
  17. is_local: 是否使用本地模型(True: 本地模型使用requests, False: 在线模型使用OpenAI SDK)
  18. """
  19. self.api_url = api_url
  20. self.api_key = api_key
  21. self.is_local = is_local
  22. # 如果是在线模型,初始化OpenAI客户端
  23. if not is_local and api_key:
  24. self.client = OpenAI(
  25. base_url=api_url.replace('/chat/completions', ''), # 移除末尾的路径
  26. api_key=api_key
  27. )
  28. else:
  29. self.client = None
  30. self.system_prompt = """
  31. # 角色定位 (Role)
  32. 你是建筑施工方案语义逻辑审查专家,专注于识别文本中的逻辑矛盾、语义冲突和表述混乱问题。
  33. 你的职责是发现真实存在的逻辑错误,而非挑剔文字表达或提出主观性建议。
  34. # 审查范围 (Scope)
  35. 仅审查以下三类明确的语义逻辑问题:
  36. 1. **逻辑矛盾** - 同一文档内出现相互冲突的陈述
  37. 示例:前文说"采用A方法",后文说"不采用A方法"
  38. 2. **因果关系错误** - 原因与结果之间不存在合理的逻辑关联
  39. 示例:"因为天气晴朗,所以混凝土强度不足"(因果无关)
  40. 3. **条件与结论不匹配** - 给定条件无法推导出所述结论
  41. 示例:"当温度低于5℃时,可正常施工"(违背常识)
  42. # 工作流程 (Workflow)
  43. 步骤1:通读全文,理解整体语境和专业背景
  44. 步骤2:识别关键陈述、条件判断、因果关系
  45. 步骤3:检查是否存在上述三类明确的逻辑问题
  46. 步骤4:对于疑似问题,进行二次验证:
  47. - 是否确实存在逻辑冲突?
  48. - 是否可能是专业术语的正常表达?
  49. - 是否可能是上下文理解不足导致的误判?
  50. - 如果你的上文中的内容是另外一个板块的规则,不可用于下一个板块的逻辑判断。
  51. 步骤5:仅输出确认无误的问题
  52. # 严格规则 (Strict Rules)
  53. 禁止行为:
  54. 1. 禁止对正确内容提出修改建议
  55. 2. 禁止对专业术语的标准表达提出质疑
  56. 3. 禁止对文字风格、表达习惯提出意见
  57. 4. 禁止对表格格式、制表符进行检查
  58. 5. 禁止对同一问题重复输出
  59. 6. 禁止在没有明确逻辑错误时输出问题
  60. 7. 禁止将"表达不够完美"当作"逻辑错误"
  61. 8. 禁止将"可以优化"当作"必须修改"
  62. 9. 禁止在无上下文的情况猜测规则,禁止臆想规则。你的无上下文的规则不应该作为评判的依据。
  63. 必须遵守:
  64. 1. 必须基于客观事实和逻辑规则判断
  65. 2. 必须确保问题的真实性和严重性
  66. 3. 必须结合建筑施工专业知识理解内容
  67. 4. 必须区分"逻辑错误"与"表达习惯"
  68. 5. 必须在不确定时选择"无明显问题"
  69. 6. 必须保持高标准:宁缺毋滥
  70. # 风险等级判定标准 (Risk Level)
  71. - **高风险**:存在明显逻辑矛盾,可能导致施工错误或安全隐患
  72. 示例:安全措施前后矛盾、施工顺序逻辑错误
  73. - **中风险**:存在因果关系错误,可能导致理解偏差
  74. 示例:原因分析不合理、条件判断不准确
  75. - **低风险**:存在轻微的表述不一致,不影响实质理解
  76. 示例:用词前后略有差异但不影响理解
  77. # 判断原则 (Principles)
  78. 1. **疑罪从无原则**:当无法确定是否为错误时,判定为无问题
  79. 2. **专业优先原则**:尊重建筑施工行业的专业术语和表达习惯
  80. 3. **语境理解原则**:必须在完整语境中理解句子含义
  81. 4. **实质审查原则**:关注实质性逻辑错误,忽略形式问题
  82. 5. **严格证据原则**:必须有明确证据证明存在逻辑错误
  83. 6. **上下章节隔离原则**: 上下不同章节之间的信息不应该一同参考,即使有冲突也不应该一同讨论,章节条例应当独立
  84. 审查参考:
  85. {review_references}
  86. """
  87. self.user_prompt_template = """
  88. # 审查任务
  89. 请对以下施工方案内容进行语义逻辑审查,严格按照系统提示词中的三类问题范围进行检查。
  90. ## 待审查内容:
  91. {review_content}
  92. ## 审查要求:
  93. 1. 仅识别明确的逻辑矛盾、因果错误、条件结论不匹配问题
  94. 2. 必须确保问题的真实性,不得对正确内容提出修改
  95. 3. 不确定是否为问题时,必须输出"无明显问题"
  96. 4. 必须结合建筑施工专业知识和完整语境判断
  97. ## 输出格式:
  98. **情况1:未发现明确的语义逻辑问题**
  99. 直接输出:“无明显问题”,不需要解释。
  100. **情况2:发现明确的语义逻辑问题**
  101. 严格按照以下JSON格式输出(仅输出确认无误的问题):
  102. ```json
  103. {{
  104. "issue_point": "[问题类型]具体问题描述(问题类型必须是:逻辑矛盾/因果关系错误/条件结论不匹配之一)",
  105. "location": "问题所在的原始条款内容及位置(如:三、施工方法 (页码: 12)),包含必要的上下文",
  106. "suggestion": "基于逻辑规则的具体修改建议(必须是纠正逻辑错误,而非优化表达)",
  107. "reason": "详细说明为何这是一个逻辑错误,包括:1)矛盾点在哪里 2)为何不符合逻辑 3)可能产生的后果",
  108. "risk_level": "高风险/中风险/低风险(严格按照系统提示词中的标准判定)"
  109. }}
  110. ```
  111. ## 特别提醒:
  112. - 如果内容表达虽不完美但逻辑正确,输出"无明显问题"
  113. - 如果是专业术语的标准表达,输出"无明显问题"
  114. - 如果只是表达习惯差异,输出"无明显问题"
  115. - 保持高标准:宁可漏报,不可误报
  116. - 上下章节隔离: 上下不同章节之间的信息不应该一同参考,即使有冲突也不应该一同讨论,章节条例应当独立
  117. """
  118. def test_prompt(self, review_content, model="Qwen3-8B", temperature=0.3, max_tokens=2000):
  119. """
  120. 测试提示词
  121. Args:
  122. review_content: 待审查的文本内容
  123. model: 模型名称
  124. temperature: 温度参数
  125. max_tokens: 最大token数
  126. Returns:
  127. API响应结果
  128. """
  129. # 填充用户提示词
  130. user_prompt = self.user_prompt_template.format(review_content=review_content)
  131. # 打印请求信息
  132. print("=" * 80)
  133. print(f"调用方式: {'本地模型 (requests)' if self.is_local else '在线模型 (OpenAI SDK)'}")
  134. print("发送请求到:", self.api_url)
  135. print("=" * 80)
  136. print("System Prompt:")
  137. print("-" * 80)
  138. print(self.system_prompt)
  139. print("=" * 80)
  140. print("User Prompt:")
  141. print("-" * 80)
  142. print(user_prompt)
  143. print("=" * 80)
  144. # 根据is_local选择不同的调用方式
  145. if self.is_local:
  146. # 本地模型:使用requests
  147. return self._call_with_requests(user_prompt, model, temperature, max_tokens)
  148. else:
  149. # 在线模型:使用OpenAI SDK
  150. return self._call_with_openai(user_prompt, model, temperature, max_tokens)
  151. def _call_with_requests(self, user_prompt, model, temperature, max_tokens):
  152. """使用requests库调用本地模型"""
  153. # 构建请求数据
  154. payload = {
  155. "model": model,
  156. "messages": [
  157. {
  158. "role": "system",
  159. "content": self.system_prompt
  160. },
  161. {
  162. "role": "user",
  163. "content": user_prompt
  164. }
  165. ],
  166. "temperature": temperature,
  167. "max_tokens": max_tokens
  168. }
  169. try:
  170. # 构建请求头
  171. headers = {"Content-Type": "application/json"}
  172. if self.api_key:
  173. headers["Authorization"] = f"Bearer {self.api_key}"
  174. # 发送POST请求
  175. response = requests.post(
  176. self.api_url,
  177. headers=headers,
  178. json=payload,
  179. timeout=60
  180. )
  181. # 检查响应状态
  182. response.raise_for_status()
  183. # 解析响应
  184. result = response.json()
  185. print("响应状态码:", response.status_code)
  186. print("=" * 80)
  187. print("API响应结果:")
  188. print("-" * 80)
  189. print(json.dumps(result, ensure_ascii=False, indent=2))
  190. print("=" * 80)
  191. # 提取AI回复内容
  192. if "choices" in result and len(result["choices"]) > 0:
  193. ai_response = result["choices"][0].get("message", {}).get("content", "")
  194. print("AI回复内容:")
  195. print("-" * 80)
  196. print(ai_response)
  197. print("=" * 80)
  198. return result
  199. except requests.exceptions.RequestException as e:
  200. print(f"请求失败: {e}")
  201. return None
  202. except json.JSONDecodeError as e:
  203. print(f"JSON解析失败: {e}")
  204. print("原始响应:", response.text)
  205. return None
  206. def _call_with_openai(self, user_prompt, model, temperature, max_tokens):
  207. """使用OpenAI SDK调用在线模型"""
  208. if not self.client:
  209. print("错误: OpenAI客户端未初始化")
  210. return None
  211. try:
  212. # 使用OpenAI SDK调用
  213. extra_body = {
  214. # enable thinking, set to False to disable test
  215. "enable_thinking": False,
  216. # use thinking_budget to contorl num of tokens used for thinking
  217. # "thinking_budget": 4096
  218. }
  219. response = self.client.chat.completions.create(
  220. model=model,
  221. messages=[
  222. {
  223. "role": "system",
  224. "content": self.system_prompt
  225. },
  226. {
  227. "role": "user",
  228. "content": user_prompt
  229. }
  230. ],
  231. temperature=temperature,
  232. max_tokens=max_tokens,
  233. extra_body=extra_body
  234. )
  235. # 转换为字典格式
  236. result = {
  237. "id": response.id,
  238. "object": response.object,
  239. "created": response.created,
  240. "model": response.model,
  241. "choices": [
  242. {
  243. "index": choice.index,
  244. "message": {
  245. "role": choice.message.role,
  246. "content": choice.message.content
  247. },
  248. "finish_reason": choice.finish_reason
  249. }
  250. for choice in response.choices
  251. ],
  252. "usage": {
  253. "prompt_tokens": response.usage.prompt_tokens,
  254. "completion_tokens": response.usage.completion_tokens,
  255. "total_tokens": response.usage.total_tokens
  256. }
  257. }
  258. print("=" * 80)
  259. print("API响应结果:")
  260. print("-" * 80)
  261. print(json.dumps(result, ensure_ascii=False, indent=2))
  262. print("=" * 80)
  263. # 提取AI回复内容
  264. if result["choices"] and len(result["choices"]) > 0:
  265. ai_response = result["choices"][0]["message"]["content"]
  266. print("AI回复内容:")
  267. print("-" * 80)
  268. print(ai_response)
  269. print("=" * 80)
  270. return result
  271. except Exception as e:
  272. print(f"OpenAI SDK调用失败: {e}")
  273. return None
  274. def main():
  275. """主函数"""
  276. # ==================== 配置区域 ====================
  277. # 是否使用本地模型(True: 本地模型, False: 在线模型)
  278. is_local = True
  279. # 本地模型配置
  280. local_config = {
  281. "api_url": "http://192.168.91.253:8003/v1/chat/completions",
  282. "api_key": "sk-123456",
  283. "model": "qwen3-30b",
  284. "temperature": 0.7,
  285. "max_tokens": 2000
  286. }
  287. # 在线模型配置(ModelScope)
  288. online_config = {
  289. "api_url": "https://api-inference.modelscope.cn/v1",
  290. "api_key": "ms-c0349a0a-8f15-466b-96be-4f96d001d8f2", # ModelScope Token
  291. "model": "Qwen/Qwen3-14B",
  292. "temperature": 0.7,
  293. "max_tokens": 2000
  294. }
  295. # ==================== 配置区域结束 ====================
  296. # 根据is_local选择配置
  297. config = local_config if is_local else online_config
  298. print("=" * 80)
  299. print(f"当前使用: {'本地模型' if is_local else '在线模型'}")
  300. print(f"API地址: {config['api_url']}")
  301. print(f"模型名称: {config['model']}")
  302. print("=" * 80)
  303. # 创建测试器
  304. tester = PromptTester(config["api_url"], config["api_key"], is_local)
  305. custom_content = """
  306. 1、验收程序
  307. (1)建立完整的质量保证体系,按施工合同约定的质量要求与质量管理程序进行作业,保证施工质量。
  308. (2)每道工序开工前施工单位进行施工技术交底,重要工序或分部工程其内容须书面报送监理工程师审查。
  309. (3)工序施工完毕,实行各道工序的操作人员“自检”、“互检”和专职质量管理人员“专检”相结合的“三检”程序,并签署有完整的检验记录。不合格,则自行返工。
  310. (4)在“自检”、“互检”和“专检”合格基础上,备齐自检资料和报验申请表,提前申请验收。
  311. (5)工程监理采用巡视、旁站、平行检查方式,及平常的工地例行检查,不能作为对施工方的施工质量的检查验收。
  312. (6)施工工序属于隐蔽工程,需提前通知监理单位验收,未经监理工程师批准,任何工程工序均不能擅自隐蔽。隐蔽验收须按施工工序步骤逐步进行,并按工序步骤记录在验收表上,验收合格后才准许隐蔽。
  313. (7)监理方接到施工方验收申请,积极组织监理方人员检查,对工程中存在的质量问题和安全隐患问题以书面的形式,要求施工单位进行整改回复、检查、再申请验收。
  314. (8)监理方按设计和施工验收规范检查,确认无质量、安全问题,组织业主、施工单位联合检验。
  315. (9)为确保工程质量,为设计和施工验收提供可靠依据,施工过程中各项试验,应严格按国家相关标准的规定进行见证抽样送检。未经监理见证送检的材料,一律不准用于工程实体。
  316. 图7-1 验收程序
  317. """
  318. tester.test_prompt(
  319. custom_content,
  320. model=config["model"],
  321. temperature=config["temperature"],
  322. max_tokens=config["max_tokens"]
  323. )
  324. if __name__ == "__main__":
  325. main()