跳到主要内容

自主 Agent 与 Ralph 自主开发循环

30 秒导读: 前面几章的 Agent 每次「你问一句、它答一句」。本章讲 Upsonic 最有辨识度的那类 agent:它自己会动手——在一个受限的工作区(workspace)里读写文件、执行 shell 命令;更进一步,RalphLoop 让它自己迭代——你只给一句「做一个 FastAPI 待办应用」,它就分解需求、列 TODO、一轮实现一个任务,直到测试全部通过。核心两件套:能动手的 AutonomousAgent / DeepAgent,和能自迭代的 RalphLoop

本章聚焦「沙箱化 + 自迭代」这一层。一次运行怎么跑完 24 步管线02-execution-pipeline.md;通用工具系统(自定义工具 / MCP / HITL)04-tools-system.md;这里只讲把工具箱预装进 agent、并把「运行」包成一个能容错的循环。


1. 这是什么(零基础也能懂)

一句话定义: 自主 Agent 是预装了「手脚」的 agent——出厂即带文件工具和 shell 工具,并把所有操作关进一个工作区目录里;Ralph 循环则是把这样的 agent 反复运行、每轮换一个全新实例、跑完一个任务的自动开发引擎。

解决什么问题 / 给谁用:

  • 想让 AI 帮你改一个真实项目的代码(读文件、改文件、跑测试)——但你不想让它误删你主目录的东西。
  • 想给 AI 一个目标(而不是一步步指令),让它整晚自己把项目写出来,早上回来看结果。

它能做什么:

能力由谁提供
读/写/编辑/搜索/移动/删除文件AutonomousFilesystemToolKit
跑 shell 命令、跑 Python 片段、查命令是否存在AutonomousShellToolKit
所有操作只限工作区,危险命令拦截两个 toolkit 的路径校验 + 命令黑名单
会话记忆(默认开)出厂注入 InMemoryStorage + Memory
可插拔虚拟文件系统(内存 / 持久化 / 混合)DeepAgent + backends
给一个 goal 自动写完项目RalphLoop

用起来什么样: 一个最小真实示例(来自 RalphLoop 类文档串,ralph/loop.py:36-45):

from upsonic import RalphLoop

loop = RalphLoop(
goal="Build a FastAPI TODO app", # 只给目标
model="openai/gpt-4o",
test_command="pytest", # 用它当「验收门」
)
result = loop.run() # 自己跑,直到 TODO 清空
print(result.summary())

一句话直觉/类比: 把它想成**「土拨鼠之日」(Groundhog Day)里的程序员**:每天早上失忆醒来(全新 agent、干净上下文),但桌上留着三份纸——需求书、待办清单、给自己的便签(learnings)。他每天只做一件待办、做完打勾、给自己写张便签,然后睡去;明天的「他」接着干。日复一日,项目就长出来了。Ralph 论文管这叫「eventually consistent(最终一致)」的开发。

本节不出现底层代码。记住两个词:沙箱(sandbox)自迭代(loop)


2. 顶层全景(它大概怎么转)

Upsonic 在通用 Agent(见 01-agent-and-task.md)之上,派生出三个「会动手」的类,再用一个循环把它们编排起来:

Agent (通用基类,第 1、2 章)
│ 继承
┌──────────────┼───────────────────┐
▼ ▼ ▼
AutonomousAgent DeepAgent (Ralph 内部临时 Agent)
├ 文件工具 ├ 可插拔虚拟FS 每轮 new 一个、用完 del
├ shell 工具 ├ 规划工具 write_todos
├ 工作区沙箱 └ 子 agent 委派 task
└ 默认内存+记忆

RalphLoop ──把「运行一个 agent」包成能容错的循环──


需求阶段 → TODO 阶段 → 增量阶段(死循环,一轮一个任务)

每轮:全新 Agent + 背压门(build/test)

怎么读这张图: 上半是三种能动手的 agent(都继承通用 Agent);下半是把 agent 反复跑的 RalphLoop。两半的连接点:Ralph 的增量阶段每轮临时 new 一个普通 Agent(不是 AutonomousAgent),给它装上 Ralph 自己的一套工具。

部件一句话职责:

部件干什么在哪个文件
AutonomousAgent预装文件+shell 工具、工作区沙箱、默认记忆agent/autonomous_agent/autonomous_agent.py:30
AutonomousFilesystemToolKit读写编辑搜索文件,含读前置校验agent/autonomous_agent/filesystem_toolkit.py:19
AutonomousShellToolKit跑命令/Python,含超时和黑名单agent/autonomous_agent/shell_toolkit.py:22
DeepAgent规划 + 可插拔虚拟文件系统 + 子 agent 委派agent/deepagent/deepagent.py:29
backends虚拟 FS 的三种后端:内存/持久化/混合路由agent/deepagent/backends/
RalphLoop三阶段编排 + 死循环 + 信号处理ralph/loop.py:24
BackpressureGate跑 build/test/lint,当「验收门」ralph/backpressure/gate.py:85
StateManager读写工作区里的状态文件(specs/fix_plan/AGENT.md)ralph/state/manager.py:16
SubagentSpawnerToolKit主 agent 派生一次性 subagent 干重活ralph/tools/subagent_spawner.py:25

主线走一遍(高层): 输入一个 goalRalphLoop.run() 先跑需求阶段(把目标写成 specs/*.md)→ TODO 阶段(把 specs 拆成 fix_plan.md 勾选表)→ 进入增量阶段死循环:每轮读状态、new 一个全新 agent、让它挑一条未勾选任务做完、跑背压门、打勾、记 learnings → 当 fix_plan.md 里没有未勾选项时,循环判定 completed 退出。


3. 核心原理之一:AutonomousAgent —— 把工具箱和沙箱预装进 agent

它要解决的小问题: 通用 Agent 你得自己配工具、自己配记忆、自己防止它乱碰文件系统。写一个「编码助手」时这些是每次都要重来的样板AutonomousAgent 把这套打包成开箱即用。

思路/直觉: 它就是一个带默认值的 Agent 子类——__init__ 里把「默认存储 + 默认记忆 + 文件工具 + shell 工具 + 一段讲清工具用法的系统提示」都准备好,再调 super().__init__()

三个默认值的装配(源码走读):

  1. 工作区兜底——没给 workspace 就用当前目录,并确保它存在:
# agent/autonomous_agent/autonomous_agent.py:216
if workspace is not None:
self.autonomous_workspace = Path(workspace).resolve()
else:
self.autonomous_workspace = Path.cwd().resolve()
  1. 默认存储/记忆——没传 storage/memory/db 时,自动 new 一个 InMemoryStorage,并据此建 Memory(autonomous_agent.py:224-259)。所以 full_session_memory 默认为 True,对话历史默认就有。

  2. 默认工具——按开关把两个 toolkit 塞进 default_tools,再和用户自带工具拼一起:

# agent/autonomous_agent/autonomous_agent.py:271
if enable_filesystem:
self.filesystem_toolkit = AutonomousFilesystemToolKit(workspace=self.autonomous_workspace)
default_tools.append(self.filesystem_toolkit)
if enable_shell:
self.shell_toolkit = AutonomousShellToolKit(workspace=self.autonomous_workspace, ...)
default_tools.append(self.shell_toolkit)
all_tools = default_tools + (tools or [])

关键细节:动态系统提示。 _build_autonomous_system_prompt(autonomous_agent.py:358)根据开了哪些工具拼出提示词:列出每个工具、给使用守则(「edit 前必须先 read」)、最后附一段安全声明——

# agent/autonomous_agent/autonomous_agent.py:470
security_notes = ["\n## Security Restrictions"]
if enable_filesystem:
security_notes.append("- All file operations are sandboxed to the workspace directory.")
security_notes.append("- Path traversal (../) outside the workspace is blocked.")
if enable_shell:
security_notes.append("- Dangerous shell commands are blocked for security.")

注意:这段提示只是告诉模型有沙箱;真正的强制在下面 §4 的 toolkit 代码里。用户若自带 system_prompt,则原样包进 <AutonomousAgent>...</AutonomousAgent>(autonomous_agent.py:379),不再拼默认那套。

附带的心跳(heartbeat)能力:heartbeat=True 后,接口层可周期性给 agent 发 heartbeat_message,由 aexecute_heartbeat(autonomous_agent.py:508)以静默方式(临时把 print 关掉)跑一次 do_async 并取回文本。这是「让 agent 定时自己动一下」的钩子。


4. 核心原理之二:两个工具箱与沙箱边界

这是自主 agent 的「手脚」。两个 toolkit 都继承通用 ToolKit(工具系统见 04-tools-system.md),差别在于每个方法都先过一道工作区校验

4.1 文件工具:路径穿越拦截 + 读前置校验

沙箱靠 _validate_path 一个函数守住——把任意路径 resolve 成绝对路径后,用 relative_to 试探是否仍在工作区内,不在就抛错:

# agent/autonomous_agent/filesystem_toolkit.py:64
def _validate_path(self, path: str) -> Path:
if path.startswith("/"):
resolved = Path(path).resolve()
else:
resolved = (self.workspace / path).resolve()
try:
resolved.relative_to(self.workspace) # 不在工作区内 → ValueError
except ValueError:
raise ValueError(f"Path '{path}' is outside workspace '{self.workspace}'")
return resolved

因为先 resolve() 再判断,../../etc/passwd 这种穿越会在解析后落到工作区外,被拦下。所有读写工具的第一行都是它。

巧妙处:read-before-edit 强制。 edit_file 不允许「盲改」——toolkit 用一个 self._read_files 集合记录读过哪些文件;read_file/write_file 成功后把路径加进去(filesystem_toolkit.py:134),而 edit_file 开头就检查:

# agent/autonomous_agent/filesystem_toolkit.py:309
if resolved_str not in self._read_files:
return (
f"❌ Error: You must call read_file('{file_path}') before editing.\n\n"
...
)

没读过就返回一条给模型看的错误(而非抛异常),引导它先 read_file 再重试。此外 edit_file 还处理「old_string 找不到」「出现多次但没开 replace_all」等情况,都以文字反馈回给模型自愈。

工具清单(都在 filesystem_toolkit.py):read_file(带行号分页)、write_fileedit_filelist_filessearch_files(glob)、grep_files(正则)、move_filecopy_filedelete_filefile_infocreate_directory。每个都有 a* 异步版。

4.2 shell 工具:超时 + 危险命令黑名单

默认黑名单在构造函数里写死了几条「毁灭性」命令:

# agent/autonomous_agent/shell_toolkit.py:74
self.blocked_commands = blocked_commands or [
"rm -rf /", "rm -rf /*", ":(){:|:&};:", "mkfs", "dd if=/dev/zero",
]

_validate_command(shell_toolkit.py:82)做子串匹配——命令小写后只要包含黑名单里任一串就拒。还可选传 allowed_commands白名单(只允许列出的基础命令)。

一个值得注意的工程决定:关掉工具层的超时和重试。 run_command 的装饰器写着 @tool(timeout=None, max_retries=0),注释解释了原因——subprocess 自己已经带 timeout,外层再包一层 wait_for 会重复、且取消时会泄漏子进程:

# agent/autonomous_agent/shell_toolkit.py:104
# Subprocess owns its own timeout; outer wait_for duplicates it and
# leaks processes on cancel. Disable the generic tool-layer retry.
@tool(timeout=None, max_retries=0)
def run_command(self, command, timeout=None, env=None, shell=True) -> str:
...
result = subprocess.run(command, shell=shell, cwd=str(self.workspace),
capture_output=True, text=True, timeout=effective_timeout, env=environment)

命令始终在工作区目录里跑(cwd=self.workspace),输出超过 max_output_length(默认 10000)会截断。三个工具:run_commandrun_python(把代码转义后用 python3 -c 跑)、check_command_exists

一句提醒: 这层沙箱是软约束——文件工具限死在工作区,但 shell 黑名单只是子串匹配,run_command 仍能跑任意未被列黑的命令(且能访问真实文件系统,只是默认 cwd 在工作区)。它防的是「模型手滑」,不是「对抗性逃逸」。真正的策略护栏见 05-safety-engine.md


5. 核心原理之三:DeepAgent —— 规划 + 可插拔虚拟文件系统

它要解决的小问题: 复杂多步任务里,你希望 agent(1)先显式拆解再动手,(2)把中间文件写进一个可换存储的虚拟盘(纯内存?落库持久化?两者混合?),(3)能把子任务委派给专职 subagent。

DeepAgent(agent/deepagent/deepagent.py:29)在通用 Agent 上加了三样,各由开关控制:

5.1 规划工具 write_todos —— 一个「认知强制函数」

PlanningToolKit(agent/deepagent/tools/planning_toolkit.py:73)提供 write_todos。它几乎不做实际计算——价值在于逼模型把任务拆成离散步骤。首调强制至少 2 条待办(TodoListmin_length=2,planning_toolkit.py:52);后续调用按 id 合并更新(planning_toolkit.py:192)。文件注释直言这是「cognitive forcing function」。

5.2 可插拔后端 —— 同一套文件工具,底下换存储

DeepAgent 的文件工具不直接碰真实磁盘,而是走一个 backend 协议(backends/protocol.py:12,一个 runtime_checkableProtocol,定义 read/write/delete/exists/list_dir/glob 六个异步方法)。三种实现:

后端存哪儿特性文件
StateBackend(默认)进程内一个 dict纯内存、快、不跨会话backends/state_backend.py:6
MemoryBackendUpsonic Storage(可 SQLite 等)持久化、跨进程、可多 agent 共享backends/memory_backend.py:41
CompositeBackend按路径前缀路由到不同后端混合:/memories/ 持久、/tmp/ 临时backends/composite_backend.py:16

DeepAgent 默认用 StateBackend(deepagent.py:114)。同一套 ls/read_file/write_file/edit_file/glob/grep 工具(tools/filesystem_toolkit.py)透过协议操作它们,底层换存储对模型完全透明。CompositeBackend 的路由是「首个匹配前缀者胜」(composite_backend.py:116),让你把「长期记忆」和「临时草稿」放进不同后端。

统一的路径纪律: 三个后端都要求绝对路径、拒绝 .. 穿越、拒绝空字节、限长 4096(见 state_backend.py:45_validate_path)。和 §4 的真实磁盘沙箱思路一致,只是这里守的是虚拟盘

5.3 子 agent 委派 —— task 工具

enable_subagents,DeepAgent 会:先确保有一个 general-purpose 子 agent(用父 agent 的工具、但 memory=None 完全隔离,deepagent.py:197),再挂上 SubagentToolKit(deepagent.py:212)。它提供 task(task_description, subagent_type) 工具:按名字查子 agent、跑 do_async、把结果返回(tools/subagent_toolkit.py:81)。这套「主 agent 派活给子 agent」的模式,正是下面 Ralph 循环的核心武器。


6. 核心原理之四:RalphLoop —— 给一个 goal,自己写完项目

这是本章的头牌。目标:输入一句话目标,输出一个能通过测试的项目。它的容错哲学是「一轮做一件小事,做错了下一轮再来」。

6.1 三阶段编排

RalphLoop.run()(ralph/loop.py:304)按顺序跑三个阶段:

run()

├─ 阶段1 需求 RequirementsPhase → 写出 specs/*.md
│ (若已传 specs 或已存在则跳过)

├─ 阶段2 TODO TodoPhase → 把 specs 拆成 fix_plan.md 勾选表

└─ 阶段3 增量 IncrementalPhase → while 死循环:
每轮 execute_iteration():
load 状态 → new Agent → 做一条任务 → 背压门 → 打勾 → 记 learnings
直到 fix_plan 无未勾选项 → final_status = "completed"
  • 需求阶段(phases/requirements.py:16):一个临时 Agent 读 goal,按 ```spec:name 格式输出多份规格,正则解析(_parse_specs,requirements.py:134)后逐个存盘。同时写下一份 PROMPT.md(DEFAULT_PROMPT_TEMPLATE,requirements.py:54),它把「RALPH 五原则」固化进去,成为每轮的系统提示底座。
  • TODO 阶段(phases/todo.py:16):读所有 specs,让 agent 产出 ```todo 勾选清单;_parse_todo_list(todo.py:102)把各种 bullet / 编号统一归一化成 - [ ] 任务 格式,写进 fix_plan.md。它反复强调「每条必须具体、可一轮做完、可测」。

6.2 增量循环:每轮一个全新 agent(Ralph/Groundhog 技术)

主循环极简(loop.py:359):

# ralph/loop.py:359 (节选)
while not self._should_stop:
iteration_count += 1
if max_iter and iteration_count > max_iter:
self._result.final_status = "max_iterations"; break
iter_result = incremental_phase.execute_iteration() # 跑一轮
...
if iter_result.plan_is_empty: # TODO 清空
self._result.final_status = "completed"; break

精髓在 execute_iteration(phases/incremental.py:227)。每一轮:

  1. 加载全新状态——state_manager.load_state() 从磁盘重读 specs / fix_plan / learnings(incremental.py:240)。这保证每轮上下文干净,没有跨轮的对话堆积
  2. 若已无未勾选项 → 直接返回 plan_is_empty=True(incremental.py:242)。
  3. new 一个全新 Agent——注意是普通 Agent,不是 AutonomousAgent,系统提示 = PROMPT.md + SCHEDULER_PROMPT,并现场装配 5 个 Ralph 工具:
# ralph/phases/incremental.py:262
agent = Agent(model=self.model, system_prompt=system_prompt, tools=tools)
...
result = agent.do(Task(description=task_description))
  1. 判断成功的方式很务实——不看 agent「说」自己做完了,而是对比这轮前后 fix_plan 里未勾选项的数量:少了一条才算真成功(incremental.py:312):
# ralph/phases/incremental.py:311
task_completed = pending_count_after < pending_count_before
  1. finally: del agent(incremental.py:333)——显式丢弃这一轮的 agent。下一轮是全新的一个。这就是「Groundhog」:每轮失忆重来,靠磁盘上的三份文件传递记忆。

这一轮 agent 拿到的 5 个工具(_create_tools,incremental.py:182):

工具作用文件
PlanUpdaterToolKit增删/勾选 fix_plan.md 条目ralph/tools/plan_updater.py:25
LearningsUpdaterToolKitAGENT.md 追加 learningsralph/tools/learnings_updater.py:18
BackpressureToolKit跑 build/test/lint 验收ralph/tools/backpressure.py:18
RalphFilesystemToolKit直接读写工作区文件ralph/tools/filesystem.py:20
SubagentSpawnerToolKit派生一次性 subagent 干重活ralph/tools/subagent_spawner.py:25

SCHEDULER_PROMPT(incremental.py:61)是给这轮 agent 的作业指南,铁律包括:只做一个任务先搜后写改前先读整文件不留 placeholder必须写测试背压过了才打勾记 learnings

6.3 背压门(backpressure gate):真·验收

思路: agent 说「做完了」不算数,得真跑一遍 build/test/lintBackpressureGate(ralph/backpressure/gate.py:85)顺序跑配置好的命令,任一失败就短路返回失败(gate.py:158-174)。

巧妙处:「没有测试」不算失败。 新项目早期还没测试,如果把 pytest 的「collected 0 items / exit code 5」当失败,循环会卡死。_is_no_tests_collected(gate.py:225)专门识别这种情形(覆盖 pytest / npm / jest / mocha 的措辞),把它当通过但提示「该加测试了」:

# ralph/backpressure/gate.py:233 (节选)
if "collected 0 items" in combined or returncode == 5:
return True # 不是失败,只是还没测试

暴露给 agent 的 run_backpressure 工具刻意标了 @tool(sequential=True, timeout=600.0)(ralph/tools/backpressure.py:37)——串行执行,因为 build/test 是资源瓶颈,同一时刻只跑一个。它把结果压成 "PASS" / "PASS (no tests found...)" / "FAIL: <原因>" 三种(gate.py:64format_for_agent)喂回模型。

6.4 状态管理:磁盘就是跨轮记忆

StateManager(ralph/state/manager.py:16)管理工作区里四类文件:PROMPT.mdspecs/*.mdfix_plan.mdAGENT.md。它是 Ralph「失忆但有笔记」得以成立的关键——每轮 load_state() 都从磁盘重读(manager.py:71)。

fix_plan.md 用 markdown 勾选框当进度状态机:- [ ] 待办、- [x] 完成。complete_fix_plan_item(manager.py:190)只是把 [ ] 改成 [x]从不删除(保留历史);remove_pending_item(manager.py:245)则只准删未勾选项,已完成的受保护删不掉。RalphState.is_plan_empty()(state/models.py:151)——「没有未勾选项」即视为全部完成,也就是循环的退出条件。

6.5 subagent 派生:保护主 agent 的上下文

主 agent 自己不去读大文件、搜代码库——那会撑爆它的上下文。它把重活派给一次性 subagent:spawn_subagent(task_description, purpose)(ralph/tools/subagent_spawner.py:135),purposesearch / analyze / write / test 四类,按类给不同的作业指令(_get_purpose_instructions,subagent_spawner.py:200)。两个设计要点:

  • 结果自动截断——_truncate_result(subagent_spawner.py:101)把子结果压到 max_result_length(默认 1000)再回给主 agent,省的是主 agent 的 context
  • 用完即弃——finally: del subagent(subagent_spawner.py:196),和主循环 del agent 一个思路。
  • test/build 是瓶颈——工具文档反复强调「不要并行派 test subagent」;真正的串行保证在 §6.3 的 sequential=True

7. 巧妙之处(可借鉴的技术)

  1. 「全新 agent + 磁盘状态」= 无限长任务不撑爆上下文。 传统 agent 跑久了对话历史越滚越长直到爆窗;Ralph 反其道:每轮丢弃 agent,只让三份磁盘文件跨轮传递(specs / fix_plan / AGENT.md)。上下文永远是「干净 + 少量笔记」。incremental.py:240 每轮重 load,:333 每轮 del agent

  2. 成功以「文件状态变化」为准,不信 agent 自述。 task_completed = pending_count_after < pending_count_before(incremental.py:311)——模型爱说「我做完了」,但只有 fix_plan.md 里真少了一条未勾选项才算数。用可观测的外部状态做判据,躲开了模型的乐观幻觉。

  3. 背压门把「没测试」和「测试挂了」分开。 一个 off-by-one 式的坑:新项目没测试时 pytest 返回码是 5,天真实现会当失败卡死循环。_is_no_tests_collected(gate.py:225)专治,返回「通过但提醒加测试」。

  4. subagent 结果强制截断 = 上下文预算的显式管理。 _truncate_result(subagent_spawner.py:101)把「干重活」和「攒上下文」解耦:重活在 subagent 的独立窗口里做,只有摘要回主线。

  5. read-before-edit 用「集合 + 文字错误」软强制。 edit_file_read_files 集合(filesystem_toolkit.py:309)拦住盲改,且返回给模型看的引导语而非抛异常——让模型自己「先 read 再 edit」地纠错。

  6. 关掉重复的超时层、避免子进程泄漏。 run_command 上的 @tool(timeout=None, max_retries=0) 及其注释(shell_toolkit.py:104)是很实在的并发工程细节:两层 timeout 会在取消时漏进程。


8. 边界与局限(诚实)

  • 沙箱是软的,不抗对抗。 文件工具限死工作区(_validate_path),但 shell 黑名单只是子串匹配(shell_toolkit.py:82),且 run_command 能跑任意未列黑命令、能触达真实文件系统。它防手滑,不防越狱。要强约束请叠加安全引擎(05-safety-engine.md)。
  • 成功判据可被「投机打勾」绕过。 判据是「未勾选项减少」;若 agent 不写实现直接调 update_fix_plan(action="complete"),循环也会记成功。背压门是唯一的实质防线——而它可能因「没测试=通过」而对空实现放行。
  • 背压对「无测试」宽容 → 可能收敛到「能跑但没验证」的项目。 no_tests_found 被当通过,极端情况下整个项目可以一条真实测试都没有就判 completed
  • 每轮全新 Agent 意味着重复的模型调用开销。 干净上下文的代价是每轮重发 PROMPT.md+specs+learnings;长项目累计 token 成本不低。
  • RalphLoop 内部临时 new 的是普通 Agent,不是 AutonomousAgent 它不复用 §3-4 那套工具箱,而是自带 RalphFilesystemToolKit(ralph/tools/filesystem.py:20)等一套平行的、无 read-before-edit 强制的文件工具。两套工具箱职责重叠但不共享代码。
  • DeepAgent 的虚拟 FS 默认不落盘。 默认 StateBackend 是纯内存(state_backend.py:6),进程结束即失;要持久化需显式换 MemoryBackend/CompositeBackend

9. 横向对比(与本章内三者)

维度AutonomousAgentDeepAgentRalphLoop
本质预装工具的 Agent 子类加规划+虚拟FS+委派的 Agent 子类把 Agent 反复跑的循环编排器
文件操作对象真实磁盘(工作区沙箱)可插拔虚拟盘(内存/持久/混合)真实磁盘(工作区)
记忆/状态出厂 InMemoryStorage+Memory可配 backend磁盘三文件跨轮传递
单次 vs 迭代单次运行(可多轮对话)单次运行多轮自迭代直到 TODO 清空
容错核心read-before-edit、命令黑名单路径校验背压门 + 全新 agent 重来
典型用途交互式编码助手复杂多步、需规划与委派的任务无人值守自动写完项目

三者的公共暗线:都靠「路径/命令校验」把 agent 的手脚关进边界,再用不同粒度的「验收」(read 前置 / 协议校验 / build-test 门)防止它把事情做坏。


10. 代码地图(导航索引)

主题文件路径符号名
自主 agent 主类src/upsonic/agent/autonomous_agent/autonomous_agent.pyAutonomousAgent_build_autonomous_system_prompt
文件工具 + 沙箱校验src/upsonic/agent/autonomous_agent/filesystem_toolkit.pyAutonomousFilesystemToolKit_validate_pathedit_file
shell 工具 + 黑名单src/upsonic/agent/autonomous_agent/shell_toolkit.pyAutonomousShellToolKit_validate_commandrun_command
DeepAgent 主类src/upsonic/agent/deepagent/deepagent.pyDeepAgent_build_deep_system_promptadd_subagent
后端协议src/upsonic/agent/deepagent/backends/protocol.pyBackendProtocol
三种后端src/upsonic/agent/deepagent/backends/StateBackendMemoryBackendCompositeBackend
规划工具src/upsonic/agent/deepagent/tools/planning_toolkit.pyPlanningToolKitwrite_todosTodoList
子 agent 委派src/upsonic/agent/deepagent/tools/subagent_toolkit.pySubagentToolKittask
Ralph 主循环src/upsonic/ralph/loop.pyRalphLooprunarun
三阶段基类src/upsonic/ralph/phases/base.pyBasePhasePhaseResult
需求 / TODO 阶段src/upsonic/ralph/phases/requirements.py.../todo.pyRequirementsPhaseTodoPhase_parse_todo_list
增量阶段(核心)src/upsonic/ralph/phases/incremental.pyIncrementalPhaseexecute_iterationSCHEDULER_PROMPT
背压门src/upsonic/ralph/backpressure/gate.pyBackpressureGatevalidate_is_no_tests_collected
背压工具(串行)src/upsonic/ralph/tools/backpressure.pyBackpressureToolKitrun_backpressure
状态管理src/upsonic/ralph/state/manager.pyStateManagerload_statecomplete_fix_plan_item
状态模型src/upsonic/ralph/state/models.pyRalphStateis_plan_emptyget_pending_items
subagent 派生src/upsonic/ralph/tools/subagent_spawner.pySubagentSpawnerToolKitspawn_subagent_truncate_result
plan / learnings 更新src/upsonic/ralph/tools/plan_updater.py.../learnings_updater.pyPlanUpdaterToolKitLearningsUpdaterToolKit
结果汇总src/upsonic/ralph/result.pyRalphLoopResultIterationRecord

相邻章节:index.md(全景) · 01-agent-and-task.md(Agent/Task) · 02-execution-pipeline.md(24 步管线) · 03-model-layer.md(模型层) · 04-tools-system.md(工具系统) · 05-safety-engine.md(安全引擎)。