/* * Copyright 2024 CloudWeGo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package main import ( "context" "fmt" "log" "os" "github.com/cloudwego/eino-ext/components/model/openai" "github.com/cloudwego/eino-ext/components/tool/googlesearch" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/components/tool/utils" "github.com/cloudwego/eino/compose" "github.com/cloudwego/eino/schema" ) func main() { fmt.Println("Hello, World!") ctx := context.Background() updateTool, err := utils.InferTool("update_todo", "Update a todo item, eg: content,deadline...", UpdateTodoFunc) if err != nil { log.Fatal(err) } // 创建 Google Search 工具 searchTool, err := googlesearch.NewGoogleSearchTool(ctx, &googlesearch.Config{ APIKey: os.Getenv("GOOGLE_API_KEY"), // Google API Key SearchEngineID: os.Getenv("GOOGLE_SEARCH_ENGINE_ID"), // 自定义搜索引擎 ID Num: 5, // 每次返回的结果数量 Lang: "zh-CN", // 搜索结果的语言 }) if err != nil { log.Fatal(err) } // 初始化 tools todoTools := []tool.BaseTool{ getAddTodoTool(), // 使用 NewTool 方式 updateTool, // 使用 InferTool 方式 &ListTodoTool{}, // 使用结构体实现方式, 此处未实现底层逻辑 searchTool, } // 创建并配置 ChatModel temp := float32(0.7) chatModel, err := openai.NewChatModel(context.Background(), &openai.ChatModelConfig{ Model: "gpt-4", APIKey: os.Getenv("OPENAI_API_KEY"), Temperature: &temp, }) if err != nil { log.Fatal(err) } // 获取工具信息, 用于绑定到 ChatModel toolInfos := make([]*schema.ToolInfo, 0, len(todoTools)) for _, tool := range todoTools { info, err := tool.Info(ctx) if err != nil { log.Fatal(err) } toolInfos = append(toolInfos, info) } // 将 tools 绑定到 ChatModel err = chatModel.BindTools(toolInfos) if err != nil { log.Fatal(err) } // 创建 tools 节点 todoToolsNode, err := compose.NewToolNode(context.Background(), &compose.ToolsNodeConfig{ Tools: todoTools, }) if err != nil { log.Fatal(err) } // 构建完整的处理链 chain := compose.NewChain[*schema.Message, []*schema.Message]() chain. AppendChatModel(chatModel, compose.WithNodeName("chat_model")). AppendToolsNode(todoToolsNode, compose.WithNodeName("tools")) // 编译并运行 chain agent, err := chain.Compile(ctx) if err != nil { log.Fatal(err) } // 运行示例 resp, err := agent.Invoke(ctx, &schema.Message{ Content: "帮我创建一个明天下午3点截止的待办事项:准备Eino项目演示文稿", }) if err != nil { log.Fatal(err) } // 输出结果 for _, msg := range resp { fmt.Println(msg.Content) } } // 获取添加 todo 工具 // 使用 utils.NewTool 创建工具 func getAddTodoTool() tool.InvokableTool { info := &schema.ToolInfo{ Name: "add_todo", Desc: "Add a todo item", ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{ "content": { Desc: "The content of the todo item", Type: schema.String, Required: true, }, "started_at": { Desc: "The started time of the todo item, in unix timestamp", Type: schema.Integer, }, "deadline": { Desc: "The deadline of the todo item, in unix timestamp", Type: schema.Integer, }, }), } return utils.NewTool(info, AddTodoFunc) } // 获取列出 todo 工具 // 自行实现 InvokableTool 接口 type ListTodoTool struct{} func (lt *ListTodoTool) Info(ctx context.Context) (*schema.ToolInfo, error) { return &schema.ToolInfo{ Name: "list_todo", Desc: "List all todo items", ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{ "finished": { Desc: "filter todo items if finished", Type: schema.Boolean, Required: false, }, }), }, nil } type TodoListParams struct { Finished *bool `json:"finished"` } type TodoUpdateParams struct { ID string `json:"id" jsonschema:"description=id of the todo"` Content *string `json:"content,omitempty" jsonschema:"description=content of the todo"` StartedAt *int64 `json:"started_at,omitempty" jsonschema:"description=start time in unix timestamp"` Deadline *int64 `json:"deadline,omitempty" jsonschema:"description=deadline of the todo in unix timestamp"` Done *bool `json:"done,omitempty" jsonschema:"description=done status"` } type TodoAddParams struct { Content string `json:"content"` StartedAt *int64 `json:"started_at,omitempty"` // 开始时间 Deadline *int64 `json:"deadline,omitempty"` } func (lt *ListTodoTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) { log.Printf("invoke tool list_todo: %s", argumentsInJSON) // 具体的调用逻辑 return `{"todos": [{"id": "1", "content": "在2024年12月10日之前完成Eino项目演示文稿的准备工作", "started_at": 1717401600, "deadline": 1717488000, "done": false}]}`, nil } func AddTodoFunc(ctx context.Context, params *TodoAddParams) (string, error) { log.Printf("invoke tool add_todo: %+v", params) // 具体的调用逻辑 return `{"msg": "success"}`, nil } func UpdateTodoFunc(ctx context.Context, params *TodoUpdateParams) (string, error) { log.Printf("invoke tool update_todo: %+v", params) // 具体的调用逻辑 return `{"msg": "success"}`, nil }