本文最后更新于 2025-05-11,墨迹未干时,知识正鲜活。随着时间推移,文章部分内容可能需要重新着墨,请您谅解。Contact

论如何利用AI IDE更加优雅地辅助文字工作之“二十大报告中'坚持'一词双语语料的提取”

引言

要提取出二十大报告双语材料中包含“坚持”一词的语料,第一反应当然是直接在Word里Ctrl F查找,但是此法有一弊——无法提取,即只能一一查找/替换,却无法批量提取出来,那么我们就得换换思路:

方案一:直接把报告全文丢给支持超长上下文的AI(如Gemini),让它负责提取,但是实测上下文过长,模型幻觉太严重了,即使我已经事先用Word自带的替换功能为它用###标记出所有"坚持"的位置,它仍然出现大量的幻觉,遂弃此方案。

方案二:既然全文太长,那么拆分一下在以单次单任务的形式喂给Gemini,是不是可以呢?实测差不多需要分20份左右才能保证它的幻觉不影响输出,如果这份报告是标准的ABAB格式,那我就写个脚本批量切分或者以工作流的形式喂给AI了,可惜这份报告一段中文对应的英文段数是不确定的,或许可以用编码格式来区分,又或许可以喂给其他AI来切分,但是太麻烦了,而且引入更多的不稳定的变量来减小误差?怕是越搞越乱,弃之如鸡肋。

实操

最后之法:正所谓结构越简单越不容易出错,正则就是这样一个好东西,随便选一个AI IDE帮你编写、调试一下Python正则匹配脚本,这里我选的是Augment,主要是因为其足以匹敌Gemini的超长上下文和方便的权限设置,另外现在EA阶段所有用户免费不限量使用。

屏幕截图 2025-05-08 171421.png

言归正传,脚本如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
提取二十大报告中包含"坚持"一词的句子
"""

import re
import os

def split_into_sentences(text):
    """
    将文本分割成句子。
    中文句子通常以句号、问号、感叹号结束,但也要考虑引号等情况。
    """
    # 使用正则表达式分割句子
    # 句子结束标志:句号、问号、感叹号,后面可能跟着引号、括号等
    sentence_endings = r'([。!?\!\?][\"\'\]\)\}]?)'
    sentences = re.split(sentence_endings, text)

    # 重新组合句子和它们的结束符
    result = []
    for i in range(0, len(sentences), 2):
        if i + 1 < len(sentences):
            result.append(sentences[i] + sentences[i + 1])
        else:
            # 处理最后一个可能没有结束符的句子
            result.append(sentences[i])

    # 过滤空句子
    return [s.strip() for s in result if s.strip()]

def extract_sentences_with_keyword(file_path, keyword):
    """
    从文件中提取包含关键词的句子
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            content = file.read()

        # 移除Markdown标记和英文部分(通常在中文段落后面)
        # 这里简单处理,假设中英文是交替出现的
        lines = content.split('\n')
        chinese_content = ""
        for line in lines:
            # 跳过空行和英文行(简单判断,可能需要更复杂的逻辑)
            if not line.strip() or (line.strip() and all(ord(c) < 128 for c in line.strip())):
                continue
            chinese_content += line + "\n"

        # 分割成句子
        sentences = split_into_sentences(chinese_content)

        # 提取包含关键词的句子
        keyword_sentences = []
        for sentence in sentences:
            if keyword in sentence:
                # 移除可能的Markdown标记
                clean_sentence = re.sub(r'[#*_`]', '', sentence)
                keyword_sentences.append(clean_sentence)

        return keyword_sentences

    except Exception as e:
        print(f"处理文件时出错: {e}")
        return []

def save_results(sentences, output_file):
    """
    将结果保存到文件
    """
    try:
        with open(output_file, 'w', encoding='utf-8') as file:
            file.write(f"# 包含\"坚持\"一词的句子\n\n")
            for i, sentence in enumerate(sentences, 1):
                file.write(f"{i}. {sentence}\n\n")
        print(f"结果已保存到 {output_file}")
    except Exception as e:
        print(f"保存结果时出错: {e}")

def main():
    input_file = "中英双语二十大报告全文.md"
    output_file = "坚持_sentences.md"
    keyword = "坚持"

    print(f"正在从 {input_file} 中提取包含\"{keyword}\"的句子...")
    sentences = extract_sentences_with_keyword(input_file, keyword)

    if sentences:
        print(f"找到 {len(sentences)} 个包含\"{keyword}\"的句子")
        save_results(sentences, output_file)
    else:
        print(f"未找到包含\"{keyword}\"的句子")

if __name__ == "__main__":
    main()

打开终端运行一下:

PS C:\Users\Administrator\Documents\augment-projects\online-chat> python extract_jianchi_with_english.py
正在从 中英双语二十大报告全文.md 中提取包含"坚持"的句子及其英文翻译...
共提取到 148 对中英文段落
找到 90 个包含"坚持"的句子
结果已保存到 坚持_sentences_with_english.md
PS C:\Users\Administrator\Documents\augment-projects\online-chat>
PS C:\Users\Administrator\Documents\augment-projects\online-chat> dir .\坚持_sentences.md


    目录: C:\Users\Administrator\Documents\augment-projects\online-chat


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----          2025/5/8     16:12          46437 坚持_sentences.md

然后新的问题又来了:正则匹配筛选后的提取物中存在只提取了中文,对应的英文没有提取的情况,在修改脚本和求助Augment中果断选择使用Augment帮我匹配。把两份文档都开放给Augment,再把它温度调低、设置一个严格的提示词(降低幻觉概率),让它使用正则匹配后添加到脚本提取物中。

这时候就体现出AI IDE的好处了,如果是那种一问一答式的交互式AI调用方式的话,这一步你不但要上传两份大文件,而且AI输出的时候还需要再大量输出,而AI IDE这种调用方式就完全没有这个烦恼,开放读取和编辑权限后,它可以做到在已有的基础上进行增删,大大减少调用成本和被截断的风险。总而言之,一百七十三条,差不多处理了二十分钟完全处理完,即得到AI处理后的完整的原始语料。

原始语料:https://cloudpaste.itvoyager.us/file/jianchi-original-linguistical-data

反查

只是拿到AI处理后的原始语料还是不够的,因为从提取物到原始语料使用了一次大语言模型的"智",即引入了不稳定的变数,即使我已经降低了模型温度、植入了严格的提示词,并且选择了指令遵循性能好的IDE模型,它依旧是变数。所以这一步需要再写一个脚本,用AI处理后的原始语料去原报告反查,脚本如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
验证提取的句子是否与原文一致的脚本
用法: python verify_sentences.py
"""

import re
import os
import sys

def load_file(file_path):
    """加载文件内容"""
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()
    except Exception as e:
        print(f"无法读取文件 {file_path}: {e}")
        sys.exit(1)

def extract_chinese_sentences(content):
    """从坚持_sentences.md中提取中文句子"""
    sentences = []
    lines = content.split('\n')
    current_item_number = None
    current_chinese_lines = []

    for line in lines:
        # 跳过标题行和空行
        if (line.startswith('#') and not line.startswith('##')) or not line.strip():
            continue

        # 如果是数字编号开头,这是一个新条目的开始
        match = re.match(r'^(\d+)\.\s', line)
        if match:
            # 保存之前的条目
            if current_chinese_lines:
                chinese_text = ' '.join(current_chinese_lines)
                if chinese_text.strip():
                    sentences.append({
                        'index': current_item_number,
                        'text': chinese_text.strip()
                    })

            # 开始新条目
            current_item_number = int(match.group(1))
            current_chinese_lines = [line[line.find('.')+1:].strip()]
        elif line.strip().startswith('##'):
            # 英文翻译部分,跳过
            continue
        # 检查是否包含英文字母(简单判断是否为英文)
        elif re.search(r'[a-zA-Z]', line) and len(re.findall(r'[\u4e00-\u9fff]', line)) < 5:
            # 主要是英文内容,跳过
            continue
        elif current_chinese_lines:
            # 继续当前条目的中文部分
            current_chinese_lines.append(line.strip())

    # 添加最后一个条目
    if current_chinese_lines:
        chinese_text = ' '.join(current_chinese_lines)
        if chinese_text.strip():
            sentences.append({
                'index': current_item_number,
                'text': chinese_text.strip()
            })

    return sentences

def verify_sentences(sentences, original_content):
    """验证句子是否在原文中存在"""
    results = []

    # 清理原文中的多余空格,便于比较
    clean_original = re.sub(r'\s+', '', original_content)

    for sentence_obj in sentences:
        sentence_index = sentence_obj['index']
        sentence_text = sentence_obj['text']

        # 清理句子中的多余空格
        clean_sentence = re.sub(r'\s+', '', sentence_text)

        # 在原文中查找句子
        found = clean_sentence in clean_original

        # 如果没找到,尝试分段查找
        if not found and len(clean_sentence) > 50:
            # 将句子分成多个部分,每部分至少50个字符
            parts = []
            start = 0
            min_part_length = 50

            while start < len(clean_sentence):
                end = min(start + 200, len(clean_sentence))
                if end < len(clean_sentence):
                    # 找到一个合适的断句点
                    while end > start + min_part_length and not (
                            clean_sentence[end] in '。,;!?' or
                            clean_sentence[end-1] in '。,;!?'):
                        end -= 1
                parts.append(clean_sentence[start:end])
                start = end

            # 检查每个部分是否都在原文中
            all_parts_found = True
            missing_parts = []
            for part in parts:
                if part and len(part) >= min_part_length and part not in clean_original:
                    all_parts_found = False
                    missing_parts.append(part)

            found = all_parts_found and len(parts) > 0

        # 记录结果
        results.append({
            'index': sentence_index,
            'sentence': sentence_text,
            'found': found,
            'length': len(clean_sentence)
        })

    # 按索引排序
    results.sort(key=lambda x: x['index'])

    return results

def generate_report(results):
    """生成验证报告"""
    total = len(results)
    found = sum(1 for r in results if r['found'])
    not_found = total - found

    report = []
    report.append("# 句子验证报告")
    report.append(f"\n## 摘要")
    report.append(f"- 总句子数: {total}")
    report.append(f"- 在原文中找到: {found}")
    report.append(f"- 未在原文中找到: {not_found}")
    report.append(f"- 准确率: {found/total*100:.2f}%\n")

    if not_found > 0:
        report.append("## 未找到的句子")
        for r in results:
            if not r['found']:
                # 显示句子长度,帮助分析问题
                report.append(f"{r['index']}. 长度: {r['length']} 字符")
                report.append(f"   {r['sentence']}")
                report.append("")

    report.append("## 详细结果")
    for r in results:
        status = "✓ 验证通过" if r['found'] else "✗ 未找到"
        report.append(f"{r['index']}. {status} (长度: {r['length']} 字符)")
        # 只显示句子的前100个字符
        preview = r['sentence'][:100] + ('...' if len(r['sentence']) > 100 else '')
        report.append(f"   {preview}\n")

    # 添加建议
    report.append("## 分析与建议")
    report.append("1. 验证脚本通过去除空格后进行全文匹配,可能会有一定的误差")
    report.append("2. 对于长句子,脚本会尝试分段匹配,但仍可能存在误判")
    report.append("3. 建议手动检查未找到的句子,特别是较长的句子")
    report.append("4. 如果句子确实在原文中存在但未被检测到,可能是因为句子被分割或有细微差异")

    # 添加英文内容过滤说明
    report.append("5. 脚本已尝试过滤英文内容,但可能仍有一些英文内容被包含在提取的句子中")
    report.append("6. 对于包含大量英文的句子,建议手动检查原文")

    return "\n".join(report)

def main():
    # 文件路径
    extracted_file = "坚持_sentences.md"
    original_file = "中英双语二十大报告全文.md"

    # 检查文件是否存在
    if not os.path.exists(extracted_file):
        print(f"错误: 文件 {extracted_file} 不存在")
        sys.exit(1)

    if not os.path.exists(original_file):
        print(f"错误: 文件 {original_file} 不存在")
        sys.exit(1)

    # 加载文件内容
    extracted_content = load_file(extracted_file)
    original_content = load_file(original_file)

    # 提取句子
    sentences = extract_chinese_sentences(extracted_content)
    print(f"从 {extracted_file} 中提取了 {len(sentences)} 个中文句子")

    # 验证句子
    results = verify_sentences(sentences, original_content)

    # 统计结果
    total = len(results)
    found = sum(1 for r in results if r['found'])
    not_found = total - found
    accuracy = found/total*100 if total > 0 else 0

    print(f"验证结果: 总计 {total} 个句子, 找到 {found} 个, 未找到 {not_found} 个, 准确率: {accuracy:.2f}%")

    # 生成报告
    report = generate_report(results)

    # 保存报告
    report_file = "验证报告.md"
    with open(report_file, 'w', encoding='utf-8') as f:
        f.write(report)

    # 如果有未找到的句子,输出到单独的文件
    if not_found > 0:
        unmatched_content = []
        unmatched_content.append("# 未匹配到的句子\n")
        unmatched_content.append("以下句子在原文中未找到匹配:\n")

        for r in results:
            if not r['found']:
                unmatched_content.append(f"## 句子 {r['index']}\n")
                unmatched_content.append(f"长度: {r['length']} 字符\n")
                unmatched_content.append(f"{r['sentence']}\n\n")

        # 保存未匹配句子到单独文件
        unmatched_file = "unmatched.md"
        with open(unmatched_file, 'w', encoding='utf-8') as f:
            f.write("\n".join(unmatched_content))

        print(f"验证完成,详细报告已保存到 {report_file}")
        print(f"未匹配的句子已保存到 {unmatched_file}")

        print("\n注意: 有些句子未在原文中找到,这可能是因为:")
        print("1. 句子在提取过程中被合并或分割")
        print("2. 句子中包含了英文内容")
        print("3. 句子中有细微的差异(如标点符号、空格等)")
    else:
        print(f"验证完成,详细报告已保存到 {report_file}")
        print("所有句子都在原文中找到匹配!")

if __name__ == "__main__":
    main()

处理结果:https://cloudpaste.itvoyager.us/file/jianchi-reverse-check

反查脚本.png

屏幕截图 2025-05-11 113243.png

现在开始看验证结果,没匹配到的一共是18 句,数量已经很少了,接下来可以人工筛查,也可以扔给Gemini,反正现在数量已经少到幻觉的概率极低,我选择人工看一遍,有一些发现:未匹配的所有句子都在原报告中客观存在,未经篡改,之所以匹配失败是因为Augment在提取匹配,生成原始语料的时候每一段的第二局都有小概率出现一个"_"下划线(如下图),所以脚本无法匹配这个下划线导致误判。总的来说,语料准确度是没问题了,接下来统计。

屏幕截图 2025-05-11 111811.png

统计

下面我们开始统计:

总共173个“坚持”,其中存在一句内包含多个“坚持”且间隔很短的情况,并且存在"省略","意译","合句"等情况,总之这一步想要用功能固定格式死板的脚本已经不现实了。

但人工一个一个识别又非我初衷,那么要想办法偷懒,我首先想到反正它翻译情况没多少种,不如先把出现频率高的先识别后剔除,然后剩余的语料大大减少,感觉直接扔给Gemini就没什么问题了,但可以剔除的也要考虑有可能被剔除的词在句中不译为”坚持“,那么还是要对被剔除的进行审查,周末快结束了,所以想进一步偷懒就只能借助AI了,在尝试了各种AI IDE后( Cursor, Augment和Roo Code),我发现或许是编程方面的预设加的有点多,导致通过IDE调用的模型别说处理翻译任务了,连给它确切的指令和目标,让它识别已经翻译好的文本都费劲。遂放弃,转向一问一答的无预设影响的调用方式来完成任务。此处我选择谷歌的AI Studio,提示词:

这是二十大报告的中文和对应的英译合订本,我需要你从这些语料中逐句甄别”坚持“一词在每一句是如何英译的,注意考虑意译或者省略的情况,如果无法确定的情况,请标注无法识别,不得子虚乌有凭空捏造含义或对原始语料进行任何程度的篡改。总共有173个坚持,请不要凭空捏造。

最终你的输出格式应当符合以下格式:
1.译为uphold....
2.意译为....
3.省略....
4.无法识别
....
汇总:”坚持“一词有...种翻译方法,其中uphold占......,commit占....,意译情况占...

jianchi-analysis.png

输出结果我放在我的R2对象存储中:https://cloudpaste.itvoyager.us/file/jianchi-analysis

emm,反正结果依然不太理想,切分语料后效果或许会更好,但是没时间了。