148 lines
5.5 KiB
Markdown
148 lines
5.5 KiB
Markdown
# 性别和年龄字段缺失问题深度修复
|
||
|
||
## 问题描述
|
||
|
||
测试数据中明明有"男性"、"男"、"年龄44岁"等明确信息,但解析结果中`target_gender`和`target_age`都是空。
|
||
|
||
## 根本原因分析
|
||
|
||
### 问题1:后处理逻辑无法访问原始输入文本
|
||
|
||
**问题**:
|
||
- 后处理函数`_post_process_inferred_fields`只能访问模型返回的JSON解析结果(`data`)
|
||
- 如果模型根本没有提取这些字段,后处理也无法从原始输入文本中提取
|
||
- 后处理逻辑只能从已提取的数据中推断,无法访问原始prompt
|
||
|
||
**影响**:
|
||
- 即使原始输入文本中明确有"男性"、"年龄44岁"等信息
|
||
- 如果模型没有提取,后处理也无法补充
|
||
|
||
### 问题2:模型可能没有正确提取
|
||
|
||
虽然我们强化了system prompt,但模型可能仍然:
|
||
- 忽略了某些字段
|
||
- 返回了空值
|
||
- 字段名错误导致规范化失败
|
||
|
||
## 修复方案
|
||
|
||
### 1. 增强后处理逻辑,支持从原始输入文本提取 ✅
|
||
|
||
**修改位置**:`services/ai_service.py` 第1236-1350行
|
||
|
||
**改进内容**:
|
||
|
||
1. **修改函数签名**,增加`prompt`参数:
|
||
```python
|
||
def _post_process_inferred_fields(self, data: Dict, output_fields: List[Dict], prompt: str = None) -> Dict:
|
||
```
|
||
|
||
2. **从原始输入文本中提取性别**:
|
||
```python
|
||
# 如果仍然没有,尝试从原始输入文本(prompt)中提取
|
||
if (not data.get('target_gender') or data.get('target_gender') == '') and prompt:
|
||
# 从prompt中提取输入文本部分(通常在"输入文本:"之后)
|
||
input_text_match = re.search(r'输入文本[::]\s*\n(.*?)(?:\n\n需要提取的字段|$)', prompt, re.DOTALL)
|
||
if input_text_match:
|
||
input_text = input_text_match.group(1)
|
||
# 匹配性别关键词:男性、女性、男、女等
|
||
if re.search(r'\b男性\b|\b男\b', input_text) and not re.search(r'\b女性\b|\b女\b', input_text):
|
||
data['target_gender'] = '男'
|
||
elif re.search(r'\b女性\b|\b女\b', input_text) and not re.search(r'\b男性\b|\b男\b', input_text):
|
||
data['target_gender'] = '女'
|
||
elif re.search(r'[,,]\s*([男女])\s*[,,]', input_text):
|
||
gender_match = re.search(r'[,,]\s*([男女])\s*[,,]', input_text)
|
||
if gender_match:
|
||
data['target_gender'] = gender_match.group(1)
|
||
```
|
||
|
||
3. **从原始输入文本中提取年龄**:
|
||
```python
|
||
# 如果还没有,尝试从原始输入文本中直接提取年龄
|
||
if (not data.get('target_age') or data.get('target_age') == '') and prompt:
|
||
input_text_match = re.search(r'输入文本[::]\s*\n(.*?)(?:\n\n需要提取的字段|$)', prompt, re.DOTALL)
|
||
if input_text_match:
|
||
input_text = input_text_match.group(1)
|
||
# 匹配年龄模式:年龄44岁、44岁、年龄44等
|
||
age_match = re.search(r'年龄\s*(\d+)\s*岁|(\d+)\s*岁|年龄\s*(\d+)', input_text)
|
||
if age_match:
|
||
age = age_match.group(1) or age_match.group(2) or age_match.group(3)
|
||
if age:
|
||
data['target_age'] = str(age)
|
||
```
|
||
|
||
4. **更新所有调用点**,传入`prompt`参数:
|
||
```python
|
||
# 修改前
|
||
normalized_data = self._post_process_inferred_fields(normalized_data, output_fields)
|
||
|
||
# 修改后
|
||
normalized_data = self._post_process_inferred_fields(normalized_data, output_fields, prompt)
|
||
```
|
||
|
||
### 2. 提取逻辑的优先级
|
||
|
||
后处理逻辑按以下优先级提取字段:
|
||
|
||
**对于性别(target_gender)**:
|
||
1. 从`target_work_basic_info`中提取(匹配`XXX,男,...`模式)
|
||
2. 从所有已提取的文本字段中查找(使用正则表达式)
|
||
3. **从原始输入文本中提取**(新增)
|
||
|
||
**对于年龄(target_age)**:
|
||
1. 从`target_date_of_birth`计算(根据出生年月和当前年份)
|
||
2. **从原始输入文本中直接提取**(新增,匹配"年龄44岁"等模式)
|
||
|
||
## 预期效果
|
||
|
||
1. **提高字段提取成功率**
|
||
- 即使模型没有提取,后处理也能从原始输入文本中提取
|
||
- 多层保障确保关键字段不会为空
|
||
|
||
2. **增强容错能力**
|
||
- 不依赖模型的提取准确性
|
||
- 即使模型返回空值,也能从原始输入中补充
|
||
|
||
3. **提高数据完整性**
|
||
- 确保性别、年龄等关键字段有值
|
||
- 减少空值的情况
|
||
|
||
## 测试建议
|
||
|
||
1. **功能测试**
|
||
- 使用包含"男性"、"年龄44岁"的测试数据
|
||
- 验证后处理是否能从原始输入文本中提取
|
||
- 检查日志输出,确认提取来源
|
||
|
||
2. **边界测试**
|
||
- 测试性别信息在不同位置的情况
|
||
- 测试年龄的不同表述方式("44岁"、"年龄44"、"年龄44岁"等)
|
||
- 测试模型返回空值的情况
|
||
|
||
3. **日志检查**
|
||
- 查看日志中的"后处理"信息
|
||
- 确认是从哪个来源提取的字段
|
||
- 验证提取逻辑是否正确执行
|
||
|
||
## 调试建议
|
||
|
||
如果问题仍然存在,可以:
|
||
|
||
1. **检查日志输出**
|
||
- 查看`[AI服务] 后处理:从原始输入文本中提取...`的日志
|
||
- 确认prompt是否正确传入
|
||
- 确认正则表达式是否匹配成功
|
||
|
||
2. **手动测试正则表达式**
|
||
- 测试`r'输入文本[::]\s*\n(.*?)(?:\n\n需要提取的字段|$)'`是否能正确提取输入文本
|
||
- 测试性别和年龄的正则表达式是否能匹配
|
||
|
||
3. **检查prompt格式**
|
||
- 确认prompt中确实包含"输入文本:"标签
|
||
- 确认输入文本的格式是否符合预期
|
||
|
||
## 总结
|
||
|
||
通过增强后处理逻辑,让它能够访问原始输入文本(prompt),即使模型没有正确提取字段,也能从原始输入中补充。这提供了多层保障,确保关键字段不会为空。
|
||
|