diff options
Diffstat (limited to '.agents/skills/citation-verification/references/verification-rules.md')
| -rw-r--r-- | .agents/skills/citation-verification/references/verification-rules.md | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/.agents/skills/citation-verification/references/verification-rules.md b/.agents/skills/citation-verification/references/verification-rules.md new file mode 100644 index 0000000..03d8a35 --- /dev/null +++ b/.agents/skills/citation-verification/references/verification-rules.md @@ -0,0 +1,400 @@ +# 验证规则 + +本文档详细说明四层验证机制的具体规则和匹配算法。 + +## Layer 1: Format Validation (格式验证) + +### BibTeX 格式检查 + +**必填字段验证:** + +不同类型的 BibTeX 条目有不同的必填字段要求: + +**@article (期刊论文):** +- 必填: `author`, `title`, `journal`, `year` +- 可选: `volume`, `number`, `pages`, `doi` + +**@inproceedings (会议论文):** +- 必填: `author`, `title`, `booktitle`, `year` +- 可选: `pages`, `organization`, `doi` + +**@book (书籍):** +- 必填: `author` 或 `editor`, `title`, `publisher`, `year` +- 可选: `volume`, `series`, `address` + +**@misc (其他):** +- 必填: `title` +- 可选: `author`, `howpublished`, `year`, `note` + +### 格式检查规则 + +**1. 条目结构检查** +```python +def check_bibtex_structure(entry): + """检查 BibTeX 条目结构""" + errors = [] + + # 检查是否有类型 + if not entry.get('ENTRYTYPE'): + errors.append("Missing entry type") + + # 检查是否有 ID + if not entry.get('ID'): + errors.append("Missing citation key") + + # 检查必填字段 + required = get_required_fields(entry.get('ENTRYTYPE')) + for field in required: + if not entry.get(field): + errors.append(f"Missing required field: {field}") + + return errors +``` + +**2. 字段格式检查** +```python +def check_field_format(entry): + """检查字段格式""" + errors = [] + + # 年份格式检查 + if 'year' in entry: + year = entry['year'] + if not year.isdigit() or len(year) != 4: + errors.append(f"Invalid year format: {year}") + if int(year) < 1900 or int(year) > 2030: + errors.append(f"Year out of reasonable range: {year}") + + # DOI 格式检查 + if 'doi' in entry: + doi = entry['doi'] + if not doi.startswith('10.'): + errors.append(f"Invalid DOI format: {doi}") + + return errors +``` + +### LaTeX 引用检查 + +**1. 引用命令检查** +```python +def check_latex_citations(tex_content): + """检查 LaTeX 引用命令""" + import re + + # 查找所有引用命令 + cite_pattern = r'\\cite(?:\[[^\]]*\])?\{([^}]+)\}' + citations = re.findall(cite_pattern, tex_content) + + # 展开多个引用 + all_keys = [] + for cite in citations: + keys = [k.strip() for k in cite.split(',')] + all_keys.extend(keys) + + return all_keys +``` + +**2. 引用一致性检查** +```python +def check_citation_consistency(tex_keys, bib_keys): + """检查引用一致性""" + tex_set = set(tex_keys) + bib_set = set(bib_keys) + + # 未定义的引用 + undefined = tex_set - bib_set + + # 未使用的引用 + unused = bib_set - tex_set + + return { + 'undefined': list(undefined), + 'unused': list(unused) + } +``` + +## Layer 2: Existence Verification (存在性验证) + +### API 验证流程 + +**验证步骤:** +1. 根据引用信息选择 API (DOI → CrossRef, arXiv ID → arXiv, 其他 → Semantic Scholar) +2. 调用 API 获取论文信息 +3. 判断论文是否存在 + +**验证结果:** +- `exists` - 论文存在 +- `not_found` - 论文不存在 +- `api_error` - API 调用失败,需要人工验证 + +### 验证代码示例 + +```python +def verify_existence(citation_info): + """验证论文存在性""" + # DOI 优先 + if citation_info.get('doi'): + result = verify_with_crossref(citation_info['doi']) + if result['status'] == 'success': + return {'exists': True, 'source': 'crossref', 'data': result['data']} + + # arXiv ID + if citation_info.get('arxiv_id'): + result = verify_with_arxiv(citation_info['arxiv_id']) + if result['status'] == 'success': + return {'exists': True, 'source': 'arxiv', 'data': result['data']} + + # 通用搜索 + if citation_info.get('title'): + result = verify_with_semantic_scholar(citation_info['title']) + if result['status'] == 'success' and result['data']: + return {'exists': True, 'source': 'semantic_scholar', 'data': result['data']} + + return {'exists': False, 'source': None} +``` + +## Layer 3: Information Matching (信息匹配) + +### 匹配算法 + +**1. 标题匹配** + +使用模糊匹配算法,允许轻微差异: + +```python +from difflib import SequenceMatcher + +def match_title(title1, title2, threshold=0.85): + """标题匹配""" + # 标准化:小写、去除标点 + def normalize(text): + import re + text = text.lower() + text = re.sub(r'[^\w\s]', '', text) + return ' '.join(text.split()) + + t1 = normalize(title1) + t2 = normalize(title2) + + # 计算相似度 + ratio = SequenceMatcher(None, t1, t2).ratio() + + return { + 'match': ratio >= threshold, + 'similarity': ratio + } +``` + +**2. 作者匹配** + +考虑作者顺序和名字格式差异: + +```python +def match_authors(authors1, authors2, threshold=0.7): + """作者匹配""" + def normalize_name(name): + # 处理 "Last, First" 和 "First Last" 格式 + parts = name.replace(',', '').split() + return ' '.join(sorted(parts)).lower() + + names1 = [normalize_name(a) for a in authors1] + names2 = [normalize_name(a) for a in authors2] + + # 计算交集比例 + set1 = set(names1) + set2 = set(names2) + intersection = len(set1 & set2) + union = len(set1 | set2) + + if union == 0: + return {'match': False, 'similarity': 0} + + ratio = intersection / union + + return { + 'match': ratio >= threshold, + 'similarity': ratio + } +``` + +**3. 年份匹配** + +允许 ±1 年的差异(考虑预印本和正式发表的时间差): + +```python +def match_year(year1, year2, tolerance=1): + """年份匹配""" + try: + y1 = int(year1) + y2 = int(year2) + diff = abs(y1 - y2) + return { + 'match': diff <= tolerance, + 'difference': diff + } + except (ValueError, TypeError): + return {'match': False, 'difference': None} +``` + +## Layer 4: Content Validation (内容验证) + +### 综合匹配评分 + +综合所有匹配结果,计算总体匹配分数: + +```python +def calculate_match_score(citation, api_data): + """计算综合匹配分数""" + scores = {} + weights = { + 'title': 0.4, + 'authors': 0.3, + 'year': 0.2, + 'venue': 0.1 + } + + # 标题匹配 + if citation.get('title') and api_data.get('title'): + result = match_title(citation['title'], api_data['title']) + scores['title'] = result['similarity'] + + # 作者匹配 + if citation.get('authors') and api_data.get('authors'): + result = match_authors(citation['authors'], api_data['authors']) + scores['authors'] = result['similarity'] + + # 年份匹配 + if citation.get('year') and api_data.get('year'): + result = match_year(citation['year'], api_data['year']) + scores['year'] = 1.0 if result['match'] else 0.0 + + # 计算加权总分 + total_score = 0 + total_weight = 0 + for key, weight in weights.items(): + if key in scores: + total_score += scores[key] * weight + total_weight += weight + + if total_weight == 0: + return 0 + + return total_score / total_weight +``` + +### 验证结果判定 + +根据匹配分数判定验证结果: + +```python +def judge_verification_result(match_score): + """判定验证结果""" + if match_score >= 0.9: + return { + 'status': 'verified', + 'level': 'high_confidence', + 'message': '✅ 验证通过 - 信息完全匹配' + } + elif match_score >= 0.7: + return { + 'status': 'partial_match', + 'level': 'medium_confidence', + 'message': '⚠️ 部分匹配 - 信息有轻微差异,建议人工确认' + } + elif match_score >= 0.5: + return { + 'status': 'low_match', + 'level': 'low_confidence', + 'message': '❌ 匹配度低 - 信息差异较大,需要人工验证' + } + else: + return { + 'status': 'failed', + 'level': 'no_confidence', + 'message': '❌ 验证失败 - 信息严重不匹配或论文不存在' + } +``` + +## 完整验证流程 + +### 主验证函数 + +```python +def verify_citation_complete(citation): + """完整的引用验证流程""" + result = { + 'citation_key': citation.get('ID'), + 'layers': {} + } + + # Layer 1: 格式验证 + format_errors = check_bibtex_structure(citation) + format_errors.extend(check_field_format(citation)) + result['layers']['format'] = { + 'passed': len(format_errors) == 0, + 'errors': format_errors + } + + # Layer 2: 存在性验证 + existence = verify_existence(citation) + result['layers']['existence'] = existence + + if not existence['exists']: + result['final_status'] = 'not_found' + return result + + # Layer 3 & 4: 信息匹配和内容验证 + api_data = existence['data'] + match_score = calculate_match_score(citation, api_data) + judgment = judge_verification_result(match_score) + + result['layers']['matching'] = { + 'score': match_score, + 'judgment': judgment + } + + result['final_status'] = judgment['status'] + result['confidence'] = judgment['level'] + + return result +``` + +## 验证阈值配置 + +### 可调整的阈值参数 + +```python +VERIFICATION_THRESHOLDS = { + # 匹配阈值 + 'title_similarity': 0.85, # 标题相似度阈值 + 'author_similarity': 0.70, # 作者相似度阈值 + 'year_tolerance': 1, # 年份容差 + + # 判定阈值 + 'high_confidence': 0.90, # 高置信度阈值 + 'medium_confidence': 0.70, # 中等置信度阈值 + 'low_confidence': 0.50, # 低置信度阈值 + + # 权重配置 + 'weights': { + 'title': 0.4, + 'authors': 0.3, + 'year': 0.2, + 'venue': 0.1 + } +} +``` + +### 阈值调整建议 + +**严格模式** (用于正式发表): +- title_similarity: 0.90 +- author_similarity: 0.80 +- high_confidence: 0.95 + +**宽松模式** (用于初稿): +- title_similarity: 0.80 +- author_similarity: 0.60 +- high_confidence: 0.85 + |
