# 问题记录:硬编码与"千人社会"模拟的业务一致性 > 记录日期:2026-09-27 > 记录人:项目相关方 > 状态:仅记录问题,不附解决方案 --- ## 背景 我想搞清楚一个问题:在当前的项目实现里,如果用户设置 1000 个市民,整个模拟引擎到底是怎么跑的?我担心两个事情: 1. 供应商的 TPS 顶不顶得住; 2. 这个所谓的"千人社会模拟",在业务层面到底是不是真的有意义。 下面是我一边看代码一边问出来的问题。 --- ## 一、先确认运行机制 我看到的是这样一条路径: - 模拟每一天被分成三轮(morning / afternoon / evening),全年 365 天,共 1095 轮。 - 每一轮里,并不是所有人都去问 LLM,而是有一个 `_select_active_agents` 的机制去抽样。 - 抽样的基准是 `active_agents_per_round_min = 3`、`active_agents_per_round_max = 10`,带情绪、事件、派系、沉睡等权重加成。 - 然后这一批被抽中的人,去并发地打 LLM,做决策。 - 之后再走反应、研究、叙事等若干个 LLM 调用。 看到这里的时候,我的第一个问题浮出来了。 --- ## 二、问题 ### 问题 1:抽样率随人口规模塌缩 1000 人的社区,每一轮只有 3–10 个人被问,这是什么比例? - 100 人社区:3%–10%(看起来是合理的"采样") - 1000 人社区:0.3%–1% - 10000 人社区:0.03% 我卖的产品叫"千人社会模拟"。可是跑出来,每一轮只有不到 10 个人在表态,那剩下 990 多个人在干什么?我看到的"社会"是从 3–10 个人里推出来的。 ### 问题 2:业务参数和成本参数混在同一个常量里 那 3 和 10 到底是产品决策还是工程决策? - 如果是产品决策 —— 它凭什么不随人口规模变? - 如果是工程决策 —— 它为什么硬编码在 `TimeConfig` 这样一个看起来是"世界设定"的数据类里? 我觉得这两个里总有一个不对劲。 ### 问题 3:上限被钳到 60%,但实际上根本用不到 我注意到有这么一行: ```python max_active = max(base_count, int(len(agents) * 0.6)) target = min(base_count + (3 if event_occurred else 0), max_active) ``` 看起来是给 1000 人准备的"60% 上限",但由于 `base_count` 只有 3–10,那个 0.6 的上限永远摸不到。也就是说这个上限是一个"为更大规模准备的逻辑",但在没有人为改 3–10 之前,它永远是死代码。 那它在暗示什么?是不是原来设想里,这个 3–10 本来就应该随规模动起来? ### 问题 4:3–10 个人的表态,能代表什么? 我再往深想一层。民意、情绪、派系分布、冲突演化 —— 整个产品叙事都建立在"涌现"两个字上。 那 3–10 个人做出的决策,能涌现出什么?尤其是当 active 抽样里还包含了"沉默偏向"(默认 w=0.3,平静的人权重天然偏低),抽样结果会进一步偏向情绪激动的小群体。 所以这到底是"千人社会的涌现",还是"6 个最激动的人的噪声"? ### 问题 5:业务承诺和实际行为之间,是不是有错配? 用户为"千人社会模拟"付费。系统在生成阶段认真生成了 1000 个市民的 backstory、性格、记忆、关系。一轮跑下来,认真读了 prompt 的只有 6 个人。 这种错配在业务上叫什么?我不太确定。但我直觉它不只是"性能问题"。 ### 问题 6:除了 active 数,还有哪些是硬编码的"看似业务参数"? 我在 `world.py` 里看到了: ```python total_days: int = 365 rounds_per_day: int = 3 active_agents_per_round_min: int = 3 active_agents_per_round_max: int = 10 ``` 这四个数字看起来都是默认值。但 `total_days` 和 `rounds_per_day` 是用户故事的核心节奏参数 —— 用户应该在产品层能感知到它们。 而 `active_agents_per_round_min/max` 这个东西,用户感知不到,因为它从来没出现在 UI 里。但它却对"千人模拟"的语义有决定性影响。 这到底是一个用户应该配置的旋钮,还是一个工程内部值?我越看越觉得,它**应该**是前者。 --- ## 三、我没有结论,只有问题 到目前为止我没找到一份文档说明: 1. 为什么 `active_agents_per_round_min/max` 默认是 3–10; 2. 这个区间在不同人口规模下是怎么被论证过的; 3. 它是被当作"LLM 成本阀门"还是"模拟质量参数"设计的; 4. 是否有人为"千人社会"做过代表性 / 抽样率的论证。 如果不回答这四个问题,"千人社会模拟"四个字,目前在产品上只是启动时填了一个数字而已。 --- ## 四、补充记录:跟 TPS 那条线是分开的两件事 我一开始问的是 TPS(供应商限流),得到的答案是: - semaphore 默认并发 10; - 每轮实际只打 3–10 次决策 LLM,加若干反应 / 研究 / 叙事; - 1000 人下瞬时并发不会超过 semaphore 上限。 这条线结论清楚:当前实现下,**TPS 没问题**。 但顺着这个问题我又往下看了一眼抽样代码,发现了上面那些"业务没意义"的疑问。所以这两件事其实是分开的两件事: - TPS:**没风险**(这是工程结论) - 千人模拟是否成立:**存疑**(这是产品结论) 我把它们分开记在这里,免得有人把"TPS 没问题"误读成"千人模拟没问题"。 --- ## 五、相关代码位置 - 抽样逻辑:`backend/app/services/engine.py` `_select_active_agents`(约 765–833 行) - 配置常量:`backend/app/models/world.py` `TimeConfig`(约 14–17 行) - 决策并发:`backend/app/services/llm.py` `LLMClient.generate_batch` - 轮循环入口:`backend/app/services/engine.py` `run` 主循环(`while round_num < total_rounds`)