增强AI服务的内容提取逻辑,更新提取助手的描述,添加后处理逻辑以推断缺失的性别、职级和线索来源字段,确保提取结果的准确性和完整性。

This commit is contained in:
python 2025-12-09 15:32:25 +08:00
parent 563d97184b
commit 24fdfdea4c
2 changed files with 255 additions and 1 deletions

View File

@ -234,7 +234,7 @@ class AIService:
"messages": [
{
"role": "system",
"content": "你是一个专业的数据提取助手。请从输入文本中提取结构化信息并严格按照JSON格式返回结果。\n\n核心要求:\n1. 仔细阅读输入文本,提取所有相关信息\n2. 如果文本中明确提到信息(如性别、年龄、职务、职级等),必须提取,不能设为空\n3. 性别字段:识别\"\"\"\"\"男性\"\"女性\"等词汇,统一转换为\"\"\"\"\n4. 只返回JSON对象不要包含任何其他文字、思考过程或markdown标记\n5. 字段名必须严格按照示例格式,使用正确的字段编码:\n - 使用\"target_professional_rank\",不要使用\"_professional_rank\"\n - 使用\"clue_source\"不要使用\"_source\"\"source\"\n - 使用\"target_organization\",不要使用\"target_organisation\"\n6. JSON格式必须完整且有效所有字段名使用双引号"
"content": "你是一个专业的数据提取助手。请从输入文本中提取结构化信息并严格按照JSON格式返回结果。\n\n⚠️ 核心要求(必须严格遵守):\n\n1. 字段提取要求:\n - 如果文本中明确提到信息(如性别、年龄、职务、职级、线索来源等),必须提取,绝对不能设为空字符串\n - 性别字段target_gender如果文本中出现\"\"\"\"\"男性\"\"女性\"\"先生\"\"女士\"等任何表示性别的词汇,必须提取并转换为\"\"\"\",不能为空\n - 职级字段target_professional_rank如果文本中提到\"正处级\"\"副处级\"\"正科级\"等,必须提取,不能为空\n - 线索来源字段clue_source如果文本中提到\"举报\"\"群众举报\"\"来信\"等,必须提取,不能为空\n\n2. 字段名格式要求(严格禁止错误):\n - 必须使用\"target_professional_rank\",禁止使用\"_professional_rank\"或任何下划线前缀\n - 必须使用\"clue_source\"禁止使用\"_source\"\"source\"或任何下划线前缀\n - 必须使用\"target_organization\",禁止使用\"target_organisation\"(英式拼写)\n - 所有字段名必须严格按照JSON示例中的字段编码不能随意修改\n\n3. JSON格式要求\n - 只返回JSON对象不要包含任何其他文字、思考过程、markdown代码块标记或```json标记\n - 所有字段名必须使用双引号\n - 必须返回所有要求的字段即使值为空字符串也要包含在JSON中\n - JSON格式必须完整且有效不能有语法错误\n\n4. 提取逻辑:\n - 逐字逐句仔细阅读输入文本,不要遗漏任何信息\n - 对于性别、职级、线索来源等关键字段,请特别仔细查找\n - 如果文本中明确提到某个信息,必须提取出来,不能设为空"
},
{
"role": "user",
@ -1273,6 +1273,75 @@ class AIService:
data['target_position'] = pos
print(f"[AI服务] 后处理:从单位及职务 '{org_pos}' 提取职务: {pos}")
# 3. 从工作基本情况中提取性别如果target_gender为空
if 'target_gender' in field_code_map and (not data.get('target_gender') or data.get('target_gender') == ''):
# 尝试从工作基本情况中提取性别
work_info = data.get('target_work_basic_info', '')
if work_info:
# 匹配模式XXX... 或 XXX...
gender_match = re.search(r'[,]\s*([男女])\s*[,]', work_info)
if gender_match:
gender = gender_match.group(1)
data['target_gender'] = gender
print(f"[AI服务] 后处理:从工作基本情况中提取性别: {gender}")
# 如果还没有,尝试从其他字段中查找
if not data.get('target_gender') or data.get('target_gender') == '':
# 检查所有文本字段中是否包含性别信息
for key, value in data.items():
if isinstance(value, str) and value:
# 匹配"男"或"女"
if re.search(r'\b男\b', value) and not re.search(r'\b女\b', value):
data['target_gender'] = ''
print(f"[AI服务] 后处理:从字段 '{key}' 中推断性别: 男")
break
elif re.search(r'\b女\b', value) and not re.search(r'\b男\b', value):
data['target_gender'] = ''
print(f"[AI服务] 后处理:从字段 '{key}' 中推断性别: 女")
break
# 4. 从工作基本情况中提取职级如果target_professional_rank为空
if 'target_professional_rank' in field_code_map and (not data.get('target_professional_rank') or data.get('target_professional_rank') == ''):
# 尝试从工作基本情况或其他文本字段中提取职级
work_info = data.get('target_work_basic_info', '')
if work_info:
# 匹配职级模式:正处级、副处级、正科级等
rank_match = re.search(r'([正副][处科厅局]级)', work_info)
if rank_match:
rank = rank_match.group(1)
data['target_professional_rank'] = rank
print(f"[AI服务] 后处理:从工作基本情况中提取职级: {rank}")
# 如果还没有,检查其他文本字段
if not data.get('target_professional_rank') or data.get('target_professional_rank') == '':
for key, value in data.items():
if isinstance(value, str) and value:
rank_match = re.search(r'([正副][处科厅局]级)', value)
if rank_match:
rank = rank_match.group(1)
data['target_professional_rank'] = rank
print(f"[AI服务] 后处理:从字段 '{key}' 中提取职级: {rank}")
break
# 5. 从问题线索描述中提取线索来源如果clue_source为空
if 'clue_source' in field_code_map and (not data.get('clue_source') or data.get('clue_source') == ''):
issue_desc = data.get('target_issue_description', '')
# 检查所有文本字段
all_text = ' '.join([str(v) for v in data.values() if isinstance(v, str)])
if '举报' in all_text or '被举报' in all_text:
if '群众举报' in all_text:
data['clue_source'] = '群众举报'
elif '网络' in all_text or '网上' in all_text:
data['clue_source'] = '网络举报'
elif '电话' in all_text or '来电' in all_text:
data['clue_source'] = '来电举报'
elif '来信' in all_text:
data['clue_source'] = '来信举报'
else:
data['clue_source'] = '举报'
print(f"[AI服务] 后处理:从文本中推断线索来源: {data['clue_source']}")
return data
def _calculate_age_from_birth_date(self, birth_date: str) -> Optional[int]:

View File

@ -0,0 +1,185 @@
# 性别字段缺失问题分析与修复
## 问题描述
模型在思考过程中正确识别了性别信息("性别方面,无论是在哪里,都明确指出是男性或者男,所以统一转换为'男'即可"但在最终的JSON输出中`target_gender`字段却是空字符串。同时,`target_professional_rank``clue_source`字段也存在类似问题。
## 问题分析
### 1. 根本原因
**问题1System Prompt不够强调**
- 虽然system prompt提到了性别字段但可能不够强调
- 模型在生成JSON时可能因为某些原因跳过了某些字段
- 需要更明确地在提示词中强调每个字段都必须填写,不能为空
**问题2字段名错误**
- 模型返回了错误的字段名:`_professional_rank``_source`
- 说明模型没有严格遵循system prompt中的字段名要求
- 需要更明确地禁止使用下划线前缀
**问题3后处理机制不完善**
- 虽然代码中有后处理逻辑,但对于性别、职级等关键字段的推断不够完善
- 需要增强后处理机制,从已有数据中推断缺失字段
### 2. 具体表现
从用户提供的返回结果来看:
```json
{
"target_name": "张三",
"target_political_status": "中共党员",
"target_date_of_birth": "1980年05月",
"target_organization_and_position": "某公司总经理",
"target_issue_description": "违反国家计划生育有关政策规定于2010年10月生育二胎。",
"target_gender": "", // ❌ 应该是"男"
"_professional_rank": "", // ❌ 字段名错误,应该是"target_professional_rank",值应该是"正处级"
"_source": "", // ❌ 字段名错误,应该是"clue_source",值应该是"群众举报"
}
```
**问题点**
1. `target_gender`为空,但思考过程中明确识别了性别
2. 字段名错误:`_professional_rank`应该是`target_professional_rank`
3. 字段名错误:`_source`应该是`clue_source`
4. 值缺失:职级和线索来源的值都是空的
## 修复方案
### 1. 强化System Prompt ✅
**修改位置**`services/ai_service.py` 第237行
**改进内容**
- 使用⚠️标记强调核心要求
- 明确列出关键字段(性别、职级、线索来源)的提取要求
- 明确禁止使用下划线前缀的字段名
- 强调如果文本中明确提到信息,必须提取,不能为空
**新的System Prompt**
```
你是一个专业的数据提取助手。请从输入文本中提取结构化信息并严格按照JSON格式返回结果。
⚠️ 核心要求(必须严格遵守):
1. 字段提取要求:
- 如果文本中明确提到信息(如性别、年龄、职务、职级、线索来源等),必须提取,绝对不能设为空字符串
- 性别字段target_gender如果文本中出现"男"、"女"、"男性"、"女性"、"先生"、"女士"等任何表示性别的词汇,必须提取并转换为"男"或"女",不能为空
- 职级字段target_professional_rank如果文本中提到"正处级"、"副处级"、"正科级"等,必须提取,不能为空
- 线索来源字段clue_source如果文本中提到"举报"、"群众举报"、"来信"等,必须提取,不能为空
2. 字段名格式要求(严格禁止错误):
- 必须使用"target_professional_rank",禁止使用"_professional_rank"或任何下划线前缀
- 必须使用"clue_source",禁止使用"_source"、"source"或任何下划线前缀
- 必须使用"target_organization",禁止使用"target_organisation"(英式拼写)
- 所有字段名必须严格按照JSON示例中的字段编码不能随意修改
3. JSON格式要求
- 只返回JSON对象不要包含任何其他文字、思考过程、markdown代码块标记或```json标记
- 所有字段名必须使用双引号
- 必须返回所有要求的字段即使值为空字符串也要包含在JSON中
- JSON格式必须完整且有效不能有语法错误
4. 提取逻辑:
- 逐字逐句仔细阅读输入文本,不要遗漏任何信息
- 对于性别、职级、线索来源等关键字段,请特别仔细查找
- 如果文本中明确提到某个信息,必须提取出来,不能设为空
```
### 2. 增强后处理机制 ✅
**修改位置**`services/ai_service.py` 第1233-1320行
**新增功能**
1. **从工作基本情况中提取性别**
- 匹配模式:`XXX...``XXX...`
- 如果`target_gender`为空,从`target_work_basic_info`中提取
2. **从所有文本字段中推断性别**
- 如果工作基本情况中没有,检查所有文本字段
- 使用正则表达式匹配"男"或"女"
3. **从工作基本情况中提取职级**
- 匹配模式:`正处级``副处级``正科级`
- 如果`target_professional_rank`为空,从文本中提取
4. **从文本中推断线索来源**
- 检查所有文本字段中是否包含"举报"、"群众举报"等关键词
- 根据关键词推断线索来源类型
**后处理逻辑**
```python
# 3. 从工作基本情况中提取性别如果target_gender为空
if 'target_gender' in field_code_map and (not data.get('target_gender') or data.get('target_gender') == ''):
# 尝试从工作基本情况中提取性别
work_info = data.get('target_work_basic_info', '')
if work_info:
gender_match = re.search(r'[,]\s*([男女])\s*[,]', work_info)
if gender_match:
gender = gender_match.group(1)
data['target_gender'] = gender
# 如果还没有,尝试从其他字段中查找
if not data.get('target_gender'):
for key, value in data.items():
if isinstance(value, str) and value:
if re.search(r'\b男\b', value) and not re.search(r'\b女\b', value):
data['target_gender'] = '男'
break
elif re.search(r'\b女\b', value) and not re.search(r'\b男\b', value):
data['target_gender'] = '女'
break
```
## 预期效果
1. **提高字段提取准确性**
- 强化后的system prompt明确要求提取关键字段
- 模型更可能正确提取性别、职级、线索来源等信息
2. **修复字段名错误**
- 明确禁止使用下划线前缀
- JSON修复机制可以处理字段名错误
3. **增强容错能力**
- 即使模型没有正确提取,后处理机制可以从已有数据中推断
- 多层保障确保关键字段不会为空
## 测试建议
1. **功能测试**
- 使用相同的输入数据测试修复后的代码
- 验证性别、职级、线索来源字段是否正确提取
- 检查字段名是否正确
2. **边界测试**
- 测试性别信息在不同位置的情况(工作基本情况、问题线索等)
- 测试职级信息的不同表述方式
- 测试线索来源的不同表述方式
3. **错误处理测试**
- 测试模型返回错误字段名的情况
- 验证JSON修复机制是否能正确处理
## 后续优化建议
1. **如果问题持续存在**
- 考虑进一步降低temperature参数当前0.2可以尝试0.1
- 考虑调整其他参数top_p, top_k等
- 联系模型服务提供商寻求支持
2. **监控和日志**
- 记录修复前后的字段提取准确率
- 分析仍然存在的错误模式
- 持续优化提示词和后处理机制
3. **考虑使用Few-shot示例**
- 在system prompt中添加正确的JSON示例
- 展示如何正确提取性别、职级等字段
## 总结
通过强化system prompt和增强后处理机制应该能够解决性别字段缺失的问题。如果问题仍然存在可能需要进一步调整模型参数或联系服务提供商。