Skip to content

kcampbel/bio-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bio-agent

An agentic interface to biological databases — UniProt, Ensembl, and NCBI Gene — with input guardrails and explicit failure-mode handling.

An LLM answers a natural-language question by calling small, validated tools. The tools never let the model fabricate a fact about a gene or protein: every query is validated before it hits the network, and every response comes back as a structured envelope (ok / not_found / malformed_input / upstream_error) that the model has to account for.

Why this exists

Biological database queries fail in quiet, characteristic ways, and a naive agent will rationalize right past them:

  • a gene symbol (TP53) gets passed where an accession (P04637) is expected;
  • a common name (human) gets passed where a species slug (homo_sapiens) is expected;
  • a valid query legitimately returns nothing, which is different from the service being down.

bio-agent treats these as first-class outcomes. The guardrail layer rejects malformed queries with actionable messages; the tool layer distinguishes "found nothing" from "call failed." That taxonomy is exactly what you need to evaluate an agent's biological reasoning, which is why it ships with an eval harness.

Architecture

question ──► agent loop (Claude tool-use) ──► tool ──► guardrails.precheck ──► HTTP ──► UniProt / Ensembl / NCBI
                    ▲                                       │
                    └──────── structured result ◄──────────┘
        {status: ok | not_found | malformed_input | upstream_error, data, message}
  • src/bio_agent/guardrails.py — input validation + a precheck used by the evals
  • src/bio_agent/tools.py — lookups (get_protein, lookup_gene, search_gene) plus the drug-target toolset (resolve_target, get_sequence, expression_hpa, get_structures, get_known_drugs, build_boltz_input, and the planned stubs) + Anthropic tool schemas
  • src/bio_agent/dossier.py — the drug-target dossier orchestrator + CLI
  • src/bio_agent/agent.py — the tool-calling loop
  • tests/ — offline unit tests (network mocked)
  • evals/ — guardrail eval harness + cases.jsonl

Install

pip install -e ".[dev]"        # tools, tests, evals (no API key needed)
pip install -e ".[agent]"      # adds the anthropic SDK for the live agent

Use the tools directly (no API key)

from bio_agent.tools import get_protein, lookup_gene, search_gene

get_protein("P04637")
# {'status': 'ok', 'data': {'gene': 'TP53', 'organism': 'Homo sapiens', 'length': 393, ...}}

get_protein("TP53")   # a gene symbol, not an accession
# {'status': 'malformed_input', 'message': "'TP53' is not a valid UniProt accession ..."}

lookup_gene("BRCA1", "human")   # wrong species format
# {'status': 'malformed_input', 'message': "'human' is not a valid species slug ..."}

Run the agent (needs the agent extra + ANTHROPIC_API_KEY)

The anthropic SDK is an optional dependency, so install the agent extra first (the tools, tests, and dossier all work without it):

pip install -e ".[agent]"                  # installs the anthropic SDK
export ANTHROPIC_API_KEY=sk-...
export BIO_AGENT_MODEL=claude-sonnet-5     # or whichever model you have access to
python -m bio_agent.agent "What is protein P04637, and where is BRCA1 in the human genome?"

Tests & evals

pytest -q                  # offline unit tests
python evals/run_evals.py  # guardrail eval — scores accept/reject on cases.jsonl

Example eval output:

case                            expected        got             result
------------------------------------------------------------------------
uniprot_valid                   ok              ok              PASS
uniprot_symbol_not_accession    malformed_input malformed_input PASS
gene_common_name_species        malformed_input malformed_input PASS
...
------------------------------------------------------------------------
12/12 passed (100%)

CI (.github/workflows/ci.yml) runs on Python 3.9 / 3.11 / 3.12.

Drug-target dossier mode

Given a gene symbol or UniProt accession, bio-agent can assemble a single targetability dossier by orchestrating tools across sources — identity, expression, structure, and known drugs — and emit a ready-to-run input for structure prediction.

python -m bio_agent.dossier BRCA1                 # Markdown report
python -m bio_agent.dossier P04637 --json         # structured JSON
python -m bio_agent.dossier BRCA1 --boltz-out target.yaml

What it pulls together:

Section Source Status
Identity, sequence, cross-refs UniProt live
Gene → accession resolution UniProt search live
Tissue / single-cell-type expression, subcellular location Human Protein Atlas live
Experimental structures + AlphaFold model UniProt xrefs (PDB) + AlphaFold DB live
Known drug/gene interactions DGIdb live
Boltz input (apo; add a ligand SMILES for complex prediction) generated live
Cell-type expression CZ CELLxGENE census planned
Chemical-similarity / antibody-motif search ChEMBL + RDKit + SAbDab/IMGT planned

The planned tools ship with real interfaces and honest status: "planned" responses (with the intended data source) rather than fabricated results — the failure taxonomy applies to "not built yet," too. Every dossier includes a provenance block reporting the status of each underlying call, so a partial dossier is transparent about what succeeded.

The dossier runs deterministically without an LLM (each step is a plain tool call); the same tools are also exposed to the agent, so you can ask conversationally, e.g. "How druggable is BRCA1, and what structures exist?"

Scope & roadmap

This is intentionally small and readable. Near-term: wire the two planned tools (CELLxGENE census expression; ChEMBL/RDKit similarity + antibody-motif search), pull a top-ranked ligand's SMILES from ChEMBL into the Boltz input automatically, add semantic evals that score the agent's final answer against a rubric (not just query validity), and cache/rate-limit the HTTP layer for batch use.

A note on how this was built

Developed iteratively with Claude as a pair-programmer — which is also how I use these models in my day-to-day computational-biology work. The design decisions (the failure taxonomy, the guardrail-before-network contract, the eval framing) are the point; the boilerplate is where an LLM helps most.

License

MIT © 2026 Katie Campbell

About

Agentic interface to biological databases (UniProt, Ensembl, NCBI) with input guardrails, evals, and a drug-target dossier mode.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages