Eino简单学习

Published on in Technology with 0 views and 0 comments

  • Eino框架

  • 是由字节开发的Go的大模型应用框架,为go开发者提供类似LangChain的能力。

  • 核心特性

    • 组件化设计:提供chatModel、Embedding、Retrivcer、Tool等丰富的原子组件
    • 灵活编排:支持Chain和Grapher两张编排模式。
    • 生态集成:支持OpenAI,ARK、Allama,Qwen等多种大模型。
    • 高性能:基于Go,天然支持高并发场景。
    • 易扩展:清晰的接口设计,方便自定义组件。
  • 简单使用

    • go
      package main
      
      import (
      	"context"
      	"fmt"
      	"log"
      	"os"
      
      	"github.com/cloudwego/eino-ext/components/model/deepseek"
      	"github.com/cloudwego/eino/schema"
      )
      
      func main() {
      
      	ctx := context.Background()
      
      	//创建模型
      	model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
      		APIKey:  os.Getenv("API_KEY"),
      		Model:   os.Getenv("deepseek-chat"),
      		BaseURL: "https://api.deepseek.com",
      	})
      	if err != nil {
      		log.Fatalf("create model failed: %v", err)
      	}
      	//开始对话
      	messages := []*schema.Message{
      		schema.SystemMessage("你是一个很好的ai助手"),
      		schema.UserMessage("你好,请介绍一下Eino框架"),
      	}
      	response, err := model.Generate(ctx, messages)
      	if err != nil {
      		log.Fatalf("generate failed: %v", err)
      	}
      
      	content := response.Content
      	//输出结果
      	fmt.Println(content)
      	if response.ResponseMeta != nil  && response.ResponseMeta.Usage != nil {
      		fmt.Println(response.ResponseMeta.Usage)
      		fmt.Printf("input token;%d\n",response.ResponseMeta.Usage.PromptTokens)
      		fmt.Printf("output token;%d\n",response.ResponseMeta.Usage.CompletionTokens)
      		fmt.Printf("total token:%d\n",response.ResponseMeta.Usage.TotalTokens)
      	}
      
      }
      
    • Model:就是大模型实例,需要配置相关key和url。
    • Schema:模式。这个模式当中Message有三种角色。systemMessage、userMessage。system是给系统的提示词,确定了大模型的身份。user是用户输入的信息。
    • 多轮交互
    • go
      func multiChatModel() {
      	ctx := context.Background()
      
      	//创建模型
      	model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
      		APIKey:  os.Getenv("API_KEY"),
      		Model:   os.Getenv("deepseek-chat"),
      		BaseURL: "https://api.deepseek.com",
      	})
      	if err != nil {
      		log.Fatalf("create model failed: %v", err)
      	}
      	//开始对话
      	messages := []*schema.Message{
      		schema.SystemMessage("你是一个很好的ai助手"),
      	}
      
      	scanner := bufio.NewScanner(os.Stdin)
      	fmt.Printf("开始对话(输入exit退出)")
      	for {
      		fmt.Printf("\n你:")
      		if !scanner.Scan() {
      			break
      		}
      		input := strings.TrimSpace(scanner.Text())
      		if input == "exit" {
      			fmt.Println("bye")
      			break
      		}
      		if input == "" {
      			continue
      		}
      		//添加到message中
      		messages = append(messages, schema.UserMessage(input))
      
      		response, err := model.Generate(ctx, messages)
      		if err != nil {
      			log.Fatalf("generate failed: %v", err)
      		}
      		//添加AI响应到历史
      		messages = append(messages, response)
      		fmt.Printf("\nAI: %s\n", response.Content)
      	}
      }
      
    • 流式交互
    • go
      func streamInput() {
      	ctx := context.Background()
      	model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
      		APIKey:  os.Getenv("API_KEY"),
      		Model:   os.Getenv("deepseek-chat"),
      		BaseURL: "https://api.deepseek.com",
      	})
      
      	if err != nil {
      		log.Fatalf("create model failed: %v", err)
      	}
      	messages := []*schema.Message{
      		schema.SystemMessage("你是一个程序员"),
      		schema.UserMessage("请列举5个GO的特点"),
      	}
      	stream, err := model.Stream(ctx, messages)
      	if err != nil {
      		log.Fatalf("stream input failed: %v", err)
      	}
      	defer stream.Close()
      	var fullContent strings.Builder
      
      	for {
      		chunk, err := stream.Recv()
      		if err != nil {
      			if err == io.EOF {
      				break
      			}
      			log.Fatalf("receive failed: %v", err)
      		}
      		fmt.Printf(chunk.Content)
      		fullContent.WriteString(chunk.Content)
      	}
      	fmt.Println(fullContent.String())
      }
      
  • 组件详解

    • ChatModel
      • ChatModelConfig
        • Temperature:随机性,默认0.7
        • Topp:核采样参数,默认0.9
        • MaxTokens:500
        • Stop:遇到这些文本停止生成
        • PresencePenalty:惩罚范围 0.6
        • FrequencyPenalty:惩罚频率,0.5
    • ChatTemplate:一个消息模版,只需要按照设定的模版填充关键指令即可。
      • go
        func chatTemplate() {
        	ctx := context.Background()
        	template := prompt.FromMessages(
        		schema.FString,
        		schema.SystemMessage("你是一个{role}"),
        		schema.UserMessage("{question}"),
        	)
        	//准备变量
        	variables := map[string]any{
        		"role":     "专业的Go程序猿",
        		"question": "请详解一下interface",
        	}
        
        	messages, err := template.Format(ctx, variables)
        	if err != nil {
        		log.Fatalf("format failed: %v", err)
        	}
        	for _, message := range messages {
        		fmt.Println(message.Role, message.Content)
        	}
        	model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
        		APIKey:  os.Getenv("API_KEY"),
        		Model:   os.Getenv("deepseek-chat"),
        		BaseURL: "https://api.deepseek.com",
        	})
        	if err != nil {
        		log.Fatalf("create model failed: %v", err)
        	}
        	generateAndInput(ctx, model, messages)
        }
        
        func generateAndInput(ctx context.Context, model *deepseek.ChatModel, messages []*schema.Message) {
        	resp, err := model.Generate(ctx, messages)
        	if err != nil {
        		log.Fatalf("generate failed: %v", err)
        	}
        	content := resp.Content
        	fmt.Println(content)
        }
        
      • 模版就是可以通过文本,结构体,配置等信息填充模版,还可以设置不同角色模版去做不同的事情。上述只是一个简单的例子,用户可根据实际使用灵活使用。
    • Chain链式编排:Chain是Eino中用于组合多个组件的编排方式。它将多个组件按照顺序连接,前一个组件的输出可以作为后一个组件的输入,形成一个流水线。
      • 简单的template+model编排
      • go
        func simpleChain() {
        	ctx := context.Background()
        	template := prompt.FromMessages(
        		schema.FString,
        		schema.SystemMessage("你是一个{role}"),
        		schema.UserMessage("{question}"),
        	)
        
        	// 创建model
        	model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
        		APIKey:  os.Getenv("API_KEY"),
        		Model:   os.Getenv("deepseek-chat"),
        		BaseURL: "https://api.deepseek.com",
        	})
        	if err != nil {
        		log.Fatalf("create model failed: %v", err)
        	}
        
        	//创建chain
        	chain := compose.NewChain[map[string]any, *schema.Message]()
        	chain.AppendChatTemplate(template) //格式化模版
        	chain.AppendChatModel(model)       //调用模型
        	//编译chain
        	runnable, err := chain.Compile(ctx)
        	if err != nil {
        		log.Fatalf("compile failed: %v", err)
        	}
        	//执行chain
        	input := map[string]any{
        		"role":     "专业的Go程序猿",
        		"question": "请详解一下interface",
        	}
        	output, err := runnable.Invoke(ctx, input)
        	if err != nil {
        		log.Fatalf("execute failed: %v", err)
        	}
        	fmt.Println(output.Content)
        }
        
    • Lambda组件:是chain中的自定义处理节点,可以插入任意逻辑。
      • go
        func simpleLambda() {
        	ctx := context.Background()
        	//创建一个简单chain:输入字符串-转大写字母-天假前缀-输出
        	chain := compose.NewChain[string, string]()
        
        	chain.AppendLambda(
        		compose.InvokableLambda(func(ctx context.Context, input string) (output string, err error) {
        			fmt.Printf("步骤1:输入=%s\n", input)
        			result := strings.ToUpper(input)
        			fmt.Printf("步骤1:输出=%s\n", result)
        			return result, nil
        		})).
        		AppendLambda(
        			compose.InvokableLambda(func(ctx context.Context, input string) (output string, err error) {
        				fmt.Printf("步骤2输入=%s\n", input)
        				result := "prefix" + input
        				fmt.Printf("步骤2输出=%s\n", result)
        				return result, nil
        			}),
        		)
        	compile, err := chain.Compile(ctx)
        	if err != nil {
        		log.Fatalf("compile failed: %v", err)
        	}
        	output, err := compile.Invoke(ctx, "Hello Eino")
        	if err != nil {
        		log.Fatalf("execute failed: %v", err)
        	}
        	fmt.Println(output)
        }
        
      • 从以上代码可以看出来,Lambda组件就是可以在任何节点编排用户自定义的逻辑。
      • Lambda组件其实就是一个匿名函数,其中使用责任链模式以及泛型实现。
      • 复杂Chain-多步骤处理
        • go
          func complicateChain() {
          	ctx := context.Background()
          	// 数据清洗-分析-总结
          
          	// 创建model
          	model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
          		APIKey:  os.Getenv("API_KEY"),
          		Model:   os.Getenv("deepseek-chat"),
          		BaseURL: "https://api.deepseek.com",
          	})
          	if err != nil {
          		log.Fatalf("create model failed: %v", err)
          	}
          	// 创建chain
          	chain := compose.NewChain[string, string]()
          
          	chain.AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) (output string, err error) {
          		// 对字符串去空格换行等
          		cleaned := strings.TrimSpace(input)
          		strings.ReplaceAll(cleaned, "\n\n", "\n")
          		return cleaned, nil
          	})).
          		AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) (map[string]any, error) {
          			fmt.Println(input)
          			return map[string]any{
          				"text": input,
          			}, nil
          		})).
          		AppendGraph(func() *compose.Chain[map[string]any, *schema.Message] {
          			analysisChain := compose.NewChain[map[string]any, *schema.Message]()
          			template := prompt.FromMessages(
          				schema.FString,
          				schema.SystemMessage("你是一个文本分析专家,请分析一下文本的关键信息,主题和情感"),
          				schema.UserMessage("{text}"),
          			)
          			analysisChain.AppendChatTemplate(template)
          			analysisChain.AppendChatModel(model)
          			return analysisChain
          		}()).
          		AppendLambda(compose.InvokableLambda(func(ctx context.Context, msg *schema.Message) (output string, err error) {
          			fmt.Printf("步骤3提取结果")
          			return msg.Content, nil
          		}))
          	compile, err := chain.Compile(ctx)
          	if err != nil {
          		log.Fatalf("compile failed: %v", err)
          	}
          	output, err := compile.Invoke(ctx, "Hello Eino")
          	if err != nil {
          		log.Fatalf("execute failed: %v", err)
          	}
          	fmt.Println(output)
          }
          
        • appendGraph追加的是整个Graph,Graph内部可以有多个节点分支并行处理等。从代码可以看出来,追加的是一个chain。
        • appendLambda仅仅追加单个Lambda函数。
      • 并行处理多个任务
        • javascript
          func parallelChain() {
          	ctx := context.Background()
          	// 创建model
          	model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
          		APIKey:  os.Getenv("API_KEY"),
          		Model:   os.Getenv("deepseek-chat"),
          		BaseURL: "https://api.deepseek.com",
          	})
          	if err != nil {
          		log.Fatalf("create model failed: %v", err)
          	}
          	//创建并行节点
          	parallel := compose.NewParallel()
          
          	// 任务1:提取关键字
          	parallel.AddLambda("keywords", compose.InvokableLambda(func(ctx context.Context, input map[string]any) (output string, err error) {
          		fmt.Println("并行任务1:提取关键字")
          		template := prompt.FromMessages(
          			schema.FString,
          			schema.SystemMessage("请提取文本中的关键字,用逗号分隔"),
          			schema.UserMessage("{text}"),
          		)
          		messages, err := template.Format(ctx, input)
          		if err != nil {
          			log.Fatalf("format failed: %v", err)
          		}
          		resp, err := model.Generate(ctx, messages)
          		if err != nil {
          			log.Fatalf("generate failed: %v", err)
          		}
          		return resp.Content, nil
          	}))
          
          	//并行任务2 情感分析
          	parallel.AddLambda("sentiment", compose.InvokableLambda(func(ctx context.Context, input map[string]any) (output string, err error) {
          		fmt.Println("并行任务2:情感分析")
          		template := prompt.FromMessages(
          			schema.FString,
          			schema.SystemMessage("请分析文本的情感倾向(正面/负面/中性"),
          			schema.UserMessage("{text}"),
          		)
          		messages, err := template.Format(ctx, input)
          		if err != nil {
          			log.Fatalf("format failed: %v", err)
          		}
          		resp, err := model.Generate(ctx, messages)
          		if err != nil {
          			log.Fatalf("generate failed: %v", err)
          		}
          		return resp.Content, nil
          	}))
          
          	//以上生成了两个并行任务集合
          	//现在创建chain
          	chain := compose.NewChain[string, map[string]any]()
          	chain.AppendLambda(compose.InvokableLambda(func(ctx context.Context, input string) (output map[string]any, err error) {
          		return map[string]any{"text": input}, nil
          	})).
          		AppendParallel(parallel).
          		AppendLambda(compose.InvokableLambda(func(ctx context.Context, input map[string]any) (output map[string]any, err error) {
          			fmt.Println("所有任务完成")
          			return input, nil
          	}))
          
          	compile, err := chain.Compile(ctx)
          	if err != nil {
          		log.Fatalf("compile failed: %v", err)
          	}
          	text:= "Eino是一个优秀的开发框架"
          
          	output, err := compile.Invoke(ctx, text)
          	if err != nil {
          		log.Fatalf("execute failed: %v", err)
          	}
          	fmt.Println("任务1",output["keywords"])
          	fmt.Println("任务2",output["sentiment"])
          }
          
      • Branch条件分支
        • go
          func branchChain() {
          	ctx := context.Background()
          	// 定义分支条件
          	branchCondition := func(ctx context.Context, input map[string]any) (string, error) {
          		language := input["language"].(string)
          		language = strings.ToLower(language)
          
          		if language == "go" {
          			return "go_branch", nil
          		}
          		if language == "python" {
          			return "py_branch", nil
          		}
          		return "other_branch", nil
          	}
          
          	// 定义go分支处理
          	goBranch := compose.InvokableLambda(func(ctx context.Context, input map[string]any) (output map[string]any, err error) {
          		fmt.Println("执行go分支")
          		input["advice"] = "推荐使用Eino框架开发"
          		input["features"] = []string{"高性能", "并发支持", "类型安全"}
          		return input, nil
          	})
          
          	// python分支处理
          	pyBranch := compose.InvokableLambda(func(ctx context.Context, input map[string]any) (output map[string]any, err error) {
          		fmt.Println("执行py分支")
          		input["advice"] = "推荐使用LangChain框架开发"
          		input["features"] = []string{"生态好", "易上手", "社区活跃"}
          		return input, nil
          	})
          	// 其他分支
          	otherBranch := compose.InvokableLambda(func(ctx context.Context, input map[string]any) (output map[string]any, err error) {
          		fmt.Println("执行other分支")
          		input["advice"] = "不推荐"
          		input["features"] = []string{"生态好", "易上手", "社区活跃"}
          		return input, nil
          	})
          
          	chain := compose.NewChain[map[string]any, map[string]any]()
          	chain.AppendLambda(compose.InvokableLambda(func(ctx context.Context, input map[string]any) (output map[string]any, err error) {
          		fmt.Println("开始处理")
          		return input, nil
          	})).
          		AppendBranch(
          			compose.NewChainBranch(branchCondition).
          				AddLambda("go_branch", goBranch).
          				AddLambda("py_branch", pyBranch).
          				AddLambda("other_branch", otherBranch),
          		).
          		AppendLambda(compose.InvokableLambda(func(ctx context.Context, input map[string]any) (map[string]any, error) {
          			fmt.Println("处理完成")
          			return input, nil
          		}))
          	compile, err := chain.Compile(ctx)
          	if err != nil {
          		log.Fatalf("compile failed: %v", err)
          	}
          	testCase := []map[string]any{
          		{"language": "go"},
          		{"language": "java"},
          		{"language": "python"},
          	}
          	for _, test := range testCase {
          		fmt.Println("测试")
          		output, err := compile.Invoke(ctx, test)
          		if err != nil {
          			log.Fatalf("execute failed: %v", err)
          		}
          		fmt.Println(output["advice"])
          		fmt.Println(output["features"])
          	}
          }
          
    • Tool工具开发:Tool是AI Agent的双手,让大模型能够执行具体的操作。通过tool可以查询数据库或api、读写文件、执行计算、访问网络资源、生成图表等。
      • 通过实现InvokableTool接口的两个方法实现一个工具。
      • javascript
        // BaseTool get tool info for ChatModel intent recognition.
        type BaseTool interface {
        	Info(ctx context.Context) (*schema.ToolInfo, error)
        }
        
        // InvokableTool the tool for ChatModel intent recognition and ToolsNode execution.
        type InvokableTool interface {
        	BaseTool
        
        	// InvokableRun call function with arguments in JSON format
        	InvokableRun(ctx context.Context, argumentsInJSON string, opts ...Option) (string, error)
        }
        
      • 通过tool。NewTool创建
      • go
        package tool
        
        import (
        	"context"
        	"encoding/json"
        	"fmt"
        	"time"
        
        	"github.com/cloudwego/eino/components/tool/utils"
        	"github.com/cloudwego/eino/schema"
        )
        
        // 通过使用NewTool创建
        
        type TimeParams struct {
        	Format string `json:"format"`
        }
        
        type TimeResult struct {
        	CurrentTime string `json:"current_time"`
        }
        
        func GetCurrentTime(ctx context.Context, params *TimeParams) (*TimeResult, error) {
        	now := time.Now()
        	var result string
        	switch params.Format {
        	case "date":
        		result = now.Format("2006-01-02")
        	case "time":
        		result = now.Format("15:04:05")
        	default:
        		result = now.Format("2006-01-02 15:04:05")
        	}
        	return &TimeResult{CurrentTime: result}, nil
        }
        
        func run() {
        	ctx := context.Background()
        	// 使用util.NewTool将函数封装成工具
        
        	timeTool := utils.NewTool(&schema.ToolInfo{
        		Name: "get_current_time",//这个工具的名称
        		Desc: "获取当前时间",//工具的描述
        		ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
        			"format": {
        				Type:     schema.String,
        				Desc:     "时间格式:date(日期),time(时间),datetime(日期时间)",
        				Required: false,
        			},//info接口中需要知道传参的字段名,以及这个字段名的定义格式和相关描述等。这个是个map,所以可以将需要的参数全部告诉info接口
        		}),
        	}, GetCurrentTime)
        
        	testCase := []string{"date", "time", "datetime"}
        	for _, format := range testCase {
        		params := TimeParams{Format: format}
        		marshal, err := json.Marshal(params)
        		if err != nil {
        			fmt.Println(err)
        		}
        		outPutJson, err := timeTool.InvokableRun(ctx, string(marshal))
        		if err != nil {
        			fmt.Println(err)
        		}
        		fmt.Printf("格式=%s,结果=%s\n", format, outPutJson)
        	}
        }
        
      • ToolsNode
      • go
        package tool
        
        import (
        	"context"
        	"fmt"
        	"os"
        
        	"github.com/cloudwego/eino-ext/components/model/deepseek"
        	"github.com/cloudwego/eino/components/model"
        	"github.com/cloudwego/eino/components/tool"
        	"github.com/cloudwego/eino/components/tool/utils"
        	"github.com/cloudwego/eino/compose"
        	"github.com/cloudwego/eino/schema"
        )
        
        func ToolsNodeCase() {
        	ctx := context.Background()
        
        	currentTime := utils.NewTool(&schema.ToolInfo{
        		Name: "get_cuurent_time",
        		Desc: "获取当前时间",
        		ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
        			"format": {
        				Type:     schema.String,
        				Desc:     "输出格式",
        				Required: true,
        			},
        		}),
        	}, GetCurrentTime)
        
        	calculator := utils.NewTool(&schema.ToolInfo{
        		Name: "加法计算器",
        		Desc: "加法计算器",
        		ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
        			"input": {
        				Type:     "string",
        				Desc:     "输入",
        				Required: false,
        			},
        		}),
        	}, func(ctx context.Context, params map[string]any) (string, error) {
        		return "30", nil
        	})
        
        	chatModel, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
        		APIKey:  os.Getenv("CHAT_MODEL_API_KEY"),
        		Model:   os.Getenv("CHAT_MODEL_MODEL"),
        		BaseURL: os.Getenv("CHAT_MODEL_BASE_URL"),
        	})
        	if err != nil {
        		fmt.Println(err)
        	}
        
        	//创建toolsNOde
        	toolNode, err := compose.NewToolNode(ctx, &compose.ToolsNodeConfig{
        		Tools: []tool.BaseTool{calculator, currentTime},
        	})
        	if err != nil {
        		fmt.Println(err)
        	}
        
        	//获取工具列表信息
        	calInfo, err := calculator.Info(ctx)
        	if err != nil {
        		fmt.Println(err)
        	}
        	timeInfo, err := currentTime.Info(ctx)
        	if err != nil {
        		fmt.Println(err)
        	}
        
        	toolinfos := []*schema.ToolInfo{calInfo, timeInfo}
        
        	testCases := []string{
        		"现在几点了?",
        		"帮我计算一下10+20等于多少?",
        		"你好,请介绍一下自己",
        	}
        
        	for _, testCase := range testCases {
        		messages := []*schema.Message{
        			schema.UserMessage(testCase),
        		}
        		resp, err := chatModel.Generate(ctx, messages, model.WithTools(toolinfos))
        		if err != nil {
        			fmt.Println(err)
        		}
        
        		if len(resp.ToolCalls) > 0 {
        			for _, toolCall := range resp.ToolCalls {
        				fmt.Println("使用工具", toolCall.Function.Name)
        				toolResult, err := toolNode.Invoke(ctx, resp)
        				if err != nil {
        					fmt.Println(err)
        					continue
        				}
        				fmt.Println("工具调用结果", toolResult)
        			}
        		} else {
        			fmt.Println("直接回答", resp.Content)
        		}
        
        	}
        
        }
        
  • React Agent

    • React Agent是一种能够推理和行动循环的智能代理,它能够理解用户意图,规划需要使用的工具,执行工具的调用,分析工具返回的结果,生成最后的答案。
    • 用户通过输入需求,Agent通过思考决定调用哪些可使用的工具得到相关信息,然后最后分析工具返回的结果生成最后的答案。
    • go
      package tool
      
      import (
      	"context"
      	"fmt"
      	"os"
      
      	"github.com/cloudwego/eino-ext/components/model/deepseek"
      	"github.com/cloudwego/eino/components/tool"
      	"github.com/cloudwego/eino/components/tool/utils"
      	"github.com/cloudwego/eino/compose"
      	"github.com/cloudwego/eino/flow/agent/react"
      	"github.com/cloudwego/eino/schema"
      )
      
      func ReactAgentCase() {
      	ctx := context.Background()
      
      	currentTime := utils.NewTool(&schema.ToolInfo{
      		Name: "get_cuurent_time",
      		Desc: "获取当前时间",
      		ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
      			"format": {
      				Type:     schema.String,
      				Desc:     "输出格式",
      				Required: true,
      			},
      		}),
      	}, GetCurrentTime)
      
      	calculator := utils.NewTool(&schema.ToolInfo{
      		Name: "加法计算器",
      		Desc: "加法计算器",
      		ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
      			"input": {
      				Type:     "string",
      				Desc:     "输入",
      				Required: false,
      			},
      		}),
      	}, func(ctx context.Context, params map[string]any) (string, error) {
      		return "30", nil
      	})
      
      	chatModel, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
      		APIKey:  os.Getenv("CHAT_MODEL_API_KEY"),
      		Model:   os.Getenv("CHAT_MODEL_MODEL"),
      		BaseURL: os.Getenv("CHAT_MODEL_BASE_URL"),
      	})
      	if err != nil {
      		fmt.Println(err)
      	}
      
      	agent, err := react.NewAgent(ctx, &react.AgentConfig{
      		ToolCallingModel: chatModel,
      		ToolsConfig: compose.ToolsNodeConfig{
      			Tools: []tool.BaseTool{calculator, currentTime},
      		},
      	})
      	if err != nil {
      		fmt.Println(err)
      	}
      
      	testCases := []string{
      		"现在几点了?",
      		"帮我计算一下10+20等于多少?",
      		"你好,请介绍一下自己",
      	}
      
      	for _, testCase := range testCases {
      		messages := []*schema.Message{
      			schema.UserMessage(testCase),
      		}
      		resp, err := agent.Generate(ctx, messages)
      		if err != nil {
      			fmt.Println(err)
      		}
      		fmt.Println("agent回答:", resp.Content)
      	}
      
      }
      

标题:Eino简单学习
作者:wangzhaoo
地址:http://www.bangnimang.top/eino