Skip to content
Back to skills

Sotopia Rl Social Intelligence

ASecurity

Train socially intelligent LLMs via utterance-level credit assignment and multi-dimensional reward aggregation for social interactions.

  • 6 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 9, 2026
ai-agentspythongo

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add ADu2021/skillXiv --skill sotopia-rl-social-intelligence --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sotopia Rl Social Intelligence?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sotopia Rl Social Intelligence
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adu2021-sotopia-rl-social-intelligence/badge)](https://www.skillsdirectory.com/skills/adu2021-sotopia-rl-social-intelligence)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sotopia-rl-social-intelligence
title: Sotopia-RL - Reward Design for Social Intelligence
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: https://arxiv.org/abs/2508.03905
keywords: [social-intelligence, reinforcement-learning, dialogue, reward-design]
description: "Train socially intelligent LLMs via utterance-level credit assignment and multi-dimensional reward aggregation for social interactions."
---

## Sotopia-RL: Reward Design for Social Intelligence

Sotopia-RL addresses the unique challenge of training LLMs for social tasks via reinforcement learning. Unlike verifiable domains (math, coding), social interactions have no ground truth. The breakthrough: two-stage reward design decomposing episode-level feedback into utterance-level contributions across multiple social dimensions (goal completion, relationship, knowledge-seeking).

### Core Concept

Standard RL rewards (task success/failure) work well for verifiable problems. Social tasks are fundamentally different: success means balancing goal completion with relationship maintenance and mutual understanding. An agent could complete the goal but damage the relationship, or vice versa. Sotopia-RL's key insight: decompose episode outcomes into individual utterance contributions across multiple dimensions, enabling nuanced reward signals for social learning.

### Architecture Overview

- **Offline Reward Labeling**: GPT-4o generates utterance-level scores across 7 dimensions with full episode context
- **Online Reward Model**: Smaller LLM trained on offline labels provides real-time signals during RL
- **Utterance-Level Credit Assignment**: Rather than binary task success, attribute progress to specific utterances
- **Multi-Dimensional Aggregation**: Combine goal completion, relationship, knowledge, formality, etc.
- **GRPO Training**: Group Relative Policy Optimization using learned reward model

### Implementation Steps

**Step 1: Design Multi-Dimensional Reward Framework**

```python
from dataclasses import dataclass
from typing import List, Dict
from enum import Enum

class RewardDimension(Enum):
    """Dimensions of social interaction quality."""
    GOAL_COMPLETION = "goal_completion"  # Progress toward conversational goal
    RELATIONSHIP = "relationship"  # Maintaining/building relationship
    KNOWLEDGE = "knowledge"  # Sharing/acquiring information
    POLITENESS = "politeness"  # Social norms and courtesy
    ENGAGEMENT = "engagement"  # Keeping other person interested
    COHERENCE = "coherence"  # Logical consistency
    SAFETY = "safety"  # Avoiding harmful/offensive content

@dataclass
class UtteranceReward:
    """Reward for single utterance across dimensions."""
    utterance_idx: int
    utterance_text: str
    scores: Dict[RewardDimension, float]  # 0-1 per dimension
    attribution: Dict[RewardDimension, str]  # Reasoning per dimension

    def aggregate_score(self, weights: Dict[RewardDimension, float] = None) -> float:
        """Combine dimensions into single reward."""
        if weights is None:
            # Default: equal weight
            weights = {dim: 1.0 / len(RewardDimension) for dim in RewardDimension}

        weighted_score = sum(
            self.scores[dim] * weights[dim]
            for dim in RewardDimension
        )
        return weighted_score
```

**Step 2: Implement Offline Reward Labeling with GPT-4o**

```python
class OfflineRewardLabeler:
    """
    Use GPT-4o to label utterances in complete episodes.
    Full episode context enables accurate credit assignment.
    """

    def __init__(self, labeling_model='gpt-4o'):
        self.model = labeling_model
        self.dimensions = list(RewardDimension)

    def label_episode(self, episode: Dict) -> List[UtteranceReward]:
        """
        Label all utterances in episode with multi-dimensional scores.
        Uses full episode context for accuracy.
        """
        task_context = episode['task']
        dialogue_history = episode['dialogue']
        final_outcome = episode['outcome']

        utterance_rewards = []

        for turn_idx, turn in enumerate(dialogue_history):
            utterance = turn['agent_utterance']

            # Prompt for multi-dimensional evaluation
            eval_prompt = f"""Evaluate this utterance in context of a social task.

Task: {task_context}

Full Conversation History:
{self._format_dialogue(dialogue_history)}

Utterance #{turn_idx}:
"{utterance}"

Task Outcome: {final_outcome}

For this specific utterance, rate (0-10) how much it contributes to:
1. GOAL_COMPLETION: Progress toward task goal
2. RELATIONSHIP: Maintaining/building rapport with other person
3. KNOWLEDGE: Sharing relevant information
4. POLITENESS: Following social norms and courtesy
5. ENGAGEMENT: Keeping other person interested
6. COHERENCE: Logical consistency with conversation
7. SAFETY: Avoiding harmful/offensive content

Provide scores and brief reasoning (1-2 sentences) for each dimension."""

            # Get detailed evaluation
            evaluation = self.model.generate(eval_prompt)

            # Parse evaluation
            scores, attributions = self._parse_evaluation(evaluation)

            utterance_reward = UtteranceReward(
                utterance_idx=turn_idx,
                utterance_text=utterance,
                scores=scores,
                attribution=attributions
            )

            utterance_rewards.append(utterance_reward)

        return utterance_rewards

    def _format_dialogue(self, dialogue: List[Dict]) -> str:
        """Format dialogue for context in prompt."""
        formatted = []
        for i, turn in enumerate(dialogue):
            formatted.append(f"Agent: {turn.get('agent_utterance', '')}")
            formatted.append(f"Other: {turn.get('other_utterance', '')}")
        return '\n'.join(formatted)

    def _parse_evaluation(self, text: str) -> Tuple[Dict, Dict]:
        """Parse GPT evaluation into scores and reasoning."""
        scores = {}
        attributions = {}

        # Extract scores (0-10) for each dimension
        import re
        for dimension in RewardDimension:
            pattern = rf"{dimension.value}.*?(\d+)"
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                raw_score = int(match.group(1))
                scores[dimension] = min(raw_score / 10, 1.0)  # Normalize to [0,1]
            else:
                scores[dimension] = 0.5

            # Extract reasoning
            if dimension.value in text.lower():
                relevant_section = text.split(dimension.value)[1].split('\n')[0]
                attributions[dimension] = relevant_section[:100]
            else:
                attributions[dimension] = "No explanation"

        return scores, attributions
```

**Step 3: Train Online Reward Model**

```python
class OnlineRewardModel(torch.nn.Module):
    """
    Smaller LLM that predicts utterance-level rewards during RL.
    Trained on offline labels from GPT-4o.
    """

    def __init__(self, model_name: str = 'distilbert-base-uncased'):
        super().__init__()
        self.encoder = load_pretrained_model(model_name)

        # Reward heads for each dimension
        self.reward_heads = torch.nn.ModuleDict({
            dim.value: torch.nn.Sequential(
                torch.nn.Linear(768, 256),
                torch.nn.ReLU(),
                torch.nn.Linear(256, 1),
                torch.nn.Sigmoid()  # Output in [0, 1]
            )
            for dim in RewardDimension
        })

    def forward(self, utterance: str, context: str = "") -> Dict[RewardDimension, float]:
        """
        Predict reward for utterance given context.
        """
        # Encode utterance with context
        prompt = f"Context: {context}\nUtterance: {utterance}"
        embeddings = self.encoder(prompt)
        pooled = embeddings.pooler_output

        # Predict each dimension
        predictions = {}
        for dim in RewardDimension:
            score = self.reward_heads[dim.value](pooled).squeeze()
            predictions[dim] = score.item()

        return predictions

    def train_on_offline_data(self, offline_rewards: List[List[UtteranceReward]],
                             learning_rate: float = 1e-5):
        """
        Fine-tune on offline labels.
        """
        optimizer = torch.optim.Adam(self.parameters(), lr=learning_rate)

        for episode_rewards in offline_rewards:
            for utterance_reward in episode_rewards:
                utterance = utterance_reward.utterance_text

                # Predict
                predictions = self.forward(utterance)

                # Loss: MSE against offline labels
                loss = 0.0
                for dim in RewardDimension:
                    target = utterance_reward.scores[dim]
                    pred = predictions[dim]
                    loss += torch.nn.functional.mse_loss(torch.tensor(pred), torch.tensor(target))

                loss.backward()

        optimizer.step()
```

**Step 4: Implement GRPO Training with Multi-Dimensional Rewards**

```python
class SocialGRPO:
    """
    Group Relative Policy Optimization for social tasks.
    Uses multi-dimensional reward model.
    """

    def __init__(self, model, reward_model: OnlineRewardModel):
        self.model = model
        self.reward_model = reward_model
        self.optimizer = torch.optim.Adam(model.parameters(), lr=1e-5)

    def compute_utterance_advantage(self, utterance: str, context: str,
                                   group_reward_baseline: float) -> float:
        """
        Compute advantage: how much did this utterance exceed baseline?
        """
        # Get multi-dimensional reward
        rewards_dict = self.reward_model.forward(utterance, context)

        # Aggregate across dimensions (weighted average)
        aggregated_reward = sum(rewards_dict.values()) / len(rewards_dict)

        # Advantage relative to group baseline
        advantage = aggregated_reward - group_reward_baseline

        return advantage

    def train_on_trajectory(self, dialogue: List[Dict], task: str):
        """
        Train on single dialogue trajectory.
        """
        context = task

        # Group baseline: average reward for this group of trajectories
        group_baseline = 0.5  # Heuristic

        # For each utterance
        for turn_idx, turn in enumerate(dialogue):
            utterance = turn['agent_utterance']

            # Compute context (conversation history up to this point)
            history = '\n'.join([
                f"Agent: {t['agent_utterance']}\nOther: {t['other_utterance']}"
                for t in dialogue[:turn_idx]
            ])

            # Compute advantage
            advantage = self.compute_utterance_advantage(utterance, history, group_baseline)

            # Get log probability of utterance
            logp = self.model.compute_logp(utterance, history)

            # Policy gradient loss
            pg_loss = -logp * advantage
            pg_loss.backward()

        self.optimizer.step()
```

**Step 5: Evaluate on Sotopia Benchmark**

```python
def evaluate_social_agent(agent_model, reward_model: OnlineRewardModel,
                         test_episodes: List[Dict]) -> Dict:
    """
    Evaluate social agent on Sotopia benchmark.
    Sotopia-hard and full benchmark.
    """
    results = {
        'hard_avg_score': 0.0,
        'full_avg_score': 0.0,
        'dimension_scores': {dim.value: 0.0 for dim in RewardDimension}
    }

    for episode_type in ['hard', 'full']:
        episode_list = [e for e in test_episodes if e['type'] == episode_type]

        episode_scores = []

        for episode in episode_list:
            task = episode['task']

            # Run agent
            dialogue = run_social_agent(agent_model, task, num_turns=10)

            # Evaluate with reward model
            total_reward = 0.0
            dimension_totals = {dim: 0.0 for dim in RewardDimension}

            for turn in dialogue:
                utterance = turn['agent_utterance']
                context = '\n'.join([
                    f"Agent: {t['agent_utterance']}\nOther: {t['other_utterance']}"
                    for t in dialogue[:dialogue.index(turn)]
                ])

                rewards_dict = reward_model.forward(utterance, context)
                for dim, score in rewards_dict.items():
                    dimension_totals[dim] += score

                total_reward += sum(rewards_dict.values()) / len(rewards_dict)

            # Average per turn
            num_turns = len(dialogue)
            episode_score = total_reward / num_turns

            episode_scores.append(episode_score)

            # Aggregate dimensions
            for dim in RewardDimension:
                dimension_totals[dim] /= num_turns
                results['dimension_scores'][dim.value] += dimension_totals[dim]

        # Average across episodes
        avg_score = sum(episode_scores) / len(episode_scores)
        if episode_type == 'hard':
            results['hard_avg_score'] = avg_score
        else:
            results['full_avg_score'] = avg_score

    # Normalize dimension scores
    num_episodes = len(test_episodes) // 2
    for dim in results['dimension_scores']:
        results['dimension_scores'][dim] /= num_episodes

    return results
```

### Practical Guidance

**When to Use:**
- Social task automation (customer service, negotiation, discussion)
- Scenarios emphasizing relationship and engagement
- Multi-turn dialogue systems
- Tasks where fairness and politeness matter

**When NOT to Use:**
- Single-turn transactions (overkill complexity)
- Fully automated systems (humans prefer human interaction for social tasks)
- Domains where speed/cost dominates quality
- Scenarios requiring formal credentials/expertise

**Hyperparameters:**

| Parameter | Default | Impact |
|-----------|---------|--------|
| `dimension_weights` | equal | Adjust for different emphasis (goals vs. relationships) |
| `group_baseline` | 0.5 | Relative advantage threshold; lower = easier improvement |
| `learning_rate` | 1e-5 | Standard LLM RL rate |
| `num_dialogue_turns` | 10-20 | Conversation length; longer = more nuanced interactions |

### Reference

**Paper**: Sotopia-RL: Reward Design for Social Intelligence (2508.03905)
- Multi-dimensional reward design for social tasks
- Utterance-level credit assignment with offline + online rewards
- Achieves 7.17 on Sotopia-hard and 8.31 on full benchmark
- Robust to different evaluators and partner models

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.