阿恒
2026-06-02
来自美国
如果接入统一网关,例如类似New API大语言模型 (LLM) 网关,是不是回更方便一些
山山而川
2026-06-01
来自四川
工具本地执行耗时统计的代码实现 1、依然采用中间件的方式实现,在Registry中新增一个 type AroundFunc func(ctx context.Context, call schema.ToolCall, next func() (string, error)) (string, error) 这个函数的中最后一个参数的声明就是这个中间件需要执行的函数,在我们现在的需求中,对应的就是请求模型的函数调用。 2、然后在Registry接口中,新增一个函数声明: // UseAround 挂载一个环绕中间件到系统中(洋葱圈模型,先注册的最外层) UseAround(around AroundFunc) 3、在registryImpl中新增一个成员: // registryImpl 是 Registry 接口的默认实现 type registryImpl struct { // 使用 map 以工具的 Name 作为 Key 进行快速 O(1) 路由查找 tools map[string]BaseTool mw []MiddlewareFunc around []AroundFunc // 新增 } 4、这个耗时统计的中间件的具体实现: // DurationLogMiddleware 返回一个 AroundFunc,用于记录每次工具执行的耗时和结果摘要 func DurationLogMiddleware() AroundFunc { return func(ctx context.Context, call schema.ToolCall, next func() (string, error)) (string, error) { start := time.Now() output, err := next() elapsed := time.Since(start) if err != nil { log.Printf("[Registry] 工具 '%s' 执行完成 | 耗时: %v | 失败 | 错误: %v\n", call.Name, elapsed, err) } else { log.Printf("[Registry] 工具 '%s' 执行完成 | 耗时: %v | 成功 | 输出: %s\n", call.Name, elapsed, formatBytes(len(output))) } return output, err } } // formatBytes 将字节数格式化为人类可读的形式 func formatBytes(n int) string { switch { case n >= 1024*1024: return fmt.Sprintf("%.1f MB (%d bytes)", float64(n)/(1024*1024), n) case n >= 1024: return fmt.Sprintf("%.1f KB (%d bytes)", float64(n)/1024, n) default: return fmt.Sprintf("%d bytes", n) } } 5、main.go 中的代码改造: registry.UseAround(tools.DurationLogMiddleware()) 6、执行输出的日志如下所示(评论区粘贴不了太多的日志......): 2026/06/01 15:17:51 [Registry] 工具 'bash' 执行完成 | 耗时: 317.6668ms
展开