Generative agents 代码分析 二

上一篇文章对项目的核心文件的功能做了单独介绍。接下来我们就具体看看各个模块的功能实现。这一篇先看前端环境模拟部分。

之前介绍编译运行的文章中提到,启动和常用功能大概有下面几项:

  1. 🚀 启动 environment 服务
  2. 启动 simulation 服务
  3. 运行和保存 Simulation
  4. 重放之前保存的 simulation
  5. 演示 simulation

以上 5 点可以分为两类。一部分是真正调用 LLM 大模型生成对话和记忆,然后检索规划,最终保存整个过程。另一部分是把前面运行的过程保存下来的场景,进行重放和演示。

功能介绍

今天重点学习重放 replay,启动 environment 前端服务。前端环境是一个基于 Django 框架的应用。

python 复制代码
cd environment/frontend_server
python manage.py runserver

打开 http://localhost:8000/浏览器显示"Your environment server is up and running,"说明运行成功了。

打开 http://localhost:8000/replay/July1_the_ville_isabella_maria_klaus-step-3-20/1/开始 replay。

整个页面分为三部分:

  1. 地图及角色动画展示,基于 Phaser 3.0 实现。这部分后面有时间单独介绍。
  2. 时间和回放控制
  3. 👯 角色列表和角色详情,核心信息展示。

代码

plain 复制代码
# http://localhost:8000/replay/July1_the_ville_isabella_maria_klaus-step-3-20/1/
# 拆解
http://localhost:8000/	# base url
replay/	# command
July1_the_ville_isabella_maria_klaus-step-3-20/	# simulation 文件
1/	# 步骤,可以手动指定第几步

启动 django 服务,指定默认配置文件目录为 frontend_server.settings

python 复制代码
def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'frontend_server.settings')
    try:
        from django.core.management import execute_from_command_line
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

环境配置文件

python 复制代码
# 需要跟随 django 启动的模块
INSTALLED_APPS = [
    # ...
    'translator',
    'corsheaders',
    'storages',
]
# 项目的 URL 路由入口模块
ROOT_URLCONF = 'frontend_server.urls'

# 静态资源与媒体文件
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_root")
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static_dirs"),
)

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "media_root")

解析刚才的 url,匹配到 replay/,转到 translator.replay方法

bash 复制代码
from translator import views as translator_views

urlpatterns = [
    url(r'^$', translator_views.landing, name='landing'),
    url(r'^simulator_home$', translator_views.home, name='home'),
    url(r'^demo/(?P<sim_code>[\w-]+)/(?P<step>[\w-]+)/(?P<play_speed>[\w-]+)/$', translator_views.demo, name='demo'),
    url(r'^replay/(?P<sim_code>[\w-]+)/(?P<step>[\w-]+)/$', translator_views.replay, name='replay'),
    url(r'^replay_persona_state/(?P<sim_code>[\w-]+)/(?P<step>[\w-]+)/(?P<persona_name>[\w-]+)/$', translator_views.replay_persona_state, name='replay_persona_state'),
    url(r'^process_environment/$', translator_views.process_environment, name='process_environment'),
    url(r'^update_environment/$', translator_views.update_environment, name='update_environment'),
    url(r'^path_tester/$', translator_views.path_tester, name='path_tester'),
    url(r'^path_tester_update/$', translator_views.path_tester_update, name='path_tester_update'),
    path('admin/', admin.site.urls),
]

解析

python 复制代码
def replay(request, sim_code, step): 

    persona_names_set = set()	# 人物角色列表
    for i in find_filenames(f"storage/{sim_code}/personas", ""): 	# 遍历存储的 replay 文件,找到人物角色
            persona_names_set.add(x)

    for i in find_filenames(f"storage/{sim_code}/environment", ".json"):

            file_count += [int(x.split(".")[0])]
    curr_json = f'storage/{sim_code}/environment/{str(max(file_count))}.json'
    with open(curr_json) as json_file:  
        persona_init_pos_dict = json.load(json_file)
        for key, val in persona_init_pos_dict.items(): 
            if key in persona_names_set: 
                persona_init_pos += [[key, val["x"], val["y"]]]

    context = {"sim_code": sim_code,		# 模拟文件名:July1_the_ville_isabella_maria_klaus-step-3-20
               "step": step,				# 对应 environment/ 下面的 *.json 文件,游戏里面的 10 秒代表一步,也就是 10s 一个 json 文件
               "persona_names": persona_names,	# 对应 personas 目录下的名字
               "persona_init_pos": persona_init_pos, 	# 角色 初始的 位置
               "mode": "replay"}			# 控制是否显示 play/pause 按钮
    template = "home/home.html"
    return render(request, template, context)

replay函数读取的 json 文件:

plain 复制代码
July1_the_ville_isabella_maria_klaus-step-3-20
├── environment
│   ├── 0.json	# 角色坐标文件
│   ├── 1.json
│   ├── 10.json
│   ├── 100.json
│   ├── 1000.json
│   ├── 1001.json
│   ├── ...
├── personas
│   ├── Isabella\ Rodriguez		# 角色文件
│   │   └── bootstrap_memory
│   │       ├── associative_memory	# 关联记忆
│   │       │   ├── embeddings.json		# embedding 矢量存储
│   │       │   ├── kw_strength.json	#	?
│   │       │   └── nodes.json				# 记忆节点
│   │       ├── scratch.json		# 角色的基础信息
│   │       └── spatial_memory.json		# 空间环境记忆
│   ├── Klaus\ Mueller
│   │   └── bootstrap_memory
│   │       ├── associative_memory
│   │       │   ├── embeddings.json
│   │       │   ├── kw_strength.json
│   │       │   └── nodes.json
│   │       ├── scratch.json
│   │       └── spatial_memory.json
│   └── Maria\ Lopez
│       └── bootstrap_memory
│           ├── associative_memory
│           │   ├── embeddings.json
│           │   ├── kw_strength.json
│           │   └── nodes.json
│           ├── scratch.json
│           └── spatial_memory.json
└── reverie
    └── meta.json		# simulator 基本信息

接下来 render 开始渲染界面 home/home.html,并且引入了 phaser 和 main_script.html脚本。

bash 复制代码
<script src='https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js'></script>
{% include 'home/main_script.html' %}

main_script.html主要负责游戏界面处理,同时负责和 django 服务通信。

bash 复制代码
function preload() {
}
function create() {}

function update(time, delta) {
  if (phase == "process") {
    var retrieve_xobj = new XMLHttpRequest();
    retrieve_xobj.overrideMimeType("application/json");
    retrieve_xobj.open('POST', "{% url 'process_environment' %}", true);
    retrieve_xobj.send(json);   
    // Finally, we update the phase variable to start the "udpate" process. 
    // Now that we sent all persona locations to the backend server, we need
    // to wait until the backend determines what the personas will do next. 
    phase = "update";
  } else if (phase == "update") {
  	var update_xobj = new XMLHttpRequest();
    update_xobj.overrideMimeType("application/json");
    update_xobj.open('POST', "{% url 'update_environment' %}", true);
    update_xobj.send(JSON.stringify({"step": step, "sim_code": sim_code }));   
    phase = "execute";
  } else {
    phase = "process";
  }
}

调用 process_environmentupdate_environment接口处理数据

python 复制代码
def process_environment(request): 
    """
    <FRONTEND to BACKEND> 
    This sends the frontend visual world information to the backend server. 
    It does this by writing the current environment representation to 
    "storage/environment.json" file. 
    """
    data = json.loads(request.body)
    step = data["step"]
    sim_code = data["sim_code"]
    environment = data["environment"]

    with open(f"storage/{sim_code}/environment/{step}.json", "w") as outfile:
        outfile.write(json.dumps(environment, indent=2))

    return HttpResponse("received")


def update_environment(request): 
    """
  <BACKEND to FRONTEND> 
  This sends the backend computation of the persona behavior to the frontend
  visual server. 
  It does this by reading the new movement information from 
  "storage/movement.json" file.
  """

    data = json.loads(request.body)
    step = data["step"]
    sim_code = data["sim_code"]

    response_data = {"<step>": -1}
    if (check_if_file_exists(f"storage/{sim_code}/movement/{step}.json")):
        with open(f"storage/{sim_code}/movement/{step}.json") as json_file: 
            response_data = json.load(json_file)
            response_data["<step>"] = step

    return JsonResponse(response_data)

Agent 数据结构

关于一个 Agent 的描述

相关推荐
三桥君3 小时前
AI智能体从请求到响应,这系统过程中究竟藏着什么?
人工智能·agent
大明哥_5 小时前
Coze + DeepSeek + 飞影数字人制作老祖宗爆款视频“回答我”,仅需 4 步带你完美复刻(保姆级教程)
人工智能·agent
ATM00614 小时前
人机协作系列(四)AI编程的下一个范式革命——看Factory AI如何重构软件工程?
人工智能·大模型·agent·人机协作·人机协同
AI大模型1 天前
MCP快速入门—快速构建自己的服务器
llm·agent·mcp
冯骐1 天前
从论文提示词注入看智能体安全
安全·agent
饼干哥哥1 天前
两句话,让Claude Code + Kimi K2 跑了3小时爬完17个竞品网站、做了一份深度市场数据分析报告
数据分析·agent·ai编程
ai2things2 天前
Generative agents 代码分析 一
agent
大模型教程2 天前
一文速通提示词工程Prompt Engineering
程序员·llm·agent
大明哥_2 天前
100 个 Coze 精品案例:抖音爆款星座 IP 混剪视频,用 Coze 工作流轻轻松松日更 100 条
agent