第 4 卷
| 等待点 | 等待的内容 | 等待 |
|---|---|---|
| 模型流(llm.stream) | provider把chunk吐完 | for |
| 工具分发(executeToolCalls) | 所有工具执行完 | 并行 |
四个监听器跑完:agent/pre-step(改这一步要发的消息)、agent/request(改这次的调用配置)、
四类扩展点agent/request-error(返回 retry 就重试,不处理即三个终态)、agent/turn-stopping(turn 要关了,可再
插一步让它继续)
本讲小结
今天这一讲,我们先把零件组装成一个 Agent:六个包按 inject 声明依赖;装出来的 Agent 由五样组成,从 announce(agent) 发出 agent/created 那一刻起才算一个
Agent;它的生灭都挂在注册表上。
再装上 AgentLoop 驱动它自己跑:一个轮次从 turn/start 开账,跑成一个个 step(组装请求 → 流式响应 → 记进日志 → 要不要工具),直到没有工具、没有新 steering 才
turn/end;跑完之后还跑不跑,看有没有新的 followup 或 steer 把它叫起来。叫起来后再看队列里有没有活。
这背后真正的变化是:你不再把 Agent 当成一个现成的东⻄,而是知道它是怎么装起来的;
也知道它是怎么一轮轮驱动下去的。
到这里,你已经知道一个 Agent 是怎么装起来、又怎么被驱动起来了。接下来的问题是:同一份 dsh,怎么让不同会话各有各的一套?下一讲,我们讲 Agent Preset。
第 1、2、3 次 stream() 各 yield 一个 tool-call 块(工具名还是 echo),第 4 次才给文字答案。重跑 npm run start:ch13,回答两个问题:
- 第 1 轮里出现了几个 step/start?turn/end 落在第几条 seq?
- 这期间 agent/status 变过几次?
别把它改成“每次都要工具”:那会让 await agent.whenIdle() 永不返回、日志无限增长。这正是官方 README 那条“没有内置轮次预算”:想让它停,得自己挂 agent/turn-
stopping 监听器、或在工具执行处抛错,循环不会自己叫停。
小改动:在 main() 里、收尾(拆掉循环那个 fiber)之前,也就是第 2 轮跑完、agent 正空闲的时候,用两种方式各排一条:先 agent.followup(createUserMessage({
content: [{ type: 'text', text: 'A:下一轮再答我' }], source: { kind:
'user' } })),紧接着 agent.steer(createUserMessage({ content: [{ type:
'text', text: 'B:这一步就插进来' }], source: { kind: 'user' } })),最后 await agent.whenIdle()。
先猜:两条消息会落进同一个 turn/start 之后,还是分属两个轮次?再重跑,数一数日志里 agent/inbox/spliced 的位置来验证你的猜测。提示:想想这两条队分别在什么时候
被取走,答案可能与直觉不同。
欢迎把你的运行结果分享出来。如果你觉得这节课对你有帮助,也欢迎分享给其他朋友,我们下节课再见!
© 版权归极客邦科技所有,未经许可不得传播售卖。页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
精选留言