常见问题¶
安装与运行¶
试用需要 LLM API key 吗?¶
不需要。安装、测试、环境/人群构建、以及规则式决策的研究完全无 key 运行。 LLM 驱动的研究可以用确定性客户端 干跑。只有真实的 LLM 决策运行才需要 key。
有些测试跳过了,安装坏了吗?¶
没坏——依赖大型外部数据集的测试在数据缺失时自动跳过。 「有跳过、零失败」= 健康的安装。
必须用 Claude Code 吗?¶
只有 agentic 工作流(/sv-* skill)需要。
编程路径——写产物、
build_simulator、run()、SQL——是纯 Python。
可以并行跑多个研究吗?¶
一个进程一个研究。 包装遗留引擎的研究可能 patch 模块全局量, 不是线程安全的。批量实验用独立进程(例如进程池),每个进程一个研究。
可以把 /sv-run 丢到后台,让 agent 继续干别的吗?¶
不可以。 /sv-run 必须在前台跑——发出命令、让它阻塞,上限约 10 分钟。
不要用 run_in_background、结尾 & 或 nohup 把它包起来。
原因是结构性的:在 headless / 托管的 agent 里,后台任务结束时没有任何东西会 重新唤起 agent。运行完成在一片虚空里,agent 永远不知道它跑完了,整条流程就 这样静默卡住。前台阻塞的运行才会带着结果把控制权交回来。
如果某次运行确实需要超过这个上限:不要丢后台,而是把规模压下来(更少 agent、 更少步数),或者提前告知用户、由他决定。
一定要有事件服务或 user pool MCP 吗?¶
不需要。两者都是可选能力,且都会优雅降级:事件客户端会退到本地缓存、再退到 普通网络检索;persona 池不可用时退到「先锚定再合成」或用户自备的 persona 文件。 你损失的是便利和一部分锚定强度,而不是跑研究的能力。见 外部能力。
本地跑和用托管服务有什么区别?¶
框架一样、产物一样。本地跑:LLM key 和可选服务端点都由你自己提供,机器也归你。 托管服务:LLM provider、事件服务、persona 池、以及一份配好中文字体的 matplotlib 都是现成接好的,运行与配额替你计量,dashboard 是服务出来的而不用自己起。见 托管服务。
结果与可复现性¶
运行可以复现吗?¶
- 干跑(规则式或确定性客户端):可以,精确复现——端到端由种子决定。
- 真实 LLM 运行:不行——非零温度采样每次不同。但每次已记录的运行都 永久保存在它的 DuckDB 存储里,而且 热启动迭代会精确回放 已存储的行为,不重新询问 LLM。
我的结果在哪里?里面有什么?¶
studies/<id>/trajectory/study.duckdb —— 表 panel(每个 agent 每步
一行)、metrics(每步一行)、events(触发的干预),若研究用了消息
总线还有 messages。旁边有 Parquet 导出。reports/report.md 是渲染版。
我改了产物重跑了一次,旧结果没了。为什么?¶
为新一次运行打开存储会替换它——这正是那条规则存在的原因:修改既有
研究要走 /sv-iterate,它的版本门会先把现行目录快照到
versions/vN/。凡在版本快照之下的内容永不删除。
图里的中文为什么变成方块了?¶
matplotlib 默认不带 CJK 字体,所以每个汉字都渲染成豆腐块(□□□)。
装一个中文字体并让 matplotlib 指过去:
import matplotlib
matplotlib.rcParams["font.sans-serif"] = ["Noto Sans CJK SC"]
matplotlib.rcParams["axes.unicode_minus"] = False # 负号也别变方块
刚装的字体如果 matplotlib 还看不见,清一下它的缓存
(rm -rf ~/.cache/matplotlib)。托管服务已预装并配好中文字体,图里的中文
开箱即正常。
可以直接查 DuckDB 存储吗?¶
可以——存储才是结果本身,报告只是它的一种渲染。study.duckdb 就是一个普通的
DuckDB 文件,用 CLI、Python API、或任何会说 DuckDB 的工具都能打开。表结构:
| 表 | 列 |
|---|---|
panel |
agent_id、step、state(JSON)、action_kind、action_payload(JSON) |
metrics |
step 加上研究发出的每个指标各一列 |
events |
step、note |
messages(仅当用了消息总线) |
author_id、step、round、channel、content、audience |
state 与 action_payload 是 JSON,里面的键是各研究自定的——照抄下面的
例子前,先去自己的 model.py 里确认字段名:
-- 在某个数值型 state 字段上,看谁在两步之间变化最大
WITH s AS (
SELECT agent_id, step,
CAST(state ->> '$.opinion' AS DOUBLE) AS opinion
FROM panel WHERE step IN (0, 12)
)
SELECT a.agent_id,
a.opinion AS opinion_t0,
b.opinion AS opinion_t12,
b.opinion - a.opinion AS delta
FROM s a JOIN s b USING (agent_id)
WHERE a.step = 0 AND b.step = 12
ORDER BY abs(delta) DESC
LIMIT 20;
-- 某一步里每个 agent 给出的理由
SELECT agent_id, action_kind, action_payload ->> '$.reason' AS reason
FROM panel WHERE step = 5 AND reason IS NOT NULL;
-- 行为构成随时间怎么变
SELECT step, action_kind, count(*) AS n
FROM panel GROUP BY step, action_kind ORDER BY step, n DESC;
-- 把指标和同一步触发的干预对齐起来看
SELECT m.*, e.note
FROM metrics m LEFT JOIN events e USING (step)
ORDER BY m.step;
旁边还有 Parquet 导出(panel.parquet、metrics.parquet)供 pandas / R 用。
概念¶
别的框架也能跑很多步,「纵向」特殊在哪?¶
人群是固定的、带持久 id 的,且每个 agent 每步记录一行面板数据—— 所以你能追踪个体轨迹,而不只是聚合曲线。横截面框架通常每次实验重新 抽样人群;这里同一批 agent 一直存在,这才是输出成为真正面板数据的原因。
LLM 到底在哪个位置?¶
只在一个接口里:DecisionModel.decide_batch。环境、人群、存储、报告
都不含 LLM。见 LLM 接入与干跑。
是什么防止模型凭空编数字?¶
grounding 契约:承重数值要引用 grounding/grounding.json 里的事实或
声明的假设,而报告会把这份台账渲染在结果旁边。它是供审阅的溯源,
不是运行时校验器——见
真实世界锚定与溯源。
扩展¶
我有自己的模拟器,能接进来吗?¶
能——那就是 Path C:把它包装到四个接口 后面(源码零改动),在固定种子上证明一致性,它就成为一个可路由、可 fork 的研究。
怎么接入我自己的数据(personas、环境数据源)?¶
人群:把 provider_ref 指向通用的 file.personas provider(带
agent_id 列的 CSV/Parquet),或实现你自己的 PopulationProvider。
环境数据源:声明为层的 source 并在构建时物化。外部服务走
能力注册表。