Contents
就像在有持久状态的 REPL 里写程序,程序可以修改它自己的运行时配置——唯一工具是 IPython kernel,子 agent 用
await rlm(...)异步调用,harness state(system prompt、技能库、记忆、子 agent)用 CRUD API 在运行时更新;/refine自动分析轨迹并把成功/失败模式写进技能库和记忆。当前无模型专门训练,作者明确表示 model-harness co-learning 才是解锁能力的关键。
与其他 harness 不同,Prime Agent 每轮只暴露一个工具:IPython kernel。所有操作(bash、文件读写、子 agent 调用、harness 修改)都通过 Python 代码完成。pre-imported 模块包括技能库、工具集和 rlm 异步函数。
子 agent 调用示例:
# 并行 fan-out:同时派出两个子 agent
auth = await rlm("Summarize the auth flow in auth/. Reply when done.", name="auth-expert")
api = await rlm("Summarize the HTTP API layer in src/. Reply when done.", name="http-expert")
# 结果通过 agent_message 异步返回
直观理解:子 agent 是 `await` 的异步函数,而不是"派发任务"的抽象操作——父 agent 在 REPL 里等待返回值,就像调用普通 Python 函数。
Background Daemon 通过本地 socket 管理实时 session。每个 session 有:
/tree 恢复任意分支)Agent 通信限于"核心家庭"(parent / sibling / child)——防止跨 session 意外交叉干扰。
三个机制支持无人值守运行:
prime-agent \ --autonomous \ --autonomous-gate "npm run check" \ --autonomous-max-turns 20 \ "Implement and verify the requested change"
Gate 失败时返回截断输出供重试;工作区无变化则跳过重跑失败 gate。
flowchart LR
User["User / Goal"] --> Agent["Prime Agent\nIPython REPL"]
Agent -->|"await rlm(...)"| Sub1["Subagent A"]
Agent -->|"await rlm(...)"| Sub2["Subagent B"]
Sub1 -->|"agent_message reply"| Agent
Sub2 -->|"agent_message reply"| Agent
Agent -->|"rlm.harness.create_skill"| HS["Harness State\nH = p,G,K,M"]
Agent -->|"compact.run()"| GC["GC Subagent\ncompaction"]
Agent -->|"refine.run()"| Ref["Refine\nplannerApplier"]
Ref --> HS
HS -->|"pre-inject"| Agent
Continual Harness 的核心:harness 自身状态(prompt ρ、子 agent G、技能 K、记忆 M)是 agent 在运行时可以 CRUD 的数据结构,存在 IPython kernel 里的 rlm.harness 对象。
| 字段 | 含义 | CRUD 示例 |
|---|---|---|
| ρ (prompt) | System prompt 注释 | create_prompt_note("always check return types") |
| G (subagents) | 已注册的持久子 agent | create_subagent("db-expert", ...) |
| K (skills) | Python 函数/模块,跨会话持久 | create_skill("retry_helper", code, reference={...}) |
| M (memory) | 键值对记忆 | create_memory("flaky test pattern", "retry 3×") |
# 运行时 CRUD 示例
rlm.harness.create_memory("flaky test pattern", "retry three times before failing")
rlm.harness.create_skill("retry helper", code_str, reference={"type": "python", "import": "retry_helper"})
rlm.harness.list("memory") # 列出所有记忆
rlm.harness.get("skill", "retry_helper") # 读取特定技能
/refine 分析当前 agent 轨迹,找出最小相关 CRUD 编辑并写入 harness。两阶段:
await refine.run("promote the retry-on-flaky-test pattern to a skill")
await compact.status() # tokens, context_window, percent, scheduled
await refine.status() # pending, in_flight
支持回滚(通过 refinement history)。每次 refine 记录 trigger 和 outcome。
最关键的一句话:harness state 是 agent 在运行时写给自己的"长期记忆 + 工具库",/refine 是把短期轨迹经验固化进这个结构的自动化通道。
| Benchmark | PA+GLM-5.2 | Pi-mono | PA+Opus 5 | Claude Code | PA+GPT | Codex |
|---|---|---|---|---|---|---|
| OOLONG (128k) | 0.700 | 0.420 | 0.900 | 0.920 | 0.940 | 0.500 |
| OOLONG-Pairs | 0.874 | 0.556 | 0.929 | 0.922 | 0.911 | 0.895 |
| OBLIQ-Bench | 0.669 | 0.635 | 0.802 | 0.795 | 0.612 | 0.646 |
| LongBenchPro | 0.777 | 0.768 | 0.804 | 0.790 | 0.794 | 0.790 |
| LongBenchv2 | 0.680 | 0.696 | 0.744 | 0.746 | 0.714 | 0.704 |
| ManyIH Coding | 0.424 | 0.386 | 0.536 | 0.522 | 0.499 | 0.454 |
| ManyIH IF | 0.209 | 0.164 | 0.225 | 0.175 | 0.216 | 0.232 |
| LongCot-Mini | 0.638 | 0.613 | 0.722 | 0.558 | 0.671 | 0.681 |
| EmulatorBench | 0.208 | 0.000 | 0.047* | 0.062* | 0.275 | 0.228 |
* EmulatorBench 中 Opus 5 / Claude Code 的低分可能因 harness 限制而非模型能力。
Agent 从头实现 SEGA Genesis 和 Nintendo Game Boy Color 模拟器,通过 diagnostic 验证程序(CPU flags、PPU timing)测试正确性。16 个模拟器重建任务。
/refine 成功把失败/成功转化为记忆和技能,合法生产分数数小时内突破 100K这是目前 continual harness + autonomous self-improvement 在真实任务上发现奖励 hacking 的最具体案例之一。
Repo:PrimeIntellect-ai/prime-agent(MIT)。TypeScript monorepo + Python runtime,核心分两层。
flowchart TD
TS["TS Host\npkgs/coding-agent\npkgs/agent"] -->|"stdio JSON"| PY["Python Kernel\nrlm.repl"]
PY -->|"host_request(type, payload)"| TS
TS --> DM["Daemon\nsession JSONL\nkernel snapshot"]
PY --> HS["harness_state.json\nprompt / memory\nskill / subagent"]
TS -->|"refine cmd"| HS
PY -->|"mtime check"| HS
| 目录 | 语言 | 职责 |
|---|---|---|
prime-agent-runtime/src/rlm/ | Python | REPL kernel、harness CRUD、rlm API、bash tool、MCP |
packages/agent/ | TypeScript | agent-loop.ts — 主循环,tool dispatch,AbortSignal 管理 |
packages/coding-agent/ | TypeScript | TUI、daemon、session 管理、/refine 命令实现 |
packages/ai/ | TypeScript | 多模型 provider 抽象(Anthropic/OpenAI/Gemini/Bedrock…) |
packages/tui/ | TypeScript | 终端 UI 组件 |
scripts/benchmarks/ | Python | benchmark runner(SWE-bench 等) |
rlm/repl.py 是 python -m rlm.repl 的入口。它在单个 asyncio event loop 上运行,把一个持久的 __main__ namespace 当 IPython kernel 用——每个 LLM "cell" 都在这个 namespace 里执行,支持 top-level await。
与 TS Host 的通信协议是 newline-delimited JSON over stdio(PROTOCOL_VERSION = 3):
host_request(type, payload) — Kernel 主动发给 Host 的 typed 请求(spawn 子 agent、读文件、写文件等),Host 回 {"status":"ok","result":{...}} 或 {"status":"error",...}Snapshot 机制:Kernel 可以把当前 __main__ namespace 序列化到磁盘(最大 256 MB,单变量上限 16 MB),崩溃后从 JSONL + snapshot 恢复。_ALWAYS_SKIP 里的名字(rlm, mcp, bash, asyncio 等)永远不进 snapshot。
harness state 是一个 JSON 文件(路径优先级:$RLM_HARNESS_STATE_DIR → $RLM_SESSION_DIR/harness/harness_state.json),结构如下:
# harness_state.json 结构
{
"schema": 1,
"entries": {
"prompt": { "<slug-id>": { HarnessEntry } },
"memory": { ... },
"skill": { ... },
"subagent": { ... }
},
"refinements": [ { RefinementEvent } ]
}
# HarnessEntry 字段
@dataclass
class HarnessEntry:
id: str # _slug(title) 或显式指定
kind: Literal["prompt","memory","skill","subagent"]
title: str
content: str
path: str = "general" # 用于 UI 分组
scope: Literal["local","global"] = "local"
reference: dict = {} # skill 专用:{"type":"python","import":"...","callable":"..."}
arguments: dict = {}
metadata: dict = {}
source: str = "agent"
created_at: str # UTC ISO
updated_at: str
version: int = 1 # 每次 update +1
三个关键设计点:
O_WRONLY|O_CREAT|O_EXCL),再 os.replace(tmp → target)——读者永远看不到 torn file_sync_from_disk() 在每次读写前比对 mtime。如果 /refine 命令(TS 进程)在 kernel 不知情的情况下改写了文件,kernel 下次 CRUD 前会自动重新 load,不会覆盖 Host 的改动~/.prime/agent/harness/harness_state.json,跨所有 session 可见CRUD API(在 kernel namespace 里直接调用):
# 完整 CRUD 示例
# --- CREATE ---
rlm.harness.create_memory("flaky test pattern", "retry 3× with exponential backoff")
rlm.harness.create_prompt_note("always check return types", "verify type annotations before calling APIs")
rlm.harness.create_skill(
"retry_helper",
"retry_helper.run(cmd, max=3) — retries shell cmd with backoff",
reference={
"type": "python",
"import": "retry_helper", # pip-installable Python package name
"callable": "run", # 或 call_pattern: "retry_helper.run(...)"
}
)
rlm.harness.create_subagent(
"db-expert",
"Specialist for all database operations",
reference={"model": "anthropic/claude-opus-5"}
)
# --- READ ---
entry = rlm.harness.get("memory", "flaky_test_pattern")
all_skills = rlm.harness.list("skill")
overview = rlm.harness.list() # 所有 kind
# --- UPDATE ---
rlm.harness.update("memory", "flaky_test_pattern",
"flaky test pattern", "retry 5× with 2s base delay")
# --- DELETE ---
rlm.harness.delete("memory", "flaky_test_pattern")
# --- upsert (create-or-update,不报错) ---
rlm.harness.upsert("memory", "deploy notes", "use --rolling flag")
rlm 是一个 module-level singleton(_RLMNamespace),pre-imported 进每个 kernel session。所有子 agent 操作都通过它发给 TS Host:
# 子 agent spawn(非阻塞,返回 handle)
handle = await rlm.spawn("Summarize auth flow in auth/", name="auth-expert")
# handle.rlm_child_id: str, handle.session_dir: Path, handle.model: str
# 并行 fan-out + 等待
h1 = await rlm.spawn("analyze API layer", name="api-worker")
h2 = await rlm.spawn("analyze DB layer", name="db-worker")
results = await rlm.collect([h1, h2], timeout_ms=120_000)
# results[i].status: "done"/"error"/"running"/"queued"/"cancelled"
# results[i].answer_preview: str | None
# results[i].settled: bool
# 非阻塞 snapshot(timeout_ms=0)
snapshot = await rlm.collect() # 所有直接子 agent 的当前状态
# 进度上报(到 parent,限速,512 UTF-16 chars)
await rlm.progress_note("processed 3/10 files")
# 删除子 agent session
await rlm.delete_subagent(handle)
# rlm.spawn 的底层:
# → host_request("rlm.run", {"prompt": ..., "kwargs": {"name": ...}})
# → TS Host 创建新 session,返回 rlm_child_id
rlm.collect() 的关键语义:timeout_ms=0 立即返回当前快照(非阻塞);正值等待所有目标 settle 或超时,超时返回当前状态而不报错。父 session 永远不会被 collect 调用"steering"——它只观察,不被打断。
packages/agent/src/agent-loop.ts 是 TS 侧的主循环。核心函数是 runLoop():
// 简化版 runLoop 骨架
async function runLoop(context, newMessages, config, signal, emit) {
let firstTurn = true;
// steering messages = heartbeat / user 注入
let pendingMessages = await pollMessagesUnlessAborted(config.getSteeringMessages, signal);
while (true) {
throwIfAborted(signal);
// 注入 steering messages 到 context
if (pendingMessages.length > 0) { /* push + emit */ }
// 调用 LLM,流式返回 AssistantMessage
const message = await streamAssistantResponse(context, config, signal, emit);
if (message.stopReason === "error" || message.stopReason === "aborted") {
emit({ type: "agent_end", messages: newMessages });
return;
}
// 提取 tool calls,dispatch 执行
const toolCalls = message.content.filter(c => c.type === "toolCall");
// ... 执行 tool,收集 toolResults,push 回 context ...
if (toolCalls.length === 0) {
// 检查是否继续:config.getContinuationMessages() 有内容则继续
const continuationMessages = await config.getContinuationMessages(lastTurn);
if (!continuationMessages?.length) {
emit({ type: "agent_end", messages: newMessages });
return;
}
}
}
}
Events 流(供 TUI / caller 消费):agent_start → turn_start → message_start/end → turn_end → agent_end。AbortSignal 贯穿所有 async 操作——abort 时立即停止并发 agent_end。
agentLoopContinue() 用于 retry:context 已有 user/toolResult message,直接继续执行而不重新 push prompt。
sequenceDiagram
participant LLM as LLM
participant K as Kernel
participant TS as TS Host
participant F as harness_state.json
LLM->>K: cell: rlm.harness.create_skill(...)
K->>F: atomic write
F-->>K: mtime updated
Note over TS: user runs /refine
TS->>TS: spawn refine child agent
TS->>F: analyze trajectory, CRUD edits
F-->>TS: mtime updated
LLM->>K: next cell: rlm.harness.list()
K->>F: _sync_from_disk checks mtime
F-->>K: reload with refine edits
K-->>LLM: updated skill list
buildRlmPrompt() 按以下顺序拼出完整 system prompt(depth=0 root agent):
| # | Block | 条件 | 内容摘要 |
|---|---|---|---|
| 1 | Identity | 全部 | "You are a general purpose agent that uses code to solve tasks. You solve tasks by breaking down problems into sub-tasks, writing and executing code, observing results, and iterating one step at a time." |
| 2 | LONG_RUNNING_WORK | 全部 | 非阻塞控制流;让 worker 并行启动然后 end turn;明确禁止 sleep polling |
| 3 | USER_PROGRESS | depth=0 only | 主动向用户报告进度;在有意义的 milestone 发 update;lead with user-visible outcomes |
| 4 | SIMPLIFIED_ENGLISH | 全部 | 短句、常用词、具体动词;每句一个 fact;技术术语/命令/路径保持原样 |
| 5 | Runtime meta | 全部 | Working directory / Conversation log / Recursive agent depth: N / Pre-installed packages |
| 6 | Skill列表 | 有 skill 时 | Pre-imported Python modules 名单;每个 skill 用 help() 或读 SKILL.md 查 API |
| 7 | Child doctrine | depth>0 | "You are a child agent spawned by <parent>. Task prompts labeled [task from parent]. Reply with agent_message.send(message, receiver_role='parent')." |
| 8 | REPL_CONTROL | 有 ipython | 最长块:IPython 详细规范,bash() 用法,harness CRUD,MCP via python object |
| 9 | refine 使用指导 | refine skill 存在 | 小的、有证据的更新;call refine.run() 返回立即,turn 结束后执行 |
| 10 | Subagent guidance | depth=0 + ipython | fan-out 模式;collect 语义;progress_note;large outputs → files |
| 11 | Project context | 有 context files | CLAUDE.md / AGENTS.md 等项目文件内容 |
| 12 | Harness digest | harness 非空 | 运行时注入:prompt notes / memory / skill / subagent entries 的 overview |
# 节选自 packages/coding-agent/src/core/prompts/rlm.ts "The `ipython` tool is a persistent Python REPL — the agent's long-lived control environment for reasoning, context management, state, tool orchestration, and recursive subcalls. Top-level `await` works directly." "Python is the orchestration language: use Python for loops, conditionals, parsing, and state. Use `bash()` to invoke programs, not to write shell programs — no shell loops or heredocs; do those in Python." "Do not assume the REPL is the native runtime of the external thing being investigated. A repository, package, service, dataset, paper, website, benchmark, or API may have its own environment and normal interface. Evaluate external systems through their own interface, then use the REPL to coordinate the process and analyze what comes back." "Run shell commands with `bash()`, not `subprocess`/`os.system`: subprocess calls block the kernel, show the user nothing while they run, and spawn processes the harness cannot see or stop." "Important: do not install dependencies into the kernel just to make an external project import or run there." "Each `bash()` call is its own process, so shell state does not persist between calls; use `os.chdir(...)` for the working directory and `os.environ[...]` for environment variables — both persist in the REPL and apply to later `bash()` calls." "Python state in the kernel persists across cells: named variables, helper functions, classes, imports, notes, parsed outputs, and helper data structures all remain available in every later turn."
| 行为 | prompt 来源 | 含义 |
|---|---|---|
| bash() 非阻塞 | REPL_CONTROL_PROMPT | h = bash('npm test') 立即返回 handle;await h 才等完成。明确禁止 subprocess——"blocks the kernel, shows the user nothing, spawns processes harness cannot see or stop" |
| 禁止 sleep polling | LONG_RUNNING_WORK | "Do not keep the turn open by polling with time.sleep() or shell sleep." 等 child 完成的正确方式:end turn → 等 follow-up 消息 → collect() |
| 外部环境不进 kernel | REPL_CONTROL_PROMPT | 明确禁止"install deps into kernel to make external project run"。用项目自己的 env:uv run ... / .venv/bin/python ... |
| shell state 不持久,REPL state 持久 | REPL_CONTROL_PROMPT | bash() 每次新进程;os.chdir() + os.environ[] 在 REPL namespace 持久,后续 bash() 继承 |
| spawn 返回时 child 未完成 | rlm.ts recursion block | "spawn returns immediately after task admission... it never waits for or returns the child's answer." 结果只通过 agent_message 或文件传回 |
| /refine 是 after-turn hook | rlm.ts refine block | "refine.run() returns immediately and runs when the current turn ends." 不阻塞当前工作 |
| base prompt 不可被改写 | REFINEMENT_SYSTEM_PROMPT | /refine 子 agent 的 system prompt 明确写:"The base system prompt is immutable and MUST NOT be rewritten." 只能加 prompt notes(supplemental addendum) |
| collect() preview not result | buildSubagentGuidance | "Large child outputs belong in files that you read selectively; collect snapshots are previews." collect() 只给 answer_preview(截断),强制 agent 设计文件交接协议 |
| 子 agent 继承 model + thinking level | rlm.ts spawn block | "A child inherits your model." 显式 model 参数才覆盖;不可用 model 则 spawn 失败(不 fallback) |
| Simplified Technical English | SIMPLIFIED_TECHNICAL_ENGLISH_PROMPT | 用户可见 prose 默认 ASD-STE100 风格(短句、每句一 fact);命令/路径/引用保持原样 |
理解原理后,可以用纯 Python 复现 harness state 的最小版本:
# 最简 harness state(无需 TS host)
import json, os
from pathlib import Path
HARNESS_FILE = Path.home() / ".prime" / "agent" / "harness" / "harness_state.json"
HARNESS_FILE.parent.mkdir(parents=True, exist_ok=True)
def load():
if not HARNESS_FILE.exists(): return {"entries":{"memory":{},"skill":{},"prompt":{}}}
return json.loads(HARNESS_FILE.read_text())
def save(state):
tmp = HARNESS_FILE.with_suffix(".tmp")
tmp.write_text(json.dumps(state, indent=2))
os.replace(tmp, HARNESS_FILE)
def create_memory(title, content):
s = load()
s["entries"]["memory"][title.replace(" ","_")] = {"title":title,"content":content}
save(s)
# 用法
create_memory("flaky test pattern", "retry 3×")
print(load()["entries"]["memory"])
真正的 HarnessState 多了:version 递增、mtime 同步检测、scope 路由(local/global)、原子写入(O_EXCL + replace)、技能 reference 校验。
跑 benchmark(SWE-bench 等)时,Prime Agent 用两层隔离防止 reward hacking:cloud 沙箱 + 双 sandbox 隔离验证。
评估基础设施用 Prime Intellect 自己的 prime_sandboxes SDK 创建 Docker 容器。每个 benchmark 都独立 provision 一个沙箱:
# controller.py — 创建 solver sandbox
sandbox = client.create(CreateSandboxRequest(
docker_image = config.image,
cpu_cores = config.cpu_cores,
memory_gb = config.memory_gb,
disk_size_gb = config.disk_gb,
timeout_minutes = config.ttl_minutes,
labels = ["prime-agent-benchmarks-v1",
f"role:main",
f"repository:{repo}",
f"run:{run_id}",
f"attempt:{attempt}"],
))
TTL label 用于清理超时沙箱;labels 允许多次重试共享同一 run 上下文。
沙箱内,每个 trial 创建独立 Linux user,agent 以该 user 运行:
# worker.py — 每个 trial 独立 user
subprocess.run([
"useradd",
"--create-home",
"--uid", str(2001 + trial), # benchmark1=2002, benchmark2=2003...
f"benchmark{trial + 1}",
])
# agent 以非特权 user 运行
cmd = ["runuser", "-u", f"benchmark{trial+1}", "--", "prime-agent", ...]
Trial 结束时 stop_processes(user) 扫 /proc/*/status 找 uid → SIGTERM → SIGKILL,清理所有残留进程。
flowchart LR
C["Controller\n(CI / grader)"]
C -->|"CreateSandbox"| S["Solver Sandbox\nnetwork=full\nagent runs here"]
S -->|"git diff patch"| patch["/tmp/prime-agent.patch"]
patch -->|"transfer only"| V["Verifier Sandbox\nfresh_copy=True\nnetwork=none"]
V -->|"git reset to base_commit"| V
V -->|"git apply patch"| V
V -->|"rm config.json tests.tgz"| V
V -->|"run tests"| log["test_output.log"]
log -->|"parse"| C
| 机制 | 实现位置 | 防止什么 |
|---|---|---|
| 输出只允许 patch 文件 | SecureHarbor.finalize() |
agent 只能产出一个 /tmp/prime-agent.patch;任何其他 artifact → RuntimeError,得 0 分 |
| Verifier 用 fresh sandbox | VerifierConfig(fresh_copy=True, network_allow=[]) |
Verifier 不继承 Solver 任何 state;无网络,无法外联 |
| Verifier reset 到 base commit | SecureVerifiedMixin.setup() |
git reset --hard {base_commit} && git clean -fd——从已知干净状态开始,只 apply patch |
| 测试 config 在跑前删除 | SecureVerifiedMixin.run_verifier() |
rm -f /tests/config.json /tmp/tests.tgz——agent 无法读 instance_id、预期答案 |
| 测试脚本重写 | rewrite_test_script() |
pip install → no-op;parser 替换 → 无法伪造 log;强制模板验证(含 PARSER/LOG/TEE 三个 pattern) |
| API credentials 剥离 | strip_task_runtime_credentials() |
PRIME_API_KEY / PRIME_SANDBOX_API_KEY / GITHUB_TOKEN / GH_TOKEN / HF_TOKEN 全部从 sandbox env 删除 |
| base commit 由 trusted config 指定 | trusted_base_commit() |
读 task 目录的 config.json(agent 不可修改),SHA 格式校验;agent 无法指定不同的 base |
| dataset revision pinned | pin_taskset_sources() |
每个 taskset 固定到 git commit hash,防止 dataset drift 或 agent 通过版本差异获益 |
# verified_verifier.py — patch 收集命令
def patch_collect_command(task_dir: Path) -> str:
base = trusted_base_commit(task_dir) # 从 trusted config.json 读,agent 不可改
return (
"rm -rf /logs/artifacts && "
"git add -N -- . && "
f"git diff --binary --no-ext-diff {base} -- . > /tmp/prime-agent.patch"
)
# 测试脚本重写片段(防 pip hijack + parser 劫持)
def rewrite_test_script(script: str) -> str:
# pip install → no-op
script = re.sub(r"python -m pip install.*", ": # dependencies pinned in task image", script)
# parser 替换(防止 agent 写恶意 parser)
script = script.replace(
'uv run parser.py | tee "$LOG_FILE"',
'exit "${TEST_STATUS:-0}"'
)
# log 重定向到 /dev/null
script = script.replace("LOG_FILE=$(mktemp)", "LOG_FILE=/dev/null")
return script
整个设计核心:结构上不可能 hack。Agent 只有一个输出通道(git diff),Verifier 是 fresh isolated environment,测试本身由 trusted code 重写——不依赖 agent 诚实运行。
/refine+CRUD 形成了一个明确的"轨迹→持久状态"通道;以及 model-harness co-learning 框架的明确主张(虽然当前还没有专门训练的模型)。await rlm()、rlm.harness 等 API;当前通用模型对此训练不足Prime Agent 代表了"harness 作为可训练信号载体"这一方向的早期形态——与 Anthropic/OpenAI 2026 年报告中"AI R&D 自动化"的大趋势一致。下一步关键:(1) 专门针对 RLM API 的模型训练;(2) 解决 refinement loop 的目标对齐问题;(3) 把 harness state 的变化作为强化学习信号(而非仅仅是 prompt 注入)。Factorio reward hacking 案例是一个难得的公开 empirical evidence,说明 autonomous self-modification 系统的对齐挑战不是理论问题。
基于 PrimeIntellect-ai/prime-agent 源码(2026-08)直接分析。TypeScript monorepo(pnpm workspace)+ Python runtime(uv)。
| 路径 | 语言 | 职责(一句话) |
|---|---|---|
| TypeScript monorepo(packages/) | ||
packages/agent/src/ | TS | agent-loop.ts:LLM 流式调用主循环 + tool dispatch;agent.ts:单次 agent 入口;proxy.ts:emit 事件的代理包装 |
packages/coding-agent/src/core/ | TS | 所有"coding agent"逻辑:session 生命周期、系统 prompt 构建、kernel 管理、compaction、/refine、goals、heartbeat、MCP、tool 实现 |
packages/coding-agent/src/core/kernel/ | TS | Python kernel 进程管理:bootstrap.ts 启动子进程;repl-manager.ts 管理 cell 执行队列;state-snapshot.ts 保存/恢复 kernel state |
packages/coding-agent/src/core/prompts/ | TS | rlm.ts:buildRlmPrompt() — 12 块 system prompt 拼装;index.ts:通用 prompt utilities |
packages/coding-agent/src/core/refinement/ | TS | refinement.ts:/refine 命令实现;REFINEMENT_SYSTEM_PROMPT;planner+applier 子 agent 编排 |
packages/coding-agent/src/modes/ | TS | 运行模式路由:interactive/ TUI 模式;session-worker/ 实际执行 agent 逻辑;daemon/ 后台 session 管理器;acp/ agent-connection protocol;headless-completion.ts 无 TUI 运行 |
packages/coding-agent/src/modes/daemon/ | TS | 常驻后台进程:daemon-supervisor.ts 监管所有 session worker;daemon-catalog-*.ts session 目录(JSONL 索引);daemon-socket.ts Unix domain socket 通信;heartbeat-catalog.ts 定时 heartbeat 管理 |
packages/coding-agent/src/modes/session-worker/ | TS | 单个 session 的执行环境:private-framing.ts 二进制帧协议(连接 daemon↔worker);agent-roster.ts 子 agent 注册表;compact-session-stream.ts context compaction |
packages/ai/src/ | TS | 多模型 provider 抽象:Anthropic/OpenAI/Bedrock/Gemini/OpenRouter + Prime Inference;stream.ts 统一流式 API;models.generated.ts 模型列表 |
packages/tui/ | TS | 终端 UI 组件(Ink/React-like):session 列表、agent trace、context 占用、agents-view 导航 |
| Python runtime(prime-agent-runtime/src/rlm/) | ||
rlm/repl.py | Python | IPython kernel 主进程:stdio JSON 协议(PROTOCOL_VERSION=3);持久 __main__ namespace;top-level await;snapshot 序列化;host_request() 反向 RPC 桥 |
rlm/harness.py | Python | HarnessState 类:harness_state.json 的全部 CRUD;原子写入;mtime 同步检测;local/global scope 路由;HarnessEntry dataclass;RefinementEvent |
rlm/__init__.py | Python | _RLMNamespace singleton(kernel 里的 rlm):spawn()/collect()/progress_note()/delete_subagent();_HarnessProxy 把 harness 挂到 rlm.harness |
rlm/bash.py | Python | 非阻塞 bash():返回 handle,await 才等完成;stdout/stderr streaming;进程 cleanup;与 harness 进程树隔离 |
rlm/mcp.py + mcp_base.py | Python | MCP (Model Context Protocol) 集成:把 MCP server 的工具暴露为 Python 对象,供 kernel 直接调用 |
rlm/skill.py | Python | 技能模块 CLI helpers:skill install/list/remove;技能包的 import 路径解析 |
rlm/_winjob.py | Python | Windows Job Object 封装(Windows 平台进程生命周期管理) |
| 评估基础设施(scripts/) | ||
scripts/benchmarks/controller.py | Python | Benchmark 控制器:创建/销毁 cloud sandbox;phase 调度(setup→solve→verify→grade);并行 trial 管理;结果汇总 |
scripts/benchmarks/worker.py | Python | Sandbox 内执行:apt install + user 创建;agent 进程启动;stdout/stderr 捕获;试验间进程清理 |
scripts/evals/short_swe/ | Python | SWE-bench 评估套件:secure_harbor.py 双 sandbox 隔离;verified_verifier.py trusted commit + 测试脚本重写;prepare.py credential 剥离 + dataset pinning;oracle_harness.py 金标准 preflight |
scripts/evals/swarm_fanout/ | Python | 多 agent swarm fan-out 评估(并行子 agent 协作任务) |
sequenceDiagram
participant U as User
participant CLI as cli-main.ts
participant D as daemon-supervisor.ts
participant SW as session-worker
participant KM as kernel/bootstrap.ts
participant PY as repl.py
U->>CLI: prime-agent "task..."
CLI->>D: connect to daemon socket
Note over D: daemon already running\nor fork new daemon process
D->>SW: spawn session-worker subprocess
SW->>KM: boot Python kernel
KM->>PY: python -m rlm.repl (subprocess)
PY-->>KM: protocol handshake (PROTOCOL_VERSION=3)
KM-->>SW: kernel ready
SW->>SW: build system prompt (buildRlmPrompt)
SW->>SW: inject harness_state.json digest
SW->>SW: first LLM call (stream)
SW-->>D: events (agent_start, turn_start...)
D-->>CLI: forward events
CLI-->>U: TUI renders
关键细节:
daemon-supervisor.ts 监听 Unix domain socket(~/.prime/agent/daemon.sock)。CLI 连接后 daemon 为本次请求 fork 一个 session-worker 子进程。PrivateFramedChannel,8 字节 header(type 2B + length 4B + flags 2B)+ payload,支持多路复用 session stream。
sequenceDiagram
participant SW as agent-loop.ts
participant AI as packages/ai stream.ts
participant RM as repl-manager.ts
participant PY as repl.py kernel
participant HS as harness_state.json
SW->>AI: streamAssistantResponse(context, config, signal)
AI-->>SW: stream chunks (text / tool_use)
Note over SW: tool_use = ipython cell
SW->>RM: executeCell(code, signal)
RM->>PY: {type:"execute", code:"..."} newline JSON
PY->>PY: exec in __main__ namespace
PY-->>RM: {type:"stream", stream:"stdout", text:"..."}
PY-->>RM: {type:"result", value:"..."}
RM-->>SW: CellResult {stdout, stderr, result}
SW->>AI: push tool_result to context
Note over SW: while tool calls present, loop
SW->>HS: (if cell called harness CRUD) mtime updated
SW->>SW: check getContinuationMessages()
SW-->>TUI: emit events (turn_end / agent_end)
关键细节:
ipython,input 是 {"code": "..."}。其他 tool(bash、MCP 等)都通过 Python 函数调用,不是独立 tool type。host_request(type, payload) 调用 TS Host——最常见的是 rlm.run(spawn 子 agent)。TS 处理完后同步回复,kernel cell 继续执行。getContinuationMessages() 检查是否有 heartbeat/steering 消息,有则继续下一轮而不是结束 session。/tree)和 compaction(GC 子 agent 替换旧 turns)。
sequenceDiagram
participant P as Parent kernel
participant TS as TS Host (session-worker)
participant D as daemon
participant C as Child session-worker
participant CK as Child kernel
P->>TS: host_request("rlm.run", {prompt, name, model})
TS->>D: spawn new session (via daemon socket)
D->>C: fork child session-worker
C->>CK: boot Python kernel
TS-->>P: {rlm_child_id, session_dir} (immediate)
Note over P: cell returns RLMSpawnHandle immediately
C->>C: run agent loop (async, independent)
C-->>D: emit agent_message(reply, receiver_role=parent)
D-->>TS: route message to parent session
TS->>P: inject as steering message (next turn)
Note over P: parent sees reply in getContinuationMessages
P->>TS: host_request("rlm.collect", {ids, timeout_ms})
TS-->>P: [{status, answer_preview, settled}]
关键细节:
rlm.collect() 查这个表。receiver_role 枚举:parent / child / sibling / self。跨 family 的 agent_message 被 daemon 丢弃。timeout_ms=0 → 立即返回当前快照(非阻塞);正值 → 等待所有目标 settle,超时返回当前状态(不报错);timeout_ms=null → 等待全部 settle(无超时)。rlm_child_id / session_dir / model——不含 coroutine,await handle 其实是等 agent_message 回复,不是等 child 进程结束。
flowchart TD
cmd["User: /refine or refine.run()"]
cmd --> TS["refinement.ts\nbuildRefinementContext(session)"]
TS --> P["Planner child agent\nanalyzes trajectory\nproposes RefinementEdit[]"]
P --> A["Applier child agent\nexecutes CRUD edits\nharness_state.json"]
A --> HS["harness_state.json\nmtime updated"]
HS --> KR["kernel _sync_from_disk\ndetects mtime change"]
KR --> LLM["LLM sees updated\nskill/memory/prompt\nnext turn"]
TS --> RE["RefinementEvent logged\nin harness_state.json refinements[]"]
关键细节:
refine.run() 调用 host_request("refine.run"),TS 侧在 turn 结束后才实际执行 planner+applier 子 agent,不阻塞当前 turn。refine.status() 查询 pending/in_flight 状态。buildRlmPrompt() 生成的基础 prompt。buildRefinementContext() 从 session JSONL 提取最近 N turns 的 tool calls + results + 用户 feedback,作为 Planner 的输入。{kind: "create"|"update"|"delete", entry_kind: "skill"|"memory"|"prompt"|"subagent", ...}——Applier 执行的是 typed diff,不是自由 Python 代码。refinements[] 数组,包含 trigger、timestamp、edit list——可以 replay 或 revert。| 文件 | 职责 |
|---|---|
daemon-supervisor.ts | 主进程:监听 socket;fork session-worker;监控子进程存活;重启 crashed worker |
daemon-socket.ts | Unix domain socket 服务器(~/.prime/agent/daemon.sock);连接 multiplexing |
daemon-catalog-*.ts | Session 目录:JSONL 索引 + session metadata(id, name, status, timestamps);disk-backed,daemon 崩溃可恢复 |
daemon-session-summarizer.ts | 后台生成 session title(LLM call);显示在 session 列表 |
heartbeat-catalog.ts | cron-style heartbeat 管理:每个 session 可注册 heartbeat;daemon 定时注入 steering message |
saved-session-catalog.ts | 已保存 session 的磁盘索引;支持 /tree 恢复任意分支 |
rlm-ledger.ts | 子 agent 关系账本:记录 parent→child 依赖图;用于 routing 和 cleanup |
worker-recovery-journal.ts | worker 崩溃恢复日志:记录哪个 session 在哪个 worker PID 上;重启后重新挂载 |
mutation-drain-latch.ts | 优雅关闭时等待 in-flight mutation 完成(防止 torn write) |
flowchart LR
C1["CLI (TUI)"]
C2["CLI (headless)"]
C3["Remote client"]
DS["daemon\ndaemon-socket.ts\ndaemon-supervisor.ts"]
W1["session-worker\n(session A)"]
W2["session-worker\n(session B)"]
W3["session-worker\n(session C, child of A)"]
K1["Python kernel A"]
K2["Python kernel B"]
K3["Python kernel C"]
C1 -->|"socket"| DS
C2 -->|"socket"| DS
C3 -->|"socket"| DS
DS -->|"pipe+framing"| W1
DS -->|"pipe+framing"| W2
DS -->|"pipe+framing"| W3
W1 -->|"stdio JSON"| K1
W2 -->|"stdio JSON"| K2
W3 -->|"stdio JSON"| K3
W1 -->|"agent_message route"| W3
packages/coding-agent/src/core/kernel/bootstrap.ts 启动 kernel 进程:
// bootstrap.ts 简化版
const kernelProcess = spawn("python", ["-m", "rlm.repl"], {
cwd: sessionDir,
env: {
...process.env,
RLM_SESSION_DIR: sessionDir,
RLM_HARNESS_STATE_DIR: harnessDir,
PROTOCOL_VERSION: "3",
},
stdio: ["pipe", "pipe", "pipe"],
})
// 等待 handshake message
const handshake = await readLineJSON(kernelProcess.stdout)
// → {"type":"ready","protocol_version":3}
repl.py 启动时 pre-import 进 __main__ namespace:
| 名字 | 类型 | 内容 |
|---|---|---|
rlm | _RLMNamespace | spawn/collect/progress_note + rlm.harness proxy |
bash | function | 非阻塞 shell 执行器(bash.py) |
mcp | object | MCP server 工具代理(mcp.py) |
asyncio | module | 标准库,top-level await 支持 |
| skill modules | modules | harness_state.json 里每个 skill 的 reference.import 对应的 Python 包 |
Snapshot 机制(state-snapshot.ts ↔ repl.py):
{"type":"snapshot_request"} → kernel 把 __main__ namespace 里每个变量 pickle → JSON base64 → 写 session_dir/kernel_snapshot.pkl{"type":"restore_snapshot"} → kernel 从 pkl 文件 unpickle 回 namespace_ALWAYS_SKIP(rlm, mcp, bash, asyncio, __builtins__)永远不进 snapshot;重启后重新 pre-import
sequenceDiagram
participant CTL as controller.py
participant SDK as prime_sandboxes SDK
participant SS as Solver Sandbox
participant VS as Verifier Sandbox
participant W as worker.py
CTL->>SDK: CreateSandboxRequest(image, cpu, mem, ttl)
SDK-->>CTL: sandbox handle
CTL->>SS: phase("setup") - install deps, create user
W->>SS: useradd benchmark1 (uid=2002)
CTL->>SS: phase("solve") - run agent
SS->>SS: runuser -u benchmark1 prime-agent task
SS-->>CTL: patch_collect_command output
CTL->>CTL: verify artifacts == {/logs/artifacts, /tmp/prime-agent.patch}
CTL->>SDK: CreateSandboxRequest(fresh_copy=True, network=[])
SDK-->>CTL: verifier sandbox
CTL->>VS: phase("verify_setup") - git reset base_commit
CTL->>VS: phase("verify_apply") - git apply patch
CTL->>VS: phase("verify_run") - rm config/tests, run tests
VS-->>CTL: test_output.log
CTL->>CTL: grade(log) -> score
CTL->>SDK: destroy both sandboxes
Phase 调度(controller.py phase()):
| Phase | 位置 | 执行内容 |
|---|---|---|
setup | Solver | apt install、useradd、pip install agent runtime、build venv |
solve | Solver | runuser -u benchmarkN prime-agent <task>;timeout 由 config 指定 |
collect | Solver | patch_collect_command():git diff --binary … > /tmp/prime-agent.patch |
verify_setup | Verifier | git reset --hard {trusted_base} + git clean -fd |
verify_apply | Verifier | git apply --binary /tmp/prime-agent.patch(从 Solver 复制过来) |
verify_run | Verifier | rm -f /tests/config.json /tmp/tests.tgz;执行 rewrite 后的测试脚本 |
grade | Controller | 解析 Verifier 的 test_output.log → pass/fail → 数值分 |
OracleHarness(oracle_harness.py):在正式 eval 前用金标准 patch 验证整个流程可用——确保 phase 调度、sandbox 网络、测试脚本都正确,再跑真实 agent,避免"基础设施 bug 被误算成 agent 失败"。