本作者原文地址
https://juejin.cn/spost/7514982917199888393
Eino市场定位
Eino 基于明确的“组件”定义,提供强大的流程“编排”,覆盖开发全流程,旨在帮助开发者以最快的速度实现最有深度的大模型应用。
产品特点
-
内核稳定,API 简单易懂,有明确的上手路径,平滑的学习曲线。
-
极致的扩展性,研发工作高度活跃,长期可持续。
-
基于强类型语言 Golang,代码能看懂,易维护,高可靠。
-
背靠字节跳动核心业务线的充分实践经验。
-
提供开箱即用的配套工具。
项目地址:https://github.com/cloudwego/eino,https://github.com/cloudwego/eino-ext
快速认识Eino
Eino 是覆盖 devops 全流程的大模型应用开发框架,从最佳实践样例的 Eino Examples,到各环节的工具链,都是 Eino 的领域:
个人的认知当中,eino不仅仅是一个项目,而注重的是一个产品,这个产品整体上是以eino这个项目为主导,衍生出多个分支下的组件进行相辅相成
在目前初步认识eino的前提下,确定根据官方文档,主要是从这三个项目中进行展开,找到学习eino相关的突破口
eino的作用
那么 Eino 具体能做什么?首先,Eino 由一个个大模型领域的“组件”组成,比如最核心的是与大模型交互的 Chat Model:
model, _ := ark.NewChatModel(ctx, config) // 创建一个豆包大模型 message, _ := model.Generate(ctx, []*Message{ SystemMessage("you are a helpful assistant."), UserMessage("what does the future AI App look like?")}
以 ReAct Agent 为例:一个 ChatModel(大模型),“绑定”了 Tool(工具),接收输入的 Message,由 ChatModel 自主判断是否调用 Tool 或输出最终结果。Tool 执行结果会再次成为给到 ChatModel 的 Message,并作为下一轮自主判断的上下文。
// 构建一个 ReAct Agent,编译为一个输入为 []*Message,输出为 *Message 的 Runnable // 创建包含 state 的 Graph,用户存储请求维度的 Message 上下文 graph = NewGraph[[]*Message, *Message]( WithGenLocalState(func(ctx context.Context) *state { return &state{Messages: make([]*Message, 0, config.MaxStep+1)} })) // 将一个轮次中的上下文和响应,存储到 Graph 的临时状态中 modelPreHandle = func(ctx context.Context, input []*Message, state *state) ([]*Message, error) { state.Messages = append(state.Messages, input...) return state.Messages, nil } _ = graph.AddChatModelNode(nodeKeyModel, chatModel, WithStatePreHandler(modelPreHandle)) _ = graph.AddEdge(START, nodeKeyModel) _ = graph.AddToolsNode(nodeKeyTools, toolsNode) // chatModel 的输出可能是多个 Message 的流 // 这个 StreamGraphBranch 根据流的首个包即可完成判断,降低延迟 modelPostBranch = NewStreamGraphBranch( func(_ context.Context, sr *schema.StreamReader[*Message]) (endNode string, err error) { defer sr.Close() if msg, err := sr.Recv(); err != nil { return "", err } else if len(msg.ToolCalls) == 0 { return END, nil } return nodeKeyTools, nil }, map[string]bool{nodeKeyTools: true, END: true}) _ = graph.AddBranch(nodeKeyModel, modelPostBranch) // toolsNode 执行结果反馈给 chatModel _ = graph.AddEdge(nodeKeyTools, nodeKeyModel) // 编译 Graph:类型检查、callback 注入、自动流式转换、生成执行器 agent, _ := graph.Compile(ctx, WithMaxRunSteps(config.MaxStep))
在上面这几十行代码的背后,Eino 自动做了一些事情:
-
类型检查,在 compile 时确保相邻的节点的类型对齐。
-
流式封装,编译出的 Runnable 既可以 Invoke 调用,也可以 Stream 调用,无论内部的 Tool 是否支持流。
-
并发管理,对 state 这个公共状态的读写是并发安全的。
-
横切面注入,如果某个组件(比如一个 tool)没有实现 callbacks 注入,则 Eino 自动注入。
-
Option 分配,编译出的 Runnable 可以灵活接收并把 option 分配给指定的节点。
Eino的独特优势
Eino尽力去做到,既需要封装领域内“不变”的通用核心要素,又需要基于最新进展敏捷的横向和纵向扩展。
另一方面,目前较为主流的框架如 LangChain,LlamaIndex 等,都基于 Python,虽然能借助 Python 较为丰富的生态快速实现多样的功能,但是同时也继承了 Python 作为动态语言所带来的“弱类型检验”和“长期维护成本高”等问题。在大模型应用快速进入大规模线上运行阶段的当下,基于 Golang 这一强类型语言而实现的高可靠性和高可维护性,逐渐具有更大的价值。
在Python垄断的主流框架之下,更希望使用Golang这样的强类型语言去对大模型进行开发
内核稳定
每类组件作为一个 interface,有完善、稳定的定义:具体的输入输出类型,明确的运行时 option,以及明确的流处理范式。(在对于开发规范和项目整体设计是要有明确的规定)
敏捷扩展
每类组件都可以横向扩展出不同的实现,比如 ChatModel 组件可以有 OpenAI、Gemini、Claude 等不同的实现等。这些具体的实现,在实现组件 interface 从而可作为组件参与编排的基础上,可以实现和持续扩展自身的特殊功能。
当实际业务场景中,出现需要进入编排但是不对应任何组件定义的功能时,Eino 支持将自定义 function 声明为 Lambda 类型。Lambda 有用户声明的输入输出以及 option 类型,可支持全部的流处理范式,具备完整的 Callback 能力,在编排视角等价于官方组件。
高可用易维护
基于 Golang 写 Eino 代码时,开发者可以充分利用 Golang 的强类型特性,为所有的组件、Lambda、编排产物等声明具体类型。这像是为代码绘制了一幅精确的地图,开发者可以沿着清晰的路径进行维护和扩展,即使在项目规模不断扩大、功能持续迭代的情况下,依然能够保有较高的可维护性。
同时,Eino 编排能力也充分利用了强类型系统的编译时校验能力,尽可能将类型匹配问题暴露的时机提前到 graph 的编译时,而不是 graph 的运行时。尽早并明确的暴露类型匹配问题,有助于开发者迅速定位和修复,减少因类型错误在运行时引发的难以排查的故障和性能问题。
另一方面,Eino 遵循模块化设计,核心库以及各组件实现是单独的 go module,每个 go module 做到依赖最小化。同时,API 设计以“精简”、“直观"和“同构性”为原则,辅以由浅入深的全面文档,尽可能让学习曲线更平滑。最重要的是,Eino 采用清晰的分层设计,每层职责明确、功能内聚,在提升维护性的同时能更好的保证稳定性
工具生态完善
链路追踪、调试、可视化,是编排引擎的三个重要辅助工具。Eino 内置了 tracing callback,并与 APMPlus 和 Langfuse 平台做了集成。同时提供了 IDE 插件,可以在写代码的过程中随时可视化查看编排出的 graph,并进行调试运行,甚至可以通过 UI 拖拽的方式快速构建 graph 并导出为 Eino 代码。
对于Eino个人理解
对于笔者而言,也是由Go语言服务端开发,慢慢去熟悉大模型应用相关的领域;在开始学习Eino这样的大语言模型应用开发框架时也是十分吃力的,有些地方也是比较难去理解;但是笔者一个很好的朋友告诉我,难上手是正常的,多写几遍,就像你高考写解析几何一样,熟练度来自踩坑 踩的坑越多熟练度会越高;笔者也十分坚定,携风而行,滴水石穿!