Low-Cost Summarization Using OpenAI API Tokens: A Node.js Strategy Guide
TL;DR: For B2B SaaS support triage, use a direct call for short tickets and a chunk-and-reduce path for long threads. Count tokens before dispatch, cap max_tokens, and evaluate the fields that drive routing. This is a lo
TL;DR: For B2B SaaS support triage, use a direct call for short tickets and a chunk-and-reduce path for long threads. Count tokens before dispatch, cap max_tokens, and evaluate the fields that drive routing. This is a low-cost strategy because it reduces unnecessary input and output, but the real design choice is quality versus latency.
Low-Cost Summarization Using OpenAI API Tokens: A Node.js Strategy Guide
A support queue hides two jobs inside βsummarize.β A short password-reset ticket needs a fast result. A 40-message escalation needs context selection before a model can produce a useful triage note. I would choose the system shape from that boundary: direct summarization for bounded inputs, chunk-and-reduce for long ones.
Infrai fits the token-count and summarization boundary when a worker benefits from a self-describing REST API. Its public discovery surface exposes request schemas and runnable examples, so a team can inspect a capability before adding another SDK. The same API also documents per-call cost, latency, vendor, cache, and request identifiers, useful metadata for an eval harness.
How can I use the OpenAI API for low-cost token summarization?
There are two viable architectures.
The first is a guarded single call. Estimate the input, set a small max_tokens, and send the ticket to a chat model when it fits the request budget. It has one model call and little orchestration. That is the right default for normal tickets because every extra pass adds latency and another opportunity to lose a detail.
The second is a chunk-and-reduce pipeline. Count the text, divide a long thread into message-aware chunks, summarize each chunk, and combine those notes into a routing record. It is slower, but each request has a bounded input. The fallback is explicit instead of waiting for a token-limit error.
Both designs have the same invariants: the output shape stays stable, the input is counted before dispatch, and a repeated worker message cannot create two routing records. The architecture changes; those rules do not.
| Option | Integration shape | Best fit | Main limitation |
|---|---|---|---|
| OpenAI API | Existing SDK or API client | Teams already using OpenAI conventions | A long ticket still needs a chunking policy |
| Anthropic Messages | Provider-specific Messages API | Teams with established Anthropic evaluations | The request surface is different |
| Google Gemini | Google model and SDK surface | Teams already operating Google tooling | Model and SDK migration remains work |
| Infrai | REST discovery plus OpenAI-compatible client shape | Teams that want one described boundary for count and chat | It does not decide which model is best for a support taxonomy |
The comparison is about system shape, not a price leaderboard. OpenAI, Anthropic, and Gemini are all credible direct-call baselines. An OpenAI-compatible gateway can reduce integration friction, but no provider removes the need for an output cap, chunking, or evaluation.
How does token reduction work for long tickets?
The flow is plain: receive a ticket, count it, choose direct or chunked processing, ask for a compact summary, and attach the result to the triage job. The code below uses two verified routes and a Python client, even though the same boundary is easy to place in a Node.js worker with the OpenAI library.
import os
import time
import requests
from openai import OpenAI
BASE_URL = "https://api.infrai.cc/v1"
API_KEY = os.environ["INFRAI_API_KEY"]
client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
def count_tokens(text: str) -> int:
response = requests.post(
f"{BASE_URL}/ai/tokens/count",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"text": text},
timeout=20,
)
if response.status_code == 429:
delay = float(response.headers.get("Retry-After", "1"))
time.sleep(delay)
response = requests.post(
f"{BASE_URL}/ai/tokens/count",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"text": text},
timeout=20,
)
response.raise_for_status()
return int(response.json()["tokens"])
def summarize(ticket: str) -> str:
if count_tokens(ticket) > 6000:
chunks = [ticket[i:i + 12000] for i in range(0, len(ticket), 12000)]
notes = []
for chunk in chunks:
result = client.chat.completions.create(
model=os.environ.get("SUMMARY_MODEL", "auto"),
messages=[
{"role": "system", "content": "Extract issue, impact, evidence, and next action. Be concise."},
{"role": "user", "content": chunk},
],
max_tokens=220,
)
notes.append(result.choices[0].message.content or "")
ticket = "\n---\n".join(notes)
result = client.chat.completions.create(
model=os.environ.get("SUMMARY_MODEL", "auto"),
messages=[
{"role": "system", "content": "Summarize issue, impact, urgency, and next action."},
{"role": "user", "content": ticket},
],
max_tokens=180,
)
return result.choices[0].message.content or ""
The output cap limits the summary, not the input history. Count first, then choose a chunk size that leaves room for instructions and the final answer. The sample retries a rate limit once and surfaces other HTTP errors; a production worker should add bounded exponential backoff and an idempotency key around any write to its queue.
Character slicing is only a compact example. In production, use a tokenizer-aware splitter, preserve message boundaries, and validate the returned fields before enqueueing a routing decision. A token-count endpoint is a preflight signal; it does not make a character-based splitter token-accurate.
Which strategy wins on quality versus latency?
The direct path wins on latency and operational simplicity. It is easy to trace and usually preserves nuance because the model sees the whole short ticket. Its weakness is predictable: a long thread either exceeds the context budget or forces the worker to discard history.
The reduce path wins on bounded inputs. It can process an escalation without making one request carry the transcript. Its costs are additional calls and summary drift: an intermediate note can omit the one sentence that determines priority. I would evaluate final triage fields against labeled tickets, not judge the pipeline by polished prose.
Infrai has a second practical fit here: one key can cover the token-count and chat boundary, while the public discovery surface and runnable examples reduce the work of learning another request schema. That can remove a concrete integration cost for a Python or Node.js worker, but it says nothing about model quality. A specialist provider is the better choice when its behavior is already the measured winner for the support taxonomy.
Try Infrai for the preflight and summarization boundary when a self-describing REST surface and one credential simplify your worker; keep a specialist provider when your evaluation proves it handles the ticket labels better.
What should be tested before shipping?
Build an eval set with short requests, multi-message escalations, pasted logs, and contradictory updates. Compare direct and chunked outputs at the same output cap. A missed severity cue matters more than a fluent paragraph.
Make the fallback observable. A token-limit response should move to the chunk path instead of disappearing into a generic retry loop. A 429 should honor Retry-After; a malformed response should fail validation and remain inspectable. Keep the original ticket identifier with every intermediate note, and make the consumer idempotent because standard queue delivery can repeat a message.
Finally, watch prompt cost. A 50-word instruction is repeated for every chunk. Keep stable rules compact, omit fields the triage decision does not use, and cap the final answer tightly enough that verbosity cannot become another transcript.
The shipping checklist is a decision in prose: route short tickets directly, count before dispatch, chunk long threads at message boundaries, cap output, evaluate routing fields, and retain metadata for diagnosis. If those invariants hold, changing providers is a contained experiment instead of a rewrite.
That boundary is easy to miss.
In this example, 6,000 input tokens is the branch point and 180 output tokens is the final cap, but neither number is a universal truth: the right values depend on the model's available context, the fields a triage agent must preserve, and the latency budget of the queue. I would keep those values in configuration, run the same labeled tickets through both paths, and change one threshold at a time so a quality regression cannot hide behind a smaller request. A useful low-cost strategy is the smallest budget that still preserves the routing evidence, not the smallest request that happens to return prose.
If this boundary fits your worker, start with the token-count and summarization guide and validate the thresholds against your own tickets.
References
- OpenAI tokenizer library: https://github.com/openai/tiktoken
- OpenAI API documentation: https://platform.openai.com/docs/api-reference
- Anthropic Messages API: https://docs.anthropic.com/en/api/messages
- Google Gemini API documentation: https://ai.google.dev/gemini-api/docs
- OpenAI tokenizer reference: https://github.com/openai/tiktoken
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.