当前位置: 首页 > news >正文

源码分析Eino框架工具调用--创建篇

Eino框架中通过tool node这个官方的组件给模型加上了手脚,工具有多种创建方式,本文不讨论如何创建tool而是聚焦于调用工具过程的底层实现,关于工具的其他内容可以参考这里创建tool
调用一个工具需要这些东西:名称,描述,参数说明以及实现(本地or mcp)
先看tool node的创建,总的来说创建节点的过程分为以下几步

  1. info方法检测
  2. invoke && stream方法实现,二选一即可
  3. 打包原信息,和运行时有关
  4. 打包具体的实现了runnable这个interface的struct,至此通过下面的函数实现了所有工具以来信息的
// NewToolNode creates a new ToolsNode.
// e.g.
//
//	conf := &ToolsNodeConfig{
//		Tools: []tool.BaseTool{invokableTool1, streamableTool2},
//	}
//	toolsNode, err := NewToolNode(ctx, conf)
func NewToolNode(ctx context.Context, conf *ToolsNodeConfig) (*ToolsNode, error) {tuple, err := convTools(ctx, conf.Tools)if err != nil {return nil, err}return &ToolsNode{tuple:                tuple,unknownToolHandler:   conf.UnknownToolsHandler,executeSequentially:  conf.ExecuteSequentially,toolArgumentsHandler: conf.ToolArgumentsHandler,}, nil
}

最后的ToolNode结构其实是这样的

type ToolsNode struct {tuple                *toolsTuple // 核心结构unknownToolHandler   func(ctx context.Context, name, input string) (string, error) // 当模型调用了不存在的func时触发这个handler,若没有指定会直接报错executeSequentially  bool // 多个工具的调用顺序是穿行还是并行toolArgumentsHandler func(ctx context.Context, name, input string) (string, error) // 处理入参的handler
}
/* 
这个是toolNode的核心结构,可以看到indexes是map其他的都是切片,这点是为了根据被调用工具的名字快速找到index后去meta和rps中找到需要的其他数据
meta存储一些元信息
rps是工具执行的关键,实现了eino框架的invoke或者是stream
*/
type toolsTuple struct {indexes map[string]int meta    []*executorMetarps     []*runnablePacker[string, string, tool.Option]
}

我们这里重点关注一下tuple的创建过程,以invoke调用进行说明,创建tuple的源码如下

func convTools(ctx context.Context, tools []tool.BaseTool) (*toolsTuple, error) {ret := &toolsTuple{indexes: make(map[string]int),meta:    make([]*executorMeta, len(tools)),rps:     make([]*runnablePacker[string, string, tool.Option], len(tools)),}for idx, bt := range tools {// 检测是否实现了info方法tl, err := bt.Info(ctx)if err != nil {return nil, fmt.Errorf("(NewToolNode) failed to get tool info at idx= %d: %w", idx, err)}toolName := tl.Namevar (st tool.StreamableToolit tool.InvokableToolinvokable  func(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error)streamable func(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (*schema.StreamReader[string], error)ok   boolmeta *executorMeta)if st, ok = bt.(tool.StreamableTool); ok {streamable = st.StreamableRun}if it, ok = bt.(tool.InvokableTool); ok {invokable = it.InvokableRun}// 工具只有invoke和stream两种调用方式,如果这两个方法都没实现会直接error,同时进行了流的转换,因为eino框架默认支持了流的拼接if st == nil && it == nil {return nil, fmt.Errorf("tool %s is not invokable or streamable", toolName)}// 设置上面所说的meta信息if st != nil {meta = parseExecutorInfoFromComponent(components.ComponentOfTool, st)} else {meta = parseExecutorInfoFromComponent(components.ComponentOfTool, it)}ret.indexes[toolName] = idxret.meta[idx] = meta// 这个packer通过源码可以看到是包装出一个struct实现了runnable这个interface,也就是说我们最终调用工具的时候,其实是通过这个interface的具体实现来的ret.rps[idx] = newRunnablePacker(invokable, streamable,nil, nil, !meta.isComponentCallbackEnabled)}return ret, nil
}func parseExecutorInfoFromComponent(c component, executor any) *executorMeta {componentImplType, ok := components.GetType(executor)if !ok {componentImplType = generic.ParseTypeName(reflect.ValueOf(executor))}return &executorMeta{component:                  c,isComponentCallbackEnabled: components.IsCallbacksEnabled(executor),componentImplType:          componentImplType,}
}
http://www.dtcms.com/a/326490.html

相关文章:

  • Redis RDB和AOF 流程、优缺点详细介绍
  • python每日一题练习 有效的字母异位词 非常简单
  • Linux软件编程--IO
  • Linux 软件编程:IO——标准IO
  • 《录井管理与工程》书籍第一章要点及相应思考
  • 工业数采引擎-通信协议(Modbus/DTU/自定义协议)
  • FFmepg源码系列-avformat_open_input()
  • python之uv使用
  • [动态规划]最长公共子序列(LCS)
  • Nacos添加权限
  • uart通信中出现乱码,可能的原因是什么 ?
  • Linux软件编程:标准IO(ASCII文件)
  • Discuz论坛和java应用的架构部署
  • 视频剪辑的工作流程
  • 笔试——Day35
  • 用 Flink SQL 和 Paimon 打造实时数仓:深度解析与实践指南
  • GitHub的简单使用方法----(1)
  • 论文阅读 arxiv 2024 MemGPT: Towards LLMs as Operating Systems
  • 平衡二叉树(AVL)解析与实现
  • python每日一题 1的数量 非常简单
  • 松灵机器人 scout ros2 galactic 驱动 安装,并且跑巡线算法
  • 深入剖析 C++ STL 中的 std::list 容器
  • 一篇文章解决Unity没有添加模块选项的问题
  • Linux系统编程 | 线程池
  • Redis7 GEO功能介绍与电商场景案例解析
  • Static CXL Switch:静态CXL交换机相关内容
  • leecode875 爱吃香蕉的珂珂
  • 【Unity】打包学习笔记
  • pip 和 conda,到底用哪个安装?
  • 【已解决】【obsidian插件开发】svg图标路径不正确