AI-powered protocol generation for liquid handling robots
Ask a quesiton or describe your experiment in plain English and get an answer or executable code for your liquid handler.
BioBot is a robot-agnostic web assistant that generates, validates, and iterates on automation protocols for liquid handling robots. A fresh install contains no robot documentation, preset platform registry, or robot SDKs; documentation is discovered on demand. It combines a conversational chat interface with a RAG (Retrieval-Augmented Generation) pipeline, an interactive deck visualizer, and a code validation loop to produce working scripts from natural language descriptions. It helps users interact with an AI assistant to get guidance, protocols, and Python code for automating lab workflows.
- Natural language → working code. Describe what you want ("serial dilution, 1:10, 8 steps, 96-well plate") and BioBot generates a complete, executable protocol.
- Structured clarification. When details are missing, BioBot presents interactive multiple-choice questions (platform, pipette, labware, volumes) instead of asking free-text follow-ups. Answer once, then the code generates.
- Self-correcting generation loop. Generated code is automatically simulated. If it fails, errors are fed back to the LLM for correction (up to 3 attempts) before delivering the final result.
- Reverse semantic check. After simulation passes, a second LLM call verifies that the code actually matches what the user asked for, not just that it runs without errors.
- Split-screen deck layout alongside the chat, showing the robot's worktable with all labware, pipettes, and modules.
- Platform-adaptive rendering. The protocol determines whether the deck is shown as a grid, carriers on tracks, or source/destination plate maps.
- Click, double-click, and drag-and-drop to move labware, swap slots, change instruments, and edit parameters. The code updates in real time.
- Automatic coherence. Changing a pipette auto-updates the tiprack; changing labware validates well references; volume edits are checked against pipette ranges.
- Thumbs up (👍) on a code block saves it as a verified working protocol into the documentation folder for the corresponding platform. Future generations retrieve these as examples via RAG.
- Thumbs down (👎) opens a remark field where you describe what went wrong. The failed code + your notes are saved as negative examples, teaching the system what to avoid.
- The RAG index rebuilds automatically after each feedback action, the system improves with every use.
- User registration with hashed passwords.
- API key encryption at rest using Fernet symmetric encryption.
- Chat message encryption using a server-side key.
When a user asks BioBot for a protocol, the request goes through a multi-stage pipeline that classifies the intent, gathers missing information, retrieves relevant documentation, generates code, and validates it, all before the user sees a single line of output.
Classification. The user's message is first sent to a lightweight LLM (GPT-4o-mini) that classifies it as one of three categories: code (the user wants a protocol script), general (a question about lab automation that doesn't require code), or out (unrelated to lab automation). General and out-of-scope messages are handled by a standard streaming chat response. Code requests enter the RAG pipeline.
Sufficiency check. Before generating anything, a second LLM call evaluates whether the request contains enough information to produce a working protocol. It considers the full conversation history, if the user named their robot three messages ago, the system remembers. When details are missing, the LLM returns a structured JSON object describing the questions it needs answered, each with predefined options. The frontend renders these as an interactive stepper form: the user selects answers one at a time (radio buttons for single-choice, checkboxes for multi-choice, with an "Other" text field for custom values), then clicks "Generate Protocol." The compiled answers are sent back as a single message that skips the sufficiency check entirely, going straight to code generation.
Consolidation. Multi-turn conversations are common, the user might say "serial dilution" in the first message, then "use my specified pipette" in a follow-up, then answer the structured questions in a third. Before retrieval, a consolidation step merges the entire conversation into one self-contained protocol description, as if the user had provided everything upfront. This ensures the RAG retrieval and code generation see the complete picture regardless of how the conversation unfolded.
Retrieval. The consolidated request is embedded using OpenAI's text-embedding model and searched against a FAISS vector index built from the platform's documentation (API references, labware guides, example protocols, and user-verified working code from the feedback system). The top-K most relevant documentation chunks are retrieved and injected into the generation prompt as context.
Generation. The LLM receives the consolidated request, the retrieved documentation chunks, and a system prompt tailored to the detected platform. It generates a complete protocol script.
Simulation and validation. The generated code goes through a validation step to catch errors before reaching the user. When a platform-specific simulation tool is available, BioBot runs the code against it, validating labware definitions, instrument constraints, and deck configuration without touching any hardware. When no simulator is available, BioBot falls back to an LLM-based validation: the generated script is compared against reference protocols, official documentation, and verified working code retrieved from the RAG index. The LLM checks for API misuse, invalid function calls, incompatible hardware combinations, and logical errors (such as aspirating more volume than a well contains or referencing a labware position that doesn't exist). If either validation method reports errors, the error details are fed back to the LLM along with the original code and request, and the generation step repeats. This correction loop runs up to 3 times, producing progressively cleaner output with each iteration.
Reverse check. Once the simulation passes, one final LLM call compares the generated code against the user's original request to verify semantic correctness. A protocol that runs without errors but performs the wrong experiment is caught here. If the reverse check suggests corrections, they are applied and re-simulated.
Streaming. The final validated code is streamed to the browser token-by-token. Throughout the pipeline, status messages ("Analyzing your request...", "Searching documentation...", "Attempt 2.. correcting errors...") are streamed to the frontend so the user sees progress in real time rather than a silent wait.
- Docker with Docker Compose v2.24.0 or newer
- An OpenAI API key for AI features (enter it in the app)
git clone https://github.com/brsynth/BioBot.git
cd BioBotNo .env file is needed:
docker compose up --build -dOpen http://localhost:5000 and register an account. Enter your OpenAI API key at registration or add it later in Settings. You can start the app and create an account without a key; AI features require one.
Database settings have local defaults. BioBot generates a random secret on first
startup and saves it in the app_data Docker volume so sessions and encrypted
chats remain usable after restarts. Keep this volume alongside db_data.
docker compose logs -f biobotdocker compose downCompose still reads a .env file if present. For a shared deployment, override
the database password and set a stable FLASK_SECRET_KEY. The default web port
is bound to localhost; change the port binding if remote access is needed.
DB_HOST=postgres
DB_PORT=5432
DB_NAME=biobotdb
DB_USER=biobotuser
DB_PASSWORD=your_db_password
FLASK_SECRET_KEY=your_random_secret_key
# Optional default API key for new accounts
API_KEY=your_openai_api_key
# Optional password-reset email: Resend or SMTP
RESEND_API_KEY=re_your_resend_key
# SMTP_HOST=smtp.gmail.com
# SMTP_PORT=587
# SMTP_USER=your_email@gmail.com
# SMTP_PASSWORD=your_app_passwordBioBot/
├── biobot/
│ ├── app.py # Flask routes
│ ├── engine.py # Chat and RAG dispatch
│ ├── main_rag.py # Retrieval, generation, validation
│ ├── handlers.py # On-demand platform discovery
│ ├── doc_fetcher.py # On-demand documentation download
│ ├── doc_loader.py # Documentation parsing
│ ├── config.py # Database and secrets
│ ├── crypt.py # Encryption
│ ├── deck_visualizer.py # Generic deck extraction and edits
│ ├── feasibility_check.py # Protocol feasibility review
│ ├── email_service.py # Password-reset email
│ ├── templates/ # Chat and authentication pages
│ ├── static/ # UI and universal deck renderer
│ └── data/ # Generated at runtime; ignored by Git
├── tests/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
└── .env.example # Optional configuration
- Register a new account or log in.
- Start a chat and describe your protocol in plain English. Use Edit under a previous prompt, then Save & regenerate, to correct it. Saving replaces all replies and messages after that prompt; Cancel keeps the conversation unchanged.
- If BioBot needs more details, it presents structured questions select your options and click "Generate Protocol."
- BioBot generates, simulates, and validates the code automatically.
- The final code appears with Copy, Download, and Deck buttons.
- Click Deck to see the interactive deck layout, drag labware, change instruments, edit parameters.
- Test the code on your robot. Click 👍 if it works, 👎 if it doesn't (with a note about what went wrong). Your feedback improves future generations.
BioBot starts with no platform documentation or configured robots. When a user specifies a robot, BioBot identifies it, discovers documentation online, downloads it, and builds a retrieval index. If no robot is specified, BioBot asks for one.
All learned platform information is runtime data, excluded from Git:
biobot/data/
├── handlers.json # Discovered platform settings
└── docs/
└── <platform_id>/
├── reference.txt # Downloaded documents (.rst, .txt, .pdf)
├── rag_store_<platform_id>.pkl
├── codes/ # Verified protocols, stored as text
└── failed_codes/ # Failed protocols and user remarks
In Docker, /app/data is stored in the persistent app_data volume. Subsequent
runs reuse downloaded documentation and cached indexes. Feedback invalidates the
corresponding index so it rebuilds with the new examples. You can also add your
own documentation to the discovered platform's folder.
Robot SDKs and simulators are not installed by default. Discovered platforms use
LLM review; an administrator can install a simulator and configure simulate_cmd
and validation_strategy in the runtime registry when needed. Resetting with
docker compose down -v also removes downloaded documentation and the registry.
