在多轮对话或多 Agent 协作流程里,系统需要一个地方来承载上下文并沉淀中间产物,这样后续步骤才能“接着上一步继续做”,而不是每次从零开始。
一句话理解:
在 Blades 中,State 本质上可以理解为:map[string]any
它用于跨步骤(跨 Agent)共享数据:上一步写入,下一个 Agent 的 Prompt 模板直接读取。
在 Agent 的配置里,可以通过 WithOutputKey 方法,指定某个步骤的输出结果要写入 State 里的哪个 key。
比如 WriterAgent 负责产出草稿,把输出落到 draft:
writerAgent, err := blades.NewAgent( "WriterAgent", blades.WithModel(model), blades.WithInstruction("Draft a short paragraph on climate change."), blades.WithOutputKey("draft"),)同理 ReviewerAgent 的输出落到 suggestions:
reviewerAgent, err := blades.NewAgent( "ReviewerAgent", blades.WithModel(model), blades.WithInstruction("Review the draft and suggest improvements."), blades.WithOutputKey("suggestions"),)当你在 WithInstruction 里写 Go template({{.draft}} / {{.suggestions}}),Blades 会把当前 Session 的 State 注入模板上下文,于是你能像下面这样直接使用:
**Draft**{{.draft}}
Here are the suggestions to consider:{{.suggestions}}创建 Session(可选初始化 State):
session := blades.NewSession()也可以带着初始状态启动(常用于:已有草稿、已有用户信息、或恢复一次中断的流程):
session := blades.NewSession(map[string]any{ "draft": "Climate change refers to long-term shifts in temperatures and weather patterns...",})只有把 session 注入运行(blades.WithSession(session)),你前面说的 State 才会在该次运行链路里共享起来。
你的代码本质是一个“写作-审阅”闭环:
package main
import ( "context" "log" "os" "strings"
"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"), }) writerAgent, err := blades.NewAgent( "WriterAgent", blades.WithModel(model), blades.WithInstruction(`Draft a short paragraph on climate change. {{if .suggestions}} **Draft** {{.draft}}
Here are the suggestions to consider: {{.suggestions}} {{end}} `), blades.WithOutputKey("draft"), ) if err != nil { log.Fatal(err) } reviewerAgent, err := blades.NewAgent( "ReviewerAgent", blades.WithModel(model), blades.WithInstruction(`Review the draft and suggest improvements. If the draft is good, respond with "The draft is good".
**Draft** {{.draft}} `), blades.WithOutputKey("suggestions"), ) if err != nil { log.Fatal(err) } loopAgent := flow.NewLoopAgent(flow.LoopConfig{ Name: "WritingReviewFlow", Description: "An agent that loops between writing and reviewing until the draft is good.", MaxIterations: 3, Condition: func(ctx context.Context, output *blades.Message) (bool, error) { return !strings.Contains(output.Text(), "The draft is good"), nil }, SubAgents: []blades.Agent{ writerAgent, reviewerAgent, }, }) input := blades.UserMessage("Please write a short paragraph about climate change.") runner := blades.NewRunner(loopAgent) stream := runner.RunStream(context.Background(), input) for message, err := range stream { if err != nil { log.Fatal(err) } log.Println(message.Author, message.Text()) }}