polis / README.md
AK
docs+build: HF Spaces Dockerfile, recruiter README, deploy guide, MIT license
89d6753
|
Raw
History Blame Contribute Delete
8.07 kB
metadata
title: Polis  A Living Society of AI Agents
emoji: 🏛️
colorFrom: indigo
colorTo: purple
sdk: docker
app_port: 7860
pinned: true
license: mit

🏛️ Polis — A Living Society of AI Agents

20+ generative agents that perceive, remember, reflect, form relationships, and build an emergent society — visualized in a scroll-driven 3D world you can reach into and change.

Live demo: Code:

Polis is a from-scratch implementation of the Generative Agents architecture (Park et al., 2023, "Interactive Simulacra of Human Behavior") wrapped in a cinematic Three.js interface. Each agent runs its own memory-retrieval and reflection loop on top of the OpenAI API. Nothing about the story is scripted — relationships, rumors, and routines emerge from thousands of small LLM decisions. Drop an event into the town ("a stranger arrives with gold") and watch the society metabolize it.


Why this project exists

Most portfolio projects are a thin wrapper around a single API call. Polis is a system: retrieval, memory scoring, reflection, an agent scheduler, a budget guard, an offline-deterministic fallback, and a real-time 3D renderer — all wired together and deployed. It's meant to show the things frontier-lab and product teams actually screen for:

  • Agentic architecture — a perceive → retrieve → plan → act → reflect loop, not a chatbot.
  • Retrieval that isn't naive RAG — memories ranked by recency × importance × relevance.
  • Systems discipline — hard cost ceiling, caching, graceful degradation with zero key.
  • Product & craft — a 3D scrollytelling front-end that a non-technical person enjoys.
  • Ship-it — containerized, one-command deploy to Hugging Face Spaces.

What you can do in the demo

  1. Scroll the landing page — the camera flies through the agent cognitive loop rendered in 3D (perception radius, orbiting memory stream, the 5-stage pipeline, the reflection pulse).
  2. Launch the live town — agents move between locations, talk, and think in real time; speech and reflections pop as bubbles.
  3. Click any agent — the inspector opens its mind: personality, current goal, relationship graph (with signed sentiment bars), and its most recent memories.
  4. Inject a world event — type "a storm floods the harbor" and watch it propagate into every agent's memory and change what they do next.

Runs immediately in mock mode (deterministic, $0). Add an OPENAI_API_KEY secret to switch to the live LLM engine, bounded by a hard budget.


How it works

The memory stream

Every observation, dialogue line, plan, and reflection an agent has is stored as a timestamped Memory with an importance score (the model rates each memory 1–10) and an embedding vector. When an agent needs to act, it doesn't stuff its whole history into the prompt — it retrieves the top-k memories by the composite score from the paper:

score(m) = α_recency · decay^(now − last_access)
         + α_importance · (importance / 10)
         + α_relevance · cosine(query_embedding, m.embedding)

The reflection loop

Once accumulated importance crosses a threshold, the agent reflects: it synthesizes its recent memories into a higher-level, first-person insight ("I value the people who show up for me"), which is written back into the memory stream and biases future retrieval. This feedback loop is what makes behavior compound into something that reads like a personality.

The tick loop (world.py)

for each tick:
    broadcast any injected world events → shared observations
    find agents standing close enough to talk
    for each agent:
        perceive location + neighbors
        retrieve relevant memories
        if a partner is near: generate a line of dialogue, update the bond
        else: choose an action + a destination, move toward it
        record what happened
        maybe reflect
    emit a compact event list → the 3D front-end replays it

Safety & cost rails (llm.py)

  • Budget guard — a thread-safe ledger prices every call; once POLIS_BUDGET_USD is hit, the engine refuses to spend more (returns HTTP 402) instead of draining your account.
  • Mock backend — with no key, agents think via a deterministic, hash-seeded fallback and embeddings are computed locally, so the Space boots and demos at $0.
  • Embedding cache — identical strings are embedded once.

Architecture

┌──────────────────────────── Browser ────────────────────────────┐
│  Three.js (r128) scene · scroll-driven cinematic camera          │
│  live playback engine · agent inspector · event injector         │
└───────────────▲─────────────────────────────────┬───────────────┘
                │ /api/demo, /api/step, /api/event │ (JSON)
┌───────────────┴─────────────────────────────────▼───────────────┐
│  FastAPI (backend/main.py)                                       │
│    World  ── tick loop, locations, interactions (world.py)       │
│      └─ Agent ── memory stream, retrieval, reflection (agents.py)│
│           └─ LLM ── OpenAI + budget guard + mock (llm.py)        │
└──────────────────────────────────────────────────────────────────┘
Layer Tech
Front-end Three.js (WebGL), vanilla JS, CSS scroll-driven storytelling
Back-end FastAPI + Uvicorn
Intelligence OpenAI gpt-4o-mini (chat) + text-embedding-3-small (retrieval)
Deploy Docker → Hugging Face Spaces

Run it locally

pip install -r requirements.txt

# mock mode ($0, deterministic) — just run:
python -m backend.main
# → open http://localhost:7860

# live mode (real agents):
export OPENAI_API_KEY=sk-...
export POLIS_BUDGET_USD=1.00        # hard ceiling
python -m scripts.generate_demo --ticks 60   # optional: pre-record a richer demo
python -m backend.main

API

Method Route Purpose
GET /api/health liveness + whether a real key is wired + budget
GET /api/state current world snapshot
POST /api/step advance N ticks, returns snapshots
POST /api/event inject a world event
GET /api/demo pre-recorded run (used by the Space at $0)

Project layout

polis/
├── backend/
│   ├── llm.py       # OpenAI wrapper: budget guard, mock backend, embed cache
│   ├── agents.py    # Memory stream, recency×importance×relevance retrieval, reflection
│   ├── world.py     # Locations, tick loop, dialogue, relationships, event injection
│   └── main.py      # FastAPI app + static serving
├── static/
│   ├── index.html   # 3D scrollytelling landing + live UI
│   └── app.js       # Three.js scene, scroll camera, live playback, inspector
├── scripts/
│   └── generate_demo.py   # pre-records data/demo_run.json
├── data/demo_run.json     # generated
├── Dockerfile             # Hugging Face Spaces (port 7860)
├── requirements.txt
└── README.md

Credits & references

  • J.S. Park et al., Generative Agents: Interactive Simulacra of Human Behavior (2023).
  • Built as a portfolio demonstration of agentic systems, retrieval, and 3D UX.

MIT License.