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:
126
engine-python/app/social_influence.py
Normal file
126
engine-python/app/social_influence.py
Normal 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))
|
||||
Reference in New Issue
Block a user