前面的系列已经介绍了 API 调用、上下文组织、结构化输出、错误处理、评估和人工确认。本篇把这些能力组合成一个小项目:读取待翻译文本,逐条调用模型,校验结构化结果,并把每条成功结果立即写入文件。程序中途退出后可以继续处理未完成的项目,人工审阅也不会被模型调用自动跳过。重点不是做一个完整翻译平台,而是观察如何把一次模型调用变成可恢复、可检查的业务流程。
先定义数据和边界 输入文件使用 JSONL,每行一个对象。为了便于复跑,给每条文本一个稳定的 id:
1 2 { "id" : "welcome" , "source" : "欢迎使用我们的产品。" } { "id" : "timeout" , "source" : "请求超时时,请稍后重试。" }
模型只负责提出译文和备注,程序负责读取文件、检查字段、保存进度。它不能直接发布译文,也不能修改原始输入。输出同样使用 JSONL,成功记录包含 id、translation 和 note;失败记录包含 id 和错误类型。这样,人工可以先审阅输出,再决定是否进入后续系统。
准备环境和密钥 使用虚拟环境安装 OpenAI 官方 Python SDK:
1 2 3 4 5 python -m venv .venv source .venv/bin/activatepython -m pip install openai export OPENAI_API_KEY="替换为你的真实密钥" export MODEL_NAME="替换为你可用的模型名称"
密钥只能从环境变量读取,不要写进脚本、输入文件或结果文件。下面使用 Responses API 的 responses.create 和 output_text;如果使用其他服务,应先查该服务的官方文档确认客户端和字段是否一致。
编写最小流水线 创建 translate_review.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 import jsonimport osimport sysfrom pathlib import Pathfrom openai import OpenAIdef load_done (path: Path ) -> set [str ]: if not path.exists(): return set () done = set () for line in path.read_text(encoding="utf-8" ).splitlines(): if not line.strip(): continue item = json.loads(line) if item.get("status" ) == "ok" : done.add(item["id" ]) return done def translate (client: OpenAI, source: str ) -> dict : response = client.responses.create( model=os.environ["MODEL_NAME" ], instructions=( "你是中英翻译助手。把输入翻译成自然、准确的中文。" '只返回 JSON:{"translation":"译文","note":"必要时说明歧义,否则为空字符串"}。' "不要添加 Markdown。" ), input =source, ) result = json.loads(response.output_text) if not isinstance (result.get("translation" ), str ) or not result["translation" ].strip(): raise ValueError("translation 不是非空字符串" ) if not isinstance (result.get("note" ), str ): raise ValueError("note 不是字符串" ) return result def main () -> None : if len (sys.argv) != 3 : raise SystemExit("用法:python translate_review.py input.jsonl output.jsonl" ) input_path, output_path = map (Path, sys.argv[1 :]) done = load_done(output_path) client = OpenAI(api_key=os.environ["OPENAI_API_KEY" ]) with input_path.open (encoding="utf-8" ) as source_file, output_path.open ( "a" , encoding="utf-8" ) as result_file: for line_number, line in enumerate (source_file, 1 ): if not line.strip(): continue item = json.loads(line) item_id = item.get("id" ) source = item.get("source" ) if not isinstance (item_id, str ) or not isinstance (source, str ) or not source: raise ValueError(f"第 {line_number} 行输入无效" ) if item_id in done: continue try : result = translate(client, source) record = {"id" : item_id, "status" : "ok" , **result} done.add(item_id) except (json.JSONDecodeError, KeyError, TypeError, ValueError) as exc: record = {"id" : item_id, "status" : "error" , "error" : type (exc).__name__} result_file.write(json.dumps(record, ensure_ascii=False ) + "\n" ) result_file.flush() print (item_id, record["status" ]) if __name__ == "__main__" : main()
运行命令如下:
1 python translate_review.py input.jsonl output.jsonl
程序不会伪造某个翻译结果,因为真实文本取决于模型和服务状态。可验证的行为是:每条输入最多在一次成功后被记录为 ok,输出文件会在每条记录后立即刷新;再次运行时,load_done 会跳过已经完成的 id。
为什么这样设计 load_done 是恢复能力的关键。它只把状态为 ok 的记录加入集合,因此上次运行中断后,失败项仍然会再次尝试。追加写入比最后一次性写完整文件更能保留进度,但也要求输入的 id 稳定且唯一。生产代码还应检测重复 ID,否则同一业务对象可能被误认为已经完成。
json.loads 只检查 JSON 语法,后面的 translation 和 note 检查才是业务协议校验。模型返回合法 JSON,不代表字段一定可用。当前示例把失败写入结果文件而不是静默丢弃;真实项目可以增加有限次数的指数退避,但认证失败、输入错误等问题不应无条件重试。
人工审阅应当是独立步骤。例如用下面的标准库脚本筛选需要查看的记录:
1 2 3 4 5 6 7 import jsonfrom pathlib import Pathfor line in Path("output.jsonl" ).read_text(encoding="utf-8" ).splitlines(): item = json.loads(line) if item.get("status" ) == "ok" : print (item["id" ], item["translation" ], item["note" ], sep=" | " )
审阅者可以把批准状态写入另一份文件,而不是直接覆盖模型输出。这样既保留原始证据,也能区分“模型生成”“人工批准”和“最终发布”三个阶段。
常见问题 为什么不把所有文本一次发给模型? 批量请求可能超出上下文窗口,也难以定位单条失败。逐条处理更容易重试和恢复;数据量很大时,可以在确认供应商批处理能力和限制后再优化。
重跑会不会产生重复结果? 成功记录会按 id 跳过,但若输出文件被手工修改,程序无法判断修改是否可信。实际项目应保存输入版本、提示词版本和模型名,并在恢复前校验这些元数据。
能否让模型直接决定是否发布? 不建议。模型可以提供翻译和风险备注,但发布属于业务副作用,应由程序规则或人工审批完成。尤其是法律、医疗和品牌文本,必须设定人工审阅边界。
为什么不显示一个固定的运行结果? 模型输出、网络延迟和服务状态都不是本文可以预先保证的。应检查命令退出状态、输出文件格式、成功与失败记录数量,并用脱敏测试数据验证恢复逻辑。
小结 这个项目把结构化输出、文件校验、逐条处理、立即落盘、失败记录和人工审阅串成了一条最小流水线。模型负责生成候选译文,Python 负责定义协议、保存进度和隔离发布动作。以后替换提示词或模型时,只要保留稳定的输入 ID、结果状态和审阅记录,就能把一次性脚本逐步演进为可恢复、可审计的 AI 功能。