跳到主要内容

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 种是产品成熟后的样子,不是起点。 如果错,会错在: 如果第一版就要支持"等人批准"和"压缩",那至少要五种;硬压成三种会把这两件事塞进别的指令里,反而更乱。

  • 四个插槽要求每个注入器明确选一个。 选错了不会报错,只会让缓存变差或信息过期。
  • "决策产出纯数据"要求决策方不能持有任何句柄(文件、连接、回调)。这是个不小的约束,但也正是可序列化的代价。