前面我们学习完基础组件:ChatModel、ChatTemplate、ToolsNode、ChatModelAgent。如果业务需要把多个组件按固定先后顺序串联执行,手动写大量变量传递、错误处理会很繁琐。Eino compose包提供Chain(线性链式编排),专门处理无分支、无循环、顺序执行的流水线任务。
📌重要:Chain是Graph的简化特化版本,只支持单向顺序执行;没有条件分支、没有循环。当业务需要分支、判断、回环的时候,就要升级到Graph组件。
💡概念区分
- 1. 直接调用组件:业务手写代码,调用A拿到结果,传给B,再调用B;变量、错误全部自己管理。
- 2. Chain编排:声明式把多个节点Append追加,框架自动处理数据流转、类型校验、错误透传。
通俗比喻:
- • 手写调用 = 手工流水线,每一步自己搬运物料;
- • Chain = 自动化传送带,物料从前一个工位输出,自动送到下一个工位输入,按顺序跑完整条流水线。
一、Chain核心原理
compose.NewChain[Input, Output]() 通过泛型声明整条Chain的输入类型与最终输出类型。
- 1. 使用
AppendXXX()系列方法依次追加节点,节点严格按Append顺序执行; - 2. 前一个节点返回值直接作为下一个节点入参;
- 3. 调用
Compile(ctx)编译Chain,编译阶段校验上下游节点输入输出类型是否匹配,类型不匹配直接报错,不用等到运行时; - 4. Compile后得到
Runnable执行器,调用Invoke()同步执行,或者Stream()流式执行; - 5. 任意节点发生error,整个Chain立刻终止,错误向上返回调用方。
⚠️关键点:每一个Append追加的节点,输出类型必须和下一个节点输入类型对齐,Compile做静态类型检查,Go泛型约束保证安全。
Chain支持追加哪些节点:
| 追加方法 | 对应组件 |
|---|---|
| AppendChatTemplate | Prompt模板组件 |
| AppendChatModel | 大模型调用组件 |
| AppendToolsNode | 工具执行节点 |
| AppendLambda | 自定义Go逻辑(数据转换、清洗、解析) |
| AppendChain | 嵌套子Chain |
| AppendGraph | 嵌套Graph复杂子流程 |
二、Chain完整可运行Demo
业务场景:简单文本摘要流水线
原始用户query → Lambda预处理填充参数 → ChatTemplate组装提示词 → ChatModel调用大模型做摘要 → Lambda提取content字符串输出。
package main
import (
"context"
"fmt"
"os"
eino_openai "github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/prompt"
"github.com/cloudwego/eino/schema"
)
// ptr 辅助函数,返回指针
func ptr[T any](v T) *T { return &v }
// newChatModel 创建模型实例
func newChatModel(ctx context.Context) (model.BaseChatModel, error) {
apiKey := os.Getenv("DEEPSEEK_API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("请设置环境变量 DEEPSEEK_API_KEY")
}
return eino_openai.NewChatModel(ctx, &eino_openai.ChatModelConfig{
BaseURL: "https://api.deepseek.com",
APIKey: apiKey,
Model: "deepseek-v4-flash",
Temperature: ptr(float32(0.3)),
})
}
// buildSummaryChain 构建摘要线性Chain
func buildSummaryChain(ctx context.Context) (compose.Runnable[string, string], error) {
chatModel, err := newChatModel(ctx)
if err != nil {
return nil, err
}
// 1. 定义Prompt模板,变量 {user_text}
tpl, err := prompt.FromMessages(schema.FString,
schema.SystemMessage("你是文本摘要助手,把用户输入的文本精简成2-3句话摘要。"),
schema.UserMessage("待摘要文本:{user_text}"),
)
if err != nil {
return nil, err
}
// 构建Chain:输入string,输出string
chain := compose.NewChain[string, string]()
chain.
// 节点1 Lambda:把输入字符串包装成map,给ChatTemplate使用
AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) (map[string]any, error) {
return map[string]any{
"user_text": input,
}, nil
})).
// 节点2:模板渲染,map输入,输出[]*schema.Message
AppendChatTemplate(tpl).
// 节点3:调用大模型,[]*schema.Message输入,输出*schema.Message
AppendChatModel(chatModel).
// 节点4 Lambda:提取message的content,输出string
AppendLambda(compose.InvokableLambda(func(ctx context.Context, msg *schema.Message) (string, error) {
return msg.Content, nil
}))
// Compile编译,做类型校验
runnable, err := chain.Compile(ctx)
if err != nil {
return nil, fmt.Errorf("chain编译失败: %w", err)
}
return runnable, nil
}
func main() {
ctx := context.Background()
run, err := buildSummaryChain(ctx)
if err != nil {
fmt.Printf("❌ 创建chain失败:%v\n", err)
return
}
userInput := `Eino是CloudWeGo开源的Go原生大模型应用开发框架,提供组件化抽象,
支持ChatModel、Prompt、Tool、编排能力,包含Chain、Graph、Workflow三种编排方式,
可以快速构建Agent、RAG等大模型工程化应用。`
result, err := run.Invoke(ctx, userInput)
if err != nil {
fmt.Printf("❌ chain执行失败:%v\n", err)
return
}
fmt.Println("===== Chain执行结果 =====")
fmt.Println(result)
}执行内部流程(框架自动处理)
输入字符串
↓ Lambda1
map[string]any{"user_text": "..."}
↓ ChatTemplate
[]*schema.Message 组装好的消息数组
↓ ChatModel
*schema.Message 模型返回完整消息
↓ Lambda2
string 最终摘要文本输出三、Chain关键知识点
1. Compile编译做了什么
- 1. 遍历所有Append节点,校验相邻节点输入输出类型是否兼容,类型不匹配直接返回编译错误;
- 2. 构建内部可执行拓扑;
- 3. 注册回调、中间件钩子点;
优势:大部分类型错误开发阶段就暴露,而不是线上运行才panic。
2. Invoke同步 / Stream流式两种执行模式
编译得到Runnable对象支持两套接口:
- •
Invoke(ctx, input):同步调用,等待全部执行完毕返回最终输出; - •
Stream(ctx, input):流式执行,返回*schema.StreamReader[T],适合模型流式输出场景。
示例流式调用片段:
streamR, err := run.Stream(ctx, userInput)
if err != nil {
return err
}
defer streamR.Close()
for {
chunk, err := streamR.Read()
if err != nil {
break
}
fmt.Print(chunk)
}3. Chain嵌套
Chain节点可以嵌套子Chain,使用AppendChain(subChain)。适合把一段复用流水线封装子链,在多个主流程复用。
subChain := compose.NewChain[map[string]any, *schema.Message]()
// ...子链节点配置
mainChain.AppendChain(subChain)四、Chain、Graph、Workflow三者选型对比
| 组件 | 能力 | 适用场景 |
|---|---|---|
| Chain | 仅线性顺序执行,无分支循环;Append追加节点;编译强类型校验 | 简单流水线:摘要、翻译、预处理→prompt→模型;步骤固定无判断逻辑 |
| Graph | 有向图;支持分支、并行、循环回环;AddNode+AddEdge显式连线 | Agent、ReAct循环、条件路由;需要做判断分支逻辑 |
| Workflow | DAG有向无环图;支持结构体字段级映射;面向业务结构体 | 工程化业务服务,多字段映射,对接数据库、API服务层 |
开发建议:能Chain就优先Chain;出现分支/循环再升级Graph;业务是结构体驱动的后端业务,选Workflow。
五、新手避坑清单
❌ 前后节点输入输出类型不匹配,Compile直接报错。一定要看每个组件输入输出类型。
❌ Chain不要写条件分支逻辑,分支逻辑交给Graph;Chain只适合纯顺序流水线。
❌ 忘记调用Compile(),直接调用Invoke会报错;Append只是声明流程,Compile才生成执行器。
❌ Lambda函数输入输出类型写错,泛型校验失败。
✅ 调试技巧:给Runnable增加Callback处理器,打印每一个节点的入参出参,观察流水线数据流转。
✅ 复杂逻辑不要硬塞Lambda,优先拆成子Chain或者升级Graph。
六、组件知识串联总结
组件层级回顾:
- 1. 基础原子组件:ChatModel、ChatTemplate、ToolsNode、InvokableTool
- 2. 编排层:
- • Chain:线性顺序流水线
- • Graph:支持分支循环通用图编排
- 3. 高层封装ADK:ChatModelAgent,内部基于Graph实现ReAct循环。
执行链路示例(Chain串联原子组件):
业务输入 → Lambda(数据转换) → ChatTemplate → ChatModel → Lambda(结果解析) → 输出
Chain本质:把手写的“调用A拿结果传给B”的业务代码,改成声明式编排,框架处理流转、类型、错误、回调。
MiaoAll