Agent Routing is the core component in the Blades framework for implementing route transitions. It can determine which operation to execute next based on the input information from the previous step. You can use the pre-packaged HandoffAgent in Blades to implement routing logic, or customize your own routing logic.
HandoffAgent encapsulates the routing transition logic, requiring only parameter input:
name : The name of the handoffAgentdescription : The description of the handoffAgentmodel : blades.ModelProvidersubAgents : List of subAgentsagent, err := flow.NewHandoffAgent(flow.HandoffConfig{ Name: "TriageAgent", Description: "You determine which agent to use based on the user's homework question", Model: model, SubAgents: []blades.Agent{ mathTutorAgent, historyTutorAgent, },})During the execution of handoffAgent, it will automatically select the appropriate SubAgent internally. If no suitable SubAgent is found, the result will be returned in err:
target agent no found:Agent Routing is an indispensable part of the Blades workflow and is crucial during intelligent routing scheduling. First, define the structure type of workflow:
type RoutingWorkflow struct { blades.Agent routes map[string]string agents map[string]blades.Agent}package main
import ( "context" "log" "os"
"github.com/go-kratos/blades" "github.com/go-kratos/blades/contrib/openai" "github.com/go-kratos/blades/flow")
func main() { model := openai.NewModel(os.Getenv("OPENAI_MODEL"), openai.Config{ APIKey: os.Getenv("OPENAI_API_KEY"), }) mathTutorAgent, err := blades.NewAgent( "MathTutor", blades.WithDescription("An agent that helps with math questions"), blades.WithInstruction("You are a helpful math tutor. Answer questions related to mathematics."), blades.WithModel(model), ) if err != nil { log.Fatal(err) } historyTutorAgent, err := blades.NewAgent( "HistoryTutor", blades.WithDescription("An agent that helps with history questions"), blades.WithInstruction("You are a helpful history tutor. Answer questions related to history."), blades.WithModel(model), ) if err != nil { log.Fatal(err) } agent, err := flow.NewHandoffAgent(flow.HandoffConfig{ Name: "TriageAgent", Description: "You determine which agent to use based on the user's homework question", Model: model, SubAgents: []blades.Agent{ mathTutorAgent, historyTutorAgent, }, }) if err != nil { log.Fatal(err)
} input := blades.UserMessage("What is the capital of France?") runner := blades.NewRunner(agent) output, err := runner.Run(context.Background(), input) if err != nil { log.Fatal(err) } log.Println(output.Text())}RoutingWorkflow contains three parameters: the routing agent, route names, and the corresponding agents for each route.
blades.Agentmap[string]stringAvailable parameters:
routes = map[string]string{ "math_agent": "You provide help with math problems. Explain your reasoning at each step and include examples.", "geo_agent": "You provide assistance with geographical queries. Explain geographic concepts, locations, and spatial relationships clearly.",}map[string]blades.AgentSpecific structure form:
agents = map[string]blades.Agent{ "math_agent": mathAgent, "geo_agent": geoAgent,}Next, we explain how to implement Agent routing in Blades.
Initialize the corresponding agent instances during the workflow initialization process.
func NewRoutingWorkflow(routes map[string]string) (*RoutingWorkflow, error) { model := openai.NewModel("deepseek-chat", openai.Config{ APIKey: os.Getenv("OPENAI_API_KEY"), }) router, err := blades.NewAgent( "triage_agent", blades.WithModel(model), blades.WithInstruction("You determine which agent to use based on the user's homework question"), ) if err != nil { return nil, err } agents := make(map[string]blades.Agent, len(routes)) for name, instructions := range routes { agent, err := blades.NewAgent( name, blades.WithModel(model), blades.WithInstruction(instructions), ) if err != nil { return nil, err } agents[name] = agent } return &RoutingWorkflow{ Agent: router, routes: routes, agents: agents, }, nil}Add a method selectRoute to the RoutingWorkflow struct, used to select the appropriate route based on the user’s original input information invocation.
func (r *RoutingWorkflow) selectRoute(ctx context.Context, invocation *blades.Invocation) (blades.Agent, error) { var buf strings.Builder buf.WriteString("You are a routing agent.\n") buf.WriteString("Choose the single best route key for handling the user's request.\n") buf.WriteString("User message: " + invocation.Message.Text() + "\n") buf.WriteString("Available route keys (choose exactly one):\n") routes, err := json.Marshal(r.routes) if err != nil { return nil, err } buf.WriteString(string(routes)) buf.WriteString("\nOnly return the name of the routing key.") for res, err := range r.Agent.Run(ctx, &blades.Invocation{Message: blades.UserMessage(buf.String())}) { if err != nil { return nil, err } choice := strings.TrimSpace(res.Text()) if a, ok := r.agents[choice]; ok { return a, nil } } return nil, fmt.Errorf("no route selected")}Here, the corresponding agent is selected based on the return value after the routing agent executes, and this agent is returned as the result of the selectRoute method.
func (r *RoutingWorkflow) Run(ctx context.Context, invocation *blades.Invocation) blades.Generator[*blades.Message, error] { return func(yield func(*blades.Message, error) bool) { agent, err := r.selectRoute(ctx, invocation) if err != nil { yield(nil, err) return } stream := agent.Run(ctx, invocation) for msg, err := range stream { if !yield(msg, err) { break } } }}func main() { var ( routes = map[string]string{ "math_agent": "You provide help with math problems. Explain your reasoning at each step and include examples.", "geo_agent": "You provide assistance with geographical queries. Explain geographic concepts, locations, and spatial relationships clearly.", } ) routing, err := NewRoutingWorkflow(routes) if err != nil { log.Fatal(err) } // Example prompt that will be routed to the history_agent input := blades.UserMessage("What is the capital of France?") runner := blades.NewRunner(routing) res, err := runner.Run(context.Background(), input) if err != nil { log.Fatal(err) } log.Println(res.Text())}