主管道:一次请求的一生(Stream)
30 秒导读:
Assistant.Stream是 Yao 智能体运行时的中央循环——一次用户请求进来,从校验、装缓冲、选模型、拼历史,到调 LLM、跑工具、收尾落库,全部走这一个函数。本章按执行顺序端到端走一遍这条控制流,重点讲清楚"错误 / 中断 / panic 时,状态和落库怎么保证不丢"。Hook、工具循环、委派、记忆、沙箱各自的内部机制留给专章,本章只把它们当管道上的调用点串起来。
阅读前置:建议先看 装载篇——知道一个 Assistant 是怎么从 DSL 变出来的,再 看它被"跑起来"会更顺。
1. 这是什么(零基础也能懂)
一句话定义: Stream 是"跑一次智能体"的主函数——你给它输入消息,它负责把整条流水线走完,并通过流式(SSE)把结果一段段吐给前端。
它解决什么问题: 一次 AI 对话请求,背后要做的事远不止"调一次大模型"。要先确认你有没有权限、要把历史对话捞出来拼进去、要挑一个合适的模型连接器、模型可能要求调工具、工具可能报错要重试、整个过程随时可能被用户按"停止"、也可能中途 panic——而且无论怎么结束,这次对话的消息和(出错时的)断点都得可靠落库,好让前端刷新后还能看到、甚至能续跑。
Stream 就是把这一大堆"必须按顺序做、且必须善后"的事,收进一个函数里管起来。
一句话直觉: 把 Stream 想成一条工厂流水线的总控。原料(用户消息)从一头进,依次经过若干工位(校验 → 缓冲 → 选模型 → 拼历史 → 沙箱 → Create Hook → LLM → 工具重试 → Next Hook → 收尾),从另一头出成品(响应)。而流水线最关键的不是某个工位,是总控挂在门口的一排"善后钩子"(defer):不管中途哪个工位炸了、还是有人拉了急停,出厂时这排钩子一定会把"这批货记账、关灯锁门"做掉。这排 defer 就是本章的暗线。
它在代码里长这样(真实入口):
// agent/assistant/agent.go:21 func (ast *Assistant) Stream
func (ast *Assistant) Stream(
ctx *context.Context,
inputMessages []context.Message,
options ...*context.Options,
) (*context.Response, error)
调用者给三样东西:请求上下文 ctx(贯穿全程的"这次请求的世界")、输入消息 inputMessages、可选的 options(连接器、历史长度、skip 开关等)。返回一个 *context.Response 和 error。