跳转至

LLM 接入与干跑

在 SocioVerse 里,LLM 只坐在一个位置:决策模型decide_batch(observations, memories) 是计算 B = f(P, E) 的地方, 这个计算是规则、统计模型还是批式 LLM 调用,由研究自己选择。其余一切—— 环境、人群、存储、报告——两种方式下完全相同地运行。

配置

LLM 驱动的决策模型从环境变量读取设置(经由 gitignore 的 .env):

变量 含义
SV_LLM_API_KEY 主 API key(OPENAI_API_KEY 作为备选)
SV_LLM_BASE_URL 可选的端点覆写——任何 OpenAI 兼容网关
SV_LLM_MODEL 可选的模型选择
cp .env.example .env   # 填入你的 key;.env 已被 gitignore

批式调用是契约

decide_batch 一次接收该步(或该分组——Persona.group_key 定义批处理 分组)的全部观察。一个行为良好的 LLM 决策模型会:

  • 把每个观察的四象限视图渲染进 prompt (Observation.rendered 是放置备好文本的惯例位置);
  • 以 agent 的 AgentMemory(它自己过往行为的滚动窗口)为条件—— 「我已经搬过两次家了,这次留下」
  • 发起批式调用,绝不每个 agent 每步一个请求;
  • 返回类型化的 Action,让 apply() 能折回 E。

确定性干跑

你应当能在不花一个 token 的情况下验证全部管线——循环、产物、存储、 指标。两种等价做法:

规则式决策模型(随仓库提供的从零模板就是这样):决策是观察的纯函数, 运行结果由种子完全复现。

确定性替身客户端:保留你的 LLM 决策模型,但注入一个 complete() 是输入的固定函数的客户端。最小的替身:

class DeterministicLLMClient:
    """替代真实客户端:同输入 → 同输出,不走网络。"""

    def complete(self, prompt: str, **kwargs) -> str:
        # 选一个稳定、无聊的策略——例如永远选第一个选项
        return "stay"

在决策模型接收客户端的地方注入它(simulation/simulation.jsondecision_args 是这类接线的惯例位置)。包装遗留引擎的内置研究会自带 各自的确定性客户端,用途正是于此——查阅对应研究的 README。

干跑也是仓库一致性测试(parity test)的工作方式:包装遗留引擎的研究 断言自己在同一种子下复现原版轨迹,确定性客户端消除了唯一的非确定性来源。

关于可复现性,诚实地说

真实 LLM 运行不可复现

真实 LLM 调用在非零温度下采样:同一研究连跑两次结果会不同。 可复现的对象是:(a) 干跑——端到端由种子决定;(b) 任何已记录的 运行——它的面板存储是永久的,而且热启动的迭代精确回放已存储的行为,而不是重新询问 LLM。

成本控制

  • /sv-run 在花钱之前展示运行配置并要求确认——花费闸门。
  • 迭代产物时优先用干跑;每个有意义的配置只上线跑一次。
  • 热启动通过回放继承父版本的 0..K 步(零 LLM),只为新步数花钱。