跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://simplellmfunc.cn/llms.txt

Use this file to discover all available pages before exploring further.

编译管道

编译管道将 invocation 配置、基础对话记录和待处理的运行时补丁转换为发送给 LLM 提供商的最终消息。这是一个两阶段的过程,对话记录补丁应用与请求渲染之间有着清晰的边界。

两个阶段

compile_invocation_turn(spec, transcript, pending_mutations, selfref_snapshot)

├─► 阶段 1:reduce_turn_context(transcript, mutations, selfref_snapshot)
│       • 将所有待处理的运行时补丁应用到对话记录
│       • 如检测到标记,刷新 selfref 快照
│       • 克隆结果(无共享引用)
│       → 返回:ReducedTurnContext

└─► 阶段 2:convert_to_llm_request(reduced, prompt_contract)
        • 解析系统提示词(selfref > 显式设置 > 对话记录 > docstring)
        • 在对话记录中放置/替换系统消息
        • 渲染最终消息(注入工具规格、must_principles)
        → 返回:CompiledTurnContext

阶段 1:归约轮次上下文

reduce_turn_context 接收当前基础对话记录和所有待处理的运行时补丁,输出一份干净的、已应用补丁的对话记录。
def reduce_turn_context(
    transcript: NormalizedMessageList,
    pending_mutations: List[ContextMutation],
    selfref_snapshot: Optional[DataFromSelfRef] = None,
) -> ReducedTurnContext:
处理过程:
  1. 应用运行时补丁apply_mutations(transcript, pending_mutations) 按顺序处理每个 mutation:
    • AssistantMessageMutation → 追加助手消息
    • ToolResultMutation → 追加工具结果
    • ContextReplaceMutation → 替换整个列表
    • ContextSummaryMutation → 替换为摘要,存储经验
    • ExperienceRemember/Forget → 累积后在下一个非经验 mutation 之前批量提交
    • 等等
  2. 刷新 selfref 快照 — 如果 mutation 应用后的对话记录包含 selfref 标记(经验、摘要),则从对话内容重新解析 DataFromSelfRef。这确保快照反映的是刚刚应用的压缩或经验 mutation 的结果。
  3. 克隆 — 结果是深拷贝,不存在共享状态的修改。
输出:
@dataclass
class ReducedTurnContext:
    transcript: NormalizedMessageList      # Mutation-applied, cloned
    selfref_snapshot: Optional[DataFromSelfRef]  # Refreshed if needed

阶段 2:转换为 LLM 请求

convert_to_llm_request 接收归约后的对话记录和 invocation 的 prompt contract,生成发送给提供商的最终消息。
def convert_to_llm_request(
    reduced: ReducedTurnContext,
    prompt_contract: PromptContract,
) -> CompiledTurnContext:
处理过程:
  1. 解析系统提示词 — 优先级顺序:
    • 如果 selfref_snapshot 存在 → 渲染基础提示词 + 经验块
    • 否则如果 prompt_contract.system_prompt 已设置 → 直接使用
    • 否则如果对话记录中有系统消息 → 提取其内容
    • 否则如果 prompt_contract.base_instruction 存在 → 使用 docstring 兜底
  2. 放置系统消息 — 替换对话记录中已有的系统消息,或在开头插入新的系统消息。如果没有解析到系统提示词,则移除已有的系统消息。
  3. 渲染 LLM 消息render_llm_input_messages() 完成消息的最终处理:
    • 如果挂载了工具,在开头注入 <tool_best_practices>
    • 如果需要,追加 <must_principles> 块(指示模型使用原生工具调用)
    • 返回可直接发送给提供商的最终消息列表
输出:
@dataclass
class CompiledTurnContext:
    transcript: NormalizedMessageList       # The transcript after system prompt resolution
    system_prompt: Optional[str]           # The resolved system prompt text
    llm_messages: NormalizedMessageList    # Final messages for the provider
    selfref_snapshot: Optional[DataFromSelfRef]  # Carried forward

在 ReAct 循环中的位置

# Simplified ReAct loop structure
while has_more_work:
    # 1. Collect mutations from hooks
    hook_mutations = collect_hook_mutations(state)
    
    # 2. Compile context (Stage 1 only — apply mutations)
    compiled_context = compile_context(state, hook_mutations + pending)
    
    # 3. Compile for LLM (Stage 1 + Stage 2 — full pipeline)
    turn = compile_invocation_turn(spec, compiled_context.messages, [], selfref)
    
    # 4. Send to LLM
    llm_result = execute_single_llm_phase(turn.llm_messages, ...)
    
    # 5. Execute tools if needed
    tool_result = schedule_tool_batch(llm_result.tool_calls, ...)
    
    # 6. Collect all new mutations for next iteration
    pending = llm_result.mutations + tool_result.mutations
每次迭代都经过完整的管道。Runtime 副作用不会“直接追加到 live list”,而是产生补丁并在边界应用。这保证了即使经过 50 次工具调用,对话记录状态依然一致且可审计。

唯一入口点

所有编译流程都经过同一个函数:
def compile_invocation_turn(
    spec: InvocationSpec,
    transcript: NormalizedMessageList,
    pending_mutations: Optional[List[ContextMutation]] = None,
    selfref_snapshot: Optional[DataFromSelfRef] = None,
) -> CompiledTurnContext:
@llm_function@llm_chat 使用相同的入口点。不同的装饰器模式不存在独立的编译路径。

为什么分两个阶段?

这种拆分带来以下优势:
  • 单独使用阶段 1 用于内部状态管理(例如 ReAct 循环中的 compile_context 更新状态而不渲染给 LLM)
  • 阶段 2 仅在实际调用 LLM 时添加提供商相关的渲染(工具注入、系统提示词放置)
  • 测试 — 可以独立测试 mutation 应用和提示词渲染
  • SelfRef 刷新 — 发生在两个阶段之间,确保快照在提示词解析之前是最新的

实际意义

对大多数用户来说,这些都是不可见的。你写函数、传 history、挂载工具、消费事件即可。 但当你需要调试内部行为:
  • 调试对话记录问题 → 检查产生了哪些运行时补丁、以什么顺序
  • 理解系统提示词行为 → 了解阶段 2 中的优先级顺序
  • 构建框架扩展 → 使用编译边界,而不是直接修改 live messages
重要区别:mutation 是内部对话记录补丁。它不是 docstring、模板参数、工具 schema 或初始 history 的来源。

下一节:SelfRef 自引用

持久上下文(经验、压缩、分叉)如何通过 SelfReference 系统工作。