This tutorial shows how to use TxGemma to reason about ADMET properties on a real molecule. We are going to take a SMILES string, send it to TxGemma with a structured ADMET question, and walk through what the model returns. No local GPU required.
The goal is not to replace a validated ADMET predictor. The goal is to show how a chemistry-literate LLM can give you the reasoning layer that traditional property predictors are missing. Numbers tell you whether there is a problem. Reasoning tells you where it lives in the molecule.
The setup
You need three things to run this tutorial:
- A free SciRouter API key from the dashboard.
- A SMILES string for the molecule you want to profile.
- Any HTTP client. Below we use
curland Python.
We will use the SMILES for a simple small molecule throughout the tutorial so the output is easy to read. In a real workflow you would loop over your own candidate set.
Calling the TxGemma interpret endpoint
SciRouter exposes TxGemma under the interpret family of endpoints, which wrap a chat-style request in a consistent schema. A minimal call looks like this:
curl -X POST https://scirouter-gateway-production.up.railway.app/v1/interpret/txgemma \
-H "Authorization: Bearer sk-sci-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"smiles": "CC(=O)OC1=CC=CC=C1C(=O)O",
"question": "Profile this molecule on the standard ADMET endpoints. For each endpoint, give a short verdict and a one-sentence rationale grounded in the structure."
}'The SMILES in that call is aspirin. It is a useful starting molecule because its ADMET profile is well known — good oral absorption, significant plasma protein binding, fast hydrolysis to salicylate — so you can immediately check whether TxGemma is producing sensible output.
What TxGemma returns
The response is structured. You get a free-text rationale per endpoint plus a short verdict. A trimmed version of what you should expect looks like this:
{
"model": "txgemma-9b",
"smiles": "CC(=O)OC1=CC=CC=C1C(=O)O",
"endpoints": {
"absorption": {
"verdict": "high",
"rationale": "Small molecule with low molecular weight and balanced logP. Carboxylic acid provides solubility, acetate preserves permeability. Passes Lipinski rule of five comfortably."
},
"cyp_inhibition": {
"verdict": "low",
"rationale": "No large aromatic systems or heterocycles typically associated with CYP3A4 or CYP2D6 liability. Clean isoform profile expected."
},
"herg": {
"verdict": "low",
"rationale": "Acid functionality and compact size give low probability of cardiac hERG channel blockade."
},
"metabolism": {
"verdict": "fast",
"rationale": "Ester bond is hydrolytically labile, leading to rapid conversion to salicylate in plasma and liver."
},
"toxicity": {
"verdict": "moderate",
"rationale": "Low intrinsic toxicity at therapeutic doses. Known GI irritation liability tied to local acidity and COX inhibition."
}
}
}Two things are worth noticing. First, the verdicts are qualitative (high, low, moderate). TxGemma is a reasoning model, not a calibrated regressor. Second, the rationales are grounded in the structural features of the molecule. That is what you are paying for when you use an LLM for ADMET instead of a bare property predictor.
Wiring it into a Python workflow
For anything beyond a one-off curl command you want this in code. Here is the minimum Python client:
import os
import httpx
API_KEY = os.environ["SCIROUTER_API_KEY"]
BASE_URL = "https://scirouter-gateway-production.up.railway.app"
def admet_reason(smiles: str, question: str | None = None) -> dict:
question = question or (
"Profile this molecule on absorption, CYP inhibition, hERG, "
"metabolism, and toxicity. Give a verdict and a one-sentence "
"structural rationale per endpoint."
)
resp = httpx.post(
f"{BASE_URL}/v1/interpret/txgemma",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"smiles": smiles, "question": question},
timeout=90.0,
)
resp.raise_for_status()
return resp.json()
if __name__ == "__main__":
result = admet_reason("CC(=O)OC1=CC=CC=C1C(=O)O")
for endpoint, body in result["endpoints"].items():
print(f"{endpoint}: {body['verdict']}")
print(f" -> {body['rationale']}")
print()This is the pattern you extend. A real triage script loops over your hit list, calls admet_reason on each molecule, and persists the rationale alongside your existing property predictions. When a chemist reviews a hit, they see both the number and the explanation.
Combining TxGemma with a physical ADMET predictor
TxGemma is strongest when you use it alongside a calibrated predictor, not instead of it. A useful pattern is to call both and compare.
- Call your ADMET predictor to get numeric scores per endpoint.
- Call TxGemma to get a rationale per endpoint.
- Flag cases where TxGemma's verdict disagrees with the numeric model. These are the interesting molecules — either TxGemma is hallucinating or the numeric model is missing structural context.
- Route disagreements to human review. Route agreements to automatic triage.
This pattern catches more failure modes than either tool alone, and it gives chemists a more useful review surface than a sea of uninterpreted numbers.
Common pitfalls
Asking too many endpoints at once
If you cram twenty endpoints into a single prompt the model will cut corners. Ask for five endpoints per call. If you need more, call twice.
Forgetting to include the SMILES
It sounds obvious, but if you send a question without the SMILES string the model will happily generate a generic ADMET lecture that is unrelated to your molecule. Always include structure.
Expecting calibrated probabilities
TxGemma verdicts are categorical. Do not compare “high” to 0.87. If you need a probability, use a calibrated model and keep TxGemma for the rationale.
Not retrying on long molecules
For very long SMILES or fused ring systems the model can truncate. If the rationale looks suspiciously short, resend with a prompt that asks for a short answer per endpoint.
Bottom line
TxGemma does for ADMET what a good medicinal chemist does at a design review: it reads the structure, recalls the relevant rules, and gives you a reasoned verdict. That is different from what a numeric property predictor does, and the two are more useful together than apart.