Agent Routing是Blades框架中用于实现路由跳转的核心组件,它可以根据前者的输入信息判断接下来该执行哪一部分操作。你可以使用Blades已经封装好的HandoffAgent实现路由逻辑,也可以自己定制属于自己的路由逻辑。
HandoffAgent 封装了路由跳转逻辑,只需要传入参数即可:
name : handoffAgent 的名称description : handoffAgent 的描述说明model : blades.ModelProvidersubAgents : subAgent列表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, },})在 handoffAgent 执行过程中,会在内部自动选择合适的 SubAgent 执行,若没有找到合适的 Subgent 则会在 err 中返回结果:
target agent no found:Agent Routing 是Blades工作流中不可或缺的存在,在执行智能路由调度过程中十分重要,首先定义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 包含三个参数,分别是路由agent、路由名、路由对应的agent
blades.Agentmap[string]string可传入参数:
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.Agent具体结构形式如下:
agents = map[string]blades.Agent{ "math_agent": mathAgent, "geo_agent": geoAgent,}接下来讲解如何在Blades中实现Agent routing
在初始化 workflow 过程中初始化对应的agent实例。
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}在 RoutingWorkflow 结构体中添加一个方法 selectRoute,用于根据用户原始的输入信息 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")}此处根据路由agent执行后的返回值选择对应的agent多作为 selectRoute 方法的返回值。
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())}