Skip to content
鼓励作者:欢迎打赏犒劳

eino整合Tools

单次对话

go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/cloudwego/eino-ext/components/model/ollama"
	"github.com/cloudwego/eino/adk"
	"github.com/cloudwego/eino/components/tool"
	"github.com/cloudwego/eino/components/tool/utils"
	"github.com/cloudwego/eino/compose"
	"github.com/cloudwego/eino/schema"
)

type WeatherParams struct {
	City string `json:"city" jsonschema:"required" jsonschema_description:"城市名称,例如:北京、上海、广州"`
}

type WeatherResult struct {
	City        string  `json:"city"`
	Temperature float64 `json:"temperature"`
	Condition   string  `json:"condition"`
	WindSpeed   float64 `json:"wind_speed"`
}

func getWeather(ctx context.Context, params WeatherParams) (WeatherResult, error) {
	fmt.Printf("正在调用天气查询工具,查询城市:%s\n", params.City)

	weatherData := map[string]WeatherResult{
		"北京": {
			City:        "北京",
			Temperature: 25.5,
			Condition:   "晴",
			WindSpeed:   3.2,
		},
		"上海": {
			City:        "上海",
			Temperature: 28.3,
			Condition:   "多云",
			WindSpeed:   2.8,
		},
		"广州": {
			City:        "广州",
			Temperature: 32.1,
			Condition:   "雷阵雨",
			WindSpeed:   4.5,
		},
	}

	result, ok := weatherData[params.City]
	if !ok {
		result = WeatherResult{
			City:        params.City,
			Temperature: 20.0,
			Condition:   "未知城市,默认天气",
			WindSpeed:   1.0,
		}
	}

	return result, nil
}

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

	baseModel, err := ollama.NewChatModel(ctx, &ollama.ChatModelConfig{
		BaseURL: "http://localhost:11434",
		Model:   "qwen2.5:7b",
		Options: &ollama.Options{
			Temperature: 0.7,
		},
	})
	if err != nil {
		log.Fatalf("初始化模型失败:%v", err)
	}

	weatherTool, err := utils.InferTool[WeatherParams, WeatherResult](
		"get_weather",
		"获取指定城市的天气信息,例如:北京、上海、广州",
		getWeather,
	)
	if err != nil {
		log.Fatalf("创建工具失败:%v", err)
	}

	agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
		Model: baseModel,
		ToolsConfig: adk.ToolsConfig{
			ToolsNodeConfig: compose.ToolsNodeConfig{
				Tools: []tool.BaseTool{weatherTool},
			},
		},
	})
	if err != nil {
		log.Fatalf("创建 Agent 失败:%v", err)
	}

	runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})

	query := "北京今天天气怎么样?"
	fmt.Printf("用户提问:%s\n\n", query)

	iter := runner.Query(ctx, query)
	fmt.Println("Agent 响应:")
	for {
		event, ok := iter.Next()
		if !ok {
			break
		}

		if event.Err != nil {
			fmt.Printf("\n错误:%v\n", event.Err)
			continue
		}

		if event.Output != nil && event.Output.MessageOutput != nil {
			msgOutput := event.Output.MessageOutput
			msg := msgOutput.Message
			// 展示工具调用请求(由模型生成)
			if msgOutput.Role == schema.Assistant && len(msg.ToolCalls) > 0 {
				fmt.Println("\n📞 [模型请求调用工具]")
				for _, tc := range msg.ToolCalls {
					fmt.Printf("   函数: %s\n", tc.Function.Name)
					fmt.Printf("   参数: %s\n", tc.Function.Arguments)
				}
				continue
			}
			// 展示工具返回结果
			if msgOutput.Role == schema.Tool {
				fmt.Printf("\n🔧 [工具返回] 工具: %s\n", msg.ToolName)
				fmt.Printf("   内容: %s\n", msg.Content)
				continue
			}
			if msgOutput.Role == schema.Assistant {
				if msgOutput.IsStreaming {
					msg, err := msgOutput.GetMessage()
					if err == nil {
						fmt.Print(msg.Content)
					}
				} else {
					fmt.Print(msgOutput.Message.Content)
				}
			}
		}
	}
	fmt.Println()
}

连续对话

连续对话,要注意携带历史信息。

go
package main

import (
	"bufio"
	"context"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/cloudwego/eino-ext/components/model/ollama"
	"github.com/cloudwego/eino/adk"
	"github.com/cloudwego/eino/components/tool"
	"github.com/cloudwego/eino/components/tool/utils"
	"github.com/cloudwego/eino/compose"
	"github.com/cloudwego/eino/schema"
)

// ---------- 工具定义(保持不变) ----------
type WeatherParams struct {
	City string `json:"city" jsonschema:"required" jsonschema_description:"城市名称,例如:北京、上海、广州"`
}

type WeatherResult struct {
	City        string  `json:"city"`
	Temperature float64 `json:"temperature"`
	Condition   string  `json:"condition"`
	WindSpeed   float64 `json:"wind_speed"`
}

func getWeather(ctx context.Context, params WeatherParams) (WeatherResult, error) {
	fmt.Printf("🌤️  [工具执行] 正在查询城市:%s\n", params.City)

	weatherData := map[string]WeatherResult{
		"北京": {City: "北京", Temperature: 25.5, Condition: "晴", WindSpeed: 3.2},
		"上海": {City: "上海", Temperature: 28.3, Condition: "多云", WindSpeed: 2.8},
		"广州": {City: "广州", Temperature: 32.1, Condition: "雷阵雨", WindSpeed: 4.5},
	}

	if result, ok := weatherData[params.City]; ok {
		return result, nil
	}
	return WeatherResult{
		City:        params.City,
		Temperature: 20.0,
		Condition:   "未知城市,默认天气",
		WindSpeed:   1.0,
	}, nil
}

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

	// ---------- 初始化模型 ----------
	baseModel, err := ollama.NewChatModel(ctx, &ollama.ChatModelConfig{
		BaseURL: "http://localhost:11434",
		Model:   "qwen2.5:7b",
		Options: &ollama.Options{Temperature: 0.7},
	})
	if err != nil {
		log.Fatalf("初始化模型失败:%v", err)
	}

	// ---------- 创建工具 ----------
	weatherTool, err := utils.InferTool[WeatherParams, WeatherResult](
		"get_weather",
		"获取指定城市的天气信息,例如:北京、上海、广州",
		getWeather,
	)
	if err != nil {
		log.Fatalf("创建工具失败:%v", err)
	}

	// ---------- 构建 Agent ----------
	agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
		Model: baseModel,
		ToolsConfig: adk.ToolsConfig{
			ToolsNodeConfig: compose.ToolsNodeConfig{
				Tools: []tool.BaseTool{weatherTool},
			},
		},
	})
	if err != nil {
		log.Fatalf("创建 Agent 失败:%v", err)
	}

	// ---------- 创建 Runner ----------
	runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})

	// ---------- 手动维护对话历史 ----------
	var history []*schema.Message

	fmt.Println("🤖 连续对话模式启动!输入 'exit' 或 'quit' 退出程序。")
	scanner := bufio.NewScanner(os.Stdin)
	for {
		fmt.Print("\n👤 你:")
		if !scanner.Scan() {
			break
		}
		userInput := strings.TrimSpace(scanner.Text())
		if userInput == "" {
			continue
		}
		if userInput == "exit" || userInput == "quit" {
			fmt.Println("👋 再见!")
			break
		}

		// 1. 添加用户消息到历史
		userMsg := schema.UserMessage(userInput)
		history = append(history, userMsg)

		// 2. 调用 Runner.Run() 传入完整历史
		iter := runner.Run(ctx, history)
		fmt.Print("🤖 Agent:")

		var assistantContent string
		var tempMessages []*schema.Message // 用于暂存本次生成的消息

		for {
			event, ok := iter.Next()
			if !ok {
				break
			}
			if event.Err != nil {
				fmt.Printf("\n❌ 错误:%v\n", event.Err)
				continue
			}

			if event.Output != nil && event.Output.MessageOutput != nil {
				msgOutput := event.Output.MessageOutput
				msg := msgOutput.Message

				// 暂存所有消息,稍后追加到 history
				tempMessages = append(tempMessages, msg)

				// 展示工具调用请求(由模型生成)
				if msgOutput.Role == schema.Assistant && len(msg.ToolCalls) > 0 {
					fmt.Println("\n📞 [模型请求调用工具]")
					for _, tc := range msg.ToolCalls {
						fmt.Printf("   函数: %s\n", tc.Function.Name)
						fmt.Printf("   参数: %s\n", tc.Function.Arguments)
					}
					continue
				}

				// 展示工具返回结果
				if msgOutput.Role == schema.Tool {
					fmt.Printf("\n🔧 [工具返回] 工具: %s\n", msg.ToolName)
					fmt.Printf("   内容: %s\n", msg.Content)
					continue
				}

				// 展示最终文本回答
				if msgOutput.Role == schema.Assistant {
					if msgOutput.IsStreaming {
						streamMsg, _ := msgOutput.GetMessage()
						fmt.Print(streamMsg.Content)
						assistantContent += streamMsg.Content
					} else {
						fmt.Print(msg.Content)
						assistantContent = msg.Content
					}
				}
			}
		}

		// 3. 将本次生成的所有消息追加到 history(包括 assistant 消息、tool 消息等)
		history = append(history, tempMessages...)
		fmt.Println() // 换行美观
	}
}

如有转载或 CV 的请标注本站原文地址