Eino - 翻译助手实现

张开发
2026/4/13 7:51:25 15 分钟阅读

分享文章

Eino - 翻译助手实现
Eino - 翻译助手实现前言翻译助手是 AI 应用中的典型场景之一。本文将基于 lab03/case/tran_assistant.go 的实现详细解析如何利用 Eino 框架构建一个功能完善的翻译助手应用代码链接。一、项目概述1.1 功能特性翻译助手具备以下核心功能多语言翻译支持任意目标语言的翻译格式保留保持原文的换行和列表格式结果纯净只输出译文不添加引号或解释错误重试网络波动时自动重试超时控制防止无限等待1.2 代码结构tran_assistant.go ├── Config / ModelConfig / AppConfig # 配置结构体 ├── loadConfig() # 配置加载函数 ├── Translator # 翻译器结构体 │ ├── chatModel # 内部聊天模型 │ ├── NewTranslator() # 构造函数 │ └── Translate() # 翻译方法 └── main() # 程序入口二、设计原则2.1 面向失败设计好的翻译器必须考虑各种失败情况func(t*Translator)Translate(ctx context.Context,text,targetLangstring)(string,error){// 1. 输入验证textstrings.TrimSpace(text)iftext{return,errors.New(empty text)}iftargetLang{return,errors.New(empty target language)}// 2. 超时控制ctx,cancel:context.WithTimeout(ctx,30*time.Second)defercancel()// 3. 重试机制varlastErrerrorforattempt:0;attempt2;attempt{resp,err:t.chatModel.Generate(ctx,messages)iferrnil{returnstrings.TrimSpace(resp.Content),nil}lastErrerr// Context 取消则停止重试iferrors.Is(ctx.Err(),context.DeadlineExceeded){break}// 退避重试time.Sleep(time.Duration(attempt1)*300*time.Millisecond)}return,lastErr}2.2 配置外部化将配置与代码分离便于不同环境使用// main 函数中configPath:flag.String(config,config.yml,配置文件路径)flag.Parse()cfg,err:loadConfig(*configPath)// 创建翻译器时使用配置translator,err:NewTranslator(TranslatorConfig{APIKey:cfg.Model.APIKey,Model:cfg.Model.ModelName,BaseURL:cfg.Model.BaseURL,Timeout:time.Duration(cfg.Model.Timeout)*time.Second,Retries:2,})2.3 构造函数模式通过构造函数封装复杂的创建逻辑funcNewTranslator(cfg TranslatorConfig)(*Translator,error){// 参数校验ifstrings.TrimSpace(cfg.APIKey){returnnil,errors.New(missing api key)}// 默认值设置ifcfg.Model{cfg.Modelgpt-4}ifcfg.BaseURL{cfg.BaseURLhttps://api.openai.com/v1}ifcfg.Timeout0{cfg.Timeout30*time.Second}ifcfg.Retries0{cfg.Retries0}// 创建内部模型chatModel,err:openai.NewChatModel(context.Background(),openai.ChatModelConfig{APIKey:cfg.APIKey,Model:cfg.Model,BaseURL:cfg.BaseURL,Timeout:cfg.Timeout,})iferr!nil{returnnil,err}returnTranslator{chatModel:chatModel},nil}构造函数的优势确保对象在使用前处于有效状态封装复杂的创建逻辑返回错误而非 panic可复用支持多种配置方式2.4 提示词工程通过精心设计的提示词控制输出格式system:fmt.Sprintf(你是一个专业翻译引擎。将用户输入翻译成%s。要求只输出译文不要解释保留原有换行与列表格式不要添加引号不要输出多余内容。,targetLang,)messages:[]*schema.Message{schema.SystemMessage(system),schema.UserMessage(text),}提示词设计要点要点说明角色设定明确 AI 扮演的角色任务描述具体说明要做什么格式要求明确输出格式禁止项说明不要做什么三、Go 高阶语法应用3.1 结构体标签与 YAML 解析typeModelConfigstruct{BaseURLstringyaml:base_urlAPIKeystringyaml:api_keyModelNamestringyaml:model_nameTimeoutintyaml:timeoutTemperaturefloat64yaml:temperatureTopPfloat64yaml:top_pMaxTokensintyaml:max_tokens}结构体标签的作用yaml:base_url指定 YAML 中的字段名映射编译时验证字段对应关系yaml.Unmarshal自动将 YAML 数据绑定到结构体funcloadConfig(configPathstring)(*Config,error){data,err:os.ReadFile(configPath)iferr!nil{returnnil,fmt.Errorf(读取配置文件失败: %w,err)}varconfig Configiferr:yaml.Unmarshal(data,config);err!nil{returnnil,fmt.Errorf(解析配置文件失败: %w,err)}returnconfig,nil}3.2 匿名函数与闭包虽然本代码中没有直接使用匿名函数但 Eino 框架的 Option 模式大量使用了闭包// 闭包示例来自 eino 框架funcWithTemperature(tempfloat32)model.Option{returnmodel.WrapImplSpecificOptFn(func(o*Options){o.Temperaturetemp})}闭包特性可以访问定义时作用域内的变量变量是被捕获的引用而非副本常用于回调和延迟执行场景3.3 错误包装使用%w进行错误包装保留错误链funcloadConfig(configPathstring)(*Config,error){data,err:os.ReadFile(configPath)iferr!nil{returnnil,fmt.Errorf(读取配置文件失败: %w,err)}varconfig Configiferr:yaml.Unmarshal(data,config);err!nil{returnnil,fmt.Errorf(解析配置文件失败: %w,err)}returnconfig,nil}错误链的优势保留完整的错误上下文可以使用errors.Is/errors.As判断错误类型便于调试和日志记录3.4 defer 与资源清理func(t*Translator)Translate(ctx context.Context,text,targetLangstring)(string,error){// 超时控制ctx,cancel:context.WithTimeout(ctx,30*time.Second)defercancel()// 确保函数返回前取消 context// ... 业务逻辑 ...}defer 的执行时机无论函数正常返回还是发生错误都会执行按照 LIFO后进先出顺序执行用于释放资源、关闭连接、取消操作等3.5 切片与匿名结构体使用匿名结构体和切片定义测试用例tests:[]struct{contentstringtargetstring}{{Hello, how are you?,中文},{Eino is a powerful AI development framework,中文},{Les roses sont rouges,中文},{- item1\n- item2\n,中文},}for_,item:rangetests{result,err:translator.Translate(context.Background(),item.content,item.target)// ...}匿名结构体优势无需预先定义结构体类型适合临时使用的数据集合提高代码可读性3.6 strings 包常用方法// TrimSpace - 去除首尾空白textstrings.TrimSpace(text)// TrimSpace - 也用于输入验证ifstrings.TrimSpace(cfg.APIKey){returnnil,errors.New(missing api key)}3.7 time.Duration 类型// time.Duration 是 time 包定义的类型本质是 int64Timeout time.Duration// 乘法运算需要使用 time 包常量time.Duration(cfg.Model.Timeout)*time.Second// 延迟时间time.Sleep(time.Duration(attempt1)*300*time.Millisecond)time.Duration 常用单位常量含义time.Second秒time.Millisecond毫秒time.Minute分钟time.Hour小时3.8 context 与超时控制// 创建带超时的 contextctx,cancel:context.WithTimeout(ctx,30*time.Second)defercancel()// 判断是否超时iferrors.Is(ctx.Err(),context.DeadlineExceeded){break}context 的三大作用作用说明截止时间通过WithTimeout设置取消信号通过WithCancel设置传递数据通过WithValue传递3.9 errors.Is 错误判断iferrors.Is(ctx.Err(),context.DeadlineExceeded)||errors.Is(ctx.Err(),context.Canceled){break}errors.Is vs 直接比较// 不推荐直接比较可能失败错误可能被包装iferrcontext.DeadlineExceeded{...}// 推荐errors.Is 可以穿透包装iferrors.Is(err,context.DeadlineExceeded){...}3.10 fmt.Sprintf 格式化字符串system:fmt.Sprintf(你是一个专业翻译引擎。将用户输入翻译成%s。要求只输出译文不要解释保留原有换行与列表格式不要添加引号不要输出多余内容。,targetLang,)fmt.Sprintf 常用格式化占位符说明%s字符串%d整数%f浮点数%v任意值%q带引号字符串四、完整代码解析4.1 配置结构体// Config 顶层配置typeConfigstruct{Model ModelConfigyaml:modelApp AppConfigyaml:app}// ModelConfig 大模型配置typeModelConfigstruct{BaseURLstringyaml:base_urlAPIKeystringyaml:api_keyModelNamestringyaml:model_nameTimeoutintyaml:timeoutTemperaturefloat64yaml:temperatureTopPfloat64yaml:top_pMaxTokensintyaml:max_tokens}// AppConfig 应用配置typeAppConfigstruct{Hoststringyaml:hostPortintyaml:port}4.2 翻译器结构体typeTranslatorstruct{chatModel*openai.ChatModel// 组合大模型}4.3 翻译流程Translate(text, targetLang) │ ├── 1. 输入验证 │ ├── TrimSpace │ └── 检查空值 │ ├── 2. 创建超时 Context │ ├── WithTimeout │ └── defer cancel │ ├── 3. 构建提示词 │ ├── SystemMessage (翻译规则) │ └── UserMessage (待翻译文本) │ ├── 4. 调用大模型带重试 │ ├── Generate │ ├── 失败 → 退避重试 │ └── 成功 → 返回结果 │ └── 5. 返回结果 └── TrimSpace 清理4.4 main 函数流程funcmain(){// 1. 解析命令行参数configPath:flag.String(config,config.yml,配置文件路径)flag.Parse()// 2. 加载配置cfg,err:loadConfig(*configPath)// 3. 创建翻译器translator,err:NewTranslator(TranslatorConfig{APIKey:cfg.Model.APIKey,Model:cfg.Model.ModelName,BaseURL:cfg.Model.BaseURL,Timeout:time.Duration(cfg.Model.Timeout)*time.Second,Retries:2,})// 4. 执行翻译测试tests:[]struct{contentstringtargetstring}{{Hello, how are you?,中文},{Eino is a powerful AI development framework,中文},// ...}for_,item:rangetests{result,err:translator.Translate(ctx,item.content,item.target)// 处理结果}}五、运行与测试5.1 配置文件model:base_url:https://api.minimaxi.com/v1api_key:your-api-keymodel_name:MiniMax-M2.7timeout:30temperature:0.7top_p:0.9max_tokens:500app:host:0.0.0.0port:80805.2 运行命令go run tran_assistant.go-config../config.yml5.3 输出示例配置加载成功: base_urlhttps://api.minimaxi.com/v1, modelMiniMax-M2.7 原文: Hello, how are you? 翻译: 你好你好吗 原文: Eino is a powerful AI development framework 翻译: Eino 是一个强大的 AI 开发框架 原文: Les roses sont rouges 翻译: 玫瑰是红色的 原文: - item1 - item2 翻译: - 项目1 - 项目2六、最佳实践总结6.1 输入验证检查项处理方式空文本返回明确错误空目标语言返回明确错误首位空白TrimSpace 处理API Key 缺失构造函数返回错误6.2 错误处理构造函数返回错误而非 panic使用 errors.Is 判断错误类型保留错误链便于排查6.3 重试策略forattempt:0;attempt2;attempt{resp,err:t.chatModel.Generate(ctx,messages)iferrnil{returnresp.Content,nil}// Context 取消则停止iferrors.Is(ctx.Err(),context.DeadlineExceeded){break}// 指数退避time.Sleep(time.Duration(attempt1)*300*time.Millisecond)}6.4 提示词设计原则明确角色指定 AI 扮演的角色具体任务清晰描述翻译任务格式要求明确输出格式要求禁止项说明不要做什么七、扩展方向7.1 支持更多翻译模式// 流式翻译func(t*Translator)TranslateStream(ctx context.Context,text,targetLangstring)(*Stream,error)// 批量翻译func(t*Translator)TranslateBatch(ctx context.Context,texts[]string,targetLangstring)([]string,error)7.2 添加 Callback 支持参考 callback/option_callback.go添加日志、埋点等功能。7.3 支持更多模型通过接口抽象支持 Deepseek、Claude 等多种模型typeTranslatorModelinterface{Generate(ctx context.Context,messages[]*schema.Message)(*schema.Message,error)}通过本文的学习你应该掌握了设计原则面向失败设计、配置外部化、构造函数模式、提示词工程Go 高阶语法结构体标签、错误包装、defer、context、超时控制工程实践输入验证、错误处理、重试策略

更多文章