编译管道
编译管道将 invocation 配置、基础对话记录和待处理的运行时补丁转换为发送给 LLM 提供商的最终消息。这是一个两阶段的过程,对话记录补丁应用与请求渲染之间有着清晰的边界。两个阶段
阶段 1:归约轮次上下文
reduce_turn_context 接收当前基础对话记录和所有待处理的运行时补丁,输出一份干净的、已应用补丁的对话记录。
-
应用运行时补丁 —
apply_mutations(transcript, pending_mutations)按顺序处理每个 mutation:AssistantMessageMutation→ 追加助手消息ToolResultMutation→ 追加工具结果ContextReplaceMutation→ 替换整个列表ContextSummaryMutation→ 替换为摘要,存储经验ExperienceRemember/Forget→ 累积后在下一个非经验 mutation 之前批量提交- 等等
-
刷新 selfref 快照 — 如果 mutation 应用后的对话记录包含 selfref 标记(经验、摘要),则从对话内容重新解析
DataFromSelfRef。这确保快照反映的是刚刚应用的压缩或经验 mutation 的结果。 - 克隆 — 结果是深拷贝,不存在共享状态的修改。
阶段 2:转换为 LLM 请求
convert_to_llm_request 接收归约后的对话记录和 invocation 的 prompt contract,生成发送给提供商的最终消息。
-
解析系统提示词 — 优先级顺序:
- 如果
selfref_snapshot存在 → 渲染基础提示词 + 经验块 - 否则如果
prompt_contract.system_prompt已设置 → 直接使用 - 否则如果对话记录中有系统消息 → 提取其内容
- 否则如果
prompt_contract.base_instruction存在 → 使用 docstring 兜底
- 如果
- 放置系统消息 — 替换对话记录中已有的系统消息,或在开头插入新的系统消息。如果没有解析到系统提示词,则移除已有的系统消息。
-
渲染 LLM 消息 —
render_llm_input_messages()完成消息的最终处理:- 如果挂载了工具,在开头注入
<tool_best_practices>块 - 如果需要,追加
<must_principles>块(指示模型使用原生工具调用) - 返回可直接发送给提供商的最终消息列表
- 如果挂载了工具,在开头注入
在 ReAct 循环中的位置
唯一入口点
所有编译流程都经过同一个函数:@llm_function 和 @llm_chat 使用相同的入口点。不同的装饰器模式不存在独立的编译路径。
为什么分两个阶段?
这种拆分带来以下优势:- 单独使用阶段 1 用于内部状态管理(例如 ReAct 循环中的
compile_context更新状态而不渲染给 LLM) - 阶段 2 仅在实际调用 LLM 时添加提供商相关的渲染(工具注入、系统提示词放置)
- 测试 — 可以独立测试 mutation 应用和提示词渲染
- SelfRef 刷新 — 发生在两个阶段之间,确保快照在提示词解析之前是最新的
实际意义
对大多数用户来说,这些都是不可见的。你写函数、传 history、挂载工具、消费事件即可。 但当你需要调试内部行为:- 调试对话记录问题 → 检查产生了哪些运行时补丁、以什么顺序
- 理解系统提示词行为 → 了解阶段 2 中的优先级顺序
- 构建框架扩展 → 使用编译边界,而不是直接修改 live messages
下一节:SelfRef 自引用
持久上下文(经验、压缩、分叉)如何通过 SelfReference 系统工作。