跳转至

LLM 接入与干跑

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

配置

LLM 驱动的决策模型从环境变量或 gitignore 的 .env 读取设置(查找顺序见 安装)。 真实 LLM 运行需要 llm extra(pip install -e ".[llm]"),它带来 OpenAI 兼容客户端。

变量 含义
SV_LLM_API_KEY 模拟中 agent 调用所用的 key(OPENAI_API_KEY 作为备选)
SV_LLM_BASE_URL 可选的端点覆写——任何 OpenAI 兼容网关(未设置时为 OpenAI 官方 API)
SV_LLM_MODEL 可选;由 scripts/demo_offline.py、芝加哥适配器以及 simulation.json 未指定模型的研究读取。随仓库提供的研究固定了 decision_args.model
cp .env.example .env   # 填入你的 key;.env 已被 gitignore

这些变量只配置模拟用的 LLM。运行 /sv-* skill 的编程智能体(Claude Code,或实验性的 Codex CLI 路径)用它自己的登录凭据——见 工作流 skill 由什么驱动。

调用方式

引擎把整步——每个 agent 的观察——一次交给 decide_batch,并期望为每个 agent 拿回一条 Action。「batch」描述的是这个接口,而不是 LLM 怎么被调用。一个行为良好的 LLM 决策模型会:

  • 把每个观察的四象限视图渲染进 prompt (Observation.rendered 是放置备好文本的惯例位置);
  • 以 agent 的 AgentMemory(它自己过往行为的滚动窗口)为条件—— 「我已经搬过两次家了,这次留下」;
  • 在从零构建的研究里,为每个 agent 各发一次 LLM 调用,把该步的调用放到有上限的 线程池里并发执行(decision_args 里的 max_workers),并逐个 agent 解析或回退到规则 (见 studies/opinion_diffusion/model.py)。绝不让模型用一条 JSON 回复覆盖全部人群: 长的结构化回复会被截断,一条坏回复就会让整步失败;
  • 在遗留适配器里,保留被包装引擎自己的调用方式(例如芝加哥模型按 archetype 分组的 调用),让它经过验证的动力学保持不变;
  • 返回类型化的 Action,让 apply() 能折回 E。

确定性干跑

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

通用做法:llm_kind: "scripted"。 每个从零构建的模板都只注册一个决策模型, 带两种模式,在 simulation/simulation.json 里切换,不用改代码:

"decision_args": { "llm_kind": "scripted" }

"scripted" 运行研究自己的确定性规则(免费,由种子完全复现);"openai" 通过 SV_LLM_* 通道让每个 agent 角色扮演,回复无法解析时只对该 agent 回退(opinion_diffusion 回退到规则;campus_dining_choice 维持该 agent 上一步的选择)。scripts/demo_offline.py 就是这样跑 opinion_diffusion 的,/sv-run 也把 scripted 模式作为免费干跑提供。 /sv-build-model 新建的研究沿用同一模式,所以规则始终留在那里当 fallback。

规则式决策模型什么都不需要:决策是观察的纯函数。

包装遗留引擎:替身客户端。 包装遗留模拟器的研究沿用那个引擎自己的 LLM 客户端, 所以它通过注入一个确定性替身来干跑。随仓库提供的实例是 chicago_schelling 的 DeterministicLLMClient(studies/chicago_schelling/adapter/fake_llm.py),以 llm_client=DeterministicLLMClient() 传给 build_chicago_simulator。它只存在于这个 适配器里,不是给其他研究用的通用客户端。一致性测试(parity test)用的就是它:被包装的 研究断言自己在同一种子下复现原版轨迹,替身消除了唯一的非确定性来源。

关于可复现性,诚实地说

真实 LLM 运行不可复现

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

成本控制

  • /sv-run 在花钱之前展示运行配置并要求确认——花费闸门。
  • 迭代产物时优先用干跑;每个有意义的配置只上线跑一次。
  • 分支重放继承父版本分叉步 之前的所有步数(零 LLM),一个反事实只为分叉步之后的部分花钱。