1. 像python的langchain 一样使用链式调用

Eino 它提供了两种编排范式:Chain(链)Graph(图)。Chain适合线性的、一步接一步的处理流程;Graph则能表达任意复杂的有向无环图(DAG),支持分支、并行、条件路由。
这两种范式底层共享同一套类型系统和编译机制,Chain本质上就是Graph的一层语法糖–它让简单场景更简洁,同时不妨碍你在需要时切换到Graph获取完整的表达能力。

2. 简单的chain调用示例

在这里插入图片描述

package main

import (
	"context"
	"fmt"
	"github.com/cloudwego/eino-ext/components/model/openai"
	"github.com/cloudwego/eino/components/prompt"
	"github.com/cloudwego/eino/compose"
	"github.com/cloudwego/eino/schema"
	"log"
)

// 这是一个chain 链式调用的示例

func main() {
	ctx := context.Background()

	// 创建模型
	model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
		BaseURL: "https://api-inference.modelscope.cn/v1/",
		APIKey:  "xxx",  // api_key 
		Model:   "Qwen/Qwen3.5-35B-A3B",
	})
	if err != nil {
		log.Fatalf("创建 ChatModel 失败: %v", err)
	}

	// 创建prompt模板
	tpl := prompt.FromMessages(schema.FString,
		schema.SystemMessage("你是一个{role}, 请用简洁专业的语言回复问题"),
		schema.UserMessage("{question}"),
	)

	// 构建chain: 模板 ->模型
	chain := compose.NewChain[map[string]any, *schema.Message]()
	chain.
		AppendChatTemplate(tpl).
		AppendChatModel(model)

	// 编译
	runner, err := chain.Compile(ctx)
	if err != nil {
		log.Fatal("编译失败:", err)
	}
	// 运行
	result, err := runner.Invoke(ctx, map[string]any{
		"role":     "Go语言专家",
		"question": "Go的channel和mutex各自适合什么场景?",
	})
	if err != nil {
		log.Fatal("运行失败:", err)
	}

	fmt.Println(result.Content)
}

3. 这是一个Graph调用示例 在这里插入图片描述

package main

import (
	"context"
	"fmt"
	"github.com/cloudwego/eino-ext/components/model/openai"
	"github.com/cloudwego/eino/components/prompt"
	"github.com/cloudwego/eino/compose"
	"github.com/cloudwego/eino/schema"
	"log"
	"strings"
)

func main() {
	ctx := context.Background()

	// 模型
	model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
		BaseURL: "https://api-inference.modelscope.cn/v1/",
		APIKey:  "xxx", // api_key 
		Model:   "Qwen/Qwen3.5-35B-A3B",
	})
	if err != nil {
		log.Fatalf("创建 ChatModel 失败: %v", err)
	}

	// 分类器
	classifier := compose.InvokableLambda(func(ctx context.Context, input map[string]any) (map[string]any, error) {
		question := input["question"].(string)
		if strings.Contains(question, "编程") || strings.Contains(question, "代码") || strings.Contains(question, "bug") {
			input["category"] = "code"
		} else if strings.Contains(question, "部署") || strings.Contains(question, "运维") || strings.Contains(question, "服务器") {
			input["category"] = "ops"
		} else {
			input["category"] = "general"
		}
		return input, nil
	})

	// 定义不同角色的模板
	codeTpl := prompt.FromMessages(schema.FString,
		schema.SystemMessage("你是一个资深Go语言开发者,擅长代码审查和问题排查,请回答用户的编程问题。"),
		schema.UserMessage("{question}"),
	)

	opsTpl := prompt.FromMessages(schema.FString,
		schema.SystemMessage("你是一个运维专家,精通Linux、Docker和K8s,请回答用户的运维问题。"),
		schema.UserMessage("{question}"),
	)

	generalTpl := prompt.FromMessages(schema.FString,
		schema.SystemMessage("你是一个友好的技术助手,请简洁地回答用户的问题。"),
		schema.UserMessage("{question}"),
	)

	// 构建 Graph
	graph := compose.NewGraph[map[string]any, *schema.Message]()

	// 添加节点
	_ = graph.AddLambdaNode("classifier", classifier)
	_ = graph.AddChatTemplateNode("code_tpl", codeTpl)
	_ = graph.AddChatTemplateNode("ops_tpl", opsTpl)
	_ = graph.AddChatTemplateNode("general_tpl", generalTpl)
	_ = graph.AddChatModelNode("model", model)

	// 定义条件路由
	_ = graph.AddEdge(compose.START, "classifier")
	_ = graph.AddBranch("classifier", compose.NewGraphBranch(
		// 条件函数:根据分类结果决定走哪个分支
		func(ctx context.Context, input map[string]any) (string, error) {
			category := input["category"].(string)
			return category + "_tpl", nil
		},
		// 分支映射:声明所有可能的下游节点
		map[string]bool{
			"code_tpl":    true,
			"ops_tpl":     true,
			"general_tpl": true,
		},
	))
	// 三条分支最终都汇聚到同一个模型节点
	_ = graph.AddEdge("code_tpl", "model")
	_ = graph.AddEdge("ops_tpl", "model")
	_ = graph.AddEdge("general_tpl", "model")
	_ = graph.AddEdge("model", compose.END)

	// 编译并运行
	runner, err := graph.Compile(ctx)
	if err != nil {
		log.Fatal("编译失败:", err)
	}

	// 测试不同类型的问题
	questions := []string{
		"Go代码里怎么避免goroutine泄漏?",
		"Docker容器部署时端口映射不生效怎么办?",
		"推荐几本学习分布式系统的书?",
	}

	for _, q := range questions {
		result, err := runner.Invoke(ctx, map[string]any{"question": q})
		if err != nil {
			log.Printf("问题: %s, 错误: %v\n", q, err)
			continue
		}
		fmt.Printf("问题: %s\n回答: %s\n\n", q, result.Content)
	}
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐