惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
WordPress大学
WordPress大学
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
小众软件
小众软件
人人都是产品经理
人人都是产品经理
美团技术团队
Blog — PlanetScale
Blog — PlanetScale
S
SegmentFault 最新的问题
博客园 - 【当耐特】
V
V2EX
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 叶小钗
Google DeepMind News
Google DeepMind News
量子位
罗磊的独立博客
月光博客
月光博客
N
Netflix TechBlog - Medium
大猫的无限游戏
大猫的无限游戏
博客园_首页
P
Proofpoint News Feed
Jina AI
Jina AI
云风的 BLOG
云风的 BLOG
博客园 - 司徒正美
腾讯CDC

Hacker News - Newest: "LLM"

GitHub - lechmazur/position_bias: A benchmark for testing whether LLM judges keep the same preference when two lightly edited versions of the same story are shown in opposite orders. Flex routing (EU and EFTA) Dark Factories: Retooling for LLM Velocity Ask HN: What would be the impact of a LLM output injection attack? GitHub - Oaklight/llm-rosetta: Production-ready LLM API translation layer for Python — bidirectional conversion between OpenAI, Anthropic & Google formats via hub-and-spoke IR. Optional API gateway. Streaming & non-streaming. Zero core deps. Contributions welcome! GitHub - browser-use/browser-harness: Self-healing browser harness that enables LLMs to complete any task. GitHub - moeen-mahmud/remen: Remen turns thoughts into something you can return to Analyzing 156 LLM Launch Posts on Hacker News ChatGPT vs Gemini vs Claude: The Best LLM Subscription You Should Buy GitHub - salaamalykum/quran-semantic-search: High-density RAG Semantic Search Engine & Quran Corpus (GEO/SEO Architecture) GitHub - NVIDIA/TensorRT-LLM: TensorRT LLM provides users with an easy-to-use Python API to define Large Language Models (LLMs) and supports state-of-the-art optimizations to perform inference efficiently on NVIDIA GPUs. TensorRT LLM also contains components to create Python and C++ runtimes that orchestrate the inference execution in a performant way. The State of LLM Bug Bounties in 2026 Operational Readiness Criteria for Tool-Using LLM Agents Meshcore: Architecture for a Decentralized P2P LLM Inference Network How an LLM becomes more coherent as we train it GitHub - seetrex-ai/laimark GitHub - Jossifresben/BibCrit: AI-assited biblical textual criticism GitHub - wastedcode/memex: File system based wiki, maintained by Claude 99helpers.com GitHub - cliver-project/AITrigram GitHub - unbody-io/adapt: A self-evolving memory layer for AI agents. GitHub - hb20007/awesome-gen-ai-fails: A list of incidents where reliance on generative AI and LLMs resulted in harm to companies, individuals, or society GitHub - nevenkordic/localmind: Run any local LLM with persistent memory and context. CLI agent over Ollama with SQLite-backed hybrid recall. No cloud. Ask HN: What are the machine requirements for a LLM like Llama-3.1-8B? Faster LLM Inference via Sequential Monte Carlo grpo explained: group relative policy optimization for llm finetuning - cgft Stop comparing price per million tokens: the hidden LLM API costs · TensorZero Andrej Karpathy's LLM Wiki Is a Bad Idea GitHub - GG-QandV/mnemostroma: Offline RAM-first cognitive leer/coprocessor for AI agents and robotics. Solves "Context Abandonment" with 20-80ms latency using a dual-thread biomimetic memory architecture (ONNX + SQLite WAL). mempalace/agent at agent · skorotkiewicz/mempalace
GitHub - EvanPaules/ctx-opt: Context Window Optimizer
ep13 · 2026-05-14 · via Hacker News - Newest: "LLM"

npm version CI install size License: MIT

Intelligent context window optimization middleware for LLM applications. Drop it in front of any chat-completion call: it takes a messages[] array, trims or compresses it to fit a token budget, and returns the optimized array plus metadata describing exactly what it did.

  • Framework-agnostic — works with the OpenAI SDK, Anthropic SDK, or anything else that consumes a chat messages[] array.
  • Strict TypeScript types. ESM and CJS builds. Node 18+ and browser-friendly.
  • No required peer dependencies — bring your own LLM client.

Install

npm install ctx-opt

Quick start

import { ContextOptimizer } from 'ctx-opt';

const optimizer = new ContextOptimizer({
  maxTokens: 8_000,
  strategy: 'sliding-window',
  slidingWindow: { size: 12 },
});

const { messages, meta } = await optimizer.optimize(history);

// Now pass `messages` to your LLM client.
console.log(`saved ${meta.saved} tokens (${meta.compressionRatio.toFixed(2)}x)`);

One-line drop-in for OpenAI or Anthropic

If you're already using one of the major SDKs, wrap your client and stop thinking about it:

import OpenAI from 'openai';
import { withOptimizer } from 'ctx-opt/openai';

const ai = withOptimizer(new OpenAI(), {
  maxTokens: 8_000,
  strategy: 'sliding-window',
});

// chat.completions.create now auto-trims `messages` to fit the budget.
const res = await ai.chat.completions.create({
  model: 'gpt-4o',
  messages: longHistory,
});

console.log(ai.lastMeta); // { saved, compressionRatio, ... }
import Anthropic from '@anthropic-ai/sdk';
import { withOptimizer } from 'ctx-opt/anthropic';

const ai = withOptimizer(new Anthropic(), {
  maxTokens: 8_000,
  strategy: 'sliding-window',
  model: 'claude-haiku-4-5-20251001',
});

const res = await ai.messages.create({
  model: 'claude-haiku-4-5-20251001',
  max_tokens: 1024,
  system: 'you are concise',
  messages: longHistory,
});
import { generateText } from 'ai';
import { withOptimizer } from 'ctx-opt/ai-sdk';

const trimmedGenerate = withOptimizer(generateText, {
  maxTokens: 8_000,
  strategy: 'sliding-window',
});

const { text } = await trimmedGenerate({
  model: openai('gpt-4o'),
  messages: longHistory,
});

openai, @anthropic-ai/sdk, and ai are optional peer deps — install only the one(s) you use. See examples/ for OpenAI, Anthropic, summarizer-with-real-LLM, and LangChain.js integrations.

Strategies

Strategy Speed Quality Needs LLM call? When to use
sliding-window Fastest Good No Default. Cheap, predictable, lossy at the tails.
summarizer Slow Best Yes Long sessions where older context still matters.
relevance Medium High Yes (scorer) Heterogeneous histories where some turns clearly aren't relevant.
hybrid Slow Best Yes (both) Production: relevance-filter first, then summarize the rest if still over budget.

All strategies preserve the system prompt by default and never split a tool-use / tool-result pair across the boundary. Multi-modal content (images, files, audio) is preserved verbatim through optimization via the passthrough content-block type; the messages reach the LLM unmodified even if ctx-opt trims around them.

Benchmarks

Reproducible workload: a 60-turn synthetic support conversation (9.8k input tokens), budget = 30% of input (2.9k tokens). Cost basis: gpt-4o ($2.50 per 1M input tokens). Run npm run bench to regenerate.

Strategy Output tokens Saved $ saved/call $ saved/1k calls Compression Time
sliding-window 717 9,147 $0.02287 $22.87 92.7% 10ms
summarizer 628 9,236 $0.02309 $23.09 93.6% 23ms
relevance 2,644 7,220 $0.01805 $18.05 73.2% 18ms
hybrid 2,644 7,220 $0.01805 $18.05 73.2% 21ms

Numbers are wall-clock on a single laptop with mock LLM + scorer (so they isolate ctx-opt's own overhead from network latency). In production the LLM-using strategies will be dominated by the model round-trip, not ctx-opt.

Try it in your browser

Open the interactive playground to paste a chat history and watch all four strategies trim it side-by-side, with live token and dollar savings.

cd playground && npm install && npm run dev

API

new ContextOptimizer(config)

interface OptimizerConfig {
  maxTokens: number;                    // hard token budget for the output
  strategy: 'sliding-window' | 'summarizer' | 'relevance' | 'hybrid';
  model?: string;                       // for token-counting accuracy (default: 'gpt-4o')
  preserveSystem?: boolean;             // default: true
  recentWindow?: number;                // never-drop window size (default: 6)

  slidingWindow?: { size: number };

  summarizer?: {
    llmCall: SummarizerLLMFn;           // your LLM call — see "Plugging in your LLM"
    maxSummaryTokens?: number;          // default: 400
    triggerThreshold?: number;          // 0..1, default: 0.85
    recentWindow?: number;              // per-strategy override
    onError?: 'fall-back' | 'throw' | ((err: unknown) => void); // default: 'fall-back'
  };

  relevance?: {
    scorer: RelevanceScorerFn;          // your scorer — returns one score per message
    minScore?: number;                  // default: 0.2
    recentWindow?: number;              // per-strategy override
  };

  pricing?: Record<string, { inputUsdPerMillion: number }>;     // override built-in pricing table
}

Built-in relevance scorers

Don't want to write your own scorer? Two are shipped under ctx-opt/scorers:

import { ContextOptimizer } from 'ctx-opt';
import { bm25Scorer, createEmbeddingScorer } from 'ctx-opt/scorers';

// Pure-JS BM25 keyword scoring. Zero deps, zero network calls.
new ContextOptimizer({
  maxTokens: 8_000,
  strategy: 'relevance',
  relevance: { scorer: bm25Scorer(), minScore: 0.05 },
});

// Embedding-based scoring. Bring your own embed function.
import OpenAI from 'openai';
const openai = new OpenAI();
new ContextOptimizer({
  maxTokens: 8_000,
  strategy: 'relevance',
  relevance: {
    scorer: createEmbeddingScorer({
      embed: async (texts) => {
        const res = await openai.embeddings.create({
          model: 'text-embedding-3-small',
          input: texts,
        });
        return res.data.map((d) => d.embedding);
      },
    }),
    minScore: 0.3,
  },
});

The embedding scorer caches per-message vectors in-process so subsequent optimize() calls only embed new messages.

Cost tracking

When model is set to a known model, meta includes the dollar cost of the optimized input and the dollars saved versus the unoptimized array:

const { meta } = await optimizer.optimize(history);
console.log(`saved $${meta.savedUsd?.toFixed(4)} this call`);

Built-in pricing covers GPT-4o family, GPT-4 Turbo, GPT-3.5, o1/o3, the Claude 3.5 / 4.x family, and Gemini 1.5 / 2.0. Override or add your own via the pricing config option.

optimize(messages, input?)

Returns { messages, meta }. If the input is already within budget, the array is returned unchanged but meta is still populated.

interface OptimizeInput {
  task?: string;                        // current user goal — used by relevance strategy
  forceStrategy?: StrategyName;         // override config strategy for this call
}

countTokens(messages)

Token count for a messages array, including per-message overhead.

withinBudget(messages)

Returns true if countTokens(messages) <= maxTokens.

updateConfig(patch)

Apply a partial update to the config without creating a new instance.

Plugging in your LLM

The summarizer and relevance strategies need you to provide the actual model call. This keeps ctx-opt zero-dependency on any specific SDK.

Anthropic example

import Anthropic from '@anthropic-ai/sdk';
import type { SummarizerLLMFn } from 'ctx-opt';

const client = new Anthropic();

const llmCall: SummarizerLLMFn = async (messages, instruction) => {
  const res = await client.messages.create({
    model: 'claude-haiku-4-5-20251001',
    max_tokens: 400,
    system: instruction,
    messages: messages.map((m) => ({
      role: m.role === 'assistant' ? 'assistant' : 'user',
      content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
    })),
  });
  const block = res.content[0];
  return block && block.type === 'text' ? block.text : '';
};

OpenAI example

import OpenAI from 'openai';
import type { SummarizerLLMFn } from 'ctx-opt';

const client = new OpenAI();

const llmCall: SummarizerLLMFn = async (messages, instruction) => {
  const res = await client.chat.completions.create({
    model: 'gpt-4o-mini',
    messages: [
      { role: 'system', content: instruction },
      ...messages.map((m) => ({
        role: m.role === 'assistant' ? 'assistant' : 'user',
        content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
      })) as any,
    ],
  });
  return res.choices[0]?.message?.content ?? '';
};

The metadata object

Every call to optimize() returns a meta describing what happened:

Field Meaning
inputTokens Token count of the input messages[].
outputTokens Token count after optimization.
saved inputTokens - outputTokens.
compressionRatio outputTokens / inputTokens.
strategyUsed Which strategy actually ran (useful when forceStrategy is set).
messagesDropped Number of messages removed from the array.
messagesSummarized Number of messages that were folded into a summary.
withinBudget true if outputTokens <= maxTokens.
inputCostUsd Dollar cost of the optimized input. Undefined if model pricing is unknown.
savedUsd Dollars saved on input cost vs the unoptimized array. Undefined if model pricing is unknown.
fellBackTo Set when the requested strategy couldn't run cleanly and fell back (e.g. summarizer's llmCall threw → falls back to sliding-window).

Token counting accuracy

ctx-opt uses js-tiktoken for token counts.

  • OpenAI models — model-specific encoding when known, falling back to cl100k_base.
  • Anthropic modelscl100k_base is the closest publicly available approximation. Counts will be within a few percent of the official tokenizer.
  • A per-message overhead of 4 tokens is added to each message to approximate the role and formatting tokens (per OpenAI's chat-completion cookbook formula).

For exact Anthropic counts, use the built-in helper that delegates to Anthropic's messages.countTokens endpoint:

import Anthropic from '@anthropic-ai/sdk';
import { countMessageTokensWithAnthropic } from 'ctx-opt';

const client = new Anthropic();
const tokens = await countMessageTokensWithAnthropic(
  client,
  messages,
  'claude-haiku-4-5-20251001'
);

Status: pre-1.0

ctx-opt is at 0.x. The core API surface (ContextOptimizer, strategies, meta shape, SDK adapters) is settling but breaking changes are still on the table until 1.0. Each minor version (0.4 -> 0.5) may contain breaking changes; patch versions (0.5.0 -> 0.5.1) will not. The CHANGELOG calls out anything breaking explicitly.

Pin to a minor version in production:

"dependencies": { "ctx-opt": "~0.5.0" }

Browser bundle

The core works in the browser, but the underlying js-tiktoken encoding tables add ~2 MB to your bundle. That's fine for an internal tool or a server-rendered app but not for a tightly performance-budgeted client. For client-side use, consider running optimization on the server and streaming the result down.

Changelog

See CHANGELOG.md for the release history.

License

MIT