LLM + 结构化输出作为翻译服务
阅读其他语言: English Español 日本語 한국어 Português
在一篇之前的文章中, 我们讨论了使用AI进行应用本地化的问题,包括自动翻译UI字符串。 针对这个任务,我选择了一个翻译工具而非LLM,基于以下理由:
…我原本计划使用OpenAI的GPT3.5 Turbo,但由于它并非严格意义上的翻译模型,需要额外设置它的提示方式。 此外,它的结果往往不够稳定,因此我选择了专业翻译服务…
那年晚些时候,一些LLM提供商引入了结构化输出功能, 使得LLMs对我们讨论的用例更加合适。 今天,我们将更详细地看看这个问题以及这个功能如何解决它。

问题
LLMs本质上是非确定性的,这意味着它们可能会为相同的输入输出不同的结果。 这种随机性使LLMs具有”创造性”,但也降低了它们在需要遵循特定输出格式时的可靠性。
考虑翻译用例,一个简单的解决方案是在提示中描述所需的格式:
> Translate 'cat' to Dutch. ONLY GIVE A TRANSLATION AND NOTHING ELSE.
虽然这个办法行得通,但偶尔LLM会理解错指令:
> Certainly, allow me to provide the translation for you.
The word 'cat' is translated as 'kat' in Dutch. Sometimes, female cats may also be referred to as 'poes'.
由于应用程序期望接收到的是单个词作为回应,所以任何非单词的回应都可能导致错误或损坏的数据, 即使进行更多的检查和重试,这样的不一致性也会破坏工作流的可靠性。
什么是结构化输出
结构化输出通过让您定义响应的架构来解决格式不一致的问题。 例如,您可以请求像这样的结构:
{
"word": "cat",
"target_locale": "nl",
"translation_1": "kat",
"translation_2": "poes"
}
在内部,结构化输出的实现会因模型而异。 常见的方法包括:
- 使用一个有限状态机来跟踪令牌之间的过渡,并剪除违反所提供的架构的生成路径
- 修改候选令牌的概率,以降低选择不符合马尔可夫属性的选项的可能性
- 用一个专注于识别JSON架构和其他结构化数据格式的数据集微调模型
这些附加机制有助于与只在提示中添加格式指令相比获得更高的可靠性。
代码
让我们更新翻译脚本。 首先,我们定义表示架构的对象:
response_format={
"type": "json_schema",
"json_schema": {
"name": "translation_service",
"schema": {
"type": "object",
"required": [
"word",
"translation"
],
"properties": {
"word": {
"type": "string",
"description": "The word that needs to be translated."
},
"translation": {
"type": "string",
"description": "The translation of the word in the target language."
}
},
"additionalProperties": False
},
"strict": True
}
}
然后,我们可以在执行请求的函数中使用架构对象:
def translate_property_llm(value, target_lang):
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {openai_key}',
}
url = 'https://api.openai.com/v1/chat/completions'
data = {
'model': 'gpt-4o-mini',
'response_format': response_format,
'messages': [
{'role': 'system',
'content': f'Translate "{value}" to {target_lang}. '
f'Only provide the translation without any additional text or explanation.'},
{'role': 'user', 'content': value}
],
}
response = requests.post(url, headers=headers, data=json.dumps(data))
try:
content_json = json.loads(response.json()["choices"][0]["message"]["content"])
return content_json["translation"]
except (json.JSONDecodeError, KeyError) as e:
raise ValueError(f"Failed to parse translation response: {str(e)}")
代码层面就这些了! 欢迎您在GitHub仓库中发现和试验项目的更多内容。
与之前的方法的比较
相比于基于翻译服务的版本, 更新版本的翻译过程花费了更长的时间。 话虽如此,所提供的代码只是最简单的实现示例,如果我们异步发送请求,可以使其更快。
在费用上,翻译到5个语种的费用不到0.01$, 比之前的版本便宜了10倍以上:

略读了一下生成的消息包,我没有注意到任何值得怀疑的地方。 虽然我看不懂新添加的任何一种语言,但格式看起来很好, 我没有发现任何’好的,我会为你翻译它’的情况🙂
为什么重要
虽然我们描述的实验解决了一种小众问题, 但大型语言模型(LLM)的更广泛且重要的特点正体现在此。 在解决特定任务时,它们可能会优于,也可能不如专业的服务, 但真正值得注意的是,LLM能够快速方便地作为解决方案,成为对更专业工具的通用替代品。
作为只对机器学习略知一二的人, 我过去会避开整个类别的任务,因为即使是马马虎虎的解决方案也需要我没有的专业知识。 然而,现在,拼凑在一起的分类器,翻译服务,LLM作为裁决者,以及无数其他应用变得极其容易。
当然,质量仍然需要考虑,但实际上,我们并不需要对许多问题达到100%的完美。 这意味着我们没有理由不去尝试!
结论
我想不出一个有意义的方式来结束这篇文章,所以这里是我今天遇到的猫的照片(这不是AI生成的!):
