Unlocking the Potential of LLMs in Biology
Introduction We are building a literature triage agent that reads biology abstracts, extracts genes, proteins, and diseases, and suggests testable hypotheses. It is meant for bioinformaticians and bench scientists who n
Introduction
We are building a literature triage agent that reads biology abstracts, extracts genes, proteins, and diseases, and suggests testable hypotheses. It is meant for bioinformaticians and bench scientists who need to scan dozens of papers without reading every word. The whole thing runs against Oxlo.ai's flat per-request endpoint, so a 10,000-token methods section costs the same as a one-sentence query.
What you will need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
- A handful of PubMed abstracts to test with
1. Configure the OpenAI-compatible client
Oxlo.ai exposes a fully OpenAI-compatible API. We instantiate the client once, point it at https://api.oxlo.ai/v1, and select a model. I use llama-3.3-70b because it handles dense scientific vocabulary reliably.
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key="YOUR_OXLO_API_KEY"
)
# Verify connectivity with a lightweight call
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[{"role": "user", "content": "Say OK"}],
max_tokens=10
)
print(response.choices[0].message.content)
2. Write the biology system prompt
The system prompt is the only manual logic we need. It forces the model to emit strict JSON containing extracted entities and confidence scores, so downstream code never has to parse free text.
SYSTEM_PROMPT = """You are a precision biology parser. Read the user-provided abstract and extract the following:
1. Genes and proteins (use official HGNC gene symbols where possible)
2. Diseases or phenotypes
3. Cell lines or organisms
4. Molecular pathways mentioned
Return ONLY a JSON object with this exact structure:
{
"entities": [
{"type": "gene", "name": "TP53", "confidence": 0.98},
{"type": "disease", "name": "glioblastoma", "confidence": 0.91}
],
"summary": "One-sentence summary of the finding"
}
If an entity is ambiguous, mark confidence below 0.8. Do not add markdown fences or commentary outside the JSON."""
3. Extract structured entities from an abstract
We call the chat completions endpoint with JSON mode enabled. Oxlo.ai supports this on all major models, which guarantees valid JSON output without brittle regex.
import json
def extract_entities(abstract: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": abstract},
],
response_format={"type": "json_object"},
temperature=0.1,
)
raw = response.choices[0].message.content
return json.loads(raw)
abstract = (
"CRISPR-Cas9 screening identified BRCA1 as a synthetic lethal target "
"in pancreatic ductal adenocarcinoma cell lines. Loss of BRCA1 function "
"increased sensitivity to PARP inhibitors via defective homologous recombination."
)
result = extract_entities(abstract)
print(json.dumps(result, indent=2))
4. Generate hypotheses from extracted entities
With entities in hand, we run a second pass to suggest experiments. I switch to kimi-k2.6 for this step because its reasoning capabilities are strong for open-ended scientific inference, but the client setup is identical.
HYPOTHESIS_PROMPT = """You are a principal investigator. Given the extracted entities from a paper, propose one testable hypothesis and one follow-up experiment. Return ONLY JSON:
{
"hypothesis": "string",
"experiment": "string",
"needed_reagents": ["list"]
}"""
def suggest_hypothesis(entities_json: dict) -> dict:
response = client.chat.completions.create(
model="kimi-k2.6",
messages=[
{"role": "system", "content": HYPOTHESIS_PROMPT},
{"role": "user", "content": json.dumps(entities_json)},
],
response_format={"type": "json_object"},
temperature=0.3,
)
return json.loads(response.choices[0].message.content)
hyp = suggest_hypothesis(result)
print(json.dumps(hyp, indent=2))
5. Batch process multiple abstracts
Real pipelines process dozens of papers at once. We wrap the two passes in a single function and iterate over a list. Because Oxlo.ai uses flat per-request pricing, long abstracts do not inflate cost the way token-based providers would. You can see exact plan details at https://oxlo.ai/pricing.
def process_papers(abstracts: list[str]) -> list[dict]:
outputs = []
for idx, text in enumerate(abstracts, 1):
entities = extract_entities(text)
hypothesis = suggest_hypothesis(entities)
outputs.append({
"paper_index": idx,
"entities": entities,
"hypothesis": hypothesis,
})
return outputs
batch = [
(
"Single-cell RNA-seq revealed a rare microglial subtype expressing TREM2 "
"in the Alzheimer's disease mouse model. This population was enriched near amyloid plaques."
),
(
"The mTORC1 pathway was hyperactivated in TSC2-deficient patient-derived "
"iPSC neurons, leading to abnormal axon guidance that was rescued by rapamycin."
),
]
findings = process_papers(batch)
print(json.dumps(findings, indent=2))
Run it
Save the script as bio_agent.py, replace YOUR_OXLO_API_KEY with your key from the portal, and execute. Here is a complete end-to-end block.
from openai import OpenAI
import json
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key="YOUR_OXLO_API_KEY"
)
SYSTEM_PROMPT = """You are a precision biology parser. Read the user-provided abstract and extract the following:
1. Genes and proteins (use official HGNC gene symbols where possible)
2. Diseases or phenotypes
3. Cell lines or organisms
4. Molecular pathways mentioned
Return ONLY a JSON object with this exact structure:
{
"entities": [
{"type": "gene", "name": "TP53", "confidence": 0.98},
{"type": "disease", "name": "glioblastoma", "confidence": 0.91}
],
"summary": "One-sentence summary of the finding"
}
If an entity is ambiguous, mark confidence below 0.8. Do not add markdown fences or commentary outside the JSON."""
HYPOTHESIS_PROMPT = """You are a principal investigator. Given the extracted entities from a paper, propose one testable hypothesis and one follow-up experiment. Return ONLY JSON:
{
"hypothesis": "string",
"experiment": "string",
"needed_reagents": ["list"]
}"""
def extract_entities(abstract: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": abstract},
],
response_format={"type": "json_object"},
temperature=0.1,
)
return json.loads(response.choices[0].message.content)
def suggest_hypothesis(entities_json: dict) -> dict:
response = client.chat.completions.create(
model="kimi-k2.6",
messages=[
{"role": "system", "content": HYPOTHESIS_PROMPT},
{"role": "user", "content": json.dumps(entities_json)},
],
response_format={"type": "json_object"},
temperature=0.3,
)
return json.loads(response.choices[0].message.content)
if __name__ == "__main__":
abstract = (
"CRISPR-Cas9 screening identified BRCA1 as a synthetic lethal target "
"in pancreatic ductal adenocarcinoma cell lines. Loss of BRCA1 function "
"increased sensitivity to PARP inhibitors via defective homologous recombination."
)
entities = extract_entities(abstract)
hyp = suggest_hypothesis(entities)
print("=== ENTITIES ===")
print(json.dumps(entities, indent=2))
print("\n=== HYPOTHESIS ===")
print(json.dumps(hyp, indent=2))
Expected output looks similar to this (your exact JSON may vary):
{
"entities": [
{"type": "gene", "name": "BRCA1", "confidence": 0.97},
{"type": "disease", "name": "pancreatic ductal adenocarcinoma", "confidence": 0.94},
{"type": "molecule", "name": "PARP inhibitors", "confidence": 0.92},
{"type": "pathway", "name": "homologous recombination", "confidence": 0.89}
],
"summary": "CRISPR screening links BRCA1 loss to PARP inhibitor sensitivity in pancreatic cancer via homologous recombination defects."
}
Wrap-up
Two concrete next steps. First, wire the JSON output into a vector database like Chroma or pgvector so you can search across hundreds of papers by gene or pathway. Second, add a tool-calling step that uses the NCBI E-utilities API to fetch full text automatically, letting the agent ground its hypotheses in the latest literature without manual copy and paste.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.