经过之前的摸索学习,现在终于可以来看一下整个论文中描述的最核心的部分 reverie
。
三个关键词:
- personas: generative agents,角色associative memory: memory stream,联想记忆reverie: 整个模拟框架
启动 reverie
之前提到整个系统分为 5 个部分,今天我们来看 2、3 部分。
- 启动 Environment 服务☕ 启动 Simulation 服务☕ 运行和保存 Simulation重放之前保存的 Simulation演示 Simulation
执行 pythone reverie.py
启动 reverie
,然后等待用户输入指令。
origin = input("Enter the name of the forked simulation: ").strip() target = input("Enter the name of the new simulation: ").strip() rs = ReverieServer(origin, target) rs.open_server()
初始化创建一个新的模拟实例,通常是从一个已有的模拟中派生。
# fs_storage = "../../environment/frontend_server/storage"# fs_temp_storage = "../../environment/frontend_server/temp_storage"def __init__(self, fork_sim_code, sim_code): copyanything(fork_folder, sim_folder) outfile.write(json.dumps(reverie_meta, indent=2)) for persona_name in reverie_meta['persona_names']: persona_folder = f"{sim_folder}/personas/{persona_name}" p_x = init_env[persona_name]["x"] p_y = init_env[persona_name]["y"] curr_persona = Persona(persona_name, persona_folder) self.personas[persona_name] = curr_persona self.personas_tile[persona_name] = (p_x, p_y) self.maze.tiles[p_y][p_x]["events"].add(curr_persona.scratch .get_curr_event_and_desc()) self.maze = Maze(reverie_meta['maze_name']) with open(f"{fs_temp_storage}/curr_sim_code.json", "w") as outfile: outfile.write(json.dumps(curr_sim_code, indent=2)) with open(f"{fs_temp_storage}/curr_step.json", "w") as outfile: outfile.write(json.dumps(curr_step, indent=2))
复制源模拟的所有文件到新目录。修改 meta.json 文件记录来源。加载起始时间、地图名称、秒每步等全局配置。实例化地图对象 Maze。🧑💼构造所有人物(Persona),并初始化它们的位置信息。写入当前模拟代码和步数到临时文件,供前端识别。
初始化完成后启动 server 控制台,server 主要提供命令行方式控制模拟,方便一步步模拟执行和调试。
def open_server(self): elif sim_command[:3].lower() == "run": # Runs the number of steps specified in the prompt. # Example: run 1000 int_count = int(sim_command.split()[-1]) rs.start_server(int_count)
支持命令:
命令 | 功能 |
---|---|
f , fin , finish , save and finish | 保存并退出模拟 |
start path tester mode | 进入路径测试模式(清空当前模拟) |
exit | 退出不保存,删除当前模拟数据 |
save | 仅保存当前状态 |
run <steps> | 自动运行指定步数 |
print persona schedule <name> | 查看某个人物的日程安排 |
print all persona schedule | 查看所有人物的日程摘要 |
print hourly org persona schedule <name> | 查看原始日程安排(未分解) |
print persona current tile <name> | 查看人物当前位置 |
print persona chatting with buffer <name> | 查看人物的聊天缓冲区 |
print persona associative memory (event/thought/chat) <name> | 查看人物的记忆流(事件/思考/对话) |
print persona spatial memory <name> | 查看人物的空间记忆 |
print current time | 查看当前模拟时间 |
print tile event <x,y> | 查看某个瓦片上的事件 |
print tile details <x,y> | 查看某个瓦片的完整信息 |
call -- analysis <name> | 与人物开启一次分析会话(不保存记忆) |
call -- load history <filename> | 从 CSV 文件加载历史记忆 |
我们输入run 100
启动服务。主要用来模拟的核心运行逻辑,处理环境输入、人物行为推理、输出下一步动作。
def start_server(self, int_counter): while (True): # 1 curr_env_file = f"{sim_folder}/environment/{self.step}.json" check_if_file_exists(curr_env_file) # 5 self.maze.add_event_from_tile(persona.scratch .get_curr_event_and_desc(), new_tile) next_tile, pronunciatio, description = persona.move(# 这里移动就会触发感知 perceive self.maze, self.personas, self.personas_tile[persona_name], self.curr_time)
等待前端环境文件更新(environment/.json)。清理上一轮添加的游戏对象事件(如床铺是否被使用)。更新人物位置:从环境文件中获取每个角色的新坐标。更新地图中的事件标记。驱动每个人物进行决策(调用 persona.move(...)):返回下一步目标位置、表情符号、描述文本、对话内容。写入下一步动作文件(movement/.json)供前端使用。更新时间与步数。循环直到指定步数完成。
核心 Persona
这是 Reverie 模拟系统中所有角色(智能体)的核心类。这个类实现了生成式智能体(Generative Agent)的行为逻辑,包含感知、记忆、规划、执行和反思等认知模块。
Perceive(感知) → Retrieve(检索) → Plan(计划) → Reflect(反思) → Execute(行动)
整体结构概览
模块 | 描述 |
---|---|
初始化 (init) | 加载或创建人物的记忆与状态 |
保存 (save) | 将当前状态保存到磁盘 |
感知 (perceive) | 获取周围环境事件 |
记忆检索 (retrieve) | 根据感知获取相关记忆 |
规划 (plan) | 制定长期与短期计划 |
执行 (execute) | 将计划转化为具体动作 |
反思 (reflect) | 更新记忆流中的深层思考 |
移动 (move) | 综合调用以上模块,返回下一步动作 |
对话会话 (open_convo_session) | 开启一个临时对话会话 |
另外可以通过 Maze 模块访问地图信息
详细分析
1. init 初始化
def __init__(self, name, folder_mem_saved=False): f_s_mem_saved = f"{folder_mem_saved}/bootstrap_memory/spatial_memory.json" self.s_mem = MemoryTree(f_s_mem_saved) # <s_mem> is the persona's associative memory. f_a_mem_saved = f"{folder_mem_saved}/bootstrap_memory/associative_memory" self.a_mem = AssociativeMemory(f_a_mem_saved) # <scratch> is the persona's scratch (short term memory) space. scratch_saved = f"{folder_mem_saved}/bootstrap_memory/scratch.json" self.scratch = Scratch(scratch_saved)
folder_mem_saved="environment/frontend_server/storage/July1_the_ville_isabella_maria_klaus-step-3-20/personas/Isabella Rodriguez/"加载 spatial(空间) 记忆,associative(联想)记忆,scratch(暂时)记忆
2. save 保存记忆到文件
def save(self, save_folder):
将当前 Persona 的状态保存到指定目录。
空间记忆树(JSON 文件)联想记忆(CSV 文件)临时记忆(JSON 文件)
3. perceive 感知环境
当角色移动的时候,调用 persona.move
,然后就会调用 persona.perceive
开始感知
def perceive(self, maze):
此函数获取当前 Maze,并返回角色周围发生的事件。重要的是,感知是由以下因素引导的
角色的两个关键超参数:
att_bandwidth: 控制最多感知多少个事件。retention: 控制多久内不重复感知同一事件。
首先,<att_bandwidth> 决定了角色可以感知的附近事件的数量。假设有10个事件在角色的视野范围内——感知这10个事件可能太多了。因此,在事件太多的情况下,角色会感知到最接近 att_bandwidth 数量的事件。
其次,角色不想在每个时间步都感知和思考同一事件。这就是 发挥作用的地方——角色记忆的内容有时间顺序。因此,如果角色的记忆中包含了最近一次记忆中发生的当前周围事件,就没有必要再去感知。
4. retrieve 检索记忆
def retrieve(self, perceived):
作用:从联想记忆中检索与感知相关的记忆。
输入:感知到的事件列表。
输出:字典结构,包含每个事件相关的上下文记忆(包括事件、思考、对话等)。
5. plan 规划行为
def plan(self, maze, personas, new_day, retrieved):
作用:制定长期与短期计划。
输入:
maze: 当前地图。personas: 所有人物字典。
<font style="background-color:rgba(255, 255, 255, 0.04);">new_day</font>
: 是否为新的一天(或第一天)。<font style="background-color:rgba(255, 255, 255, 0.04);">retrieved</font>
: 检索到的相关记忆。输出:目标动作地址(如
<font style="background-color:rgba(255, 255, 255, 0.04);">"Isabella Rodriguez is idle"</font>
)。
6. execute 执行计划
def execute(self, maze, personas, plan):
作用:将抽象计划转化为具体动作(如移动坐标、使用的对象等)。
输入:
maze: 地图。personas: 所有人物。plan: 目标动作地址。
输出:
下一步位置(
<font style="background-color:rgba(255, 255, 255, 0.04);">(x, y)</font>
坐标)表情符号(emoji)动作描述(如<font style="background-color:rgba(255, 255, 255, 0.04);">"writing her next novel @ sofa"</font>
)
7. reflect 反思机制
def reflect(self):
作用:回顾记忆并生成新的思考。
机制:
如果记忆中有未处理的事件,则触发“反思”过程。生成新的思想节点,并加入联想记忆中。
8. move 主行为函数 认知流程的主要入口
执行 run 100
会触发 persona 执行 move
动作。move
动作就是整个思考链条的起点。也是首页思考流程图的具体实现。
def move(self, maze, personas, curr_tile, curr_time): """ This is the main cognitive function where our main sequence is called. INPUT: maze: The Maze class of the current world. personas: A dictionary that contains all persona names as keys, and the Persona instance as values. curr_tile: A tuple that designates the persona's current tile location in (row, col) form. e.g., (58, 39) curr_time: datetime instance that indicates the game's current time. OUTPUT: execution: A triple set that contains the following components: <next_tile> is a x,y coordinate. e.g., (58, 9) <pronunciatio> is an emoji. <description> is a string description of the movement. e.g., writing her next novel (editing her novel) @ double studio:double studio:common room:sofa """ # Updating persona's scratch memory with <curr_tile>. self.scratch.curr_tile = curr_tile # We figure out whether the persona started a new day, and if it is a new # day, whether it is the very first day of the simulation. This is # important because we set up the persona's long term plan at the start of # a new day. new_day = False if not self.scratch.curr_time: new_day = "First day" elif (self.scratch.curr_time.strftime('%A %B %d') != curr_time.strftime('%A %B %d')): new_day = "New day" self.scratch.curr_time = curr_time # Main cognitive sequence begins here. perceived = self.perceive(maze) retrieved = self.retrieve(perceived) plan = self.plan(maze, personas, new_day, retrieved) self.reflect() # <execution> is a triple set that contains the following components: # <next_tile> is a x,y coordinate. e.g., (58, 9) # <pronunciatio> is an emoji. e.g., "\ud83d\udca4" # <description> is a string description of the movement. e.g., # writing her next novel (editing her novel) # @ double studio:double studio:common room:sofa return self.execute(maze, personas, plan)
作用:综合调用上述模块,完成一次完整的认知循环。
流程:
更新当前时间与位置。判断是否为新一天。调用 perceive 感知环境。感知 perceive 的输入是地图 maze调用 retrieve 检索记忆。检索 retrieve 的输入是感知 perceive调用 plan 制定计划。计划 plan 的输入是地图 maze、角色 persona、时间 curr_time、检索 retrieve调用 reflect 进行反思。调用 execute 执行计划,返回下一步动作。
名词
- Congitive,形容词,认知的。侧重智力层面的认知能力或相关研究领域(如认知科学),不涉及感官感知Perceive,动词,感知/察觉。包含更广泛的意义,既包含感官感知(如视觉、听觉),也包含对抽象概念的认知(如理解理论、情感)。Retrieve,检索,取回Reflect,反射,反映,反思