feat: refactor tool handling to use ToolSet for improved organization and clarity

This commit is contained in:
mlogclub
2026-04-11 22:46:47 +08:00
parent a8a33ec6e0
commit e6d0fa2ba2
6 changed files with 60 additions and 49 deletions
+22 -6
View File
@@ -11,10 +11,12 @@ import (
"cs-agent/internal/ai/runtime/internal/impl/callbacks" "cs-agent/internal/ai/runtime/internal/impl/callbacks"
"cs-agent/internal/ai/runtime/internal/impl/factory" "cs-agent/internal/ai/runtime/internal/impl/factory"
"cs-agent/internal/ai/runtime/internal/impl/retrievers" "cs-agent/internal/ai/runtime/internal/impl/retrievers"
"cs-agent/internal/ai/runtime/registry"
"cs-agent/internal/models" "cs-agent/internal/models"
"cs-agent/internal/pkg/utils" "cs-agent/internal/pkg/utils"
"github.com/cloudwego/eino/adk" "github.com/cloudwego/eino/adk"
einotool "github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/schema" "github.com/cloudwego/eino/schema"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -85,7 +87,7 @@ func (s *Service) Run(ctx context.Context, req Request) (*Summary, error) {
summary.ToolCodes = appendIfMissing(summary.ToolCodes, "builtin/tool_search") summary.ToolCodes = appendIfMissing(summary.ToolCodes, "builtin/tool_search")
toolDefsByModelName["tool_search"] = "builtin/tool_search" toolDefsByModelName["tool_search"] = "builtin/tool_search"
} }
for modelName, toolCode := range req.ExtraToolCodes { for modelName, toolCode := range toolSetStaticToolCodes(req.ToolSet) {
toolCode = strings.TrimSpace(toolCode) toolCode = strings.TrimSpace(toolCode)
modelName = strings.TrimSpace(modelName) modelName = strings.TrimSpace(modelName)
if toolCode == "" || modelName == "" { if toolCode == "" || modelName == "" {
@@ -119,8 +121,8 @@ func (s *Service) Run(ctx context.Context, req Request) (*Summary, error) {
SelectedSkill: req.SelectedSkill, SelectedSkill: req.SelectedSkill,
InstructionToolDefinitions: filteredToolDefs, InstructionToolDefinitions: filteredToolDefs,
DynamicMCPToolDefinitions: filteredToolDefs, DynamicMCPToolDefinitions: filteredToolDefs,
StaticTools: req.ExtraTools, StaticTools: toolSetStaticTools(req.ToolSet),
StaticToolCodes: req.ExtraToolCodes, StaticToolCodes: toolSetStaticToolCodes(req.ToolSet),
Collector: collector, Collector: collector,
}) })
if err != nil { if err != nil {
@@ -238,7 +240,7 @@ func (s *Service) Resume(ctx context.Context, req ResumeRequest) (*Summary, erro
summary.ToolCodes = appendIfMissing(summary.ToolCodes, "builtin/tool_search") summary.ToolCodes = appendIfMissing(summary.ToolCodes, "builtin/tool_search")
toolDefsByModelName["tool_search"] = "builtin/tool_search" toolDefsByModelName["tool_search"] = "builtin/tool_search"
} }
for modelName, toolCode := range req.ExtraToolCodes { for modelName, toolCode := range toolSetStaticToolCodes(req.ToolSet) {
toolCode = strings.TrimSpace(toolCode) toolCode = strings.TrimSpace(toolCode)
modelName = strings.TrimSpace(modelName) modelName = strings.TrimSpace(modelName)
if toolCode == "" || modelName == "" { if toolCode == "" || modelName == "" {
@@ -255,8 +257,8 @@ func (s *Service) Resume(ctx context.Context, req ResumeRequest) (*Summary, erro
AIConfig: req.AIConfig, AIConfig: req.AIConfig,
InstructionToolDefinitions: toolDefs, InstructionToolDefinitions: toolDefs,
DynamicMCPToolDefinitions: toolDefs, DynamicMCPToolDefinitions: toolDefs,
StaticTools: req.ExtraTools, StaticTools: toolSetStaticTools(req.ToolSet),
StaticToolCodes: req.ExtraToolCodes, StaticToolCodes: toolSetStaticToolCodes(req.ToolSet),
Collector: collector, Collector: collector,
}) })
if err != nil { if err != nil {
@@ -543,3 +545,17 @@ func buildKnowledgeContext(items []rag.RetrieveResult) string {
} }
return strings.TrimSpace(builder.String()) return strings.TrimSpace(builder.String())
} }
func toolSetStaticTools(toolSet *registry.ToolSet) []einotool.BaseTool {
if toolSet == nil {
return nil
}
return toolSet.StaticTools
}
func toolSetStaticToolCodes(toolSet *registry.ToolSet) map[string]string {
if toolSet == nil {
return nil
}
return toolSet.StaticToolCodes
}
+8 -11
View File
@@ -1,9 +1,8 @@
package engine package engine
import ( import (
"cs-agent/internal/ai/runtime/registry"
"cs-agent/internal/models" "cs-agent/internal/models"
einotool "github.com/cloudwego/eino/components/tool"
) )
type Request struct { type Request struct {
@@ -15,18 +14,16 @@ type Request struct {
SkillRouteReason string SkillRouteReason string
SkillRouteTrace string SkillRouteTrace string
CheckPointID string CheckPointID string
ExtraTools []einotool.BaseTool ToolSet *registry.ToolSet
ExtraToolCodes map[string]string
} }
type ResumeRequest struct { type ResumeRequest struct {
Conversation *models.Conversation Conversation *models.Conversation
AIAgent *models.AIAgent AIAgent *models.AIAgent
AIConfig *models.AIConfig AIConfig *models.AIConfig
CheckPointID string CheckPointID string
ResumeData map[string]any ResumeData map[string]any
ExtraTools []einotool.BaseTool ToolSet *registry.ToolSet
ExtraToolCodes map[string]string
} }
type InterruptContextSummary struct { type InterruptContextSummary struct {
+4 -4
View File
@@ -20,8 +20,8 @@ func NewRegistry(tools ...Tool) *Registry {
func (r *Registry) Resolve(ctx Context) (*ToolSet, error) { func (r *Registry) Resolve(ctx Context) (*ToolSet, error) {
ret := &ToolSet{ ret := &ToolSet{
Tools: make([]einotool.BaseTool, 0, len(r.tools)), StaticTools: make([]einotool.BaseTool, 0, len(r.tools)),
ToolCodes: make(map[string]string), StaticToolCodes: make(map[string]string),
} }
allowedToolCodes := makeAllowedToolCodeSet(ctx.AllowedToolCodes) allowedToolCodes := makeAllowedToolCodeSet(ctx.AllowedToolCodes)
for _, toolDef := range r.tools { for _, toolDef := range r.tools {
@@ -45,8 +45,8 @@ func (r *Registry) Resolve(ctx Context) (*ToolSet, error) {
if toolName == "" || toolCode == "" { if toolName == "" || toolCode == "" {
continue continue
} }
ret.Tools = append(ret.Tools, tool) ret.StaticTools = append(ret.StaticTools, tool)
ret.ToolCodes[toolName] = toolCode ret.StaticToolCodes[toolName] = toolCode
} }
return ret, nil return ret, nil
} }
+7 -2
View File
@@ -14,9 +14,14 @@ type Context struct {
AllowedToolCodes []string AllowedToolCodes []string
} }
// ToolSet 描述当前运行时可直接挂载到 ToolsNode 上的固定工具集合。
//
// 这里不承载通过 tool_search 动态暴露的 MCP 工具;动态工具仍由 engine 层单独装配。
type ToolSet struct { type ToolSet struct {
Tools []einotool.BaseTool // StaticTools 为固定可见工具实例,例如 Graph Tool。
ToolCodes map[string]string StaticTools []einotool.BaseTool
// StaticToolCodes 为固定工具的 modelName -> toolCode 映射,用于 trace 和运行日志归因。
StaticToolCodes map[string]string
} }
type Tool interface { type Tool interface {
+11 -15
View File
@@ -50,8 +50,7 @@ func (s *service) Run(ctx context.Context, req Request) (*Summary, error) {
SkillRouteReason: req.SkillRouteReason, SkillRouteReason: req.SkillRouteReason,
SkillRouteTrace: req.SkillRouteTrace, SkillRouteTrace: req.SkillRouteTrace,
CheckPointID: req.CheckPointID, CheckPointID: req.CheckPointID,
ExtraTools: req.ExtraTools, ToolSet: req.ToolSet,
ExtraToolCodes: req.ExtraToolCodes,
}) })
if err != nil { if err != nil {
ret := toSummary(summary) ret := toSummary(summary)
@@ -72,13 +71,12 @@ func (s *service) Resume(ctx context.Context, req ResumeRequest) (*Summary, erro
return nil, err return nil, err
} }
summary, err := s.runtime.Resume(ctx, engine.ResumeRequest{ summary, err := s.runtime.Resume(ctx, engine.ResumeRequest{
Conversation: req.Conversation, Conversation: req.Conversation,
AIAgent: req.AIAgent, AIAgent: req.AIAgent,
AIConfig: req.AIConfig, AIConfig: req.AIConfig,
CheckPointID: req.CheckPointID, CheckPointID: req.CheckPointID,
ResumeData: req.ResumeData, ResumeData: req.ResumeData,
ExtraTools: req.ExtraTools, ToolSet: req.ToolSet,
ExtraToolCodes: req.ExtraToolCodes,
}) })
if err != nil { if err != nil {
return toSummary(summary), err return toSummary(summary), err
@@ -87,7 +85,7 @@ func (s *service) Resume(ctx context.Context, req ResumeRequest) (*Summary, erro
} }
func (s *service) prepareToolsForRun(req *Request) error { func (s *service) prepareToolsForRun(req *Request) error {
if req == nil || len(req.ExtraTools) > 0 || len(req.ExtraToolCodes) > 0 || s.registry == nil { if req == nil || req.ToolSet != nil || s.registry == nil {
return nil return nil
} }
toolSet, err := s.registry.Resolve(registry.Context{ toolSet, err := s.registry.Resolve(registry.Context{
@@ -100,13 +98,12 @@ func (s *service) prepareToolsForRun(req *Request) error {
if err != nil { if err != nil {
return err return err
} }
req.ExtraTools = toolSet.Tools req.ToolSet = toolSet
req.ExtraToolCodes = toolSet.ToolCodes
return nil return nil
} }
func (s *service) prepareToolsForResume(req *ResumeRequest) error { func (s *service) prepareToolsForResume(req *ResumeRequest) error {
if req == nil || len(req.ExtraTools) > 0 || len(req.ExtraToolCodes) > 0 || s.registry == nil { if req == nil || req.ToolSet != nil || s.registry == nil {
return nil return nil
} }
toolSet, err := s.registry.Resolve(registry.Context{ toolSet, err := s.registry.Resolve(registry.Context{
@@ -118,8 +115,7 @@ func (s *service) prepareToolsForResume(req *ResumeRequest) error {
if err != nil { if err != nil {
return err return err
} }
req.ExtraTools = toolSet.Tools req.ToolSet = toolSet
req.ExtraToolCodes = toolSet.ToolCodes
return nil return nil
} }
+8 -11
View File
@@ -1,9 +1,8 @@
package runtime package runtime
import ( import (
"cs-agent/internal/ai/runtime/registry"
"cs-agent/internal/models" "cs-agent/internal/models"
einotool "github.com/cloudwego/eino/components/tool"
) )
type Request struct { type Request struct {
@@ -16,18 +15,16 @@ type Request struct {
SkillRouteReason string SkillRouteReason string
SkillRouteTrace string SkillRouteTrace string
CheckPointID string CheckPointID string
ExtraTools []einotool.BaseTool ToolSet *registry.ToolSet
ExtraToolCodes map[string]string
} }
type ResumeRequest struct { type ResumeRequest struct {
Conversation *models.Conversation Conversation *models.Conversation
AIAgent *models.AIAgent AIAgent *models.AIAgent
AIConfig *models.AIConfig AIConfig *models.AIConfig
CheckPointID string CheckPointID string
ResumeData map[string]any ResumeData map[string]any
ExtraTools []einotool.BaseTool ToolSet *registry.ToolSet
ExtraToolCodes map[string]string
} }
type InterruptContextSummary struct { type InterruptContextSummary struct {