最近,Coze 开源的代码中包含了一个名为 Eino 的框架,其基于 Go 语言的组件化设计和图编排能力引发了开发者对 AI 应用开发效率的关注。Eino 的核心理念是通过组件抽象和图结构编排,解决大模型应用中的复杂流程控制、流式处理和状态管理问题。
而与此同时,在 Java 生态中默默耕耘的 FEL 框架,也因其简洁流畅的任务编排能力,逐渐走入更多工程师的视野。它不追求炫酷的图结构,而是专注于让开发者用最自然的方式定义 AI 工作流。
两者都瞄准了同一个目标:提升 AI 应用的开发效率与可维护性。但它们走的是两条截然不同的路。
今天,我们就从一些代码示例出发,对比 Eino 和 FEL 的编排设计哲学。
一、简单场景:谁更“顺手”?
让我们先来看一个最基础的对话流程:

这几乎是所有 LLM 应用的起点。
✅ Eino 的做法:链式 or 图式?
Eino 提供了三种编排方式:Chain、Graph、Workflow。对于这个简单场景,推荐使用 Chain:
chain, _ := NewChain[map[string]any, *Message]().
AppendChatTemplate(prompt).
AppendChatModel(model).
Compile(ctx)
chain.Invoke(ctx, map[string]any{"query": "what's your name?"})
干净利落,链式调用清晰表达了执行顺序。
但如果换成 Graph 方式(即便逻辑一样),代码立刻变得复杂:
graph := NewGraph[map[string]any, *schema.Message]()
_ = graph.AddChatTemplateNode("node_template", chatTpl)
_ = graph.AddChatModelNode("node_model", chatModel)
_ = graph.AddEdge(START, "node_template")
_ = graph.AddEdge("node_template", "node_model")
_ = graph.AddEdge("node_model", END)
compiledGraph, err := graph.Compile(ctx)
if err != nil {
return err
}
compiledGraph.Invoke(ctx, map[string]any{"query":"what's your name?"})
多了节点命名、显式连边等操作——自由度更高,代价是冗余感上升。
✅ FEL 的做法:只有一种方式,但足够好用
FEL 坚持“大道至简”,只提供一种 Fluent API 风格的流程定义:
AiProcessFlow<Tip, String> flow = AiFlows.<Tip>create()
.prompt(Prompts.human("question: {query}"))
.generate(model)
.reduce(() -> "", (acc, chunk) -> acc += chunk.text())
.close();
flow.converse().offer(Tip.from("query", "what's your name?"));
没有图、没有节点 ID、没有 start/end 标记。整个流程像一条自然的语言流水线,读起来就像在描述业务本身。
这种设计的背后,是一种以开发者体验为中心的理念:你不需要理解图论,也能写出可靠的 AI 流程。
二、进阶挑战:条件分支,谁更优雅?
真实世界的应用从来不是一条直线。加入条件判断后,可以进一步校验编排能力。
我们扩展一下需求:

在模型输出后,判断是否需要记录日志。如果需要,则调用日志函数;否则直接返回。
Eino:两种路径,同一套逻辑
无论是 Chain 还是 Graph,Eino 都依赖“条件函数返回目标节点名”的机制来实现跳转。
Chain 写法:
branchCond := func(ctx context.Context, input *schema.Message) (string, error) {
if isNeedLog(input) {
return "log", nil
}
return "else", nil
}
log := compose.InvokableLambda(func(ctx context.Context, input *schema.Message) (*schema.Message, error) {
log(input)
return input, nil
})
elseBranch := compose.InvokableLambda(func(ctx context.Context, input *schema.Message) (string, error) {
return input, nil
})
chain, _ := NewChain[map[string]any, *schema.Message]().
AppendChatTemplate(prompt).
AppendChatModel(model).
AppendBranch(compose.NewChainBranch(branchCond).AddLambda("log", log).AddLambda("else", elseBranch))
Compile(ctx)
chain.Invoke(ctx, map[string]any{"query": "what's your name?"})
Graph 写法:
branchCond := func(ctx context.Context, input *schema.Message) (string, error) {
if isNeedLog(input) {
return "node_log", nil
}
return compose.END, nil
}
graph := NewGraph[map[string]any, *schema.Message]()
_ = graph.AddChatTemplateNode("node_template", chatTpl)
_ = graph.AddChatModelNode("node_model", chatModel)
_ = graph.AddLambdaNode("node_log", log)
_ = graph.AddEdge(START, "node_template")
_ = graph.AddEdge("node_template", "node_model")
_ = graph.AddBranch("node_model", branchCond)
_ = graph.AddEdge("node_log", END)
compiledGraph, err := graph.Compile(ctx)
if err != nil {
return err
}
compiledGraph.Invoke(ctx, map[string]any{"query": "what's your name?"})
可以看到,虽然整体表现方式不同,但是条件分支的核心逻辑一致:通过字符串匹配决定流向。
优点是灵活性高,支持任意拓扑;缺点也很明显——字符串硬编码易出错,调试困难。一旦拼错节点名,运行时才会报错。
FEL:条件即表达式,无需跳转
FEL 的处理方式更像是函数式编程中的 match 或 when 表达式:
AiProcessFlow<Tip, String> flow = AiFlows.<Tip>create()
.prompt(Prompts.human("question: {query}"))
.generate(model)
.reduce(() -> "", (acc, chunk) -> acc += chunk.text())
.conditions()
.when(this::isNeedLog, this::log)
.others(input -> input)
.close();
flow.converse().offer(Tip.from("query", "what's your name?"));
关键在于 conditions 这个 DSL 关键字,它把分支逻辑封装成声明式语句,完全避免了“跳转”概念。分支动作也是函数式接口,易于测试和复用。整体语法延续了之前的流畅风格,无割裂感。
你可以把它理解为:“在这个环节,根据某些规则做选择,然后继续往下走”,而不是“我要跳到哪个节点去”。
三、设计哲学的碰撞:图 vs 流
看到这里,你会发现 Eino 和 FEL 的差异远不止语法糖那么简单。它们代表了两种截然不同的设计哲学:

四、结语:我们需要什么样的 AI 编排?
对开发者而言,AI 编排工具的终极理想无疑是:越简单越好用。我们渴望的是能快速落地、易于维护的解决方案,而不是陷入复杂的架构设计中。
但现实往往需要权衡——简洁的 API 背后,是否牺牲了应对复杂场景的能力?强大的图模型,又是否会抬高使用门槛,让日常开发变得笨重?
目前来看,FEL 明确选择了“简洁至上”的路径。它通过流畅的 Fluent API 抽象掉底层细节,让开发者专注业务逻辑本身,显著提升了常规任务的开发效率。
而 Eino 则走了一条更偏“能力先行”的道路。它直接暴露图结构与节点控制,以原生支持循环、分支、动态跳转等复杂拓扑,为构建智能体、自动化流程等高级场景提供了坚实基础。
然而,真正的成熟框架,不能只停留在“简单”或“强大”的单一体验上。我们还需要它在状态管理、流式处理、循环递归、错误恢复、可观测性等方面都交出令人信服的答卷。
这场关于 AI 编排的探索才刚刚开始。接下来,我们将深入更多真实场景,逐一检验 FEL 与 Eino 的边界与潜力。
最终的问题不是“谁更好”,而是:“在我们的业务语境下,谁更合适?”
🎁 想体验?看这里!
1. 进入官网(https://modelengine-ai.net/#/download) 下载 Windows 最新版
2. 按照下载页面的指引完成安装
3. 安装成功后即可进入页面体验,立即开始你的 AI 开发之旅!
4. 更多精彩内容请查看官网文档(https://modelengine-ai.net/#/docs) 中的应用工程栏目
![]()
我们诚挚邀请您:
-
加入开源社区! ModelEngine 是开源项目!欢迎开发者 Star 我们的仓库,共同参与建设,打造更强大的 AI 应用开发平台!
-
反馈宝贵意见: 您的建议是我们持续优化的动力!
2373

被折叠的 条评论
为什么被折叠?



