基于SiliconCloud构建自修正翻译智能体Para的完整实践 去年我把手头几个翻译相关的脚本全部推翻重写换到SiliconCloud上做了一个叫Para的翻译智能体。起因很朴素当时经手的文档翻译量越来越大邮件、产品说明、论文摘要、技术手册内容五花八门通用翻译API翻出来总觉得能用但不够地道尤其是术语前后不一致、人称和语气飘忽不定同一份文档里同一个词能出现三种译法。后来我决定不在翻译引擎层面死磕而是把翻译这件事本身拆成一个智能体项目来做让模型在翻译的时候能自己查术语表、自己检查译稿、自己决定要不要重译。这篇文章就把Para从设计到落地的完整过程捋一遍包括架构思路、API接入方式、提示词工程以及我在实际使用中踩过的一堆坑。Para这个名字取自paraphrase核心定位是一个具备自我修正能力的翻译智能体。它跑在SiliconCloud平台上利用平台的函数调用能力和大模型API实现整个翻译流程的自动化。如果你正在做类似的技术写作、多语言内容本地化或者单纯想学习怎么把一个AI工具从调接口翻译一段文字升级成像真人译员一样工作的智能流程这篇文章应该能给你不少可以直接照搬的方案。1. 为什么Para没有做成套壳翻译而做成了智能体先说一个反直觉的结论单纯把翻译API的调用封装成一个好看的工具这活儿做起来很快但实际用起来价值非常有限。市面上现成的翻译API很多你花半天时间写个脚本把文本POST过去拿到译文功能上就完成了。但在真实工作流里你很快会发现几个绕不过去的问题。第一个问题是术语不一致。技术文档、公司内部规范、电商商品描述这些场景里往往有一批固定术语比如某个产品名、某个协议缩写它们在公司内部有既定译法。通用翻译引擎不会认识你的企业术语库同一个术语在不同段落甚至同一段落里可能被翻成不同说法这在正式交付时是硬伤。第二个问题是上下文不连贯。翻译不是逐句替换前后段落往往共享指代关系、语气和行文风格。如果你只是把文本一段一段丢给模型它是看不到全局的尤其当文本超过模型单次输入上限的时候你被迫分块翻译最后拼接出来的译文经常出现前半段用你后半段用您这种割裂感。第三个问题是缺少质量反馈环节。人工翻译有初译-校对-定稿的流程而直接调API的结果就是模型给你什么你就用什么中间没有任何纠错机制。我一开始也没意识到这一点直到有一次把一份合同条款的翻译拿给合作方看对方指出一处关键措辞不妥我才开始思考——为什么不能在这个工具里内置一个校对者呢1.1 智能体方案的核心价值把翻译工具改造成智能体本质上是把一次翻译请求变成一个可多步骤执行的任务。翻译这个动作不再只是输入-输出的单次函数调用而是被拆解成理解原文意图和适用场景检索并应用术语表约束执行初译对照术语表和翻译规范进行自检必要时回炉重译输出带质量标记的最终结果传统API是翻译一下就结束智能体是确保翻译结果可靠才结束。Para的核心价值就在这个闭环里。1.2 SiliconCloud在Para整个流程中扮演的角色SiliconCloud这个平台解决了两件事。第一件事是模型接入的便利性。平台集成了大量开源大模型API开发者不需要自己部署模型注册拿到API Key就能通过标准接口调用。这对我来说非常关键因为我一开始就不打算自己维护模型——个人项目的精力应该花在流程编排上而不是GPU运维上。第二件事是函数调用Function Calling能力的支持。Para规划的几个步骤里模型需要决定在什么时候调用术语检索工具、什么时候调用翻译执行器、什么时候触发质量检查。一个支持原生函数调用的模型可以稳定地输出结构化的工具调用参数这比我在提示词里要求模型输出JSON要可靠得多后者在复杂任务里经常格式飘移。我选择的模型是平台上一款足够均衡的中文多语种模型参数量级不追求最大但函数调用稳定性和指令跟随表现很好。Para这个项目本质上不是一个用最贵模型跑最重任务的项目而是一个靠流程设计把中等能力模型用出高可靠性的项目。2. Para的骨架工具调用框架与API接入流程Para整体跑起来是一个自主循环用户给出一段待翻译文本和翻译要求智能体自己决定调用哪些工具、按什么顺序调用、要不要重译。这套逻辑在代码层面非常简单熟悉LLM应用开发的人看到骨架会觉得很眼熟。2.1 预置的翻译工具集Para内部为模型提供了三个工具函数翻译流程的自主性就体现在模型对这些函数的调度上translate_text(text, target_lang, style)执行单次翻译。这里的实现就是拼好prompt调用SiliconCloud的对话模型返回译文文本。lookup_glossary(term)查询术语库。Para携带了一个简单的本地术语映射表模型在准备翻译某个词之前可以主动查询确保用词统一。review_translation(source, translation, glossary)质量检查。模拟译后审校重点是检查术语一致性、漏译、数字和专有名词的误译返回问题清单。这三个工具的关系很像真实翻译项目里的分工翻译员在动笔前查术语库翻完之后编辑再看一遍。模型被提示词引导成一个项目经理负责决定这些工具何时被调用、以什么参数调用、调用结果需要做何处理。2.2 一次翻译请求的完整执行链路举个例子用户向Para提交了一段英文产品描述要求翻译成中文并明确说术语按公司文档来。整个任务会经历这么几条路径第一步模型收到消息后不会立刻给译文而是先调用lookup_glossary检查原文里的产品名一个叫SmartSync的组件是否在术语表里有既定译法。SmartSync在术语表里被锁定为智联同步模块这一步就避免了这个名字被随意音译或者直译。第二步模型带着术语表约束去调用translate_text在翻译prompt中显式注入了SmartSync必须译为智联同步模块。此时翻译质量已经比裸调API高了一截因为关键术语被锁死了。第三步模型拿到译文后调用review_translation让审校者角色检查整段译文。审校结果如果发现问题例如同一个interface在这段里被翻成界面、上一段里却翻成接口Para就会把问题连同原文一起再次交给translate_text重译直到审校环节不再抛出错误。这一步走完最终返回给用户的不是一段裸译文而是一个JSON结构包含译文、术语使用情况、审校记录和最终质量评分。现实中一个译者的工作流被完整地还原成了一个可调用的逻辑。2.3 SiliconCloud API接入的最小可用代码这里我直接贴一段简化但可运行的核心逻辑展示整个模型决定调用工具 - 执行 - 结果回填 - 再次调用模型的循环是什么样的。import json import requests API_KEY your_siliconcloud_api_key BASE_URL https://api.siliconflow.cn/v1/chat/completions MODEL_ID 你选择的模型ID def call_model(messages, toolsNone): payload { model: MODEL_ID, messages: messages, tools: tools, tool_choice: auto, } headers { Authorization: fBearer {API_KEY}, Content-Type: application/json, } resp requests.post(BASE_URL, jsonpayload, headersheaders) data resp.json() return data[choices][0][message] def lookup_glossary(term): glossary { SmartSync: 智联同步模块, latency: 响应延迟, } return glossary.get(term, ) def translate_text(text, target_lang, style): # 实际会注入术语表和风格约束这里简化 messages [ {role: system, content: 你是专业翻译。请将用户内容翻译成 target_lang 风格 style}, {role: user, content: text}, ] result call_model(messages) return result.get(content, ) def review_translation(source, translation, glossary): review_prompt f原文本{source}\n译文{translation}\n根据术语表{glossary}检查译文指出术语不一致、漏译等问题。 result call_model([ {role: system, content: 你是严谨的翻译审校者}, {role: user, content: review_prompt}, ]) return result.get(content, ) TOOLS [ { type: function, function: { name: translate_text, description: 执行文本翻译, parameters: { type: object, properties: { text: {type: string}, target_lang: {type: string}, style: {type: string}, }, required: [text, target_lang], }, }, }, { type: function, function: { name: lookup_glossary, description: 查询术语表, parameters: { type: object, properties: { term: {type: string}, }, required: [term], }, }, }, { type: function, function: { name: review_translation, description: 审校翻译结果, parameters: { type: object, properties: { source: {type: string}, translation: {type: string}, glossary: {type: object}, }, required: [source, translation], }, }, }, ] def run_translation_agent(user_request): messages [ {role: system, content: 你是一个翻译智能体负责调度翻译工具完成高质量翻译任务。}, {role: user, content: user_request}, ] # 确保进入循环让模型自主决定每一步 while True: message call_model(messages, toolsTOOLS) if message.get(tool_calls): messages.append(message) for tool_call in message[tool_calls]: name tool_call[function][name] args json.loads(tool_call[function][arguments]) if name lookup_glossary: result lookup_glossary(args[term]) elif name translate_text: result translate_text(args[text], args[target_lang], args.get(style, neutral)) elif name review_translation: result review_translation(args[source], args[translation], args.get(glossary, {})) messages.append({ role: tool, tool_call_id: tool_call[id], content: json.dumps(result, ensure_asciiFalse), }) else: return message.get(content, ) if __name__ __main__: print(run_translation_agent( Translate the following product description into Chinese, follow company glossary.\n\n SmartSync keeps latency below 50ms even under heavy load. ))这段代码里最值得关注的是while True这个循环。它模拟的就是智能体思考-行动-观察的循环。模型每次返回结果有两种可能一种是要求调用工具一种是直接给出最终答案。只要工具没跑完对话就继续——这里的消息历史里会不断累积工具调用记录和结果模型始终拥有完整上下文。新手容易忽略的是messages的累积方式。我把tool_calls的响应消息放回了对话历史然后把每个工具执行结果以role: tool的形式再追加一条。如果漏掉这两步模型会完全不知道工具返回了什么循环就断了。这是整个接入流程里最机械但最容易被搞错的地方。2.4 为什么选用平台自带函数调用而不是自己解析JSON有些人可能觉得函数调用没必要直接在提示词里让模型输出一个JSON自己解析不是更省事吗我一开始也是这么想的后来发现这条路极其脆弱。模型的JSON输出经常出现多余的解释性文字、键名被篡改、内部引号转义错误等问题你写解析器的时间远超你的预期。而平台的原生函数调用机制在模型内部就把接下来要调用什么工具这件事格式化成结构化对象返回了。你说它多花钱吗确实贵一点点但换来的是稳定性。翻译这种流程里一步解析失败整个任务就得重来得不偿失。另外原生函数调用让模型变成由任务驱动而非由文本驱动。想想看你让模型输出一句译文它写了你让模型决定要不要调用审校工具它得先理解审校工具存在的意义再基于翻译结果做判断。这个过程更接近真实译者的工作方式也方便你在后续加更多工具比如加一个术语冲突报警工具而不需要改模型本身。3. 翻译质量的关键不在模型在提示词与术语管理很多人做翻译工具把绝大部分精力放在选模型上觉得模型聪明翻译就地道。这个观点对个人闲聊场景大体成立但对Para这种生产型翻译工具来说真正决定译文可用性的是把系统的提示词工程——尤其是术语管理和风格控制——做扎实。3.1 系统提示词应该如何分层设计我先展示Para实际使用的系统提示词骨架然后逐条拆解设计的理由你是专业翻译智能体服务于企业文档本地化场景。 你的职责是把源语言文本翻译成目标语言并确保以下事项 1. 术语一致性翻译任何文本前先查询术语表遇到术语表已有条目必须使用对应译法。 2. 准确性数字、单位、专有名词、产品版本号必须原样保留不得增删修改。 3. 风格适配根据用户指定的风格参数调整译文默认风格为中性客观。 4. 质量自检每次翻译后调用审校工具审校发现的问题必须回炉修改。 5. 输出格式最终输出包含译文、术语表匹配项、审校说明。这个提示词的核心不是告诉模型你要翻译得准确这种空话而是把Para工作流里的几个关键规则显式地嵌进模型的行为里。特别是翻译前先查术语和翻译后必须自检这两条是整个翻译闭环的行为锚点。一些开发者习惯在系统提示词里堆砌请务必一定要注意高质量等形容词这对模型的行为约束几乎为零。与其说请翻译得专业不如明确告诉它数字和版本号不得修改术语必须查询后再译。能落成规则的内容不要落成期望。3.2 术语表的运作机制Para的术语表是一个普通的JSON文件结构很简单{ SmartSync: { zh: 智联同步模块, note: 产品组件名保持统一 }, latency: { zh: 响应延迟, note: 性能指标专用 }, on-premise: { zh: 本地化部署, note: 勿译为企业内部部署 } }术语表在代码层面的调用方式由模型决定。模型在读原文时如果扫描到SmartSync这个词它可以主动调用lookup_glossary查询这个条目。查询返回的内容会作为工具结果回传给模型模型再有意识地在翻译时遵循。但要注意纯文本的lookup_glossary对模型的决策依赖很高——模型不查术语约束就不生效。为了让查术语这件事更可靠我在系统提示词里加了强制规则同时把原文里疑似术语的词语也提前用程序扫描一遍把候选词和术语表匹配结果直接交给模型作为参考。这样模型在决策时就更倾向于遵循术语约束了。说白了术语管理不能只靠模型自觉要模型查询程序预扫描双管齐下。Para在每次翻译前会预处理原文用简单的字符串匹配把出现过的术语标记出来塞进一个术语参考字段里。模型翻译时看到这一行就知道有哪些词是被锁定的这比让它在长文中自行发现要可靠得多。3.3 风格控制参数化的两种方式风格是翻译工具容易被忽视的另一个维度。同样是翻译一封邮件面向客户的和面向内部同事的用词习惯和语气应该完全不同。Para用两个参数来控制风格一个是指定风格类型formal/informal/neutral一个是提供风格样例。方法一风格类型映射为一段风格描述。比如styleformal时系统提示词里动态追加一段译文使用书面语避免口语化保持句式完整对原文的委婉语气予以保留。这比让模型自己体会正式感要具体得多。方法二提供风格参考句子。更进一步的用法是给模型一两个风格参考的句子。我经常在翻译产品文案时这样做把公司已有的中文宣传稿的两个典型句子作为样例放到上下文里让模型模仿这个调性。对于语气难以量化描述的场景比如幽默、克制、有煽动性样例比形容词有用得多。我个人的经验是风格控制要克制——只锁定必须统一的要素就够了。过度限制风格会导致译文丧失自然度变成标准得有点僵硬的语言。Para默认的风格约束只有三句话术语一致、数字原样保留、句式连贯不破碎。其他东西尽量不限制让模型自由发挥反而更自然。3.4 长文档翻译的语义连贯策略技术文档和手册动辄几千字甚至上万字单次翻译不可能塞进模型的上下文窗口。Para的思路是分段翻译加语义衔接。分段不是简单按字符数切而是按语义块切。Para会先对原文做粗颗粒度的段落切分以自然段落为边界保证每个语义块尽量完整。翻译完一块后取出这个块的最后两句译文作为上文衔接提示注入下一块的翻译prompt中。这能很有效避免上一段用了某个译法下一段突然换一种的问题。对于指代关系也有一个实用的小技巧——让模型在翻译每一块时把原文中出现的人称代词、指示代词在本块开头做一次显式还原。比如原文说its interface is intuitive在单独翻译这一句时its指代不明模型不知道是哪个产品的界面。Para的分块prompt会带上前文提到的产品为SmartSync所有代词请按该产品处理的约束这样处理后人称代词导致的误译大幅减少。4. 我踩过的坑从token爆炸到译文输出格式漂移Para从雏形到稳定运行中间踩了好几个坑有的坑差点让我直接放弃这个方案。挑最典型的几个写出来希望后面做类似智能体的少走点弯路。4.1 上下文无限增长导致的token成本飙升这是第一个坑也是最容易被忽略的一个。在智能体循环里每一次工具调用都会向消息列表中追加两条记录模型的工具调用消息和工具的执行结果。一个翻译任务如果走完查术语-翻译-审校-重译这条链路消息条数可能轻松超过15条token数也随之膨胀。多次重译时消息列表的token占用可能比用户输入本身多出好几倍。我一开始没有对历史消息做截断结果跑到第30个任务的时候API账单比预期高出一大截。最冤的是很多历史消息根本没用——前面的工具调用细节在后面的决策中几乎不会起作用模型真正依赖的只是最新一轮的工具结果。解决办法是在每轮工具执行完之后对消息列表做一次压缩。把最早的系统消息和最近一轮的上下文保留下来中间的过程性内容合并成一段摘要。这个摘要用一句话描述已经完成翻译初稿并通过审校重新作为一条系统消息注入。这样整个对话始终保持在系统提示词 任务摘要 当前轮上下文的紧凑结构里。4.2 模型输出的格式漂移与解析容错在函数调用模式下模型输出基本上能被平台规范好。但我在早期版本里曾经尝试过让模型直接把最终译文封装成JSON返回那段时间是噩梦。模型时不时在JSON外面包裹一层Markdown代码块标记或者在JSON内部加入以下是译文之类的前缀导致json.loads直接抛异常。后来我彻底放弃了让模型自由输出JSON的做法所有结构化需求全部走函数调用参数。最终译文如果需要以JSON返回我就在代码层面自己组装而不是让模型来拼。这个经验可以复用一个简单原则结构化数据永远不要在模型输出层处理要在代码层处理。函数调用的参数已经由平台保证是合法JSON剩下需要做的就是利用好它。4.3 不同模型之间的翻译风格差异我在SiliconCloud上测试过好几款模型发现一个规律模型能力排行榜上的得分和实际翻译质量的相关性比想象中低。有的模型在通用问答上表现优异但翻译出来的句子总是带着一股机器味——用词正确但节奏奇怪读起来不像人话另一些模型在力量上稍弱但翻译文本流畅得多明显是在多语种语料上有过专门训练。这个坑的教训是做翻译智能体不要频繁切换模型。先选一款模型充分调好提示词和流程让整体效果达到你能接受的最高水平然后把它固定下来。别今天换这个明天换那个否则你永远不知道当前的问题到底出在模型还是流程上。4.4 工具调用模式下多轮对话历史丢弃问题还有一个非常隐蔽的问题如果你对消息列表做了过度压缩或者不小心在工具调用循环中把之前的tool_call消息删了模型就会失忆出现一些很蠢的行为。比如之前已经查询过术语表结果模型再翻一遍或者审校已经通过了模型还要再调一次审校工具。解决方案是压缩历史时至少要保证当前这轮任务的完整工具调用链不被破坏。具体来说消息列表中的最后一条工具结果一定要保留因为模型需要知道当前状态是什么。之前的结果可以压缩成摘要但当前状态信息不能丢。这里有一个我习惯使用的检查方式在每轮循环后打日志把当前的最后5条消息打印出来看看模型能不能推理出下一步该做什么。如果模型看不到最近一次翻译的结果它大概率会推倒重来白白浪费一次调用。5. 上线为一个HTTP服务后的实测表现与成本账单Para在本地脚本里跑通之后我把它包装成了一个HTTP服务方便用网页或命令行随时调用。这个阶段的工作更像工程问题怎么部署、怎么控制并发、怎么算成本。5.1 把翻译智能体封装成服务我用开放式Web框架包了一层对外暴露一个简单的接口POST /translate Content-Type: application/json { text: SmartSync keeps latency below 50ms..., target_lang: zh-CN, style: formal }服务端拿着参数直接调用已有的run_translation_agent()逻辑把最终JSON原样返回。服务本身的实现不超过50行但有两个工程细节值得一说。一是同步调用还是异步调用。长文档翻译往往要跑几十秒HTTP连接很容易超时。我直接采用了提交任务、返回任务ID、前端轮询结果的方式。这样即便一次翻译需要一两分钟也不会受网关连接超时影响。二是并发控制。SiliconCloud的API Key一般有速率限制同时发出太多并发请求会触发限流错误。我在服务层用一个简单的信号量控制同时进行的翻译任务数量默认最大同时2个请求后续根据需要调整。宁可排队也不要被限流后重试重试带来的挫折感反而更麻烦。5.2 实测对比有审校闭环和没有审校闭环的翻译差异我拿同一篇英文技术文档做了两组翻译测试。第一组直接让同一个模型的普通API翻译不经过Para的智能体流程第二组走Para的完整流程。两组对比最明显的差异有两个。第一个差异在术语一致性上。直接翻译的版本里SmartSync出现了三种译法SmartSync、智联同步、智同步模块。这显然不可接受。而Para版本因为术语表锁定全文始终统一成智联同步模块。第二个差异在审校环节发现的数字错误。直接翻译版本在处理50ms的时候有一处被模型误写成50毫秒另一处却写成了50秒这种错误如果没人检查交付出去会造成严重问题。Para的审校工具能识别出这类数值不一致的问题并触发重译。审校闭环的代价是成本和时间。一个600词的技术文档段落直接翻译消耗约2500 token走完全链路大概消耗9000 token时间也慢了一倍左右。但这个代价对于生产级翻译来说是完全可以接受的——质量提升带来的价值远超token成本。5.3 一个万字文档翻译的成本估算这里给一个大概的数字参考。SiliconCloud平台上的模型计费各有不同以当前主流的对话模型平均价格来看我实际跑下来一份约1万英文词的文档按完整Para流程处理大约消耗40万token左右其中翻译本身占六成审校和术语查询占四成。换算成实际费用大约在几元到十几元的量级具体取决于你选的模型型号和单价。这个成本曲线很有意思——单次调用的单价提升一点整体费用可能翻倍但你换来的审校闭环能大幅减少人工校对和返工时间。我在实际工作中对比过用Para处理的文档我基本只需要通读一遍确认语气流畅即可交付裸翻译的文档我要抽出专门时间逐段核对术语和数字。前者节省的时间成本远远超过多出来的API费用。5.4 Para目前还做不到的事情说实话Para也还有几个当前版本解决得不好的场景写出来供你评估是否值得投入一个是对图片和PDF中嵌入文字的处理。Para目前只能接收纯文本PDF需要先用其他工具把文字抽出来但抽取过程经常破坏表格结构和标题层级翻译结果也就跟着不理想。这个领域的完整解决方案已经超出了翻译智能体本身的范畴需要额外的文档解析流水线配合。另一个是多语种之间的直接互译。Para的流程设计以中英互译为主要场景对其他语种的术语表和审校规则还没有细分。如果直接用法语、德语、日语的翻译任务术语表的匹配范围和审校规则的准确性都会下降。不过这两个短板不影响它在纯文本场景的可靠性。就我目前的使用频率来说Para已经替代了原先所有直接的翻译API调用成为我日常处理中英文本的默认工具。5.5 后续如果继续完善如果你也想在类似平台上做一个翻译智能体Path的方向大概有这么几条把术语表从本地JSON换成一个可多人协作维护的在线术语库这样团队内部不同成员都可以补充术语为每一个语种单独定制审校规则而不是所有语种共用一套再把长文档的段落切分策略进一步调优让语义块的划分更贴合实际句子边界。对我来说Para这个项目的价值不光在于能翻得更好更重要的是让我完整理解了智能体是怎么把一个单次模型调用变成多步骤自主流程的。如果你现在手里也有一堆用API但效果不够好的工具不妨也用同样的思路重构一下——加工具、加决策、加审校闭环你会发现工具的能力边界比想象中大得多。