lobehub — 本课题摘录
读了哪几篇: 01-agent-runtime-kernel(运行时内核)、02-context-engine(上下文工程)。
其余四篇本轮没读。
这一家把"循环放哪层"这个问题解成了一条切线:决策产出纯数据,执行是可换的函数表。
它对本课题回答了什么
决定四(架构):大脑出指令,引擎跑指令
问题很具体:同一套 agent 要在浏览器里跑、在服务端跑、在云沙箱里跑、在命令行里跑。如果把"决策"和"执行"写在一个函数里,这四份代码就得复制四遍。
切一刀:
- 决策产出的是一段可序列化的结构(叫指令);
- 执行是一张可替换的函数表(叫执行器)。
于是"大脑"只有一份,"手脚"按环境换一套。 (依据:Agent 库 · LobeHub (LobeChat) · 运行时内核:大脑出指令、引擎跑指令 —— Agent 只返回可序列化的 instruction、AgentRuntime 只负责执行指令,两者靠可持久化的 AgentState 传递,于是同一套决策逻辑能原样搬到浏览器/服务端/云沙箱/CLI 四个执行面)
它的直觉句:把决策方当成下棋的人,运行时当成棋盘和裁判。人只说"车二平五"这句话,真正把棋子挪过去、判合不合规、记时的是棋盘。换个场地只换棋盘,下棋的人不用重学。
这条跟 agentscope 的"决策函数只读状态"是同一族,但更进一步: agentscope 的动作是进程内的对象,lobehub 的指令是纯数据。
纯数据换来三样东西(它自己列的):
- 跨进程传(客户端算好丢给服务端跑);
- 落库重放(审计、追踪);
- 可以造假(测大脑时不用真跑模型)。
第三条对我们最实用:决策逻辑能单测,不用起模型。
外层循环长这样:
状态 = 初始状态(最多几步、初始消息)
while 状态不是「完成」也不是「出错」:
结果 = 引擎.走一步(状态, 上一步的产物)
把结果里的事件拿去渲染 / 落库 / 打点
状态 = 结果里的新状态
一条用户消息的旅程:
最后一条是用户消息 → 相位=「收到用户输入」
→ 大脑说:调模型
→ 引擎流式跑模型,回传相位=「模型有结果了」
→ 大脑看有没有工具调用:有就派工具,没有就收工
→ 外层拿新状态再走一步
"相位"这个词值得注意:引擎不是问大脑"下一步干什么",而是告诉大脑"现在是什么处境",大脑据此分支。 这跟 agentscope 的决策表是同一个结构,只是分支的依据从"状态查询"变成了"相位标签"。
决定一:所有"往哪儿塞内容"的花样收敛成四个插槽
它先讲清楚为什么必须区分位置——同样是"给模型多点信息",位置不同后果完全不同:
| 塞在哪 | 后果 |
|---|---|
| 系统消息 | 全局约束,但改一个字就让整段前缀失效(缓存全丢) |
| 第一条用户消息之前 | 内容稳定(知识库、记忆),前缀可复用,缓存友好 |
| 最后一条用户消息之后 | 反映当前状态(待办进度、页面内容),必须最新 |
| 每一条用户消息上 | 逐条绑定的上下文(每条消息各自的划选文本) |
(依据:Agent 库 · LobeHub (LobeChat) · 上下文工程:每次调模型前,消息和工具是怎么被拼出来的 —— 所有内容注入收敛成四个插槽基类——system 消息、第一条 user 之前、最后一条 user 之后、每一条 user 之上,位置不同对 prompt 缓存与新鲜度的影响不同)
这张表是本课题第一个决定最实用的一张表,可以直接抄进讲义。
前面 aider 给了段落顺序、kun 给了"稳定前缀 vs 可变尾巴"、hermes 给了三层—— lobehub 这一份是唯一把"位置 → 后果"直接对上的。
它把"稳定的放前面"这条规矩细化成了:稳定但不是全局约束的,放第一条用户消息之前,而不是塞系统提示里。
合并规则也讲清楚了:
| 插槽 | 多个注入器同时用时怎么合并 |
|---|---|
| 系统消息 | 找到就用空行追加,没有就新建插到最前 |
| 第一条用户消息之前 | 首个创建一条带标记的消息,后续全部追加进这一条 |
| 最后一条用户消息之后 | 复用已有的包裹结构,插在结束标记之前 |
| 每一条用户消息之上 | 逐条独立,注入条数记进元数据 |
第二条的效果值得单独记:所有静态上下文合并成一条用户消息,而不是十条。
十个注入器各插一条,历史里就多十条噪声消息;合并成一条,模型看到的是一整块背景。 这个"汇聚"靠的是在消息上打一个标记,后来者先找有没有这个标记。
末尾那个插槽多一层包裹协议:注入内容会被套上一组标记,好让下次注入能找到边界。
一条结构上的观察:流水线是一个数组,顺序执行
几十个处理器按阶段排成一个数组,从头到尾跑一遍,每步都可 能改写消息。
处理器的契约只有两个字段:名字 + 处理函数。
"拼输入"这件事在真实产品里会长成一条几十级的流水线。 但契约只有两个字段——这说明复杂度可以被摊平成"很多个简单的东西",而不是"一个复杂的东西"。
它没回答什么
- 怎么认出模型要调工具——大脑看有没有工具调用,但这一篇没讲格式。
- 一批工具怎么并发——不在这两篇。
- 历史怎么压——提到了压缩阈值判定,但策略不在这两篇。
坑与代价
- 指令联合类型有 14 个成员。 这是"大脑与引擎之间唯一的话术"的规模——每加一种能力就要加一个指令类型。
判断(无锚): 最小原型只需要三种指令:调模型、跑工具、收工。14 种是产品成熟后的样子,不是起点。 如果错,会错在: 如果第一版就要支持"等人批准"和"压缩",那至少要五种;硬压成三种会把这两件事塞进别的指令里,反而更乱。
- 四个插槽要求每个注入器明确选一个。 选错了不会报错,只会让缓存变差或信息过期。
- "决策产出纯数据"要求决策方不能持有任何句柄(文件、连接、回调)。这是个不小的约束,但也正是可序列化的代价。