跳转到主要内容

Documentation Index

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

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

SelfRef 自引用

SelfRef 是 SimpleLLMFunc 的持久自修改上下文系统——让 Agent 能够跨轮次记忆、压缩历史,并将工作委派给子 Agent。

两个组件,清晰分离

SelfReference(持久后端)

有状态的存储层。跨调用持续存在。存储:
  • History(按 memory key 分组)——完整的对话记录
  • Experiences ——持久记忆的事实/教训
  • Summaries ——压缩检查点
  • Fork state ——子 Agent 句柄与结果
from SimpleLLMFunc.builtin import SelfReference

selfref = SelfReference()
selfref.bind_history("agent_main", initial_history)

SelfRefSession(调用级插件)

单次调用的生命周期适配器。每次 @llm_chat 调用时重新创建。实现 ReAct hook:
  • collect_context_mutations() ——在每次编译前提供来自 selfref 的内部对话记录补丁
  • finalize() ——轮次结束后将最终状态持久化到 SelfReference 后端
Session 在无状态的 ReAct 循环和有状态的后端之间架起了桥梁。

连接方式

@llm_chat(self_reference_key="agent_main")


        ┌─ SelfRefSession(每次调用) ──────────────────┐
        │                                                │
        │  每次编译前:                                    │
        │    → collect_context_mutations()               │
        │    → 可能产出 Experience/Summary 补丁            │
        │                                                │
        │  轮次结束后:                                    │
        │    → finalize()                                │
        │    → 将更新后的历史持久化到后端                    │
        │                                                │
        └────────────────────────────────────────────────┘


        ┌─ SelfReference(持久后端)────────────────────┐
        │                                                │
        │  Memory["agent_main"]:                         │
        │    - history: [...]                            │
        │    - experiences: [{id, text}, ...]            │
        │    - summary: {...}                            │
        │                                                │
        └────────────────────────────────────────────────┘

DataFromSelfRef:快照

当 SelfRef 处于活跃状态时,编译管道会收到一个 DataFromSelfRef 快照:
@dataclass(frozen=True)
class DataFromSelfRef:
    base_system_prompt: str          # System prompt (may include experience markers)
    experiences: List[Dict[str, str]]  # [{id: "...", text: "..."}, ...]
    summary: Optional[Dict[str, Any]]  # Compaction metadata
    summary_message: Optional[Dict[str, Any]]  # Summary as a message
    working_messages: NormalizedMessageList  # Post-compaction working transcript
该快照决定了:
  • 系统提示词(基础提示词 + 渲染后的经验)
  • LLM 看到的消息(压缩后的 working_messages)
  • 哪些经验处于活跃状态

6 个运行时原语

@llm_chat Agent 启用了 SelfRef 并使用 PyRepl 时,以下原语可在 execute_code 中使用:

上下文原语

原语功能说明
runtime.selfref.context.inspect()返回只读快照:活跃 key、经验、摘要、消息、是否有待处理的压缩
runtime.selfref.context.remember(text)通过内部经验补丁存储持久经验
runtime.selfref.context.forget(experience_id)通过内部经验补丁移除经验
runtime.selfref.context.compact(goal, instruction, discoveries, completed, current_status, likely_next_work, relevant_files_directories, remember=[])将上下文压缩加入队列 → 稍后应用内部摘要补丁

分叉原语

原语功能说明
runtime.selfref.fork.spawn(task, instruction, ...)以分叉前的上下文快照生成子 Agent。返回 {fork_id, status}
runtime.selfref.fork.gather_all(include_history=False)等待所有已创建的子 Agent 完成。返回 dict[fork_id → ForkResult]

经验生命周期

经验是存储在系统提示词中的持久事实:
System Prompt:
  You are a coding agent...

  <experiences>
    <exp id="exp_001">User prefers dark mode terminal output</exp>
    <exp id="exp_002">Always run tests before committing</exp>
  </experiences>
  • remember("...") → 通过运行时补丁边界记录经验
  • forget("exp_001") → 移除经验
  • 经验在压缩中存活——它们存储在系统提示词中,而非工作对话记录中
  • 在编译阶段 2 中由 render_system_prompt_with_experiences() 渲染

压缩生命周期

当上下文增长过大时,Agent 可以执行压缩:
# Inside execute_code:
payload = runtime.selfref.context.compact(
    goal="Build the authentication module",
    instruction="Continue implementing OAuth flow",
    discoveries=["API requires PKCE", "Token refresh interval is 1h"],
    completed=["Set up project structure", "Added OAuth dependency"],
    current_status="Implementing token exchange endpoint",
    likely_next_work="Add refresh token logic, then write tests",
    relevant_files_directories=["src/auth/", "tests/test_auth.py"],
    remember=["OAuth endpoint requires PKCE challenge"]
)
处理过程:
  1. 压缩被加入队列(不会立即应用)
  2. 当前工具批次完成后,运行时会应用摘要补丁
  3. 系统提示词被保留
  4. 工作对话记录被替换为摘要消息
  5. remember 中的条目成为持久经验
  6. SelfReference 后端存储新状态

分叉生命周期

分叉允许 Agent 将工作委派给继承上下文的子 Agent:
# Spawn (inside execute_code)
handle = runtime.selfref.fork.spawn(
    task="Review the auth module for security issues",
    instruction="Check for: SQL injection, XSS, auth bypass. Return findings as a list.",
)
print(handle["fork_id"])  # "fork_abc123"

# ... do other work ...

# Gather (when you need results)
results = runtime.selfref.fork.gather_all()
for fork_id, result in results.items():
    print(f"{fork_id}: {result['status']} - {result['response']}")
关键规则:
  • 子 Agent 继承的是分叉前的上下文快照(不是父 Agent 的进行中状态)
  • 子 Agent 无法修改父 Agent 的上下文
  • gather_all() 会阻塞直到所有子 Agent 完成
  • 结果包含 statusresponse,以及可选的 history

激活方式

通过 @llm_chatself_reference_key 参数激活 SelfRef:
@llm_chat(
    llm_interface=llm,
    toolkit=[*repl.toolset, *file_tools],
    self_reference_key="agent_main",
)
async def agent(message: str, history: list):
    """Your agent prompt here."""
    pass
框架会自动:
  1. 为该 key 创建/获取 SelfReference 后端
  2. 将每次调用包装在 SelfRefSession
  3. 将 selfref 原语注入 PyRepl 运行时
  4. 在每轮结束后处理持久化(存储更新后的历史记录)

构建指南:llm_chat

如何在实践中使用 @llm_chat 与 SelfRef。

进阶:SelfRef 工程化

进阶模式:多 key 记忆、压缩策略、分叉编排。