Concepts
Database

Overview

Sotopia uses Redis (opens in a new tab) for two uses cases:

  1. To store data including agent profiles, environment profiles, relationship profiles, and all of the interaction logs. This is useful for reproducibility and analysis.
  2. To serve as a message broker between the Redis agent and frontend. This is useful for human user interface and other agents.

We mainly use Redis-OM (opens in a new tab) together with Pydantic (opens in a new tab) to interact with the Redis database, but also sometimes directly use the Redis-py (opens in a new tab) library for performance-critical tasks. Despite that Redis is 3rd party software, which is not included in the Sotopia package, we do realize that it is useful to include a short introduction to Redis in this documentation.

A 1-minute introduction to Redis

ℹ️

Skip this section if you are already familiar with Redis.

Redis is a key-value database, meaning that you can use it like a global Python dict. For example,

import redis
 
r = redis.Redis()
r.set("key", "value")
print(r.get("key")) # b'value'

Redis-OM, OM standing for Object Mapping, is a library that helps you easily use more complex data structures. For example, you can use it to store a person's profile like this:

from redis_om import JsonModel, Field
 
class Person(JsonModel):
    name: str = Field(index=True)
    age: int = Field(index=True, default_factory=lambda: 0)
 
# create a person profile
person = Person(name="Alice", age=30)
 
# save the person to the database
person.save()

You can then query the database like this:

# find all of the people in the database
for person in Person.find().all():
    print(person.name, person.age)
# find all of the people with the name "Alice"
for person in Person.find(name="Alice").all():
    print(person.name, person.age)

where JsonModel is a subclass of pydantic.BaseModel. If you are familiar with Pydantic, you should feel right at home with Redis-OM. Even if you are not, this is a very natural way to define data structures in Python.

Built-in data strcutures in Sotopia

In Sotopia, we have several built-in data structures that are used to store profiles, episodes, and other data, which you can used to interact with the Redis database. These include:

The data structures for message passing are:

Serialization and Deserialization

It is very easy to serialize any database structures to JSON or CSV.

Serialize simulated episodes

from sotopia.database import episodes_to_jsonl, EpisodeLog
 
episodes: list[EpisodeLog] = EpisodeLog.all()
 
episodes_to_jsonl(episodes, "episodes.jsonl")

Serialize env/agent profiles

from sotopia.database import environmentprofiles_to_jsonl, agentprofiles_to_jsonl
 
agent_profiles: list[AgentProfile] = AgentProfile.all()
 
environment_profiles: list[EnvironmentProfile] = EnvironmentProfile.all()
 
agentprofiles_to_jsonl(agent_profiles, "agent_profiles.jsonl")
environmentprofiles_to_jsonl(environment_profiles, "environment_profiles.jsonl")

Other utilities

Function NameDescriptionArgumentsReturn Type
agentprofiles_to_csvSaves agent profiles to a CSV file.agent_profiles: list[AgentProfile], csv_file_path: str = "agent_profiles.csv"None
agentprofiles_to_jsonlSaves agent profiles to a JSONL file.agent_profiles: list[AgentProfile], jsonl_file_path: str = "agent_profiles.jsonl"None
envagnetcombostorage_to_csvSaves environment-agent combo storages to a CSV file.env_agent_combo_storages: list[EnvAgentComboStorage], csv_file_path: str = "env_agent_combo_storages.csv"None
envagnetcombostorage_to_jsonlSaves environment-agent combo storages to a JSONL file.env_agent_combo_storages: list[EnvAgentComboStorage], jsonl_file_path: str = "env_agent_combo_storages.jsonl"None
environmentprofiles_to_csvSaves environment profiles to a CSV file.environment_profiles: list[EnvironmentProfile], csv_file_path: str = "environment_profiles.csv"None
environmentprofiles_to_jsonlSaves environment profiles to a JSONL file.environment_profiles: list[EnvironmentProfile], jsonl_file_path: str = "environment_profiles.jsonl"None
episodes_to_csvSaves episodes to a CSV file.episodes: list[EpisodeLog], csv_file_path: str = "episodes.csv"None
episodes_to_jsonlSaves episodes to a JSONL file.episodes: list[EpisodeLog], jsonl_file_path: str = "episodes.jsonl"None
get_rewards_from_episodeRetrieves rewards from an episode.episode: EpisodeLoglist[tuple[float, dict[str, float]]]
jsonl_to_agentprofilesLoads agent profiles from a JSONL file.jsonl_file_path: strlist[AgentProfile]
jsonl_to_envagnetcombostorageLoads environment-agent combo storages from a JSONL file.jsonl_file_path: strlist[EnvAgentComboStorage]
jsonl_to_environmentprofilesLoads environment profiles from a JSONL file.jsonl_file_path: strlist[EnvironmentProfile]
jsonl_to_episodesLoads episodes from a JSONL file.jsonl_file_path: strlist[EpisodeLog]
jsonl_to_relationshipprofilesLoads relationship profiles from a JSONL file.jsonl_file_path: strlist[RelationshipProfile]
relationshipprofiles_to_csvSaves relationship profiles to a CSV file.relationship_profiles: list[RelationshipProfile], csv_file_path: str = "relationship_profiles.csv"None
relationshipprofiles_to_jsonlSaves relationship profiles to a JSONL file.relationship_profiles: list[RelationshipProfile], jsonl_file_path: str = "relationship_profiles.jsonl"None