
标签文档翻译API、AI翻译、Python、文档处理、自动化Meta Description用同一组 PDF、Word 和扫描件样本演示如何用 Python 调用 AI 文档翻译 API覆盖上传、轮询、下载、失败重试、样本测试和批量任务控制重点说明不同文档结构下的限制与工程边界。文档翻译API这件事真正难的不是把请求发出去而是怎么在不同文档结构下把任务跑稳。本文用同一组 PDF、Word、扫描件样本演示 Python 调用 AI文档翻译 API 的完整流程重点看上传、轮询、失败处理和批量控制。先说明边界没有单一最优接法不同文件大小、版面复杂度、OCR 需求和回填方式都会直接影响结果与耗时。一、先明确你要调的不是“文本翻译接口”很多人第一次接“文档翻译”时会把它当成普通文本翻译 API上传文件名、传一段文本、拿到结果就结束。实际项目里这个理解往往不够。真正的文档翻译任务通常至少包含 4 个阶段文件上传 → 创建翻译任务 → 后台解析/OCR/翻译/版面处理 → 结果下载与复核如果文档里只有纯文本事情会简单很多但一旦碰到以下场景流程就会明显变复杂场景额外处理点常见风险可编辑 PDF / Word需要保留段落、表格、图片顺序回填后分页变化扫描版 PDF先 OCR再翻译OCR 错字会被继续放大双栏或图文混排需要页面结构分析阅读顺序错乱批量文档任务排队、速率控制、失败重试超时、限流、部分文件失败含隐私材料上传、存储、删除策略要可追溯合规风险高所以写 Python 调用逻辑之前最好先问清楚三件事接口是同步返回还是异步任务制是否支持 OCR、保留排版、批量任务失败后返回的是整单失败还是部分页面失败。二、样本测试说明本文代码是按什么边界写的为了避免代码只在“最简单样本”上成立下面的示例统一按三类样本来说明sample-manual.pdf12 页产品说明书含表格、页眉页脚、截图sample-contract-scan.pdf8 页扫描件合同带印章和浅灰底纹sample-handbook.docx20 页可编辑 Word 手册含多级标题和项目符号。本文默认 API 具备这些能力支持文件上传支持创建异步翻译任务支持传入源语言、目标语言、是否保留版面、是否启用 OCR支持轮询任务状态支持下载翻译结果支持返回失败原因或错误码。说明以下接口地址统一使用https://api.example.com/...。真实项目里字段名和认证方式可能不同但流程上的坑基本类似。三、接入前先定方案同步、异步还是批量队列不是所有接口都适合同一种接法。先看一个总览表接入方式核心思路主要限制更适合先试的场景同步请求单次请求直接等结果返回大文件容易超时长任务不稳定小体积 Word、少页数测试文件异步任务上传后拿任务 ID再轮询状态需要额外做状态管理与超时控制PDF、扫描件、保留排版任务批量队列一次提交多文件统一调度失败定位更复杂限流控制更严格企业批量文档翻译、夜间流水线如果你只是验证接口是否可用可以先试同步或单文件异步前提是样本不要过大。如果你更在意稳定性和可观测性异步任务通常更合理前提是你愿意多做一层轮询与错误处理。如果你处理的是几十到几百份文件批量队列更接近真实生产方式前提是你要能接受“不是每个失败都能立刻在界面上看出来”。四、一个更稳的 Python 接法拆成 5 个独立步骤为了让逻辑更清楚建议把代码拆成下面几步读取配置和认证信息上传文件创建翻译任务轮询任务状态下载结果并记录日志。这样做的好处是以后不管你接别的供应商还是把单文件改成批量流程改动都比较集中。4.1 准备配置importosimporttimeimportrequestsfrompathlibimportPath BASE_URLhttps://api.example.com/v1API_KEYos.environ.get(DOC_TRANSLATION_API_KEY,YOUR_API_KEY)OUTPUT_DIRPath(translated-output)OUTPUT_DIR.mkdir(exist_okTrue)HEADERS{Authorization:fBearer{API_KEY},Accept:application/json,}这里有两个常见坑不要把密钥直接写进仓库不要等到任务失败才发现输出目录没准备好。4.2 上传文件defupload_file(file_path:str)-dict:pathPath(file_path)ifnotpath.exists():raiseFileNotFoundError(ffile not found:{file_path})withpath.open(rb)asf:files{file:(path.name,f,application/octet-stream)}responserequests.post(f{BASE_URL}/files,headersHEADERS,filesfiles,timeout120,)response.raise_for_status()returnresponse.json()上传阶段最好顺手记录三类信息原始文件名、文件大小、返回的file_id。后面一旦批量任务里混入异常文件定位会快很多。4.3 创建翻译任务defcreate_translation_job(file_id:str,source_lang:str,target_lang:str,preserve_layout:boolTrue,enable_ocr:boolFalse)-dict:payload{file_id:file_id,source_lang:source_lang,target_lang:target_lang,preserve_layout:preserve_layout,enable_ocr:enable_ocr,output_format:pdf,}responserequests.post(f{BASE_URL}/document/translate,headers{**HEADERS,Content-Type:application/json},jsonpayload,timeout60,)response.raise_for_status()returnresponse.json()这里最容易忽略的是参数默认值。比如参数如果忽略会怎样建议preserve_layout结果可能只保留文本不保留版面对文档类任务显式传入enable_ocr扫描件可能直接失败或结果为空扫描件按样本显式开启output_format默认导出格式不一定符合业务要求提前固定 PDF / DOCXsource_lang自动识别在混合语言里容易偏语言已知时尽量显式传入五、轮询不是简单 while要把超时、失败和重试一起考虑很多接法的第一个版本都长这样whileTrue:statuscheck_status(job_id)ifstatusdone:breaktime.sleep(2)能跑但不太适合真实环境。问题主要有三个没有总超时接口卡住就一直等没有区分queued、running、partial_failed、failed没有限流控制批量轮询时容易把状态接口打爆。更稳的写法如下defget_job_status(job_id:str)-dict:responserequests.get(f{BASE_URL}/jobs/{job_id},headersHEADERS,timeout30,)response.raise_for_status()returnresponse.json()defwait_for_job(job_id:str,timeout_seconds:int1800,poll_interval:int5)-dict:startedtime.time()whileTrue:resultget_job_status(job_id)statusresult.get(status,unknown)ifstatusin{succeeded,completed}:returnresultifstatusin{failed,canceled,partial_failed}:raiseRuntimeError(fjob{job_id}ended with status{status}:{result})iftime.time()-startedtimeout_seconds:raiseTimeoutError(fjob{job_id}timed out after{timeout_seconds}s)time.sleep(poll_interval)如果你更在意吞吐量可以把poll_interval做成递增例如前 1 分钟每 5 秒查一次之后每 15 秒查一次。这样对长文档任务会更友好。六、把完整流程串起来单文件任务示例前面的几个函数拼起来大概是这样deftranslate_document(file_path:str,source_lang:stren,target_lang:strzh,preserve_layout:boolTrue,enable_ocr:boolFalse)-Path:upload_resultupload_file(file_path)file_idupload_result[file_id]job_resultcreate_translation_job(file_idfile_id,source_langsource_lang,target_langtarget_lang,preserve_layoutpreserve_layout,enable_ocrenable_ocr,)job_idjob_result[job_id]final_resultwait_for_job(job_id)download_urlfinal_result[download_url]output_pathOUTPUT_DIR/ftranslated-{Path(file_path).name}download_file(download_url,output_path)returnoutput_pathdefdownload_file(download_url:str,output_path:Path)-None:responserequests.get(download_url,headersHEADERS,timeout120)response.raise_for_status()output_path.write_bytes(response.content)if__name____main__:resulttranslate_document(file_pathsample-manual.pdf,source_langen,target_langzh,preserve_layoutTrue,enable_ocrFalse,)print(fsaved to:{result})这个版本已经能覆盖大部分单文件调用场景但它还不够生产化因为日志、重试和批量控制还比较薄。七、批量任务怎么写才不容易在第 17 个文件上翻车到了企业场景真正麻烦的通常不是“第 1 个文件能否成功”而是“第 17 个文件失败后整个批次怎么继续”。一个比较实用的策略是单文件失败不拖垮整个批次每个文件都写一条结构化结果针对网络错误做有限次数重试把 OCR 和非 OCR 文件分开跑避免耗时估计失真。示例fromconcurrent.futuresimportThreadPoolExecutor,as_completeddeftranslate_with_retry(file_path:str,max_retries:int2)-dict:forattemptinrange(max_retries1):try:enable_ocrfile_path.endswith(-scan.pdf)result_pathtranslate_document(file_pathfile_path,source_langen,target_langzh,preserve_layoutTrue,enable_ocrenable_ocr,)return{file:file_path,status:ok,output:str(result_path),}exceptExceptionasexc:ifattemptmax_retries:return{file:file_path,status:error,error:str(exc),}time.sleep(3*(attempt1))defrun_batch(files:list[str],max_workers:int3)-list[dict]:results[]withThreadPoolExecutor(max_workersmax_workers)asexecutor:futures[executor.submit(translate_with_retry,file_path)forfile_pathinfiles]forfutureinas_completed(futures):results.append(future.result())returnresults这里的重点不是并发本身而是别把并发开得太猛。文档翻译任务通常比普通文本接口更重如果上游有速率限制max_workers3~5往往比一口气开到 20 更稳。八、样本测试里我会重点盯 5 个指标文档翻译 API 是否适合接入不能只看“有没有结果文件”。至少要看这 5 项指标观察方式典型问题任务成功率10 份样本成功多少份扫描件更容易失败平均耗时单文件从上传到下载的总时长长文档与 OCR 波动大版面稳定性表格、页眉、双栏是否可用复杂 PDF 容易回填错位错误可诊断性失败时是否给出清楚原因很多接口只返回 generic error批量可控性第 N 份失败后是否还能继续容易出现整批中断如果你更在意上线前评估可以先把这 5 个指标记录到 CSV 或数据库里前提是样本里别只放“最容易翻”的文档。九、几个经常被低估的工程细节9.1 OCR 不要默认全开扫描件当然需要 OCR但不是所有 PDF 都要开。对已有文字层的可编辑 PDF盲目开启 OCR 有时反而会让坐标和原始文字层冲突增加版面偏移风险。9.2 不要把下载成功当成可交付结果文件能下载不代表可以直接交付。真正需要复核的通常是表格是否仍可读页码和目录是否还对应图片说明有没有串位条款编号和项目符号有没有错层。9.3 错误码最好分层处理建议至少分成三类网络层超时、连接失败、429 限流任务层上传成功但翻译任务失败结果层任务成功但下载文件损坏或内容不可用。9.4 日志别只打字符串如果后面你要追任务耗时、失败率、不同文件类型表现日志最好一开始就结构化。哪怕只是 JSON 行日志也比一大串print()更适合回溯。十、怎么选什么时候适合自己接 API什么时候不适合如果你更在意可控性、批量接入、与现有系统打通可以优先试 Python 直连 API前提是你愿意处理上传、轮询、错误码和结果复核这些工程细节。如果你只是偶尔处理少量文件且不需要接企业系统可以先用现成界面验证样本再决定要不要投入开发前提是样本规模能代表真实业务。如果你的核心问题是扫描件质量、复杂版面或多语种术语一致性那么接 API 只是第一步前提仍然是先做小样本测试而不是默认接口一接上就能稳定放量。从这组样本看最稳妥的路径通常不是“先上批量”而是“先跑 3 类样本再决定同步、异步还是队列化接入”。这比直接抄一段 demo 更接近真实项目。十一、FAQQ1为什么同样的代码Word 文件成功扫描版 PDF 却经常失败因为扫描件多了一层 OCR 和结构识别失败点比可编辑文档更多尤其在底纹、印章、低分辨率页面上更明显。Q2文档翻译 API 一定要做轮询吗不一定。小文件同步接口可以不轮询但只要任务涉及大文件、OCR 或保留排版异步轮询通常更稳。Q3为什么翻译结果能下载但表格还是错位下载成功只能说明任务完成不代表版面完全可用。表格、双栏和图文混排仍然需要单独抽样复核。Q4批量跑文档时应该先优化并发还是先优化重试通常先把重试、超时和错误分类做好再谈并发。没有这些保护并发放大后只会更难定位问题。Q5在线文档翻译接口怎么评估隐私风险重点看上传后的保留周期、删除机制、审计日志和权限边界。正式合同、客户资料、未公开文档不建议只凭宣传页描述做判断。专注AI文档翻译技术、出海本地化实战与翻译工具选型评测