今日已更新 240 条资讯 | 累计 23823 条内容
关于我们

标签:#webdev

找到 1713 篇相关文章

开发者

WebP vs AVIF vs PNG vs JPEG: A Practical Format Guide for 2026

After spending 2 years building an image compression tool, here's my no-nonsense format guide. ## The Rule | If it's... | Use... | |---|---| | Logo, icon, screenshot | PNG | | Photo, everyday image | WebP | | Smallest possible file | AVIF | | Maximum compatibility | JPEG | ## Why? PNG — Lossless. Keeps text and sharp edges crisp. Supports transparency. But files are large for photos. JPEG — Works literally everywhere since 1992. Good compression for photos. No transparency support. At 80-85% quality, the visual difference from 100% is invisible but the file is half the size. WebP — The sweet spot. 25-35% smaller than JPEG with same quality. Supports both lossy and lossless. Supports transparency. Every modern browser supports it now (97%+ global coverage). For most websites, this is the right answer. AVIF — The next-gen format. 50% smaller than JPEG, 30% smaller than WebP. Supports HDR, 12-bit color, and both lossy/lossless. The catch: not supported on older devices (iOS 15 and below). Use it with a <picture> fallback. ## Real Numbers I ran the same photo through all four formats at comparable quality: JPEG (90%): 842 KB PNG: 3,241 KB WebP (90%): 547 KB AVIF (90%): 382 KB WebP cut the JPEG size by 35%. AVIF cut it by 55%. ## What I Recommend I built CompressFast ( https://compressfast.site ) — a free browser-based image compressor that handles all these formats. No uploads, no servers, everything runs locally.

2026-07-22 原文 →
AI 资讯

Stop Screenshotting Architecture Diagrams: Build Them as Single-File HTML

TL;DR Spent today rebuilding two training diagrams — a layered reference architecture and a workflow swimlane — as single-file HTML instead of exported images. The trick: data in a plain JS array, layout in CSS Grid, connectors in an SVG overlay measured at runtime . Result: diagrams you can step through, click into, and hand over as one file that opens offline. Why not just export a PNG? Because a screenshot is stale by the next sprint, and nobody re-opens the drawing tool to fix it. Approach Editable by a dev Interactive Portable PNG from a drawing tool No (need the source file) No Yes Mermaid in a doc Yes No Needs a renderer Hand-built HTML Yes (it's a data array) Yes One file, opens anywhere The third option costs a few hours once. After that, updating a component is editing one object in an array. Separate the data from the drawing This is the whole design. Nothing about position, colour, or DOM lives in the content: const TIERS = [ { key : ' clients ' , label : ' Clients ' , sub : ' consumers · admins ' }, { key : ' edge ' , label : ' Edge ' , sub : ' TLS · load balancing ' }, // ... ]; const COMPONENTS = [ { id : ' app ' , tier : ' app ' , x : . 34 , label : ' Control Plane ' , tech : ' PHP-FPM ' , role : ' Governance UI and sync orchestration. ' , points : [{ type : ' info ' , text : ' Pushes approved config downstream ' }] }, // ... ]; const LINKS = [[ ' consumers ' , ' edge ' ], [ ' edge ' , ' gateway ' ], /* ... */ ]; tier picks the row. x is a fraction (0..1) across that row , not a pixel. So the layout survives any viewport without me hand-tuning coordinates. Layout: Grid for the boxes, SVG on top for the wires +--------------------------------------------------+ | lane label | [card 1] [card 2] [card 3] | <- CSS Grid row |------------+-------------------------------------| | lane label | [card 4] [card 5] | +--------------------------------------------------+ ^ ^ sticky column SVG overlay (position:absolute; inset:0) draws paths between measured centre

2026-07-22 原文 →
AI 资讯

I launched to zero signups, then found 5 features nobody could reach

I spent months building an AI agent platform. I launched it on Product Hunt yesterday. Zero signups. The comments were friendly. Three of the four asked for the same thing — not features, not integrations, not a lower price. They wanted to see what the agents did and what they cost . One put it better than my own landing page ever did: they liked that it wasn't "a black box." So I went to make the cost dashboard better. Instead I found out my product had been lying to me for months, and the lies had a pattern. Here's everything, with the code. 1. Every run cost $0.00 The Cost Analytics page reported $0.02 in total across ~100 executions . I'd assumed that meant the platform was cheap to run. It meant the data was being destroyed at write time. cost_cents = int ( ( llm_response . prompt_tokens * 0.5 / 1000 ) + ( llm_response . completion_tokens * 1.5 / 1000 ) ) A typical run on my platform is 56 prompt tokens and 45 completion tokens. That's 0.0843 cents . int() makes it 0 . Not some runs. Essentially every run — because almost every LLM call costs less than one cent. The production numbers: 189 agent runs, 2 with a non-zero cost. 99% of my cost data was zeroes, and the two survivors were just big enough to clear a whole cent. The rates in that formula were correct. I checked them against the providers' pricing pages; the arithmetic is right. The bug is entirely int() on a value that is almost never ≥ 1. A Decimal would have been the textbook fix, but Decimal / float raises TypeError and ~80 call sites do arithmetic on this number, so I widened the column to a float and kept the unit (cents). It's a dashboard estimate, not money — Paddle handles money — so float rounding is irrelevant here. 2. Workflow costs were never recorded at all Truncation at least loses precision. This one lost everything. WorkflowExecution.total_cost_cents and total_tokens_used had no write site anywhere in the codebase . Not a broken write — no write. The columns had been NULL since the feat

2026-07-22 原文 →
AI 资讯

Your API Retried the Request. Your Customer Got Charged Twice.

A customer clicks the Pay button, the server sends the request to a payment provider, and the charge succeeds. The trouble begins when the response never reaches the browser because the connection drops. The frontend sees a timeout and retries the same request, while the backend treats it as a brand-new payment. One customer action has now created two valid charges. This kind of failure is easy to miss because every part of the system appears to behave correctly on its own. The browser retries because it never received a response, the API processes a valid POST request, and the payment provider accepts the instruction it was given. The defect sits between those systems, where no component has enough context to know that the second request is a repeat. The same pattern can create duplicate orders, emails, subscriptions, shipments, support tickets, or background jobs. The common advice is to retry failed requests, but that advice is incomplete. A retry is safe only when the server can distinguish a repeated business operation from a new one. For payment APIs, that usually means introducing an idempotency key, storing the original result, and protecting the write path against race conditions. The rest of this article walks through that flow using Node.js, Express, and PostgreSQL. The bug starts with a normal-looking endpoint Consider a small Express endpoint that creates a payment by calling an external provider. The code receives the request body, sends the amount and customer data to the provider, and returns the resulting payment object. Nothing about this route looks obviously unsafe during a basic code review, and the happy-path test is likely to pass without trouble. The risk appears only when the request succeeds remotely but the response is lost before the client receives it. `app.post("/payments", async (req, res, next) => { try { const payment = await paymentProvider.charge({ customerId: req.body.customerId, amount: req.body.amount, currency: req.body.currenc

2026-07-22 原文 →
AI 资讯

The Bugs I Didn't Write And The Assumptions That Caused Them

This week I accidentally created my first vibe coded application. You might ask how one does this accidentally, but it's actually easier than you think. Assumptions Made: The first mistake I made was to assume that Claude remembered my setup and how I like to pair program. I have only had one previous project coded with the help of Claude and GHCP and it's a much more basic application than what I was building this week. I assumed, incorrectly, that Claude would 'remember' how I liked to work and go through the project with me as we make decisions and coding blocks together. The other assumption I made was giving a somewhat blanket approval for Claude to just run with things. I thought at some point Claude would stop, check its understanding during development and then continue but I got excited at the idea of using subagents and once I'd selected that option there was no stopping Claude on its rampage through my code! So What's the Project? I've recently started looking at doing more work with AI rather than just prompting Claude or GHCP to help with the day to day. I wanted to actually call an LLM and sift through information which could then be saved in a DB and recalled at a later point. I set myself a four week plan (with the help of Claude) to help solidify my learning with week one being a basic console application in C# that takes some text, sends to an LLM and then extracts certain information, in this case names of people, which is saved into a Postgres database. Sounds simple right? Where things went right This project started off very interesting. I had a conversation with Claude, same as I would with another developer, about the right LLM to use for this project. We went through the positives, negatives and the potential cost benefits and pitfalls of each option. In the end it was narrowed down to two choices, OpenAI or Gemini. Given that I was experimenting quite a bit and I didn't want to accidentally run up costs, I decided to go with Gemini's free t

2026-07-22 原文 →
AI 资讯

Late Night Shipping Safi Budget Engine Updates & Render Deployment published

Finished up a solid coding sprint tonight working on Safi-Budget a financial management application built around the 50/30/20 budget framework. I'm currently building and training over at Zone01Kisumu , and getting this build updated and deployed live was the main goal for today's session. What Was Updated Today Localized Currency Logic: Updated the core engine defaults from EUR over to** KES** (Kenyan Shillings) to better support local financial tracking workflows. Auth Flow Refinements:** Ironed out session management and routing logic to ensure clean sign-in and logout behavior across the app. Containerization & Deployment:** Confirmed the Go backend containerizes smoothly with Docker and runs cleanly on Render. Tech Stack Language: Go (Golang) Containerization: Docker Deployment Platform: Render Live Demo & Link You can test out the live deployment here: 👉 Safi Budget Engine Live App

2026-07-22 原文 →
AI 资讯

Build a Crypto Payment Module for SaaS Apps

Most SaaS products do not need a “crypto payment button.” They need a payment module. That distinction matters. A button can redirect a customer to a payment page. A module has to know which user is paying, which workspace should be upgraded, which plan should become active, when access should expire, how failed or expired payments should be handled, how support can inspect payment status, and how finance can export records later. That is where developers can build a serious product. A Crypto Payment Module for SaaS Apps is a reusable layer that lets SaaS builders add crypto payments without building the whole payment lifecycle from scratch. In this article, I will use OxaPay as the example crypto payment infrastructure because its documentation exposes the primitives needed for this kind of module: invoice generation, white-label payments, static addresses, webhooks, payment information, payment history, SDKs for PHP, Python and Laravel, and automation integrations. This is not a “get rich with crypto APIs” article. It is a practical blueprint for developers who want to build something SaaS founders, indie hackers, agencies, and product teams may actually pay for. The core idea A Crypto Payment Module gives SaaS apps a production-ready way to accept crypto payments and translate payment events into SaaS account states. Instead of selling this: I can integrate crypto payments into your app. You sell this: I can give your SaaS a reusable crypto billing module with invoices, payment status tracking, webhook verification, plan activation, grace periods, admin tools, and payment history sync. That is a much stronger offer. A SaaS founder does not only care that a payment happened. They care that the right account is upgraded, the right plan is applied, the right billing period is extended, the right user sees the right status, and the support team can understand what happened when something goes wrong. That is what your module should solve. Why this is a real developer

2026-07-22 原文 →
AI 资讯

How MCP Is Changing Website QA Workflows for Development Teams

Modern development teams use CI/CD pipelines, automated testing, feature flags, and AI-assisted coding to release new functionality multiple times per week. Yet despite all of these improvements, one part of the delivery process often remains surprisingly inefficient: website feedback. Clients still send screenshots through email. Designers leave comments in Slack. QA engineers create tickets manually. Developers spend time figuring out where an issue actually occurred before they can even begin fixing it. As AI becomes increasingly integrated into software development, another technology is beginning to reshape this workflow: the Model Context Protocol (MCP) . Rather than treating website feedback as disconnected conversations, MCP makes it possible for AI systems to understand the context surrounding a reported issue, helping development teams reduce unnecessary back-and-forth and resolve problems faster. Why Website QA Still Creates Bottlenecks Most website review processes haven't changed much over the past decade. Someone spots an issue, takes a screenshot, writes a short description, and sends it to a developer. The developer then has to answer a familiar set of questions. Which page? Which browser? Which screen size? Can you reproduce it? What exactly were you clicking? The actual bug may only take a few minutes to fix, but understanding the issue can consume considerably more time. As websites become increasingly dynamic, reproducing reported problems becomes even more difficult. Personalization, authentication, browser differences, JavaScript frameworks, and responsive layouts all introduce variables that aren't captured in a simple screenshot. Why Context Matters More Than Ever AI coding assistants have dramatically improved developer productivity. However, AI is only as useful as the context it receives. If an assistant only receives a vague message such as: "The button doesn't work." there is very little it can do. Now compare that with a report containi

2026-07-22 原文 →
开发者

I'm speaking at React Day Berlin 2026 — bridging React into a Preact form engine

I'm excited to share that I'll be speaking at React Day Berlin 2026 this December! My talk How I Brought React Into a Preact Form Engine: A Production Bridge Pattern I'll walk through how we integrated React into an existing Preact-based form engine in production — the bridge pattern we used, the trade-offs, and what I'd do differently next time. Duration: up to 20 minutes Dates: December 4 & 7, 2026 Format: remote or in-person (TBD) Join me (free stream access) You can register through my speaker badge and get partial free access to watch the stream: 👉 My React Day Berlin 2026 badge Speaker page: reactday.berlin/#person-sam-abaasi ReactDayBerlin #react #preact #javascript #webdev See you there!

2026-07-22 原文 →
AI 资讯

From Release Notes to Product Demo: A Repeatable AI Video Workflow for SaaS Teams

A practical workflow for turning release artifacts into an accurate, reviewable SaaS product demo without inventing product details. Shipping a feature and explaining it are different kinds of work. The code may have tests and a clean deployment path. The material needed to explain the feature is scattered across tickets, release notes, draft docs, screenshots, and a rushed screen recording. Consider a fictional SaaS team releasing workspace permissions. The feature adds Owner, Editor, and Viewer roles, plus a log of permission changes. By release day, most inputs already exist. The challenge is turning them into one accurate product demo without asking the workflow to guess. Treat release material as a versioned input bundle, then review the script and storyboard before generating video. Why shipping the feature is easier than explaining it Engineers and product managers see the feature as a diff. Viewers do not. A ticket might say "enforce role checks at the workspace boundary," while a customer needs to know where to choose Viewer and what that person can access. That translation is where demos drift. A script can inherit an internal name, skip a prerequisite, show an old label, or turn a planned benefit into a shipped claim. Set one rule before starting: the video cannot introduce a product fact that is absent from the release bundle. Every UI action must also map to the released build. Build a release-to-video source bundle Store the material in a release-specific folder with the release tag or build date. Give each input an owner who can resolve conflicts. Input What it contributes Owner Release note Shipped scope and exclusions Product manager Audience and job One viewer and the task they need to complete Product or PMM Approved claims Language the team can defend Product and legal, if needed Help-center draft Prerequisites, steps, and edge cases Docs or customer education Three current screenshots Exact labels and important UI states Designer or feature owne

2026-07-22 原文 →
AI 资讯

What is a context window, actually?

AI is moving fast, and it feels like there's a new concept to learn every week. In an effort to actually understand this whole new world instead of just skimming past it, I've been writing ELI5 articles breaking down concepts that show up constantly in AI conversations but rarely get explained simply. This time, a term that gets thrown around a lot without much explanation: the context window. AI 101 Recap The context window is the total number of input and output tokens an LLM can consider while generating a response. Your prompt, the conversation history, and even the model's response all share that same "budget" of tokens. As a conversation with an LLM grows longer, more tokens live in this window. So far so good. Every AI model has a limit on how many tokens it can hold in its "working memory" at once. So the interesting part with the context window is what happens when you reach these limits. Why are there limits? There are several reasons models have context window limits. Processing more tokens requires more memory and computation, making every request slower and more expensive. On top of that, today's models struggle to use very long contexts effectively. They naturally pay more attention to the beginning and end of a conversation than the middle ("lost in the middle" problem). The Amnesia Problem An AI model has no persistent memory between conversations. Within a long conversation, it only sees whatever still fits inside its context window. Think of it as a sliding window: as new messages come in, older ones eventually slide out and are no longer visible to the model. This is why a long conversation can feel like the model has "forgotten" something you told it early on. It doesn't actually forget, it just no longer has access to that part of the conversation, unless the product you're using has built something extra on top to handle it. How RAG helps RAG (retrieval-augmented generation) sounds technical, but the idea is simple: look it up before you answer

2026-07-22 原文 →
开发者

From Enterprise Procurement Systems to Building Browser-Based Developer Tools

Over the last 14+ years, I've been working with the Microsoft technology stack, designing and delivering enterprise applications for procurement, inventory management, warehouse operations, and EPOS systems. As a Tech Lead, I've worked on projects involving: Procurement & Purchase Order Management Inventory & Warehouse Management EPOS integrations Accounting integrations REST APIs & Microservices Azure cloud solutions Performance optimization and secure application design While enterprise software has always been my primary focus, I've recently been expanding my work with Next.js, React, and TypeScript by building browser-based productivity tools. One of my goals is to build applications that are fast, privacy-friendly, and solve real business problems directly in the browser whenever possible. Some of the tools I've been building include: YAML Studio for Kubernetes, Docker Compose, GitHub Actions, Azure DevOps, Helm, Prometheus, and Grafana configuration generation. JSON ↔ Excel Converter with support for nested JSON, multi-sheet exports, and parent-child relationships. Multilingual OCR for business documents. PDF to Excel with structured table extraction. JSON Formatter & Validator. CSV, Excel, and other data conversion tools. One thing I've learned while building document-processing tools is that file conversion is the easy part. The real challenge is preserving document structure—detecting tables, handling multi-line descriptions, reconstructing wrapped product codes, and generating output that users can actually work with instead of spending time cleaning it up. My experience in procurement has made this especially interesting because Purchase Orders, Delivery Notes, Goods Receipts, and Invoices all have different layouts and business rules. Building reliable tools requires understanding both the technology and the business process behind the documents. Alongside application development, I'm also continuing to strengthen my DevOps knowledge with Docker, Azure D

2026-07-22 原文 →
AI 资讯

Opinionated by Design: Why I Chose Sensible Defaults Over Endless Configuration

When people hear about a new project scaffolding tool, one of the first questions they ask is: "Can I choose React Query or TanStack Query?" "What about pnpm instead of Bun?" "Can I use ESLint instead of Biome?" "Can I choose Radix instead of Base UI?" "Can I skip Tailwind?" These are reasonable questions. In fact, I asked myself the same ones while building create-notils . My first instinct was to make everything configurable. The more I thought about it, the more I realized I was about to build something I didn't actually want to use. The Configuration Trap Most project generators start simple. Then someone requests another option. Another package manager. Another ORM. Another authentication provider. Another CSS framework. Another UI library. Eventually the CLI starts looking like this: ? Which package manager? ❯ npm pnpm yarn bun ? Which CSS framework? ? Which ORM? ? Which auth library? ? Which formatter? ? Which icon library? ? Which deployment target? It feels flexible. But every new option creates more combinations to support. Five choices in one prompt don't create five possible projects. They multiply with every other prompt. The complexity grows much faster than the number of features. I Built the Tool I Wanted to Use One thing I've learned from building side projects is this: the first user should always be yourself. Every project I start today uses almost exactly the same stack: Next.js 16 React 19 Bun Tailwind CSS v4 shadcn/ui Base UI Biome TypeScript Turborepo (when needed) I wasn't switching between ten different combinations every week. I was rebuilding the same foundation over and over. So instead of asking twenty questions during scaffolding, I decided to optimize for the workflow I actually have. npx create-notils my-app A few seconds later, I'm writing features instead of answering prompts. Opinionated Doesn't Mean Closed There's an important distinction between opinionated and restrictive . Some tools hide their implementation behind abstraction

2026-07-22 原文 →
AI 资讯

What Changed in Zod 4, and How I Migrated Production Schemas

Headline: Zod 4 is a rewrite of the TypeScript-first schema validation library, released as the stable major in 2025. Four changes hit my code directly: string formats moved to top-level functions ( z.email() instead of z.string().email() ), the four error options collapsed into one error parameter, error formatting moved to standalone helpers ( z.flattenError , z.treeifyError , z.prettifyError ), and .strict() / .passthrough() became z.strictObject() / z.looseObject() . The deprecated Zod 3 APIs still work with warnings, so I migrated incrementally. Key takeaways Zod 4 is the stable major of the TypeScript-first schema validator, released in 2025; it requires TypeScript 5.5 or newer. String formats are now top-level tree-shakeable functions — z.email() , z.uuid() , z.url() — and z.string().email() is deprecated but still works. A single error parameter replaces Zod 3's message , invalid_type_error , required_error , and errorMap . Error formatting moved to z.flattenError (form fields), z.treeifyError (nested), and z.prettifyError (human-readable string). The zod/mini build exposes the same validators through a functional, tree-shakeable API; z.infer , .parse() , and .safeParse() did not change. I reach for Zod on almost every project to validate untrusted input at the boundary — request bodies, form data, environment variables, API responses. Zod 4 changed enough of the surface that a mechanical upgrade tripped a handful of files, so I mapped exactly what moved. What actually changed in Zod 4? Zod 4 is a ground-up rewrite of the TypeScript-first schema validation library, released as the stable major in 2025. The headline is performance: the Zod team's release notes report large reductions in TypeScript compiler instantiations and faster runtime parsing, which matters most in large codebases where schema types dominate type-check time. Four API changes touched my code directly — string formats moved to top-level functions, the four error options collapsed into one,

2026-07-22 原文 →
AI 资讯

The Hard Part of a Global Birth-Chart Calculator Was Time

A birth-chart form looks simple: ask for a date, time, and place, then calculate. The interface may be simple. The input is not. 1992-11-01 01:30 does not identify one universal instant. It is a wall-clock reading that only becomes meaningful after you resolve the place, the historical time-zone rule, and any daylight-saving transition. If the time is unknown, inventing a convenient default can create chart features that were never supported by the user’s data. I ran into these problems while building AstroZen , a Next.js application that calculates a BaZi Four Pillars chart and a Western natal chart before generating an optional interpretation. The most important architectural decision was this: Calculation is an evidence pipeline. Interpretation is a separate layer. This post explains the calculation pipeline, the failure modes I had to remove, and why “unknown” must remain unknown. 1. A city name is not a coordinate Early prototypes often use a short city list or a default coordinate. That works for a layout demo, but it is not acceptable once location affects the result. Names are ambiguous: Paris can mean France or Texas. Springfield needs a state or region. Country abbreviations come in several forms. A valid city must resolve to both coordinates and a time-zone identifier. AstroZen sends the submitted city to Open-Meteo’s geocoding service, then scores the returned candidates against the requested country and optional region hint. It keeps the following structured result: type ResolvedPlace = { name : string ; region : string | null ; country : string ; countryCode : string ; latitude : number ; longitude : number ; timeZone : string ; // IANA, for example "Europe/Madrid" }; Candidate selection considers exact city-name matches, country matches, an optional region hint, and population as a small tie-breaker. Population never replaces the country check. The more important rule is what happens when resolution fails: if ( ! selected || ! countryMatches ( selecte

2026-07-22 原文 →
AI 资讯

Next.js 16 on Cloudflare Workers: what broke and what didn't

I shipped a Next.js 16 app on Cloudflare Workers via OpenNext. Not a demo. A real product with streaming chat, server components, D1 at the edge, and anonymous user sessions. Here is what broke, what barely worked, and what turned out to be surprisingly fine. The stack Next.js 16.2 (App Router) @opennextjs/cloudflare 1.19 D1 for SQLite at the edge Streaming chat via the AI binding (DeepSeek-V3 through a Workers proxy) React 19 Tailwind CSS 4 No auth wall, no OAuth, no database on the origin The site runs a few thousand sessions a week across ~30 persona pages, blog posts, guides, and learning content. Most pages are statically generated. The chat interaction is server-rendered components with streaming responses. What worked surprisingly well Static generation and ISR Pages, blogs, guides, persona pages — everything that does not need user-specific rendering — runs as static HTML at deploy time. Next.js 16 with generateStaticParams and fetch caching worked without modification. OpenNext handles the Cloudflare output format. The build step produces something Workers can serve. Revalidations are limited to Workers' cache API, but since most content changes at deploy time, I never hit that limit in production. The one caveat: revalidateTag() does not work the same way in a Workers runtime. Tags are Node.js memory constructs, and Workers are stateless. If you depend on tag-based revalidation for content updates, you need to either trigger deploys or accept stale-while-revalidate behavior from the CDN. D1 at the edge D1 was the least surprising part of the stack. SQL queries from Next.js route handlers feel like calling a regular database. Sessions store in D1, messages store in D1, and the latency is low enough that restoring a full chat thread from 30 messages takes under 200ms cold. The only sharp edge: D1 connections count against your Worker's concurrent request limit in development. With Next.js making its own fetch calls for compilation, I hit the D1 connection ce

2026-07-22 原文 →
AI 资讯

I Couldn’t Fix My LLM Costs Until I Measured Tokens Per Feature

My LLM bill kept growing, so I did what seemed obvious: I looked for a cheaper model. That helped a little, but it didn't explain why the bill was growing. The dashboard could tell me how many tokens the application used. It couldn't tell me what those tokens were doing. Were they coming from chat? Document summaries? Background classification? An agent retrying the same tool call? I was trying to optimize a total without knowing which product feature created it. The useful unit wasn't tokens per model . It was tokens per feature . Model-level totals hid the real problem A provider dashboard usually groups usage by model, API key, project, or time period. That is useful for billing, but not always for product decisions. Imagine an application with four LLM-powered features: interactive chat document summarization support-ticket classification an agent that prepares weekly reports If the bill increases by 30%, the model name doesn't explain which feature changed. Maybe chat traffic grew. Maybe summarization started sending entire documents instead of selected sections. Maybe the classifier received a much larger system prompt. Maybe the report agent retried after tool failures and generated the same plan several times. Those problems require completely different fixes. Switching every request to a cheaper model would reduce the bill, but it could also hide the engineering mistake. Tag every request with a feature I started giving every LLM call a small amount of application context: const context = { feature : " document_summary " , operation : " initial_summary " , customer_tier : " pro " }; The model provider doesn't need these fields. They belong in the application's usage record. I avoid using individual user IDs as the primary grouping dimension. For cost analysis, a product feature, workflow, or operation is normally more useful and creates fewer privacy problems. A practical record looks like this: { "timestamp" : "2026-07-22T03:12:48.201Z" , "feature" : "docu

2026-07-22 原文 →
AI 资讯

How We Translate Entire Books with LLMs Without Losing Context

Solving the context-window puzzle for book-length AI translation. At LectuLibre, we set out to build a service that translates entire books using large language models. The idea is simple: upload an EPUB or PDF, choose a language, and receive a polished translation. But behind the scenes, translating a hundred-thousand-word novel with LLMs isn't straightforward. The core challenge is context — LLMs have limited context windows, and books are long. Simply chopping the text into chunks and feeding each one independently leads to incoherent output. Character names change, pronouns lose referents, and tone veers wildly. Here’s how we solved that with a chunking strategy that preserves context, and the Python code that makes it tick. The Problem: Long Documents vs. Short Context Windows Modern LLMs like Claude 3 Opus can handle 200,000 tokens of context, while DeepSeek-V2 offers 128,000 tokens. That’s a lot — but a 50,000-word English novel translates to roughly 67,000 tokens (using Claude’s tokenizer). That just fits, but what about a 150,000-word fantasy epic? Even when it fits, sending an entire book in one prompt is costly, slow, and often degrades attention quality on long texts. The prevailing approach is to chunk the document. Naive chunking — say, splitting by a fixed token count — creates hard boundaries. One chunk ends, another begins, and the LLM has no idea what happened before. The result reads like a patchwork of isolated translations. We needed a method that gives each chunk enough surrounding context without exceeding token limits or breaking the bank. Our Approach: Sliding Window + Context Retrieval via Embeddings We adopted a two‑pronged strategy: Overlapping chunks : each chunk shares some sentences with the previous one, so the LLM can transition smoothly. Injected context : for every chunk, we retrieve and prepend the most relevant previous chunks, determined by embedding similarity. This way, the model always has a sense of what’s happening before a

2026-07-22 原文 →
AI 资讯

I built the performance engineering resource I wished existed - full stack, real code, 6 levels, no fluff

alright let me be real with you for a second i've been building production systems for a few years now, mostly backend with node and nestjs, react and next on top, and the one thing that always drove me absolutely crazy was how performance content online just doesn't respect your time you google "how to optimize react rendering" and you get a medium article with 47 claps that shows you useMemo on a counter app you google "how to optimize node performance" and you get a 2019 blog post that tells you to use async await neither of them has real numbers, neither of them shows you how to actually FIND the problem before you start fixing things, and absolutely none of them connect the frontend and backend story together so i spent the last few months building it myself what i built it's called frontend-backend-performance-mastery and it's structured across 6 levels, each level has a frontend folder (react, next.js, typescript) and a backend folder (node, express, nestjs), and every single folder follows the exact same 3-file structure detect.md — how to find the problem, what to look for, what tools to use, before you even open devtools fix.md — the actual fix, with a before and after, when to apply it, and just as important when NOT to apply it project/ — a fully runnable code example, npm install and npm run dev and you're looking at real numbers on your screen, not a screenshot from someone's laptop from 2021 the 6 levels level 01 — fundamentals: web vitals, profiling, baselines, benchmarking with clinic.js and autocannon level 02 — rendering: ssr vs csr vs ssg, react fiber internals, hydration, response streaming, fast-json-stringify level 03 — caching: react query, swr, service workers, redis, cache-aside pattern, cdn and http headers level 04 — database and api: n+1 queries, cursor pagination that stays fast at 10 million rows, dataloader, query optimization, indexes level 05 — advanced: wasm in next.js, worker threads, piscina, bull queue, grpc, node streams, code

2026-07-22 原文 →