LangChain is powerful. But sometimes you just need to hammer a nail, not operate a pneumatic construction system.
After building a dozen AI automation projects, I've discovered something freeing: you can often get better results with simpler, focused libraries that do one thing exceptionally well. Here are ten that have saved my sanity.
1. Instructor: When You Actually Need Structured Data
Remember spending hours writing regex to parse LLM outputs? Yeah, Instructor made me forget about those dark times too.
It's beautifully simple—you define a Pydantic model, and Instructor forces the LLM to return data in exactly that structure. No more "the AI returned a string when I needed a list" bugs at 2 AM.
import instructor
from pydantic import BaseModel
from openai import OpenAI
client = instructor.from_openai(OpenAI())
class UserInfo(BaseModel):
name: str
age: int
email: str
user = client.chat.completions.create(
model="gpt-4",
response_model=UserInfo,
messages=[{"role": "user", "content": "Extract: John Doe, 30, john@example.com"}]
)
That's it. No chains, no output parsers, no crying into your keyboard.
2. LiteLLM: The Universal Adapter
Ever started a project with OpenAI, then needed to switch to Anthropic, then your client wanted to try Google's models? LiteLLM is the adapter that keeps you sane.
One interface for 100+ LLM providers. Same code, different models. It's like having a universal charger for your phone, laptop, and that weird Bluetooth speaker.
from litellm import completion
# Works with OpenAI
response = completion(
model="gpt-4",
messages=[{"role": "user", "content": "Hello"}]
)
# Same code, different provider
response = completion(
model="claude-3-sonnet-20240229",
messages=[{"role": "user", "content": "Hello"}]
)
The best part? It handles rate limits, retries, and fallbacks automatically. Your code stays clean.
3. Tenacity: Because APIs Fail (A Lot)
Here's what nobody tells you about building with LLMs: they fail. Rate limits, timeouts, random 500 errors at the worst possible moment.
Tenacity is the library that turns "it broke in production" into "it recovered automatically." It's a retry library with actual intelligence.
from tenacity import retry, stop_after_attempt, wait_exponential
import openai
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10)
)
def call_gpt(prompt):
return openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
It waits intelligently between retries, gives up when it should, and logs everything. Production-grade reliability in five lines.
4. Pydantic: The Bouncer Your Data Needs
If Instructor is the translator, Pydantic is the security guard making sure nothing sketchy gets into your application.
You define what your data should look like, and Pydantic validates it with zero tolerance for nonsense. Wrong type? Rejected. Missing field? Rejected. Weird format? You guessed it—rejected.
from pydantic import BaseModel, EmailStr, field_validator
class User(BaseModel):
username: str
email: EmailStr
age: int
@field_validator('age')
def check_age(cls, v):
if v < 0 or v > 120:
raise ValueError('Invalid age')
return v
Every AI project I've seen that fell apart in production? They skipped proper data validation. Don't be that project.
5. Streamlit: From Script to App in Minutes
Need to show your AI creation to someone who doesn't live in a terminal? Streamlit turns Python scripts into web apps faster than you can say "npm install."
No HTML, no CSS, no JavaScript frameworks—just Python. It's perfect for internal tools, demos, and MVPs.
import streamlit as st
import openai
st.title("Simple AI Chat")
prompt = st.text_input("Ask something:")
if st.button("Send"):
response = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
st.write(response.choices[0].message.content)
Run streamlit run app.py and boom—you have a working interface. Show it to your boss, your client, your confused relatives who think you "work with computers."
6. Jinja2: Templates for Prompts That Don't Suck
Concatenating strings to build prompts is the programming equivalent of eating cereal with a fork. It works, technically, but why would you do that to yourself?
Jinja2 is the templating engine that makes prompt engineering actually manageable.
from jinja2 import Template
template = Template("""
You are a {{ role }} assistant.
User context:
- Name: {{ user.name }}
- Preferences: {{ user.preferences }}
Task: {{ task }}
""")
prompt = template.render(
role="helpful",
user={"name": "Alice", "preferences": "concise answers"},
task="Explain quantum computing"
)
Now your prompts are readable, reusable, and don't make you want to throw your laptop out the window.
7. Loguru: Logging That Doesn't Make You Angry
Python's built-in logging is fine if you hate yourself. For everyone else, there's Loguru.
It's logging that actually makes sense—colors, automatic formatting, sane defaults. Perfect for debugging those "why did the AI do that?" moments.
from loguru import logger
logger.add("ai_app.log", rotation="500 MB")
logger.info("Starting AI request")
logger.debug(f"Prompt: {prompt}")
logger.success("Got response in {time}s")
logger.error("API call failed: {error}")
When something breaks at 3 AM (and it will), you'll thank past-you for having readable logs.
8. httpx: Because requests Isn't Async
Calling multiple LLM APIs simultaneously? Python's beloved requests library will make you wait for each one sequentially like it's 2010.
httpx is the modern async HTTP client that actually respects your time.
import httpx
import asyncio
async def call_multiple_ais(prompts):
async with httpx.AsyncClient() as client:
tasks = [
client.post("https://api.openai.com/v1/chat/completions", ...)
for prompt in prompts
]
return await asyncio.gather(*tasks)
Three API calls that took 9 seconds? Now they take 3. Math has never felt this good.
9. Rich: Terminal Output That Doesn't Look Like 1995
Building AI automation often means watching progress in your terminal. Rich makes that experience not miserable.
Progress bars, formatted tables, syntax highlighting, and panels—all in your terminal, all gorgeous.
from rich.console import Console
from rich.progress import track
import time
console = Console()
console.print("[bold green]Starting AI pipeline...[/bold green]")
for step in track(range(100), description="Processing..."):
time.sleep(0.01)
console.print("[bold blue]Complete![/bold blue]")
Your terminal becomes a dashboard. Your coworkers think you're a wizard. Everyone wins.
10. DuckDB: When Your AI Needs a Database (But Not the Drama)
LLMs generate data. Lots of it. You need to store it somewhere that isn't a JSON file named data_final_final_v3_ACTUAL.json.
DuckDB is SQLite's cooler cousin—an embedded analytical database that's shockingly fast and requires zero setup.
import duckdb
con = duckdb.connect('ai_data.db')
# Store AI responses
con.execute("""
CREATE TABLE IF NOT EXISTS responses (
id INTEGER PRIMARY KEY,
prompt TEXT,
response TEXT,
model TEXT,
timestamp TIMESTAMP
)
""")
con.execute("""
INSERT INTO responses VALUES (?, ?, ?, ?, ?)
""", (1, prompt, response, "gpt-4", datetime.now()))
# Query with SQL
results = con.execute("""
SELECT model, COUNT(*) as count
FROM responses
GROUP BY model
""").fetchall()
No Docker containers, no PostgreSQL configuration files, no DevOps tickets. Just data, stored and queryable.
The Pattern I've Noticed
After using all these libraries across different projects, I've noticed something: the best AI automation setups aren't built around one giant framework. They're composed of small, excellent tools that each solve one problem really well.
LangChain tries to be everything. These libraries try to be one thing, exceptionally.
Need structured outputs? Instructor. Need reliability? Tenacity. Need to switch models? LiteLLM.
Pick what you need, ignore what you don't. Your code will be simpler, your debugging will be faster, and you'll actually understand what's happening when things break.
And they will break. But at least now you have the right tools to fix them.
What Actually Matters
Look, I'm not saying LangChain is bad. For complex agent systems with memory, routing, and multi-step reasoning, it's probably the right choice.
But most AI automation isn't that. Most of the time, you just need to:
- Call an API reliably
- Get structured data back
- Validate it
- Store it
- Show it to someone
These ten libraries do exactly that, without making you learn a new paradigm every other Tuesday.
Start simple. Add complexity only when you need it. Your future self—the one debugging at midnight—will thank you.
Which libraries are you using for AI automation? Have I missed your favorite? Let me know—I'm always hunting for tools that make this work easier.
Top comments (0)