OpenAI SDK or LangChain: when a framework helps and when it gets in the way
One scenario written with the plain SDK and with LangChain: how much code, where debugging is easier and how to keep control of token spend.
5 min · · development · сравнение
The "openai sdk vs langchain" question usually comes up when you have to pick a foundation for a project: take a thin library and write the logic yourself, or add a framework with ready-made chains. The answer depends on what you are building, not on fashion. Below is one scenario written with the OpenAI SDK and with LangChain in Python. We compare code size, debugging and token control, and finish with a rule of thumb.
Both options use a fetch_... key and the address https://api.zukko.pro/v1. Zukko exposes an OpenAI-compatible API, so the only things you change are base_url and the model name.
What the OpenAI SDK is and how it differs from LangChain
The OpenAI SDK (the openai package) is a thin wrapper over HTTP requests: you build a list of messages, call a method, and get a reply plus a usage field with token counts. Whatever happens between calls is your code.
LangChain is a framework on top of such SDKs. It adds prompt templates, output parsers, chains, memory, vector store integrations and agents. The model is just one interchangeable component.
In short: the SDK gives you one call; LangChain gives you a frame for several calls and integrations. If you need one call, you do not need the frame. More on the SDK itself in Python SDK: a complete example.
One scenario, two ways
Scenario: take a customer message and return JSON with a category and a priority.
Plain SDK
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_...")
def classify(text: str) -> dict:
resp = client.chat.completions.create(
model="gpt-6.1-sol",
messages=[
{"role": "system", "content": "Return JSON: {\"category\": str, \"priority\": \"low|mid|high\"}"},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
)
print("tokens:", resp.usage.prompt_tokens, resp.usage.completion_tokens)
return json.loads(resp.choices[0].message.content)
print(classify("The confirmation email never arrives, but the payment went through"))Everything is visible: which messages went out, how many tokens were spent, what came back. Request parameters are described in the chat completions reference.
LangChain
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
llm = ChatOpenAI(
model="gpt-6.1-sol",
base_url="https://api.zukko.pro/v1",
api_key="fetch_...",
)
prompt = ChatPromptTemplate.from_messages([
("system", "Return JSON: {{\"category\": str, \"priority\": \"low|mid|high\"}}"),
("human", "{text}"),
])
chain = prompt | llm | JsonOutputParser()
print(chain.invoke({"text": "The confirmation email never arrives, but the payment went through"}))The line count is about the same. There is no saving in size; the benefit comes later, because the prompt | llm | parser chain is easy to extend with another step. The downside is that part of what happens is hidden: the final prompt text and usage have to be fetched separately (for example from AIMessage.usage_metadata if you call the model without the parser). LangChain class and package names change between versions, so check their documentation. Another walkthrough is in LangChain through a gateway.
Where a framework helps
- Several providers in one codebase. If you want to switch between model families without rewriting calls. With Zukko that is already a one-line change of
model, but LangChain offers ready abstractions. - RAG and document handling. File loaders, chunking and vector stores take a long time to write from scratch.
- Agents with tools and state. If you need a graph of steps with branching, ready primitives save time.
- The team already knows the framework. That is a legitimate reason: a shared style is worth more than theoretical purity.
Where a framework gets in the way
- One or two model calls. The framework pulls in extra packages for something that fifteen lines can do.
- Debugging. When an answer looks odd you need the exact messages sent to the API. In the plain SDK that is a dictionary in your code; in a framework it is the output of several layers.
- Tokens and money. A chain or an agent makes as many calls as it needs, and each one carries the accumulated context. You only see it if you count.
- Updates. Framework interfaces change, and code written a year ago may need fixes. A thin SDK has a smaller surface.
Token control: a worked example
Say a LangChain agent takes five steps and each step adds about 1000 tokens to the context. Inputs per step: 2000, 3000, 4000, 5000, 6000 tokens, 20,000 in total. Output is 300 tokens per step, 1500 in total.
For gpt-6.1-sol (prices as of October 18, 2026: $0.27 per 1M input, $1.32 per 1M output):
input: 20,000 × 0.27 / 1,000,000 = $0.0054
output: 1,500 × 1.32 / 1,000,000 = $0.00198
total: about $0.0074 per task
The sum is small, but if you had budgeted the task as "one call of 2000 tokens" ($0.00054 for input), the real input cost is ten times higher. So, whichever option you choose, it helps to:
- Log
usagefor every call (resp.usagein the SDK,usage_metadataon the message in LangChain). - Watch spend in the dashboard under "Usage" and compare it with your estimate.
- Estimate request size up front with the token counting endpoint.
The current list of models and prices is GET https://api.zukko.pro/v1/models or the "Models" page in the dashboard.
A simple rule
| Situation | What to take |
|---|---|
| One to three model calls, clear logic | plain OpenAI SDK |
| You need tight token control and easy debugging | plain SDK, add a framework later |
| RAG with several sources, ready loaders | LangChain or similar |
| Agent with branching and state | a framework, but log usage |
| An evening prototype | whatever is faster for you |
Start with the SDK and add a framework once you know which of its parts you actually need. Removing a framework from a finished project is usually more expensive than adding one. Test the choice on your own task: for a small scenario writing both versions is not much work.
To try it, create a key in the dashboard and put it together with https://api.zukko.pro/v1 into any of the examples above. Python docs are here.
FAQ
Can I use the OpenAI SDK and LangChain together?
Yes. A common setup is LangChain for loading documents and search, with the model call itself made through the SDK or through ChatOpenAI with the same base_url. They do not conflict, and both go through one key.
Is LangChain slower than the plain SDK?
The framework layer adds a little processing overhead, but most of the time is the model's answer. We give no numbers: measure on your data. The difference is more visible in how many calls a chain makes.
Do I need to change code when switching models?
For both options it is enough to replace the model string, for example with claude-sonnet-5-5 or deepseek-v4.1-flash. If you rely on something specific to one model (tool format, cache), test that behavior separately.
What if I need the Anthropic format?
Then use the official Anthropic SDK with the address https://api.zukko.pro without /v1. It is a separate client; LangChain has its own package for it, but check its documentation.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- LangChain Ollama or a cloud model: one codebase, two modelsChatOllama runs a model on your machine, ChatOpenAI with a gateway base_url calls a cloud one. We write the code once and switch with environment variables.
- GPT-6 Astra or Claude Fable 5.1: Two Top Models by Price and IndexTwo premium models with the same intelligence index and different Zukko prices. We price a single request and an agent session with cache, and explain how to choose on your own data.
- Prompt Injection: What It Is and How to Protect a Bot and an AgentHow prompt injection works through user input and third-party documents, and which measures limit the damage: data isolation, tool permissions, key limits.
- Your Own Neural Network Proxy on Node.js: Keep the API Key Off the FrontendA small Express server between your frontend and the model API: the key stays on the server, and models, request size and rate are capped.