feat: 添加观点传播系统

- 新增 Stance 数据结构 (optimism/fear)
- 情绪影响 stance (happy→乐观, anxious→恐惧)
- 实现 apply_social_influence 社交影响函数
- 确定性随机选择接触对象
- 单次变化限制 ±0.1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
empty
2025-12-30 10:50:46 +08:00
parent af279bedd9
commit 554d37fd4c
6 changed files with 245 additions and 4 deletions

View File

@@ -0,0 +1,126 @@
"""社交影响系统 - 角色间观点传播"""
from typing import Dict, List, Tuple
from .models import WorldState, AgentState, Stance
# 单次 stance 变化上限
MAX_STANCE_CHANGE = 0.1
# 影响强度系数
INFLUENCE_STRENGTH = 0.05
def get_contact_targets(
agent_id: str,
all_agent_ids: List[str],
tick: int
) -> List[str]:
"""
确定性地选择 1-2 个接触对象
基于 agent_id 和 tick 确保可复现
"""
# 排除自己
others = [aid for aid in all_agent_ids if aid != agent_id]
if not others:
return []
# 基于 hash 确定性选择
seed = hash(agent_id) + tick
# 选择 1 或 2 个目标
num_targets = 1 + (seed % 2)
num_targets = min(num_targets, len(others))
targets = []
for i in range(num_targets):
idx = (seed + i * 7) % len(others)
target = others[idx]
if target not in targets:
targets.append(target)
return targets
def calculate_influence(
agent_stance: Stance,
target_stance: Stance
) -> Tuple[float, float]:
"""
计算社交影响产生的 stance 变化
逻辑:
- 相近立场 → 强化原有立场
- 相反立场 → 产生反向影响
返回: (optimism_delta, fear_delta)
"""
# 计算差异
opt_diff = target_stance.optimism - agent_stance.optimism
fear_diff = target_stance.fear - agent_stance.fear
# 相近度判断(差异小于 0.3 视为相近)
opt_similar = abs(opt_diff) < 0.3
fear_similar = abs(fear_diff) < 0.3
opt_delta = 0.0
fear_delta = 0.0
if opt_similar:
# 相近 → 强化原有立场(向中间靠拢后再强化)
opt_delta = opt_diff * INFLUENCE_STRENGTH
else:
# 相反 → 反向影响(抵抗)
opt_delta = -opt_diff * INFLUENCE_STRENGTH * 0.5
if fear_similar:
fear_delta = fear_diff * INFLUENCE_STRENGTH
else:
fear_delta = -fear_diff * INFLUENCE_STRENGTH * 0.5
# 限制单次变化幅度
opt_delta = max(-MAX_STANCE_CHANGE, min(MAX_STANCE_CHANGE, opt_delta))
fear_delta = max(-MAX_STANCE_CHANGE, min(MAX_STANCE_CHANGE, fear_delta))
return opt_delta, fear_delta
def apply_social_influence(state: WorldState) -> None:
"""
应用社交影响:每个 agent 与 1-2 个其他 agent 接触
所有变化写入 world_state
"""
agent_ids = list(state.agents.keys())
if len(agent_ids) < 2:
return
# 收集所有变化(先计算,后应用,避免顺序影响)
stance_changes: Dict[str, Tuple[float, float]] = {}
for agent_id in agent_ids:
agent = state.agents[agent_id]
targets = get_contact_targets(agent_id, agent_ids, state.tick)
total_opt_delta = 0.0
total_fear_delta = 0.0
for target_id in targets:
target = state.agents[target_id]
opt_delta, fear_delta = calculate_influence(
agent.stance, target.stance
)
total_opt_delta += opt_delta
total_fear_delta += fear_delta
# 限制总变化
total_opt_delta = max(-MAX_STANCE_CHANGE, min(MAX_STANCE_CHANGE, total_opt_delta))
total_fear_delta = max(-MAX_STANCE_CHANGE, min(MAX_STANCE_CHANGE, total_fear_delta))
stance_changes[agent_id] = (total_opt_delta, total_fear_delta)
# 应用所有变化
for agent_id, (opt_delta, fear_delta) in stance_changes.items():
agent = state.agents[agent_id]
new_opt = agent.stance.optimism + opt_delta
new_fear = agent.stance.fear + fear_delta
agent.stance.optimism = max(0.0, min(1.0, new_opt))
agent.stance.fear = max(0.0, min(1.0, new_fear))