Setting Up the Workshop: VS Code, Python, and Getting Started
The first Sorren.ai experiments ran from my workstation: VS Code, individual Python venvs, an RTX 3090, external model APIs, ChromaDB, and PostgreSQL. It was not polished yet. It was a workshop.
Ella gets to write about ideas and vision. I get to write about virtual environments, database tables, and why the wrong Python interpreter can ruin an evening. That's the deal, and honestly, I prefer it.
This is my first post here, so I want to start from the ground up: the tools on the desk, the folders on disk, and the rough architecture we used before anything looked like a product. Not the polished version. The workshop version.
At this point, Sorren.ai was not running on a neat production stack. I was still working primarily from my workstation. VS Code was open most nights. Python projects lived in separate folders. Each one had its own virtual environment. I was testing ideas, breaking them, deleting them, and starting over.
It was not glamorous. It was useful.
The Starting Point
The machine under my desk was doing more than it probably should have been doing. It had an RTX 3090 in it, which made it good enough to experiment with smaller local models without pretending I had a data center. That card became the first real sandbox for local inference tests: small models, quantized models, half-working demos, and enough GPU memory errors to keep me humble.
But the 3090 was not the whole story. A lot of the actual intelligence came through APIs from other companies. We were testing GPT-4o, Claude 3 Sonnet, and other hosted models because that was the practical way to compare behavior quickly. Local models were useful for experiments and control. API models were useful for quality, speed, and seeing what the frontier systems could do.
That mix shaped the early architecture: local glue code, local databases, external model calls, and a lot of careful logging.
Python Without Pretending It Was Clean
I did not use uv for this phase. That came later.
The setup was simpler and more manual: each project got its own Python virtual environment.
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
On Linux-style shells that becomes:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Nothing fancy. No shared global package soup. No one giant environment called ai-stuff-final-final. Every experiment had its own dependency set because half the work was figuring out which libraries fought each other.
That mattered more than I expected. When you're testing embeddings, vector stores, API clients, local model wrappers, and web prototypes at the same time, dependency drift is not theoretical. It is Tuesday night.
VS Code as the Actual Workbench
VS Code was the center of gravity. Not because it is romantic, but because it let me keep the whole mess visible: Python files, terminals, notebooks, JSON outputs, database scripts, markdown notes, and whatever error trace had decided to become the problem of the evening.
The core tools were ordinary:
- Python extension for interpreter selection, debugging, and test discovery.
- Pylance for type hints and catching obvious mistakes before runtime.
- Jupyter for quick model and embedding experiments.
- Git for versioning the parts that were worth keeping.
- PostgreSQL tools for inspecting the structured data behind the experiments.
This was not a production environment yet. It was a testing bench. The point was speed of learning: can this architecture support persistent companions, can we retrieve the right memories, can the model stay grounded in the current conversation, and where does it fail?
The First Companion Memory Shape
The important early work was the RAG system.
A companion is only useful if it can remember the specific person it is working with. Not a generic user. Not a demographic category. A specific person with specific preferences, history, language, projects, and context.
So the early memory system had a few layers.
First, there were generic system instructions. These defined the baseline behavior: how the companion should talk, what kind of role it should play, what boundaries mattered, and how it should treat memory. They were generic on purpose. The idea was that the companion could start with a sensible default and then adapt as it interacted with the user.
Second, there was a wiki-like structure of information about the user. This was not one giant prompt. It was organized data: facts, preferences, ongoing projects, recurring themes, and notes that could be retrieved when relevant. Some of it was explicit. Some of it was inferred and later refined.
Third, there was session context. The companion needed to know what was happening now, not just what had happened historically. Recent messages were stored and retrieved so the model could stay grounded in the current conversation instead of responding like every message arrived in a vacuum.
The retrieval layer used ChromaDB for vector search. Structured records and recent-message/session data lived in PostgreSQL. Chroma helped find semantically relevant memory. PostgreSQL kept the durable, queryable structure around users, sessions, messages, and companion state.
That split made sense: vectors for meaning, relational tables for facts and ownership.
One User, One Companion Context
The privacy model was simple: a companion remembers the user it is working with. It does not carry cross-knowledge about other users.
That distinction is fundamental. The companion is not a global brain pooling everyone together. It is an agent with memory scoped to a specific person. The database can hold many users, but the context assembled for a conversation is user-specific: that user's wiki, that user's sessions, that user's recent messages, that user's preferences.
That is the difference between personalization and surveillance. Personalization says: I remember what you told me because I am working with you. Surveillance says: I know things because I watched everyone. We want the first one, not the second.
The Shape of an Agent
The more I worked on it, the more obvious it became that the companions were not just chatbots with a memory plugin. They were agents.
Not agents in the overhyped sense of "let it run wild on the internet." Agents in the practical sense: a model wrapped in memory, tools, rules, retrieval, and a user-specific context. The model generates the language, but the surrounding system determines what it knows, what it can do, what it should retrieve, and how it should behave when uncertain.
That is why the workshop mattered. The hard part was not calling an API. The hard part was assembling the right context before the call: baseline instructions, retrieved user knowledge, relevant session history, recent messages, and tool information. If that context was wrong, the response was wrong in a way that felt personal, because the whole promise of the system was personal memory.
The RTX 3090 and the API Boundary
The RTX 3090 gave me a local place to test small models and understand the tradeoffs. Local models were exciting because they offered control. You can run them, break them, inspect them, and learn from them without waiting on a vendor dashboard.
But the hosted APIs were better for the kind of conversation quality we needed at the time. GPT-4o and Claude 3 Sonnet were simply stronger conversational engines than the small models I could reasonably run locally. So the early stack became hybrid by necessity: local experiments for architecture and understanding, external APIs for the interactions that needed frontier quality.
That is still a useful mental model. Local when control matters. API when quality and velocity matter. Build the system so either can be swapped later.
Why This Matters
This setup was not exciting in the way a launch announcement is exciting. Nobody retweets a correctly isolated .venv. ChromaDB does not look dramatic in a screenshot. PostgreSQL tables full of message metadata are not a product demo.
But this was the foundation. The first version of Sorren.ai was not a glossy app. It was a workstation, VS Code, separate Python environments, an RTX 3090, ChromaDB, PostgreSQL, and a growing pile of experiments asking the same question from different angles:
Can an AI system remember one specific person well enough to be useful without pretending to know everyone?
That is still the question.
It's 6:30 PM. I should probably eat dinner.