架构与可扩展性

本页介绍 AgentSociety 2 的运行时架构,以及它如何在较大规模的仿真中组织智能体、环境、LLM 调用、 trace 和 replay 存储。

AgentSociety 2 将智能体状态放在独立 workspace 中,执行时再由 Ray Task 按批重建和推进智能体。 环境路由、LLM 调度、trace、replay 等运行时组件作为共享服务存在,通过 ServiceProxy 注入到每个 智能体。这样做的目标是让智能体数量可以随实验规模增长,而不是为每个智能体长期保留一个进程或 actor。

执行模型

每个 AgentBase 子类的持久状态都保存在自己的 workspace 中,包括 config.jsonAGENT.jsonstate/*.runtime/logs/*。智能体对象只是在一次任务执行期间从这些文件重建出来的运行时对象; 一次 step() 结束后,新的状态会写回 workspace。

这一模型对应 使用智能体 中的 create / from_workspace / to_workspace 契约。对调度器来说, 一个智能体可以表示为轻量的执行说明:workspace 路径、智能体类型、智能体 id,以及共享的 ServiceProxy 句柄。Ray worker 收到任务后在本地调用 from_workspace,运行 step,再调用 to_workspace 持久化结果。智能体对象本身不会在 Ray object store 中来回传递。

环境模块使用一套对称的持久化契约:EnvBase.to_workspace() 负责写出动态状态, restore() 负责恢复。每个模块可以选择自己的状态格式,通常把文件放在 <workspace_root>/state/ENV_STATE.json。路由会在每步结束时调用 to_workspaces(); 使用 --resume 时,actor 的 init() 会通过 from_workspaces() 重建各模块。恢复发生在 模块 init() 之后,因此 checkpoint 中的状态会覆盖初始化时的重置。AgentSociety 自身的状态 写入 SOCIETY.jsonSOCIETY_STEP.json。详见 环境模块命令行界面 的 resume 说明。

AgentSociety 在每个 tick 中执行以下流程:

  1. 将智能体 id 切成若干批。

  2. 为每一批提交一个 step_agent_batch Ray Task。

  3. 每个 task 在批内用 asyncio.gather 并发推进智能体;批之间由 Ray 调度到不同 worker。

  4. 所有批次完成后,调用环境的 step,再推进仿真时钟。

默认批大小为 AGENTSOCIETY_BATCH_SIZE=256``(CLI ``--batch-size 可覆盖)。每 tick 的 Ray Task 数 = ⌈N / 批大小⌉,受 AGENTSOCIETY_LLM_RAY_MAX_WORKERS``(默认机器 CPU 核数)封顶; 单个 task 内的并发 fan-out 由批大小决定,每进程的 LLM 并发则由本地 ``LLMClient 的 AIMD 自适应控制(无人工上下限)。

digraph exec_model {
    rankdir=LR;
    node [shape=box, style=rounded];

    Driver [label="AgentSociety (driver)"];
    Batch [label="step_agent_batch\nRay Task × 批", shape=note];
    Agent [label="agent.from_workspace()\n无状态重建 + step"];
    WS [label="workspace\n(磁盘状态)", shape=cylinder];

    Services [label="共享服务\nenv / llm / trace / replay", style=filled, color=lightyellow];

    Driver -> Batch [label="切批提交"];
    Batch -> Agent;
    Agent -> WS [label="读写状态"];
    Agent -> Services [label="经 ServiceProxy"];
}

ServiceProxy

智能体不直接创建或持有 LLM dispatcher、环境 router、trace actor 或 replay actor。from_workspace 接收一个 ServiceProxy,并在 _bind_services(service_proxy) 中把相关句柄绑定到智能体实例。

slot

来源

用途

_service_proxy

入参

原始服务容器,包含 env / llm / trace / replay 句柄。

_env

service_proxy.env

环境 router(RouterBase / EnvRouterProxy)。

_dispatcher

service_proxy.llm.default

默认 LLM dispatcher(call(...))。

_trace

service_proxy.trace

trace writer 句柄(通常是 TraceProxy)。

ServiceProxy 只保存可序列化的句柄和配置,不保存锁、连接池或后台线程。Ray Task 因此只需要接收 一个服务容器;环境 router、trace 与 replay 由 driver 或 CLI 统一创建,LLM client 只携带连接参数, worker 在自己的事件循环中按需创建 litellm Router 和并发控制器。

环境路由

环境状态由环境路由统一管理。生产运行时,CLI 会通过 get_env_router_actor_class 创建专用的 Ray actor,并把 EnvRouterProxy 放入 ServiceProxy。智能体通过该 proxy 调用 askstepinitget_world_description 等接口;所有智能体看到的是同一份环境状态。

路由器(RouterBase 子类)负责把智能体的自然语言请求映射到环境模块暴露的 @tool 方法:

路由器

特点

CodeGenRouter (默认)

从环境模块提取工具签名,生成调用代码并在受限环境中执行;带 AST 守卫与缓存统计。

ReActRouter

ReAct 式工具选择。

PlanExecuteRouter

先规划再执行。

TwoTierReActRouter / TwoTierPlanExecuteRouter

两级路由,适合大工具集。

SearchToolRouter

以搜索/检索方式选择工具。

环境模块与 @tool 装饰器见 环境模块核心概念

LLM 调度

LLM 调用由 agentsociety2.config.llm_dispatcher 统一封装。当前实现使用 per-process dispatcher:LLMClient 是可序列化的连接配置,只携带 model_namebase_urlapi_key;它可以随 ServiceProxy 进入 Ray Task 或 env router actor。 每个消费者在自己的事件循环中第一次调用 call() 时,本地创建 litellm RouterAdaptiveSemaphore。这样可以避免跨 Ray task 复用 asyncio 对象导致的 event-loop 绑定问题。

并发控制发生在每个进程 / 事件循环内部:AdaptiveSemaphore 根据近期延迟和 rate-limit 错误做 AIMD(加性增、乘性减)调整,用于控制该进程内 LLM 请求 fan-out。token usage 也按 LLMClient 实例本地累计,再通过 Ray Task 返回值合并。

默认配置可直接使用;需要调参时主要关注以下环境变量(详见 安装):

环境变量

默认

含义

AGENTSOCIETY_LLM_RAY_MAX_WORKERS

机器 CPU 核数

ray.init(num_cpus=...) 的 CPU 预算,封顶每 tick 同时运行的 step_agent_batch Ray Task 数。

AGENTSOCIETY_LLM_RAY_CONCURRENCY

16

每个本地 LLMClient 的 AIMD 初始并发;无人工上下限,自动逼近 API 真实容量。

AGENTSOCIETY_BATCH_SIZE

256

每个 step_agent_batch Ray Task 处理的 agent 数;CLI --batch-size 可覆盖。

AGENTSOCIETY_LLM_LATENCY_DEGRADE_FACTOR

4.0

AIMD 的相对退避因子。调用延迟明显高于近期健康基线时触发降并发。

AGENTSOCIETY_LLM_SLOW_LATENCY_MS

未设置

可选的绝对延迟阈值(毫秒)。未设置时只使用相对因子。

init_dispatchers() 只负责初始化 Ray(用于 env router actor 和 agent Ray Tasks)。 shutdown_dispatchers() 对 LLM 侧是 no-op;本地 Router 随所在进程退出释放。

Trace

agentsociety2.trace 提供分布式追踪:

  • ShardedTraceWritertrace_id 分片写入,并通过后台线程批量落盘。

  • JsonlTraceWriter 提供 start_spantrace_spanrecord_eventend_spanTraceSpan

  • TraceActor 是常驻 Ray actor;TraceProxy 是放入 ServiceProxy 的轻量句柄。

智能体执行、memory、环境调用和 LLM 调用都可以记录为 span。运行完成后,trace 数据可用于分析慢调用、 长尾任务和环境工具调用瓶颈。

Replay 与存储

Replay 数据由 ReplaySink / ReplayWriter 以 append-only JSONL 写入 run/replay/,dataset catalog 和列元数据保存在 _schema.jsonReplayProxy 只携带 replay 目录和启用标志;env router、society 和 agent task 各自在本进程内创建 ReplaySink 并并发 append,不再经过中心 SQLite actor。读取侧由 ReplayReader 使用 DuckDB 将 JSONL shard 注册为 view,表结构与数据集注册机制见 存储与结果访问

扩展点

AgentSociety 2 的主要扩展点包括:

参考