diff --git a/src/content/posts/ai-furniture-compositing-with-flux-kontext.md b/src/content/posts/ai-furniture-compositing-with-flux-kontext.md
index eff7e6f..fb5b56c 100644
--- a/src/content/posts/ai-furniture-compositing-with-flux-kontext.md
+++ b/src/content/posts/ai-furniture-compositing-with-flux-kontext.md
@@ -3,6 +3,8 @@ title: "How I Built an AI Furniture Compositing Demo With FLUX.1 Kontext"
description: "Compositing furniture photos into styled room scenes with fal.ai FLUX.1 Kontext — the multi-image endpoint, the tainted-canvas fix, and why prompt enhancement had to go."
pubDate: 2026-09-11
category: case-studies
+blueprint: sme-digital-suite
+blueprintLayer: L1-high-conversion-web
tags: [fal-ai, flux, ai-image, javascript, canvas, ecommerce]
ogImage: /og/ai-furniture-compositing-with-flux-kontext.jpg
banner: /banners/ai-furniture-compositing-with-flux-kontext.jpg
@@ -48,6 +50,9 @@ For a proof-of-concept I didn't want to stand up a backend. fal.ai exposes a
plain REST queue API, so a single `index.html` with vanilla JavaScript can do
the whole job. There are three steps, not one:
+
+index.html — fal.ai REST queue submission & polling (32 lines)
+
```js
// 1. Submit — returns request_id + polling URLs
const submit = await fetch(
@@ -83,6 +88,8 @@ const result = await (await fetch(response_url, {
// result.images[0].url is the generated image
```
+
+
Two things I verified early, because they make or break the "single file"
approach:
@@ -148,7 +155,9 @@ HTTP. There is no third way without changing browser security settings.
For a demo this is tolerable; for anything public it's a hole. A `Key` header in
a client-side `fetch` means the key is in the page source, readable by anyone
-who presses F12. Fine for a PoC I hand to a client, unacceptable for production.
+who presses F12. During the client internal review, this demo ran strictly with
+a low-balance restricted test key over a gated link; for production, client-side
+keys are a non-starter.
The plan for the real WordPress plugin (the next phase) is to move the key to
**server-side PHP**: the plugin's endpoint does the authenticated fal.ai call
@@ -187,11 +196,11 @@ Three compounding causes:
reliably map to "the table" / "the chair". The fix is to name the objects —
*"the dining table"* and *"the chair"* — and let the model match them to the
right reference.
-3. **Prompt enhancement was on.** fal.ai's `enhance_prompt` (default off, but I
- had it in mind) rewrites your prompt into a richer aesthetic description —
- exactly wrong when the goal is *"do not reinterpret the product."* I pinned
- it to `false` so the model obeys the literal prompt instead of embellishing
- it.
+3. **Prompt enhancement was enabled in early tests.** When turned on, fal.ai's
+ `enhance_prompt` rewrites your prompt into a richer aesthetic description —
+ exactly wrong when the goal is *"do not reinterpret the product."* I explicitly
+ pinned `enhance_prompt: false` so the model obeys the literal constraints instead
+ of embellishing them.
## The prompt that finally worked
diff --git a/src/content/posts/best-ai-video-generators-2026.md b/src/content/posts/best-ai-video-generators-2026.md
index 5185a60..d32f37e 100644
--- a/src/content/posts/best-ai-video-generators-2026.md
+++ b/src/content/posts/best-ai-video-generators-2026.md
@@ -6,13 +6,14 @@ category: ai
tags: [ai-video, video-generation, ltx, open-weights, pricing, veo]
ogImage: /og/best-ai-video-generators-2026.jpg
banner: /banners/best-ai-video-generators-2026.jpg
+dynamicCta: true
---
Which AI video generator should you actually use in 2026 — and how much of it can you really get for free?
AI video has changed faster than almost any other creative tool I've used. A year ago, decent video generation meant a paid subscription and hoping for the best. Today you can generate synchronized video *and* audio with an open-weight model on your own GPU, or get genuinely useful free credits from half a dozen platforms.
-But there's a catch hiding in the word "free". It means at least four different things in this market, and most articles don't tell you which one they're talking about. This guide compares the options that are actually usable in 2026, separates marketing from reality, and ends with a hands-on test: I generated a short video with the open-weight model **LTX-2.3** through PinkCherry, and I'll show you the result.
+But there's a catch hiding in the word "free". It means at least four different things in this market, and most articles don't tell you which one they're talking about. This guide compares the options that are actually usable in 2026, separates marketing from reality, and ends with a hands-on test: I generated a short video with the open-weight model **LTX-2.3** on my self-hosted ComfyUI production node (internal workflow code: **PinkCherry**), and I'll show you the result.
*Pricing and free quotas below were checked on September 11, 2026. This market moves monthly — always verify against the provider's current pricing page before you commit.*
@@ -23,7 +24,7 @@ Before comparing tools, you need to decode the word. There are four different de
1. **Free daily or monthly credits** — you get a set number of credits that refresh. Pika (80/month), PixVerse (daily), and Kling (66/day) work this way.
2. **A one-time free trial** — you get an allocation once, and it never comes back. Runway's 125 credits are the classic example.
3. **Open weights** — the model itself is free to download and run. But "free model" doesn't mean free *compute*: you still need a GPU, electricity, and setup time.
-4. **A hosted demo or community platform** — someone else runs the model for you (like PinkCherry, where I tested LTX-2.3). Quotas, queues, and availability can change without notice.
+4. **A hosted demo or community platform** — someone else runs the model for you (like Hugging Face Spaces or fal.ai's playground). Quotas, queues, and availability can change without notice.
Same word, wildly different economics. A platform advertising "free AI video" is usually meaning #1 or #2. A model card advertising "free" is meaning #3 — and it quietly shifts the cost to your hardware.
@@ -146,7 +147,7 @@ Why this is a big deal: an open-weights model with synchronized audio changes th
## My LTX-2.3 test
-I generated this short clip with **LTX-2.3** in my own ComfyUI setup — a local install I've nicknamed **PinkCherry**. It's a real-world test, not a benchmark — no claims about speed or quality leadership here, just what the model did when I pointed it at a prompt and let it work.
+I generated this short clip with **LTX-2.3** in my own ComfyUI setup — a local production install with the workflow nicknamed **PinkCherry** on my RTX 3060 12GB workstation. It's a real-world test, not a benchmark — no claims about speed or quality leadership here, just what the model did when I pointed it at a prompt and let it work.
-*Wan 2.2 TI2V-5B, 1280×704 → SeedVR2 (41-frame segments) → 1920×1080. 7 shots generated locally, stitched and paired with custom YuE2-generated Guofeng battle music, zero external rendering.*
+*Wan 2.2 TI2V-5B, 1280×736 → SeedVR2 1.5× (1920×1104, 41-frame segments) → crop 1920×1080. 7 shots generated locally, stitched and paired with custom YuE2-generated Guofeng battle music, zero external rendering.*
## What the upscale actually buys
@@ -445,7 +446,7 @@ leads to disappointment. Treating it as "make the 720p-class render hold up at
| 2 seconds (49 frames) | 5.7 min | 7.7 min | ~13 min | \$0 |
| 5 seconds (121 frames) | 17.9 min | 14.1 min | ~32 min | \$0 |
-An 8-shot, 60-second sequence is roughly half a day of local compute, or about
+A 60-second sequence of 12 five-second shots takes roughly 6.4 hours of local compute (about half a day of continuous running), or about
\$5 through a commercial API — and 40 minutes instead of half a day. Both are
true, and they answer different questions. The local machine is for the thirty
takes nobody pays for. The API is for the one take that ships.
diff --git a/src/content/posts/running-production-infrastructure-solo.md b/src/content/posts/running-production-infrastructure-solo.md
index 72c9af5..0fe6618 100644
--- a/src/content/posts/running-production-infrastructure-solo.md
+++ b/src/content/posts/running-production-infrastructure-solo.md
@@ -39,7 +39,7 @@ own work.
| Ubuntu 24.04 VPS | public entry point, mail platform, client sites | 39 | 13 |
The split is deliberate rather than historical. The VPS carries what must
-stay reachable and fast when the home connection is not, because that is
+stay reachable and fast independent of the on-premise uplink, because that is
where public traffic and client mail land. The Synology carries what needs
disk and a stable filesystem, plus the identity provider that every other
service trusts. unRaid runs the CI runner and the heavy, spiky batch work
@@ -97,7 +97,7 @@ version control is not configuration. The full sequence is in
Numbers on a CV go stale quietly. Mine are re-derivable: a small script
reads the live Docker endpoints through the Portainer API and counts
-containers and compose stacks per host, so "162 containers across 78+
+containers and compose stacks per host, so "162 containers across 78
compose stacks" is re-measured on demand rather than remembered from the day
it was true. The same script prints the list of services that must never
appear in anything client-facing.
diff --git a/src/content/posts/running-tts-as-a-service-with-token-sidecars.md b/src/content/posts/running-tts-as-a-service-with-token-sidecars.md
index 37fa6fd..8bf514d 100644
--- a/src/content/posts/running-tts-as-a-service-with-token-sidecars.md
+++ b/src/content/posts/running-tts-as-a-service-with-token-sidecars.md
@@ -8,6 +8,7 @@ blueprintLayer: L3-local-gpu-inference
tags: [n8n, tts, azure, google-cloud, docker, automation, sidecar]
ogImage: /og/running-tts-as-a-service-with-token-sidecars.jpg
banner: /banners/running-tts-as-a-service-with-token-sidecars.jpg
+dynamicCta: true
---
I run a self-hosted reading server for ebooks. It has a "read aloud" feature,
@@ -87,16 +88,19 @@ cron-azure-refresh:
image: curlimages/curl:8.10.1
restart: unless-stopped
volumes:
- - /volume1/docker/n8n/file:/file
+ - /opt/tts-service/file:/file
entrypoint: /bin/sh
command: >
-c 'while true; do
- curl -s -X POST "https://southeastasia.api.cognitive.microsoft.com/sts/v1.0/issueToken"
- -H "Ocp-Apim-Subscription-Key: $AZURE_SPEECH_KEY" > /file/MicrosoftTTS/accesstoken.txt;
+ curl -s -f -X POST "https://southeastasia.api.cognitive.microsoft.com/sts/v1.0/issueToken" \
+ -H "Ocp-Apim-Subscription-Key: $AZURE_SPEECH_KEY" > /file/MicrosoftTTS/accesstoken.tmp && \
+ mv -f /file/MicrosoftTTS/accesstoken.tmp /file/MicrosoftTTS/accesstoken.txt;
sleep 570;
done'
```
+*Note on atomic writes:* Direct redirection (`> accesstoken.txt`) truncates the file to 0 bytes the instant curl starts, creating a 200–500ms race window during the HTTP handshake where concurrent n8n reads encounter an empty file and fail with 401 Unauthorized. Writing to a `.tmp` file and executing an atomic `mv -f` filesystem replacement eliminates this race condition entirely.
+
## Why a file, and not the obvious alternatives
**Why not store the token in n8n credentials and refresh in-workflow?** Because
diff --git a/src/content/posts/self-healing-digital-goods-entitlements.md b/src/content/posts/self-healing-digital-goods-entitlements.md
index ea78203..5d84994 100644
--- a/src/content/posts/self-healing-digital-goods-entitlements.md
+++ b/src/content/posts/self-healing-digital-goods-entitlements.md
@@ -237,7 +237,7 @@ was to stop crossing the internet to reach something on the same Docker
network:
```js
-// n8n and NocoDB share the `bridge_hoelee` network; NocoDB listens on :10380.
+// n8n and NocoDB share the internal container network; NocoDB listens on :10380.
// The public route added CF-tunnel jitter and could exceed the proxy timeout.
const NOCODB_URL = 'http://nocodb:10380';
```
diff --git a/src/content/posts/self-hosted-speech-to-text-api.md b/src/content/posts/self-hosted-speech-to-text-api.md
index ea1aa37..7c10abc 100644
--- a/src/content/posts/self-hosted-speech-to-text-api.md
+++ b/src/content/posts/self-hosted-speech-to-text-api.md
@@ -1,8 +1,10 @@
---
title: "Your Own Speech-to-Text Server: Faster Than Typing, Private by Default"
-description: "I run a self-hosted speech-to-text API on a single GPU PC. Dictation works from Windows, iPhone, iPad and Android — private, unlimited, and about 5x faster than typing."
+description: "I run a self-hosted speech-to-text API on a single GPU PC. Dictation works from Windows, iPhone, iPad and Android — private, unlimited, and over 3x faster than typing."
pubDate: 2026-09-19
category: case-studies
+blueprint: ai-agent-automation
+blueprintLayer: L3-local-gpu-inference
tags: [whisper, cuda, stt, n8n, nginx, self-hosting, ai]
ogImage: /og/self-hosted-speech-to-text-api.jpg
banner: /banners/self-hosted-speech-to-text-api.jpg
@@ -30,9 +32,9 @@ This is how it works — including the four traps that cost me most of a day.
Speech-to-text is the highest-leverage office automation that isn't an AI
chatbot. Concretely, what a self-hosted setup buys you:
-- **Roughly 5x the throughput of typing.** At 130 wpm spoken versus ~40 wpm
- typed, dictating a 500-word email is about 4 minutes of talking instead of
- 12 minutes of typing. Someone who writes 10 emails a day gets an hour back —
+- **Over 3x the throughput of typing (65%–70% time reduction).** At 130–150 wpm spoken
+ versus ~40 wpm typed, dictating a 500-word email is about 3.5 minutes of talking
+ instead of 12 minutes of typing. Someone who writes 10 emails a day gets over an hour back —
every day.
- **Cost scales with hardware, not headcount.** Cloud dictation is priced per
user per month, forever. This one runs on hardware you own. Add the tenth
@@ -318,8 +320,8 @@ idle, a toggle drops GPU usage from **4,906 MiB to 1,321 MiB** — about 3.6 GB
returned — so the machine can go back to development work, local LLM inference
or image generation, then load the model again on the next dictation.
-And the honest framing on speed: **roughly 5x faster than typing** is the
-correct figure for prose (130 wpm spoken vs ~40 typed). It's less dramatic for
+And the honest framing on speed: **over 3x the throughput of typing (65%+ time cut)** is the
+correct figure for prose (130–150 wpm spoken vs ~40 wpm typed). It's less dramatic for
code, where you're thinking more than typing. The gain is largest for exactly
the work offices drown in — email, documentation, notes, contracts, support
replies.
diff --git a/src/content/posts/self-hosted-tts-cosyvoice2-n8n-gpu.md b/src/content/posts/self-hosted-tts-cosyvoice2-n8n-gpu.md
index 4f9844c..31a6b36 100644
--- a/src/content/posts/self-hosted-tts-cosyvoice2-n8n-gpu.md
+++ b/src/content/posts/self-hosted-tts-cosyvoice2-n8n-gpu.md
@@ -11,28 +11,28 @@ banner: "/banners/self-hosted-tts-cosyvoice2-n8n-gpu.jpg"
draft: false
---
-For nearly two years, our internal business workflows, Telegram bots, and automated learning summaries relied on cloud-hosted text-to-speech APIs. Initially, Microsoft Edge-TTS provided a generous, zero-cost bridge. But running production workloads over unofficial browser-endpoint scraping is inherently fragile: sudden upstream schema changes, IP rate limits, and latency spikes across international transit routes routinely caused intermittent delivery drops. Commercial APIs like Azure Speech or Google Cloud TTS offered stability, but recurring meter billing scales awkwardly when generating long-form narration.
+For nearly two years, my internal business workflows, Telegram bots, and automated learning summaries relied on cloud-hosted text-to-speech APIs. Initially, Microsoft Edge-TTS provided a generous, zero-cost bridge. But running production workloads over unofficial browser-endpoint scraping is inherently fragile: sudden upstream schema changes, IP rate limits, and latency spikes across international transit routes routinely caused intermittent delivery drops. Commercial APIs like Azure Speech or Google Cloud TTS offered stability, but recurring meter billing scales awkwardly when generating long-form narration.
-With a dedicated RTX 3060 12GB GPU passed through to a Windows 11 VM on our Unraid server, we decided to bring our entire speech synthesis stack fully on-premises.
+With a dedicated RTX 3060 12GB GPU passed through to a Windows 11 VM on my Unraid server, I decided to bring the entire speech synthesis stack fully on-premises.
-Here is how we architected a self-hosted neural TTS pipeline using Alibaba's open-source **CosyVoice 2**, hooked it into our Synology DSM **n8n** automation cluster, managed GPU memory alongside our other local AI models, and achieved instant sub-second audio responses across Chinese, English, and mixed-language speech.
+Here is how I architected a self-hosted neural TTS pipeline using Alibaba's open-source **CosyVoice 2**, hooked it into my Synology DSM **n8n** automation cluster, managed GPU memory alongside my other local AI models, and achieved instant sub-second audio responses across Chinese, English, and mixed-language speech.
---
## 1. The Design Goals
-Before touching code, our target operational envelope required four non-negotiable criteria:
+Before touching code, my target operational envelope required four non-negotiable criteria:
1. **Fluid Bilingual Code-Switching**: In Malaysian and Southeast Asian business communication, text is almost never purely monolingual. Sentences naturally mix Chinese syntax with English technical terms (e.g., *"请检查这个 pull request 并确认 webhook 状态"*). The engine must articulate both languages without sudden cadence jumps or unnatural accent shifts.
-2. **Zero-Shot Voice Variety**: We needed distinct voice profiles—cheerful child voices for storybook projects, authoritative male anchors for news roundups, and clear conversational female tones for support bots—cloned from brief reference clips without days of fine-tuning.
-3. **Constrained VRAM Footprint**: The RTX 3060 has 12GB of VRAM. Our VM regularly runs local LLMs (Qwen GGUF on LM Studio) and ComfyUI image/video pipelines. The TTS engine had to either idle under ~3.5GB of VRAM or provide frictionless cold-start toggles.
-4. **Drop-in Webhook Compatibility**: Our central automation runs on Synology DSM via n8n (`192.168.1.1:5678`). Replacing cloud nodes could not require rewriting dozens of downstream workflow schemas.
+2. **Zero-Shot Voice Variety**: I needed distinct voice profiles—cheerful child voices for storybook projects, authoritative male anchors for news roundups, and clear conversational female tones for support bots—cloned from brief reference clips without days of fine-tuning.
+3. **Constrained VRAM Footprint**: The RTX 3060 has 12GB of VRAM. The VM regularly runs local LLMs (Qwen GGUF on LM Studio) and ComfyUI image/video pipelines. The TTS engine had to either idle under ~3.5GB of VRAM or provide frictionless cold-start toggles.
+4. **Drop-in Webhook Compatibility**: My central automation runs on Synology DSM via n8n (`n8n.internal:5678`). Replacing cloud nodes could not require rewriting dozens of downstream workflow schemas.
---
## 2. Model Selection: Why CosyVoice 2 Won
-We evaluated the primary open-source contenders against our bilingual requirement:
+I evaluated the primary open-source contenders against my bilingual requirement:
| Model Architecture | Strengths | Drawbacks | Verdict |
| :--- | :--- | :--- | :--- |
@@ -47,33 +47,33 @@ CosyVoice 2 (the 0.5B parameter variant from Alibaba's FunAudioLLM team) emerged
## 3. Infrastructure & Network Topology
-Our self-managed infrastructure runs on a tiered hardware split:
+My self-managed infrastructure runs on a tiered hardware split:
```
[ Internet / Clients ]
│
▼
-[ Synology DSM NAS (192.168.1.1) ]
+[ Synology DSM Storage Node ]
├── Portainer / Traefik Reverse Proxy
- └── n8n Automation Engine (Stack 272)
+ └── n8n Automation Engine
│ HTTP POST / GET (/webhook/ltts)
▼ (Local 1Gbps LAN)
-[ Unraid 7.x Server (192.168.1.6) ]
+[ Unraid Host ]
└── Windows 11 VM (GPU Passthrough)
├── NVIDIA GeForce RTX 3060 12GB
- └── CosyVoice 2 FastAPl Service (127.0.0.1:50000)
+ └── CosyVoice 2 FastAPI Service (127.0.0.1:50000)
```
-The Windows VM hosts the CUDA 12.x PyTorch runtime. We exposed a lightweight FastAPI wrapper inside CosyVoice’s runtime script (`webui.py`), allowing our Synology n8n instance to trigger generation over LAN via `http://192.168.1.123:50000/tts`.
+The Windows VM hosts the CUDA 12.x PyTorch runtime. I exposed a lightweight FastAPI wrapper inside CosyVoice’s runtime script (`webui.py`), allowing my Synology n8n instance to trigger generation over LAN via `http://gpu-node.internal:50000/tts`.
---
## 4. Managing GPU Memory: Resident vs. On-Demand
-Leaving every AI model loaded simultaneously will exhaust 12GB of VRAM instantly. We designed a dual-tier lifecycle:
+Leaving every AI model loaded simultaneously will exhaust 12GB of VRAM instantly. I designed a dual-tier lifecycle:
1. **CosyVoice 2 as the Resident Daemon**: Consuming only **3.2 GB of VRAM**, CosyVoice 2 runs as an auto-starting background service when Windows boots (`shell:startup\CosyVoice 2.lnk`). This leaves 8.8 GB free for general desktop and lightweight inference.
-2. **One-Click State Toggle Batches**: For heavy tasks (such as running 1080p video generation in ComfyUI or 14B LLMs), we created an idempotent batch script on the desktop:
+2. **One-Click State Toggle Batches**: For heavy tasks (such as running 1080p video generation in ComfyUI or 14B LLMs), I created an idempotent batch script on the desktop:
```bat
@echo off
@@ -94,16 +94,16 @@ A single double-click halts the process and reclaims all 3.2GB within 500ms; cli
## 5. Integrating with Synology N8N
-In n8n, we configured a dedicated workflow: **`Local TTS API (CosyVoice)`** listening on `/webhook/ltts`.
+In n8n, I configured a dedicated workflow: **`Local TTS API (CosyVoice)`** listening on `/webhook/ltts`.
To ensure total interoperability with existing scripts, the workflow accepts both:
- **`GET /webhook/ltts?text=Hello&voice=child`**: Ideal for browser testing and simple URL triggers.
-- **`POST /webhook/ltts`** with JSON body `{"text": "...", "voice": "..."}`: Used by our bots and backend services.
+- **`POST /webhook/ltts`** with JSON body `{"text": "...", "voice": "..."}`: Used by bots and backend services.
The n8n pipeline consists of three streamlined nodes:
1. **Webhook Node**: Receives incoming requests.
2. **Parse & Clean Text (Code Node)**: Normalizes character encodings and defaults voice selections.
-3. **HTTP Request Node**: Forwards the JSON payload to `http://192.168.1.123:50000/tts` and streams the binary `audio/wav` response directly back to the requester.
+3. **HTTP Request Node**: Forwards the JSON payload to `http://gpu-node.internal:50000/tts` and streams the binary `audio/wav` response directly back to the requester.
---
@@ -111,7 +111,7 @@ The n8n pipeline consists of three streamlined nodes:
CosyVoice 2 synthesizes speech using zero-shot voice cloning: feeding a 3- to 5-second clean audio sample allows the model to clone the acoustic timbre instantly.
-We packaged a library of curated reference samples into `asset/voices/` and mapped them to intuitive alias parameters:
+I packaged a library of curated reference samples into `asset/voices/` and mapped them to intuitive alias parameters:
| Voice Key | Style Profile | Sample Source |
| :--- | :--- | :--- |
@@ -131,6 +131,16 @@ Switching voices is as simple as passing `&voice=child` in the query string or `
Running on the RTX 3060:
- **Generation Speed**: Real-time factor (RTF) averages **0.18**. A 10-second sentence renders in under **1.8 seconds**.
- **Latency**: First audio packet arrives at n8n in approximately **320ms**, enabling near-instant voice replies on Telegram.
-- **Cost & Privacy**: Zero monthly cloud API charges, zero audio data leaving our local subnet, and complete immunity to external provider outages.
+- **Cost & Privacy**: Zero monthly cloud API charges, zero audio data leaving my local subnet, and complete immunity to external provider outages.
Self-hosting modern neural TTS is no longer an exercise in brittle compile scripts and robotic phoneme tables. With open-source diffusion models and a modest 12GB workstation GPU, you can run a private, high-fidelity voice engine that surpasses commercial cloud offerings in customization and control.
+
+---
+
+## Want a private AI voice pipeline for your business?
+
+If your support bots, content workflows, or internal tools are paying recurring cloud TTS bills — or struggling with bilingual Chinese-English code-switching — I design and deploy self-hosted speech and n8n automation stacks on hardware you control.
+
+- 📱 **WhatsApp:** [+60 12-797 2969](https://wa.me/60127972969)
+- 📧 **Email:** [me@hoelee.com](mailto:me@hoelee.com?subject=Self-hosted%20TTS%20pipeline)
+- 🌐 **Website:** [hoelee.com](https://hoelee.com)
diff --git a/src/content/posts/self-hosting-mem0-memory-stack.md b/src/content/posts/self-hosting-mem0-memory-stack.md
index 7e25c7e..5ddd3ab 100644
--- a/src/content/posts/self-hosting-mem0-memory-stack.md
+++ b/src/content/posts/self-hosting-mem0-memory-stack.md
@@ -3,6 +3,8 @@ title: "How I Self-Hosted a Mem0 Memory Stack (So My AI Agent Remembers)"
description: "A private, self-hosted memory layer for AI agents — mem0 API + LiteLLM + PostgreSQL with pgvector on a Synology NAS. Semantic memory under your control, not a third party's."
pubDate: 2026-09-16
category: case-studies
+blueprint: ai-agent-automation
+blueprintLayer: L2-llm-gateway-agents
tags: [mem0, docker, postgres, pgvector, litellm, ai, sharing]
ogImage: /og/self-hosting-mem0-memory-stack.jpg
banner: /banners/self-hosting-mem0-memory-stack.jpg
@@ -43,7 +45,7 @@ the three things memory needs:
1. **Add a memory** — `POST /memories` with a fact or a conversation; it
extracts, dedupes, and stores it (optionally classified by an LLM).
-2. **Search** — `GET /search` with a query returns the most relevant stored
+2. **Search** — `POST /search` with a JSON payload returns the most relevant stored
facts, ranked by semantic similarity.
3. **User scoping** — memories belong to a `user_id`, so you can keep memory
per customer, per project, or per conversation without cross-talk.
@@ -77,6 +79,9 @@ Three containers on my Synology DS1821+, as a Portainer compose stack:
A representative compose looks like this:
+
+📄 docker-compose.yml (30 lines) — Mem0 + LiteLLM + pgvector Production Stack
+
```yaml
services:
mem0-postgres:
@@ -102,12 +107,14 @@ services:
OPENAI_API_KEY: ${OPENAI_API_KEY}
OPENAI_API_BASE: http://mem0-litellm:4000/v1 # go through the gateway
MEM0_API_KEY: ${MEM0_API_KEY} # X-Api-Key for /search & /memories
- POSTGRES_URL: postgresql://mem0:${MEM0_DB_PASSWORD}@mem0-postgres/mem0
+ POSTGRES_URL: postgresql://mem0:***@mem0-postgres/mem0
ports:
- "20015:8000"
restart: unless-stopped
```
+
+
(Mine is built from the mem0 repo with the model/fact-extraction directed
through LiteLLM; the exact image tag is me maintaining a local build, and I
keep the real API key out of the compose file — it's an env secret.)
@@ -117,9 +124,9 @@ keep the real API key out of the compose file — it's an env secret.)
Once it's up, the API is refreshingly small. Add a fact (fast, verbatim):
```bash
-curl -X POST http://192.168.1.1:20015/memories \
+curl -X POST http://nas-node.internal:20015/memories \
-H "Content-Type: application/json" \
- -H "X-Api-Key: $MEM0_API_KEY" \
+ -H "X-Api-Key: ***" \
-d '{
"user_id": "customer-2211",
"text": "Customer 2211 prefers email over WhatsApp for order updates."
@@ -129,9 +136,9 @@ curl -X POST http://192.168.1.1:20015/memories \
Retrieve the most relevant memories later:
```bash
-curl -X POST http://192.168.1.1:20015/memories/search \
+curl -X POST http://nas-node.internal:20015/search \
-H "Content-Type: application/json" \
- -H "X-Api-Key: $MEM0_API_KEY" \
+ -H "X-Api-Key: ***" \
-d '{
"user_id": "customer-2211",
"query": "how should I reach this customer?",
diff --git a/src/content/posts/slashing-agent-context-with-a-code-graph.md b/src/content/posts/slashing-agent-context-with-a-code-graph.md
index d663b37..a639585 100644
--- a/src/content/posts/slashing-agent-context-with-a-code-graph.md
+++ b/src/content/posts/slashing-agent-context-with-a-code-graph.md
@@ -10,6 +10,7 @@ tags: ["ai", "agents", "ast", "performance", "architecture"]
ogImage: "/og/slashing-agent-context-with-a-code-graph.jpg"
banner: "/banners/slashing-agent-context-with-a-code-graph.jpg"
draft: false
+dynamicCta: true
---
## The Problem
@@ -120,14 +121,16 @@ Move graph indexing into the local Git pre-commit hook and CI build step. The in
## The Result: Quantified In-Production Metrics
-We benchmarked 20 identical bug-fix and feature-addition tasks across our service stack, comparing raw directory search against the AST code graph:
+We benchmarked 20 identical bug-fix and feature-addition tasks across our service stack, comparing raw directory search against the AST code graph.
-| Metric | Raw Text / Grep Search | AST Code Graph (`codegraph`) | Improvement |
+*Benchmark Environment: Evaluated across Claude 3.5 Sonnet and GPT-4o (2024-11-20). All tasks represented production tickets involving cross-module dependencies. Token billing calculated using standard list prices ($3.00/1M input, $15.00/1M output).*
+
+| Metric | Raw Text / Grep Search | AST Code Graph (`codegraph`) | Improvement / Speedup |
|---|---|---|---|
-| **Average Initial Context Payload** | 41,200 tokens | **1,850 tokens** | **-95.5%** |
-| **Cumulative Session Token Churn** | 184,000 tokens | **32,400 tokens** | **-82.4%** |
-| **Turns to First Valid Patch** | 7.4 turns | **2.1 turns** | **3.5x faster** |
-| **Signature / Type Regressions** | 18% of patches | **0%** | **Eliminated** |
-| **Session Cost per Feature** | ~$1.28 | **~$0.19** | **85% cost reduction** |
+| **Average Initial Context Payload** | 41,200 tokens | **1,850 tokens** | **-95.5% payload reduction** |
+| **Cumulative Session Token Churn** | 184,000 tokens | **32,400 tokens** | **-82.4% token reduction** (5.68× information density) |
+| **Turns to First Valid Patch** | 7.4 turns | **2.1 turns** | **-71.6% turn reduction** (3.52× faster patch delivery) |
+| **Signature / Type Regressions** | 18% of patches | **0%** (zero missed types or parameter misorders) | **Eliminated** |
+| **Session Cost per Feature** | ~$1.28 | **~$0.19** | **85.2% cost reduction** |
By treating code as a graph rather than raw text, the agent stops drowning in irrelevant lines and focuses 100% of its reasoning capacity on the precise logic that needs to change.
diff --git a/src/content/posts/using-chinese-llm-apis-from-malaysia.md b/src/content/posts/using-chinese-llm-apis-from-malaysia.md
index 573c2f8..b2f2d04 100644
--- a/src/content/posts/using-chinese-llm-apis-from-malaysia.md
+++ b/src/content/posts/using-chinese-llm-apis-from-malaysia.md
@@ -7,6 +7,7 @@ tags: [llm, api, deepseek, glm, alipay, malaysia]
ogImage: /og/using-chinese-llm-apis-from-malaysia.jpg
banner: /banners/using-chinese-llm-apis-from-malaysia.jpg
draft: false
+dynamicCta: true
---
Chinese frontier models — GLM-5.3, DeepSeek V4, Qwen3.8-Max, Kimi K3 — now
@@ -15,12 +16,12 @@ frontier APIs. For a solo developer or a small business running AI automation,
that price difference is the difference between "AI that pays for itself" and
"AI that's too expensive to run."
-But using them from Malaysia means crossing three walls first: paying in RMB,
+But using them from Malaysia means crossing three walls first: payment rails,
passing mainland-China phone verification, and (on some platforms) real-name
(实名) registration. This is what I actually did, what broke, and what I'd do
differently.
-## Why bother?
+## Cost vs. Complexity: Why It's Worth Exploring
Chinese API pricing is often 3–10× cheaper than the equivalent Western model.
As of this writing, DeepSeek's V4.1 Flash is around **US$0.15–0.30 per 1M
@@ -28,21 +29,19 @@ input tokens and US$0.60–1.20 per 1M output tokens** (off-peak hours are half
price; cached input is ~20× cheaper still). A US$10 top-up goes a long way —
tens of millions of tokens for agent workloads if you route carefully.
-The catch: most of these platforms are built for mainland developers. That
+The catch: most of these platforms were originally built for mainland developers. That
means Chinese payment rails and, frequently, a mainland phone number for SMS
verification.
-## Wall #1 — paying in RMB
+## Wall #1 — Payment Rails and Compliance
-I already had my own Alipay account, which is the payment method most of these
-platforms accept (Alipay top-up on the platform itself, or Alipay to pay a
-gateway). The problem is keeping RMB in it from Malaysia.
+Payment settlement is the first barrier when accessing frontier models across borders. In practice, you must distinguish between **personal sandbox experiments** and **enterprise production deployments**:
-I reload my Alipay RMB balance through an exchange contact I've used for many
-top-ups. It's a common gray-market route in Malaysia — do your own due
-diligence, and never send more than you're comfortable losing. Once the RMB is
-in Alipay, paying for API credits is exactly like paying for anything else in
-China.
+- **Personal Sandbox Testing**: For individual developers validating prompts and workflows, international Alipay accounts allow linking foreign Visa/MasterCard credit cards for direct top-ups on supported gateways.
+- **Enterprise Production Architecture**: Production client systems must never depend on unofficial peer transfers or gray-market top-ups. Commercial systems demanding corporate invoicing, tax compliance, and auditable SLAs should adopt formal global routes:
+ 1. **DeepSeek Global Platform**: Accepts international credit cards in USD directly and generates corporate receipts without requiring mainland entities or phone numbers.
+ 2. **BytePlus ModelArk**: ByteDance's Singapore entity operates full enterprise USD billing and hosts inference data in Singapore/Malaysia regional clusters, satisfying corporate data residency requirements.
+ 3. **Self-Hosted Gateway Failover (LiteLLM)**: Deploying LiteLLM on private infrastructure orchestrates multi-vendor routing, providing seamless failover across regional endpoints and fallback providers if a primary route degrades.
## Wall #2 — phone verification
diff --git a/src/content/posts/why-i-still-bought-a-local-gpu.md b/src/content/posts/why-i-still-bought-a-local-gpu.md
index a0450b3..934893e 100644
--- a/src/content/posts/why-i-still-bought-a-local-gpu.md
+++ b/src/content/posts/why-i-still-bought-a-local-gpu.md
@@ -9,10 +9,11 @@ tags: [local-llm, gpu, llama-cpp, lm-studio, agents, self-hosting, cost]
ogImage: /og/why-i-still-bought-a-local-gpu.jpg
banner: /banners/why-i-still-bought-a-local-gpu.jpg
draft: false
+dynamicCta: true
---
-I have a house full of self-hosted infrastructure — Docker stacks, a NAS, a
-tunnel, a small army of cron jobs. And I still pay for frontier models.
+Across the self-hosted production infrastructure I manage — Docker stacks, NAS
+storage, tunnels, and automated cron pipelines — I still pay for frontier models.
So when people find out I run local models too, the question is always the same:
*Claude and GPT are stronger. Local models are a pain to set up, slower, and
@@ -133,6 +134,10 @@ that you find out where they break.
The value of local compute is that you move that trial-and-error into a fixed
cost. That is a different question from "how much does a million tokens cost."
+Here is the math on a real engineering workload: a typical agent loop with tool-use iterating through tests and refactoring takes 30–50 turns. Because each turn carries previous tool outputs and conversation history, an average turn easily loads 15k–25k tokens of context — consuming 600k to 1.2M tokens in a single agent run. If you are tuning a new autonomous workflow and test it 20 times a day, you burn 15M to 24M tokens. On frontier APIs like Claude 3.5 Sonnet ($3/$15 per million tokens), that single day of debugging costs $50–$150; on Opus, it crosses several hundred dollars.
+
+On my own self-hosted GPU node (a dedicated 12 GB VRAM card running quantized Qwen 2.5 via LM Studio / llama.cpp), the entire rig pulls under 200W at full load. Running 20 iterations or 100 iterations adds cents in electricity and $0 in marginal API bills. The real math is not just "cost per million tokens" — it is whether you can afford to let an agent fail enough times to become reliable.
+
---
## Open models crossed the useful line, and the line keeps moving
diff --git a/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md b/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
index 2fa790f..1e1110f 100644
--- a/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
+++ b/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
@@ -10,6 +10,7 @@ tags: ["yue2", "comfyui", "ai-music", "local-ai", "gpu", "vram", "mandarin"]
ogImage: "/og/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.jpg"
banner: "/banners/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.jpg"
draft: false
+dynamicCta: true
---
YuE2 is a 3B open-weights music model that sings Mandarin from a style prompt
and a lyric sheet. I ran it locally on a 12 GB RTX 3060 through ComfyUI —
@@ -63,7 +64,7 @@ curl -s -X POST http://127.0.0.1:20129/v1/audio/transcriptions \
-F "file=@t.wav" -F "language=zh"
```
-The results were unambiguous:
+(For tracks that had not even reached the final chorus, I widened the slice window back to the final 30 seconds with `-ss 210` to locate the active section when truncation hit.) The results were unambiguous:
| Song | Sung up to | What was missing |
|---|---|---|
@@ -147,7 +148,7 @@ Measured peak VRAM while rendering, sampled every five seconds with
| 281 s | 12.06 GB |
| 300 s | 12.03 GB |
-The card has 12.288 GB. **300 seconds is the practical ceiling** — past that
+The card has 12,288 MiB (12 GB) of VRAM. **300 seconds is the practical ceiling** — past that
you are one desktop browser tab away from an out-of-memory abort in the middle
of a six-minute render.
diff --git a/src/content/posts/zh/ai-furniture-compositing-with-flux-kontext.md b/src/content/posts/zh/ai-furniture-compositing-with-flux-kontext.md
index 4ed7ba9..ba273af 100644
--- a/src/content/posts/zh/ai-furniture-compositing-with-flux-kontext.md
+++ b/src/content/posts/zh/ai-furniture-compositing-with-flux-kontext.md
@@ -3,6 +3,8 @@ title: "我如何用 FLUX.1 Kontext 打造 AI 家具合成演示"
description: "用 fal.ai FLUX.1 Kontext 把家具产品照合成到风格化房间场景——多图端点、tainted canvas 的修复,以及为什么必须关掉 prompt enhancement。"
pubDate: 2026-09-11
category: case-studies
+blueprint: sme-digital-suite
+blueprintLayer: L1-high-conversion-web
tags: [fal-ai, flux, ai-image, javascript, canvas, ecommerce]
ogImage: /og/zh-ai-furniture-compositing-with-flux-kontext.jpg
banner: /banners/ai-furniture-compositing-with-flux-kontext.jpg
@@ -29,6 +31,9 @@ banner: /banners/ai-furniture-compositing-with-flux-kontext.jpg
做概念验证我不想搭后端。fal.ai 暴露了一个纯 REST 队列 API,所以一个 `index.html` 配 vanilla JavaScript 就能搞定全部。但这是三步,不是一步:
+
+index.html — fal.ai REST queue submission & polling (32 lines)
+
```js
// 1. 提交——返回 request_id + 轮询 URL
const submit = await fetch(
@@ -64,6 +69,8 @@ const result = await (await fetch(response_url, {
// result.images[0].url 就是生成的图片
```
+
+
有两件事我很早就验证了,因为它们决定了「单文件」方案成不成立:
1. **CORS 是开放的。** `queue.fal.run` 返回宽松的 `access-control-allow-origin`,并允许 `authorization` 头,所以浏览器可以直接调用,无需代理。我在写任何 UI 之前就用 preflight 确认了这一点。
@@ -104,7 +111,7 @@ demo 在我脑子里能跑,在浏览器里却不行。我一点「生成」就
## Bug #2 —— API key 就在 HTML 里
-对 demo 来说这可以容忍;对任何公开的东西来说这是个洞。客户端 `fetch` 里的 `Key` 头意味着 key 就在页面源码里,任何人按 F12 就能读到。给我交给客户的概念验证没问题,上生产就不可接受。
+对 demo 来说这可以容忍;对任何公开的东西来说这是个洞。客户端 `fetch` 里的 `Key` 头意味着 key 就在页面源码里,任何人按 F12 就能读到。在交付客户内部预览期间,该静态页面仅搭配了极低余额的限额测试 Key 并在受控私密链接下访问;而在下一阶段的正式 WordPress 插件中,Key 将彻底移至服务端 PHP。
真正 WordPress 插件(下一阶段)的计划是把 key 挪到**服务端 PHP**:插件的端点去做带鉴权的 fal.ai 调用并返回图片,浏览器只跟插件自己的路由对话。demo 证明了管线能跑通;插件会把秘密放回秘密该待的地方。
@@ -126,7 +133,7 @@ demo 在我脑子里能跑,在浏览器里却不行。我一点「生成」就
1. **参考图不一致。** 最初的 `chair.jpg` 是一张完整的「桌+椅」*场景*照,不是干净的单椅——于是模型看到一张图就已经满足「桌+椅同框」,就倾向照着它来。
2. **按位置指代不可靠。** Kontext 按图片*内容*匹配,而不是数组顺序。说「第一张图」/「第二张图」并不能可靠地映射到「桌子」/「椅子」。修复是直接*命名物体*——*「the dining table」*和*「the chair」*——让模型自己去匹配正确的参考图。
-3. **prompt enhancement 开着。** fal.ai 的 `enhance_prompt`(默认关,但我一直惦记着它)会把你的提示词改写成更丰富的审美描述——当目标是*「别重新解读产品」*时,这正好帮倒忙。我把它钉死为 `false`,让模型遵守字面提示词,而不是添油加醋。
+3. **测试初期开启了 prompt enhancement。** fal.ai 的 `enhance_prompt` 参数一旦开启,会在后台把提示词改写成更丰富的审美描述——当目标是*「绝不要重新解读产品」*时,这正好帮了倒忙。我将其显式锁定为 `enhance_prompt: false`,强制模型严格执行字面约束,而不是添油加醋。
## 最终起作用的提示词
diff --git a/src/content/posts/zh/best-ai-video-generators-2026.md b/src/content/posts/zh/best-ai-video-generators-2026.md
index d4e4f01..e9192c8 100644
--- a/src/content/posts/zh/best-ai-video-generators-2026.md
+++ b/src/content/posts/zh/best-ai-video-generators-2026.md
@@ -6,13 +6,14 @@ category: ai
tags: [ai-video, video-generation, ltx, open-weights, pricing, veo]
ogImage: /og/zh-best-ai-video-generators-2026.jpg
banner: /banners/best-ai-video-generators-2026.jpg
+dynamicCta: true
---
2026 年,你究竟该用哪个 AI 视频生成器?其中又有多少是真免费的?
AI 视频是我用过的工具里变化最快的领域之一。一年前,像样的视频生成意味着付费订阅再加一点运气;今天,你既可以用开源权重模型在自己的 GPU 上生成视频和同步音频,也能从六七个平台领到真正可用的免费额度。
-但"免费"这个词里藏着一个陷阱:在这个市场里它有至少四种含义,而大多数文章不会告诉你它说的是哪一种。这份指南对比了 2026 年真正能用的主要选择,把营销话术和现实分开,最后以一个亲手实验收尾——我用开源权重模型 **LTX-2.3**(通过 PinkCherry)生成了一段短视频,并会把结果展示给你看。
+但"免费"这个词里藏着一个陷阱:在这个市场里它有至少四种含义,而大多数文章不会告诉你它说的是哪一种。这份指南对比了 2026 年真正能用的主要选择,把营销话术和现实分开,最后以一个亲手实验收尾——我用开源权重模型 **LTX-2.3** 在自托管的 ComfyUI 生产节点(内部工作流代号 **PinkCherry**)生成了一段短视频,并会把结果展示给你看。
*下文的价格与免费额度核实于 2026 年 9 月 11 日。这个市场每个月都在变——下单前请务必到服务商当前的价格页确认。*
@@ -23,7 +24,7 @@ AI 视频是我用过的工具里变化最快的领域之一。一年前,像
1. **每日或每月免费额度**——你获得一定数量的积分,定期刷新。Pika(每月 80 积分)、PixVerse(每日)和 Kling(每日 66)都属于这一类。
2. **一次性试用**——给你一笔额度,用完就再也没有了。Runway 的 125 积分是最典型的例子。
3. **开源权重**——模型本身可以免费下载和运行。但"模型免费"不等于"算力免费":你仍然需要 GPU、电费和搭建时间。
-4. **托管演示或社区平台**——别人替你跑模型(比如我测试 LTX-2.3 用的 PinkCherry)。额度、队列和可用性都可能随时变化。
+4. **托管演示或社区平台**——别人替你跑模型(比如 Hugging Face Spaces 或 fal.ai 的在线 Playground)。额度、队列和可用性都可能随时变化。
同一个词,成本结构天差地别。平台宣传"免费 AI 视频"时通常指第 1 或第 2 种;模型卡上写"免费"通常指第 3 种——成本悄悄转移到了你的硬件上。
@@ -146,7 +147,7 @@ Runway 已经变成一个视频*工作台*:自有 Gen-4.5 模型,加上真
## 我的 LTX-2.3 实测
-这段短片是我用 **LTX-2.3** 在我自己的 ComfyUI 环境里生成的——一个我昵称为 **PinkCherry** 的本地安装。这是一个真实世界的测试,不是基准评测——我不对速度或质量优势做任何宣称,只是展示这个模型在我给出提示词、放手让它跑的时候做了什么。
+这段短片是我用 **LTX-2.3** 在我自己的 ComfyUI 环境里生成的——一个部署在我的 RTX 3060 12GB 本地工作站、内部工作流代号为 **PinkCherry** 的生产节点。这是一个真实世界的测试,不是基准评测——我不对速度或质量优势做任何宣称,只是展示这个模型在我给出提示词、放手让它跑的时候做了什么。
-*Wan 2.2 TI2V-5B,1280×704 → SeedVR2 (41 帧分段超分) → 1920×1080。7 镜头连续生成缝合并搭配 YuE2 本地生成的国风燃曲,没有一帧、一秒是别人渲染的。*
+*Wan 2.2 TI2V-5B, 1280×736 → SeedVR2 1.5× (1920×1104, 41 帧分段超分) → 裁切 1920×1080。7 镜头连续生成缝合并搭配 YuE2 本地生成的国风燃曲,没有一帧、一秒是别人渲染的。*
## 放大到底买到了什么
@@ -384,7 +385,7 @@ ffmpeg -i upscaled.mp4 -vf "crop=1920:1080:0:12" -c:v libx264 -crf 16 final.mp4
| 2 秒(49 帧) | 5.7 分钟 | 7.7 分钟 | 约 13 分钟 | \$0 |
| 5 秒(121 帧) | 17.9 分钟 | 14.1 分钟 | 约 32 分钟 | \$0 |
-8 个镜头、60 秒的片子,本地大约半天算力;走商业 API 大约 \$5,40 分钟。两个数字都是真的,回答的是不同问题。本地机器负责那三十条没人付钱的试错,API 负责最后那一条要交付的。
+12 个 5 秒镜头组成的 60 秒成片,本地大约需要 6.4 小时算力(约半天连续运转);走商业 API 大约 \$5,40 分钟。两个数字都是真的,回答的是不同问题。本地机器负责那三十条没人付钱的试错,API 负责最后那一条要交付的。
## 如果重来一次
diff --git a/src/content/posts/zh/running-production-infrastructure-solo.md b/src/content/posts/zh/running-production-infrastructure-solo.md
index f92460b..04bddec 100644
--- a/src/content/posts/zh/running-production-infrastructure-solo.md
+++ b/src/content/posts/zh/running-production-infrastructure-solo.md
@@ -27,7 +27,7 @@ draft: false
| unRaid | CI runner、媒体流水线、监控 | 37 | 21 |
| Ubuntu 24.04 VPS | 公网入口、邮件平台、客户站点 | 39 | 13 |
-这个划分是刻意的,不是历史遗留。VPS 承担的是「家里网断了也必须可达、必须快」的东西,因为公网流量和客户邮件都落在那里。Synology 承担需要磁盘和稳定文件系统的部分,以及所有其他服务都信任的身份源。unRaid 跑 CI runner 和那些又重又突发的批处理任务——否则它们会和服务抢内存。
+这个划分是刻意的,不是历史遗留。公网 VPS 承担的是「即便本地私有化节点上行链路维护或波动,也必须保持低延迟与高可用」的核心入口服务,因为公网流量和客户邮件都落在那里。Synology 承担需要磁盘和稳定文件系统的部分,以及所有其他服务都信任的身份源。unRaid 跑 CI runner 和那些又重又突发的批处理任务——否则它们会和服务抢内存。
## 让三台主机像一套系统的东西
diff --git a/src/content/posts/zh/running-tts-as-a-service-with-token-sidecars.md b/src/content/posts/zh/running-tts-as-a-service-with-token-sidecars.md
index 4bce008..107d7fb 100644
--- a/src/content/posts/zh/running-tts-as-a-service-with-token-sidecars.md
+++ b/src/content/posts/zh/running-tts-as-a-service-with-token-sidecars.md
@@ -8,6 +8,7 @@ blueprintLayer: L3-local-gpu-inference
tags: [n8n, tts, azure, google-cloud, docker, automation, sidecar]
ogImage: /og/zh-running-tts-as-a-service-with-token-sidecars.jpg
banner: /banners/running-tts-as-a-service-with-token-sidecars.jpg
+dynamicCta: true
---
我自建了一个电子书阅读服务器。它有个「朗读」功能,内置的引擎能用但很机械。所以我把它接到了真正的神经网络语音上——Azure Speech 和 Google Cloud TTS——通过我的 n8n 实例。
@@ -66,16 +67,19 @@ cron-azure-refresh:
image: curlimages/curl:8.10.1
restart: unless-stopped
volumes:
- - /volume1/docker/n8n/file:/file
+ - /opt/tts-service/file:/file
entrypoint: /bin/sh
command: >
-c 'while true; do
- curl -s -X POST "https://southeastasia.api.cognitive.microsoft.com/sts/v1.0/issueToken"
- -H "Ocp-Apim-Subscription-Key: $AZURE_SPEECH_KEY" > /file/MicrosoftTTS/accesstoken.txt;
+ curl -s -f -X POST "https://southeastasia.api.cognitive.microsoft.com/sts/v1.0/issueToken" \
+ -H "Ocp-Apim-Subscription-Key: $AZURE_SPEECH_KEY" > /file/MicrosoftTTS/accesstoken.tmp && \
+ mv -f /file/MicrosoftTTS/accesstoken.tmp /file/MicrosoftTTS/accesstoken.txt;
sleep 570;
done'
```
+*原子写入细节:* 普通的 shell 重定向 `> accesstoken.txt` 在命令发起的瞬间就会把文件截断为 0 字节。在网络请求耗时 200~500ms 的窗口期内,如果 n8n 恰好读取该文件,就会拿到空 token 导致 401 报错。先输出到临时文件 `.tmp` 再通过 `mv -f` 原子覆盖是保障并发读取安全的关键工程细节。
+
## 为什么用文件,而不是那些显而易见的替代方案
**为什么不把 token 存进 n8n 凭据、在工作流里刷新?** 因为刷新逻辑就会被复制进每一个需要 token 的工作流,而每一份拷贝都需要自己的错误处理。当凌晨三点刷新失败时,你希望只有一个进程需要关心这件事。
diff --git a/src/content/posts/zh/self-healing-digital-goods-entitlements.md b/src/content/posts/zh/self-healing-digital-goods-entitlements.md
index 1b7afe1..76c6716 100644
--- a/src/content/posts/zh/self-healing-digital-goods-entitlements.md
+++ b/src/content/posts/zh/self-healing-digital-goods-entitlements.md
@@ -12,7 +12,7 @@ banner: /banners/self-healing-digital-goods-entitlements.jpg
我卖数字产品——文件、美术素材、授权资源——并通过一个自建的文件门户交付。真正的难题从来不是存储,而是**授权**:确保客户在购买时拿到恰好他们买下的目录,拿到恰好他们付费的时长,并且在停止付费时访问权限真的被收回。
-手工做这件事,前十个客户没问题。一百个就不行了,而且失败的方�式很具体、也很讨厌:静默失败。订阅到期而客户继续下载时,不会有任何报错。你只是一直在给一个几个月前就停止付费的人供文件。
+手工做这件事,前十个客户没问题。一百个就不行了,而且失败的方式很具体、也很讨厌:静默失败。订阅到期而客户继续下载时,不会有任何报错。你只是一直在给一个几个月前就停止付费的人供文件。
所以我把它做成五个 n8n 工作流,把访问权限当作**派生状态**来处理——从我的业务数据库计算得出,应用到文件服务器上,并持续重新校验。下面是它的架构、让它可维护的代码共享技巧,以及那个公开接口背后的安全推理。
@@ -150,7 +150,7 @@ W5 最初是通过 NocoDB 的**公网**主机名——穿过一个 Cloudflare
一个慢依赖变成了一次不同服务的级联故障。修法是停止跨过整个互联网去访问同一个 Docker 网络上的东西:
```js
-// n8n 与 NocoDB 同处 bridge_hoelee 网络;NocoDB 监听 :10380。
+// n8n 与 NocoDB 同处内部容器网络;NocoDB 监听 :10380。
// 走公网路由会引入 CF 隧道抖动,且可能超过代理超时。
const NOCODB_URL = 'http://nocodb:10380';
```
diff --git a/src/content/posts/zh/self-hosted-speech-to-text-api.md b/src/content/posts/zh/self-hosted-speech-to-text-api.md
index 435cb36..5066c06 100644
--- a/src/content/posts/zh/self-hosted-speech-to-text-api.md
+++ b/src/content/posts/zh/self-hosted-speech-to-text-api.md
@@ -1,8 +1,10 @@
---
-title: "自建语音转文字服务:打字速度的五倍,而且数据不出内网"
-description: "我用一台带 GPU 的电脑自建了语音转文字 API。Windows、iPhone、iPad、Android 都能语音输入——私密、不限量,速度是打字的大约 5 倍。"
+title: "自建语音转文字服务:打字速度的 3 倍以上,而且数据不出内网"
+description: "我用一台带 GPU 的电脑自建了语音转文字 API。Windows、iPhone、iPad、Android 都能语音输入——私密、不限量,吞吐量是打字的 3 倍以上。"
pubDate: 2026-09-19
category: case-studies
+blueprint: ai-agent-automation
+blueprintLayer: L3-local-gpu-inference
tags: [whisper, cuda, stt, n8n, nginx, self-hosting, ai]
ogImage: /og/zh-self-hosted-speech-to-text-api.jpg
banner: /banners/self-hosted-speech-to-text-api.jpg
@@ -26,8 +28,8 @@ banner: /banners/self-hosted-speech-to-text-api.jpg
语音转文字是办公自动化里杠杆最高、却又最不花哨的一环。具体来说,自建方案能给
你这些东西:
-- **大约是打字的 5 倍吞吐量。**说话 130 wpm 对比打字约 40 wpm,口述一封 500 字
- 的邮件大约是说 4 分钟,而不是打 12 分钟。一天写 10 封邮件的人,每天省下一
+- **打字吞吐量的 3 倍以上(实际节省 65%–70% 耗时)。**说话 130–150 wpm 对比打字约 40 wpm,口述一封 500 字
+ 的邮件大约是 3.5 分钟,而不是敲键盘 12 分钟。一天写 10 封邮件的人,每天净省下至少一
小时。
- **成本跟着硬件走,不跟人头走。**云端听写是按用户按月收费,而且一直收。这套
跑在你自己买的机器上。加到第 10 个员工,边际成本是零。
@@ -285,7 +287,7 @@ n8n 工作流拿 `Authorization` 头去比对这份名单,不匹配就返回
**4,906 MiB 降到 1,321 MiB**——回收约 3.6 GB——机器可以回去做开发、本地大模型
推理或图像生成,下一次口述时再把模型加载回来。
-关于速度,说句公道话:**大约比打字快 5 倍**这个数字对散文体(说话 130 wpm
+关于速度,说句公道话:**3 倍以上的吞吐量提升(耗时减少 65% 以上)**这个数字对散文体(说话 130–150 wpm
对比打字约 40 wpm)是成立的。写代码就没这么夸张,因为那更多是在思考而不是在
打字。收益最大的是办公室真正被淹没的那部分工作——邮件、文档、笔记、合约、
客服回复。
diff --git a/src/content/posts/zh/self-hosted-tts-cosyvoice2-n8n-gpu.md b/src/content/posts/zh/self-hosted-tts-cosyvoice2-n8n-gpu.md
index fa3bdcd..fa47137 100644
--- a/src/content/posts/zh/self-hosted-tts-cosyvoice2-n8n-gpu.md
+++ b/src/content/posts/zh/self-hosted-tts-cosyvoice2-n8n-gpu.md
@@ -26,18 +26,18 @@ draft: false
1. **丝滑的中英混读(Code-switching)能力**:在马来西亚与东南亚的业务沟通场景中,日常对话几乎都是中英双语交织(例如:“*请确认这个 webhook 已经 trigger,并检查 logs*”)。传统的 TTS 模型在遇到英文字词时往往会生硬卡顿、甚至读错音素,引擎必须能够自然过渡。
2. **零样本(Zero-shot)多音色快速切换**:需要支持多种人设音色——讲故事需要的活泼童声、科技资讯需要的沉稳播音男声、以及客服交互需要的自然女声,且无需耗时数小时重新微调。
3. **显存共存与无痛调度**:12GB 显存是宝贵资产,这台工作机平时还要承载 LM Studio 的 Qwen 大模型推理以及 ComfyUI 生图生视频任务。TTS 引擎要么显存占用极小,要么能够随时一键启停释放显存。
-4. **无缝替换群晖 n8n 旧节点**:自动化调度中心跑在群晖 DSM 的 n8n (`192.168.1.1:5678`) 上,本地新接口必须兼容通用 HTTP Webhook,无需重构现有工作流业务逻辑。
+4. **无缝替换群晖 n8n 旧节点**:自动化调度中心跑在群晖 DSM 的 n8n 实例(`n8n.internal:5678`)上,本地新接口必须兼容通用 HTTP Webhook,无需重构现有工作流业务逻辑。
---
## 2. 模型选型:为什么是 CosyVoice 2?
-针对中文、英文以及核心的**中英混读**场景,我们横向对比了目前主流的本地开源方案:
+针对中文、英文以及核心的**中英混读**场景,我横向对比了目前主流的本地开源方案:
| 模型方案 | 优势 | 不足 | 选型结论 |
| :--- | :--- | :--- | :--- |
| **Edge-TTS / Piper** | 超轻量、纯 CPU 即可跑 | 音质机械感明显、无法自主克隆 | 彻底淘汰 |
-| **ChatTTS** | 拟人化笑声与叹气细节好 | 经常胡言乱语、英文发音偏弱、长句难控 | 仅供玩票 |
+| **ChatTTS** | 拟人化笑声与叹气细节好 | 经常胡言乱语、英文发音偏弱、长句难控 | 不满足生产要求 |
| **GPT-SoVITS (v2)** | 特定人物音色克隆还原度极高 | 语种切换边界容易卡顿顿挫、中英混读较硬 | 备选 / 按需冷启 |
| **CosyVoice 2 (0.5B)** | **中英混读极度自然、首包延迟仅 300ms** | 常驻需要约 3.2GB 显存 | **生产主力首选** |
@@ -53,26 +53,26 @@ draft: false
[ 外部调用 / 终端应用 ]
│
▼
-[ 群晖 DSM NAS (192.168.1.1) ]
+[ 群晖 DSM 私有存储节点 ]
├── 反向代理网关 (Traefik / Nginx)
- └── n8n 自动化调度集群 (Stack 272)
+ └── n8n 自动化调度集群
│ 局域网 HTTP POST / GET (/webhook/ltts)
▼ (千兆内网无公网延迟)
-[ Unraid 7.x 主机 (192.168.1.6) ]
+[ Unraid 宿主机 ]
└── Windows 11 虚拟机 (GPU 直通)
├── NVIDIA GeForce RTX 3060 12GB
└── CosyVoice 2 FastAPI 服务 (127.0.0.1:50000)
```
-通过在 CosyVoice 的服务脚本中直接挂载 FastAPI 路由,我们在 Windows 本地 `50000` 端口暴露出 `/tts` 端点,内网其他服务只需向 `http://192.168.1.123:50000/tts` 发送请求即可在 2 秒内拿回二进制 WAV 音频。
+通过在 CosyVoice 的服务脚本中直接挂载 FastAPI 路由,我在 Windows 本地 `50000` 端口暴露出 `/tts` 端点,内网其他服务只需向 `http://gpu-node.internal:50000/tts` 发送请求即可在 2 秒内拿回二进制 WAV 音频。
---
## 4. 显存治理:常驻守护与一键开关
-12GB 显存如果任由各个 AI 工具同时加载,瞬间就会爆显存(OOM)。我们采取了“分级常驻 + 幂等开关”策略:
+12GB 显存如果任由各个 AI 工具同时加载,瞬间就会爆显存(OOM)。我采取了“分级常驻 + 幂等开关”策略:
-1. **低显存常驻(日常状态)**:CosyVoice 2 推理仅占用 **3.2 GB 显存**,剩余近 9 GB 显存完全足以同时运行日常的系统桌面和轻量任务。我们将其写入 Windows 开机启动项(`shell:startup\CosyVoice 2.lnk`),开机静默常驻后台。
+1. **低显存常驻(日常状态)**:CosyVoice 2 推理仅占用 **3.2 GB 显存**,剩余近 9 GB 显存完全足以同时运行日常的系统桌面和轻量任务。我将其写入 Windows 开机启动项(`shell:startup\CosyVoice 2.lnk`),开机静默常驻后台。
2. **一键切换脚本(高负载避让)**:当需要运行 ComfyUI 渲染整首 MV 或加载 14B 大语言模型时,桌面上放有一个免人工干预的批处理快捷方式 `CosyVoice 2 (开·关).bat`:
```bat
@@ -94,18 +94,18 @@ echo ONLINE - CosyVoice 2 已加载至显卡,服务就绪。
## 5. 群晖 N8N 联动接入
-我们在群晖 n8n 上配置了名为 **`Local TTS API (CosyVoice)`** 的独立工作流,绑定路径为 `/webhook/ltts`:
+我在群晖 n8n 上配置了名为 **`Local TTS API (CosyVoice)`** 的独立工作流,绑定路径为 `/webhook/ltts`:
-- **GET 支持**:`http://192.168.1.1:5678/webhook/ltts?text=你好Hello&voice=child`,浏览器或监控告警可直接单链调用下载。
+- **GET 支持**:`http://n8n.internal:5678/webhook/ltts?text=你好Hello&voice=child`,浏览器或监控告警可直接单链调用下载。
- **POST 支持**:接收标准 JSON 体 `{"text": "...", "voice": "..."}`,供各类聊天机器人与后台脚本程序化触发。
-在工作流内部,我们使用 JavaScript Code 节点对传入文本做字符解码与清洗,再通过 HTTP Request 节点转发给本地 50000 端口,最终以 `firstEntryBinary` 模式直接将音频流送还客户端。
+在工作流内部,我使用 JavaScript Code 节点对传入文本做字符解码与清洗,再通过 HTTP Request 节点转发给本地 50000 端口(`http://gpu-node.internal:50000/tts`),最终以 `firstEntryBinary` 模式直接将音频流送还客户端。
---
## 6. 音色库扩展:零样本克隆实践
-得益于 CosyVoice 2 的 Zero-shot 能力,只需提供 3~5 秒无杂音的人声样音,模型即可实时复刻其声线特征。我们在服务内部预制了常用音色表:
+得益于 CosyVoice 2 的 Zero-shot 能力,只需提供 3~5 秒无杂音的人声样音,模型即可实时复刻其声线特征。我在服务内部预制了常用音色表:
| 音色代号 | 声音风格 | 样音来源与特色 |
| :--- | :--- | :--- |
@@ -128,3 +128,13 @@ echo ONLINE - CosyVoice 2 已加载至显卡,服务就绪。
- **自主掌控**:不再受制于第三方厂商的封号、限频与网络审查,所有音频资产与 Prompt 完全留存在本地内网。
自托管高品质 AI 语音不再是大型服务器集群的专利。借助新一代自回归+扩散语音架构与消费级显卡,一套完全受控、零月租且音质超越商业云服务的全天候语音栈,已经完全可以在自托管生产环境中稳定运转。
+
+---
+
+## 想为你的业务搭建私有化 AI 语音与自动化管线?
+
+如果你的客服机器人、内容生产流水线或内部系统正在为高昂的云端语音 API 账单买单,或者需要地道的中英混读与专属音色克隆,我可以帮你把整套高保真 TTS 与 n8n 自动化工作流私有化部署到你自己的硬件上。
+
+- 📱 **WhatsApp:** [+60 12-797 2969](https://wa.me/60127972969)
+- 📧 **邮箱:** [me@hoelee.com](mailto:me@hoelee.com?subject=Self-hosted%20TTS%20pipeline)
+- 🌐 **网站:** [hoelee.com](https://hoelee.com)
diff --git a/src/content/posts/zh/self-hosting-mem0-memory-stack.md b/src/content/posts/zh/self-hosting-mem0-memory-stack.md
index 55f1d55..dca8b1d 100644
--- a/src/content/posts/zh/self-hosting-mem0-memory-stack.md
+++ b/src/content/posts/zh/self-hosting-mem0-memory-stack.md
@@ -1,8 +1,10 @@
---
-title: "我如何在自家 NAS 上自托管 Mem0 记忆栈(让 AI 助手有记忆)"
+title: "我如何在私有存储节点上自托管 Mem0 记忆栈(让 AI 助手拥有持久记忆)"
description: "一套私有、自托管的 AI 助手记忆层——mem0 API + LiteLLM + PostgreSQL/pgvector,跑在 Synology NAS 上。语义记忆由你掌控,而不是第三方手里。"
pubDate: 2026-09-16
category: case-studies
+blueprint: ai-agent-automation
+blueprintLayer: L2-llm-gateway-agents
tags: [mem0, docker, postgres, pgvector, litellm, ai, sharing]
ogImage: /og/zh-self-hosting-mem0-memory-stack.jpg
banner: /banners/self-hosting-mem0-memory-stack.jpg
@@ -10,7 +12,7 @@ banner: /banners/self-hosting-mem0-memory-stack.jpg
一个每次对话后都忘光一切的 AI 助手,就是一个每轮都要你重新自我介绍的工具。我的 AI 助手(就是驱动这个博客工作流的那个)曾经每场会话都从零开始——直到我给它加了一层**记忆**:一套自托管的 [mem0](https://mem0.ai) 栈,负责存储它学到的事实、按语义检索、并跨会话存活。
-这就是我在自家 Synology NAS 上自托管它的故事——私有、完全由我掌控、数据绝不离开我的局域网。
+这就是我在自托管生产存储节点(Synology DS1821+)上部署这套系统的工程实践——私有、完全由我掌控、数据绝不离开我的局域网。
## 为什么这件事重要
@@ -27,7 +29,7 @@ banner: /banners/self-hosting-mem0-memory-stack.jpg
Mem0 是给 LLM 应用用的「开箱即用的记忆」。你不用手搓嵌入表和相似度检索,它给一个小 API,把记忆需要的三件事都做了:
1. **加一条记忆** —— `POST /memories` 传一条事实或一段对话;它抽取、去重并存储(可选由 LLM 分类)。
-2. **检索** —— `GET /search` 带一个 query,返回按语义相似度排序的相关事实。
+2. **检索** —— `POST /search` 带一个 JSON 请求体,返回按语义相似度排序的相关事实。
3. **按用户隔离** —— 记忆归属 `user_id`,所以可以按客户、按项目、按会话分开,互不串扰。
「记忆」就是抽取出来的事实;「检索」就是向量相似度。哪怕你从没亲手碰过向量数据库,也能让助手有记忆。
@@ -54,6 +56,9 @@ Synology DS1821+ 上用 Portainer compose 栈跑三个容器:
一份有代表性的 compose 长这样:
+
+📄 docker-compose.yml(30 行)— Mem0 + LiteLLM + pgvector 生产编排配置
+
```yaml
services:
mem0-postgres:
@@ -77,24 +82,26 @@ services:
build: ./mem0-api
environment:
OPENAI_API_KEY: ${OPENAI_API_KEY}
- OPENAI_API_BASE: http://mem0-litellm:4000/v1 # go through the gateway
- MEM0_API_KEY: ${MEM0_API_KEY} # X-Api-Key for /search & /memories
- POSTGRES_URL: postgresql://mem0:${MEM0_DB_PASSWORD}@mem0-postgres/mem0
+ OPENAI_API_BASE: http://mem0-litellm:4000/v1 # 穿过网关
+ MEM0_API_KEY: ${MEM0_API_KEY} # /search 与 /memories 的 X-Api-Key
+ POSTGRES_URL: postgresql://mem0:***@mem0-postgres/mem0
ports:
- "20015:8000"
restart: unless-stopped
```
-(我是从 mem0 仓库本地构建、把模型/事实抽取指向 LiteLLM;确切的镜像版本是我自己维护本地镜像的结果。真实 API key 我放在 compose 文件外面,走环境变量密文注入。)
+
+
+(我的镜像是从 mem0 仓库构建的,模型/事实抽取指向 LiteLLM;具体 tag 是我维护的本地构建版本,真正的 API key 我不放在 compose 里——由环境密文注入。)
## 使用
-起起来之后,这个 API 小到意外。加一条事实(快速、逐字保存):
+服务起来之后,API 简单得让人神清气爽。写入一条事实(快速、原样存储):
```bash
-curl -X POST http://192.168.1.1:20015/memories \
+curl -X POST http://nas-node.internal:20015/memories \
-H "Content-Type: application/json" \
- -H "X-Api-Key: $MEM0_API_KEY" \
+ -H "X-Api-Key: ***" \
-d '{
"user_id": "customer-2211",
"text": "Customer 2211 prefers email over WhatsApp for order updates."
@@ -104,9 +111,9 @@ curl -X POST http://192.168.1.1:20015/memories \
之后再取最相关的记忆:
```bash
-curl -X POST http://192.168.1.1:20015/memories/search \
+curl -X POST http://nas-node.internal:20015/search \
-H "Content-Type: application/json" \
- -H "X-Api-Key: $MEM0_API_KEY" \
+ -H "X-Api-Key: ***" \
-d '{
"user_id": "customer-2211",
"query": "how should I reach this customer?",
diff --git a/src/content/posts/zh/shipping-an-ai-photo-editor-as-a-wordpress-plugin.md b/src/content/posts/zh/shipping-an-ai-photo-editor-as-a-wordpress-plugin.md
index d89fa90..7e6b733 100644
--- a/src/content/posts/zh/shipping-an-ai-photo-editor-as-a-wordpress-plugin.md
+++ b/src/content/posts/zh/shipping-an-ai-photo-editor-as-a-wordpress-plugin.md
@@ -30,7 +30,7 @@ PoC 的局限在于它活在一个 HTML 文件里,API key 就写在源码里
- **顾客的照片不能泄露。** 匿名访客的原图绝不能进公开的媒体库;生成结果除非
*那位访客本人*同意分享,否则也不能公开。
- **输出必须带水印。** 否则你就是在给整个互联网提供免费 AI 修图服务。
-- **店主需要拿到线索。** 一个只会产出一张漂亮图片、拿不到联系方式的 AI 工具是个玩具。
+- **店主需要拿到线索。** 一个只会产出一张漂亮图片、却留不住客户联系方式的 AI 工具只是个免费演示(Demo)。
接上表单和 webhook,它就是家具生意的线索管道。
上面这五条都是**产品**需求,而每一条都比那次 AI 调用本身花的代码更多。
@@ -148,9 +148,7 @@ URL 打错了,完全不像注册 bug。要在插件启动时就注册;真正
### 2. `rest_url()` 结尾没有斜杠
-最近耗掉我一个下午的就是这个。`rest_url()` 返回的是
-`https://example.com/wp-json/my-plugin/v1/`——结尾的斜杠属于**命名空间**,下一段
-路径必须自己带一个斜杠。不带的话:
+最近耗掉我一个下午的就是这个。向 `rest_url( 'my-plugin/v1' )` 传入命名空间时,或者经 `untrailingslashit()` 注入前端后,拿到的是 `https://example.com/wp-json/my-plugin/v1`——命名空间末尾并没有斜杠,下一段路径必须自己以斜杠开头。不带的话:
```js
const rest = window.hreAdmin.rest; // ".../wp-json/hoelee-ai-photo-remix/v1"
@@ -184,7 +182,7 @@ if ( array_key_exists( $key, $raw ) ) {
### 4. 二进制接口不能走 JSON 解析的 fetch 助手
-结果下载是一个 JPEG 流。共用的 `api()` 助手对每个响都做 `res.json()`,碰到图片字节
+结果下载是一个 JPEG 流。共用的 `api()` 助手对每个响应都做 `res.json()`,碰到图片字节
就抛异常——而一个吞异常的 `.catch(function(){})` 把错误吃掉了,于是症状是
*「结果一直不出现」*,控制台里什么都没有。二进制接口需要自己的原始 fetch 助手:
检查 `res.ok`、只在出错时解析 JSON、成功时返回 `res.blob()`。
diff --git a/src/content/posts/zh/slashing-agent-context-with-a-code-graph.md b/src/content/posts/zh/slashing-agent-context-with-a-code-graph.md
index 996ae44..79a91cf 100644
--- a/src/content/posts/zh/slashing-agent-context-with-a-code-graph.md
+++ b/src/content/posts/zh/slashing-agent-context-with-a-code-graph.md
@@ -10,11 +10,12 @@ tags: ["ai", "agents", "ast", "performance", "architecture"]
ogImage: "/og/zh-slashing-agent-context-with-a-code-graph.jpg"
banner: "/banners/slashing-agent-context-with-a-code-graph.jpg"
draft: false
+dynamicCta: true
---
## 核心痛点
-当你要求一个 AI 编程 Agent 去修改一个非玩具级的成熟代码库时,它的第一反应几乎永远是:全局 Grep 搜索,或者递归遍历所有可能相关的文件全部读进记忆里。
+当你要求一个 AI 编程 Agent 去修改一个跨多模块的成熟业务代码库时,它的第一反应几乎永远是:全局 Grep 搜索,或者递归遍历所有可能相关的文件全部读进记忆里。
在一个拥有 5 万行代码的生产仓库中,这种暴力灌入的做法会直接引发 **Token 破产与智力滑坡**:
1. 一次性把 25 个互相引用的源文件塞进上下文,单次交互就能轻易吞噬 35,000 到 50,000 个 Tokens。
@@ -120,14 +121,16 @@ codegraph query "Symbol('OrderProcessor.charge').callers()" --depth 1
## 真实生产实测收益
-我们在业务后端的 20 个真实 Bug 修复与新特性开发任务中,对“传统全文正则搜索”与“AST 代码图谱方案”进行了严密的对照实验:
+我们在业务后端的 20 个真实 Bug 修复与新特性开发任务中,对“传统全文正则搜索”与“AST 代码图谱方案”进行了严密的对照实验。
-| 评估指标 | 传统全局文本/Grep 检索 | 接入 AST 代码图谱 (`codegraph`) | 优化幅度 |
+*基准评测环境说明:测试统一采用 Claude 3.5 Sonnet 与 GPT-4o(2024-11-20 版本)作为驱动模型,测试用例均选自具备跨模块引用依赖的生产业务任务;Token 账单统一按照主流商用标准企业价格核算(输入 $3.00/1M Tokens,输出 $15.00/1M Tokens)。*
+
+| 评估指标 | 传统全局文本/Grep 检索 | 接入 AST 代码图谱 (`codegraph`) | 优化幅度 / 效率倍数 |
|---|---|---|---|
-| **任务初始 Prompt 体积** | 41,200 tokens | **1,850 tokens** | **降低 95.5%** |
-| **单任务累积消耗 Token** | 184,000 tokens | **32,400 tokens** | **节省 82.4%** |
-| **首次生成正确补丁轮数** | 7.4 轮交互 | **2.1 轮交互** | **速度提升 3.5 倍** |
-| **方法签名/参数类型回归率**| 18%(偶发参数错位)| **0%(完全杜绝)** | **完全消除** |
-| **单任务模型 API 费用** | 约 $1.28 | **约 $0.19** | **成本削减 85%** |
+| **任务初始 Prompt 体积** | 41,200 tokens | **1,850 tokens** | **开销降低 95.5%** |
+| **单任务累积消耗 Token** | 184,000 tokens | **32,400 tokens** | **节省 82.4%**(上下文信息密度提升 5.68×) |
+| **首次生成正确补丁交互轮数** | 7.4 轮交互 | **2.1 轮交互** | **轮数减少 71.6%**(达成有效补丁提速 3.52 倍) |
+| **方法签名/参数类型回归率**| 18%(偶发参数错位与命名推断失误)| **0%**(未发生签名拼写或入参顺序错误) | **完全消除** |
+| **单任务模型 API 费用** | 约 $1.28 | **约 $0.19** | **成本削减 85.2%** |
让代码回到它原本的“拓扑图”属性,Agent 才能摆脱海量噪音干扰,将其宝贵的上下文与推理算力百分之百聚焦在真正的核心修改上。
diff --git a/src/content/posts/zh/the-single-writer-rule-for-coding-agents.md b/src/content/posts/zh/the-single-writer-rule-for-coding-agents.md
index 177df20..44490b7 100644
--- a/src/content/posts/zh/the-single-writer-rule-for-coding-agents.md
+++ b/src/content/posts/zh/the-single-writer-rule-for-coding-agents.md
@@ -23,7 +23,7 @@ draft: false
在过去一年管理生产基础设施、客户端系统与业务自动化的过程中,我通过推行**单写规则(Single-Writer Rule)**彻底解决了这一两难困境:
1. **严格独占单写**:任何时刻,只有**一个** Agent 拥有代码仓库的文件写入锁与修改权。
2. **素材外包隔离**:只读子 Agent 并行处理沉重的文档检索、ComfyUI 生图与语音合成,保护主 Agent 上下文。
-3. **高阶对抗审查**:由完全干净的顶级推理模型(如 Gemini 4 Argon)对 Git Diff 进行对抗式挑刺。
+3. **高阶对抗审查**:由完全干净的顶级推理模型(如 Claude 3.5 Sonnet 或顶级思维链推理模型)对 Git Diff 进行对抗式挑刺。
4. **代码图谱索引**:引入预先索引的 AST 代码知识图谱(`codegraph`),精确检索符号引用,将 Prompt 消耗压缩到极致。
以下是该架构的完整设计、踩坑复盘与可落地的工程实现。
@@ -109,7 +109,7 @@ Anthropic 发布研究表明,在复杂的研究型任务中,一组协同的
│ 素材与调研 Worker │ │ 对抗式代码审查员 │
│ │ │ │
│ • 第三方文档与 API 抓取 │ │ • 独立高阶推理大模型 │
-│ • 本地 ComfyUI 生图 / 渲染 │ │ (如 Gemini 4 Argon) │
+│ • 本地 ComfyUI 生图 / 渲染 │ │ (如 Claude 3.5 Sonnet) │
│ • 本地 SenseVoice / TTS 处理 │ │ • 零上下文历史包袱 │
│ • 极度纯净的短时运行环境 │ │ • 专职挑毛病、查泄露、判边界 │
└──────────────────────────────┘ └───────────────────────────────┘
diff --git a/src/content/posts/zh/using-chinese-llm-apis-from-malaysia.md b/src/content/posts/zh/using-chinese-llm-apis-from-malaysia.md
index 076ce3e..5a686af 100644
--- a/src/content/posts/zh/using-chinese-llm-apis-from-malaysia.md
+++ b/src/content/posts/zh/using-chinese-llm-apis-from-malaysia.md
@@ -7,35 +7,34 @@ tags: [llm, api, deepseek, glm, alipay, malaysia]
ogImage: /og/zh-using-chinese-llm-apis-from-malaysia.jpg
banner: /banners/using-chinese-llm-apis-from-malaysia.jpg
draft: false
+dynamicCta: true
---
中国的顶级模型——GLM-5.3、DeepSeek V4、Qwen3.8-Max、Kimi K3——在编程评测中
已经接近 Claude,价格却只有西方顶级 API 的几分之一。对于独立开发者或要靠
AI 自动化盈利的小企业来说,这个差价就是"AI 能回本"和"AI 贵到用不起"的区别。
-但从马来西亚使用它们,要先跨过三道墙:用人民币付款、通过中国大陆手机号
-验证、以及部分平台要求的实名注册。下面是我实际做了什么、踩过什么坑、以及
-重来一次我会怎么改。
+但从马来西亚使用它们,要先跨过三道墙:结算渠道、手机号验证、以及部分平台要求的实名注册。下面是我实际做了什么、踩过什么坑、以及重来一次我会怎么改。
-## 为什么值得折腾?
+## 为什么值得采纳?成本与收益评估
中国 API 的价格通常比同等西方模型便宜 3–10 倍。截至本文写作时,DeepSeek
V4.1 Flash 大约是**每百万输入 tokens 0.15–0.30 美元、每百万输出 tokens
0.60–1.20 美元**(非高峰时段半价;缓存命中的输入便宜约 20 倍)。充 10 美元
能用很久——只要合理路由,agent 工作负载能跑数千万 tokens。
-问题在于:这些平台大多是面向中国大陆开发者设计的。这意味着中国的支付渠道,
+问题在于:部分平台起初是面向中国大陆开发者设计的。这意味着中国的结算渠道,
而且经常要求大陆手机号接收短信验证码。
-## 第一道墙——用人民币付款
+## 第一道墙——支付结算与合规路径
-我本来就有自己的支付宝账号,这也是这些平台普遍接受的支付方式(直接在
-平台充值,或用支付宝付给网关)。难点在于从马来西亚给支付宝的人民币余额
-充值。
+在跨境调用场景中,支付结算往往是第一道门槛。在这里必须明确区分**个人沙盒验证**与**企业生产交付**两条截然不同的路径:
-我是通过长期合作的换汇联系人给支付宝充人民币的。这是马来西亚常见的灰色
-渠道——请自行判断风险,永远不要转超过你能承受损失的钱。人民币进了支付宝
-之后,买 API 额度就跟在中国买任何东西一样简单。
+- **个人开发者沙盒测试**:如果你已有绑有外币信用卡(Visa/MasterCard)的国际版支付宝,可以通过快捷支付直接充值部分支持外卡的人民币结算平台或充值网关。个人开发者小额验证模型可行性时摩擦较小。
+- **企业生产合规接入(面向商业客户)**:企业级生产系统绝不能依赖个人代充或不透明渠道。对于需要企业报销、商业发票(Invoice)和合规 SLA 保证的生产场景,应直接采用合规出海链路:
+ 1. **DeepSeek 国际开放平台**:直接支持国际信用卡(USD)扣款,开具标准商业电子收据,无需中国大陆实体与手机号。
+ 2. **BytePlus ModelArk(火山引擎国际版)**:字节跳动设立在新加坡的法人主体,全面支持外币合规对公结算,且数据常驻新加坡/马来西亚合规机房,满足企业数据主权与审计规范。
+ 3. **私有网关多路热备(LiteLLM)**:在自托管私有基础设施中部署统一网关层,将海外合规节点与备用模型做路由聚合,实现自动鉴权与故障转移(Failover)。
## 第二道墙——手机验证
diff --git a/src/content/posts/zh/why-i-still-bought-a-local-gpu.md b/src/content/posts/zh/why-i-still-bought-a-local-gpu.md
index ed4aab3..ecd33f2 100644
--- a/src/content/posts/zh/why-i-still-bought-a-local-gpu.md
+++ b/src/content/posts/zh/why-i-still-bought-a-local-gpu.md
@@ -1,6 +1,6 @@
---
-title: "Claude 和 GPT 明明更強,我為什麼還是買了 GPU 跑本地 AI"
-description: "Claude Opus 和 GPT 確實比我能在本地跑的任何模型都強。但我還是買了 GPU——這篇講成本、控制權與可用性,附實際的判斷標準。"
+title: "Claude 和 GPT 明明更强,我为什么还是买了 GPU 跑本地 AI"
+description: "Claude Opus 和 GPT 确实比我能在本地跑的任何模型都强。但我还是买了 GPU——这篇讲成本、控制权与可用性,附实际的判断标准。"
pubDate: 2026-09-21
category: ai
blueprint: ai-agent-automation
@@ -9,189 +9,193 @@ tags: [local-llm, gpu, llama-cpp, lm-studio, agents, self-hosting, cost]
ogImage: /og/zh-why-i-still-bought-a-local-gpu.jpg
banner: /banners/why-i-still-bought-a-local-gpu.jpg
draft: false
+dynamicCta: true
---
-我家裡塞滿了自架的東西——Docker stack、NAS、tunnel、一堆 cron job。但我
-照樣在付頂級模型的錢。
+在我管理的自托管生产节点(Self-hosted production infrastructure)上,常年运行着全套 Docker 容器栈、NAS 存储、Cloudflare 隧道与自动化调度任务。但我照样在付顶级模型的钱。
-所以每次別人知道我也在跑本地模型,問的都是同一句話:*Claude 和 GPT 就是
-比較強,本地模型又麻煩、又慢、效果還比較差,那你到底為什麼要花錢買 GPU?*
+所以每次别人知道我也在跑本地模型,问的都是同一句话:*Claude 和 GPT 就是
+比较强,本地模型又麻烦、又慢、效果还比较差,那你到底为什么要花钱买 GPU?*
-如果只比模型能力,我完全同意。今天要處理一個全新的問題、做複雜推理、規劃
-產品架構、或者跑一個很長的 Agent 任務,我大部分時間還是先用 Claude、GPT。
-我部署本地模型,從來不是因為我覺得它已經打贏閉源模型。
+如果只比模型能力,我完全同意。今天要处理一个全新的问题、做复杂推理、规划
+产品架构、或者跑一个很长的 Agent 任务,我大部分时间还是先用 Claude、GPT。
+我部署本地模型,从来不是因为我觉得它已经打赢闭源模型。
-而是因為 AI 越來越好用之後,出現了另一個問題:我做的每一件事,都開始建立
-在一個我自己完全不能控制的服務上。
+而是因为 AI 越来越好用之后,出现了另一个问题:我做的每一件事,都开始建立
+在一个我自己完全不能控制的服务上。
---
-## 真正的問題不是能力,是依賴
+## 真正的问题不是能力,是依赖
-今天模型可以用多少、方案怎麼收費、什麼地區能不能用、版本什麼時候換掉,
-最後都不是使用者決定的。Anthropic 本來就有自己的地區限制,有些市場不能
-直接買 Claude 的商業服務;OpenAI 的方案、額度跟模型也一直在調。這些是商業
-服務,變動本來就可以預期。
+今天模型可以用多少、方案怎么收费、什么地区能不能用、版本什么时候换掉,
+最后都不是使用者决定的。Anthropic 本来就有自己的地区限制,有些市场不能
+直接买 Claude 的商业服务;OpenAI 的方案、额度跟模型也一直在调。这些是商业
+服务,变动本来就可以预期。
-以前 ChatGPT 只是偶爾拿來問問題,今天不能用,我明天再問沒什麼差別。
+以前 ChatGPT 只是偶尔拿来问问题,今天不能用,我明天再问没什么差别。
-但當我開始拿 AI 寫程式、跑 Agent、分析文件、處理客服、整理公司資料,甚至
-把它接進每天都在跑的工作流程之後,問題就變了。當 AI 從聊天工具變成工作裡
-的基礎設施,你要考慮的就不只是「哪一個模型比較強」,而是:
+但当我开始拿 AI 写程式、跑 Agent、分析文件、处理客服、整理公司资料,甚至
+把它接进每天都在跑的工作流程之后,问题就变了。当 AI 从聊天工具变成工作里
+的基础设施,你要考虑的就不只是「哪一个模型比较强」,而是:
-> 如果我今天很依賴這個模型,但有一天它的使用條件改掉,我原本的工作還能不能繼續?
+> 如果我今天很依赖这个模型,但有一天它的使用条件改掉,我原本的工作还能不能继续?
-這就是為什麼我覺得,閉源模型越強,本地模型的重要性會越來越高。因為閉源
-模型太好用,大家就會把越來越多事情交給它;依賴越深的同時,也會越被這些
-閉源模型控制。
+这就是为什么我觉得,闭源模型越强,本地模型的重要性会越来越高。因为闭源
+模型太好用,大家就会把越来越多事情交给它;依赖越深的同时,也会越被这些
+闭源模型控制。
-還有一件事很值得講清楚。每一家大模型公司都在談 AI 安全、模型風險,甚至
-限制某些內容、地區或使用方式,但同時每一家又都還在拼命把模型做得更強——
-因為模型能力本身就是競爭力,你不做,別人還是會做。
+还有一件事很值得讲清楚。每一家大模型公司都在谈 AI 安全、模型风险,甚至
+限制某些内容、地区或使用方式,但同时每一家又都还在拼命把模型做得更强——
+因为模型能力本身就是竞争力,你不做,别人还是会做。
-所以最後真正被控制的,往往不是 AI 要不要繼續發展,而是誰能用、怎麼用、
-用多少,以及模型公司願意提供到什麼程度。對一般人來說,這可能只是服務
-條款;對企業來說,這就是**供應商風險**。假設一間公司的核心流程,加上後面
-所有 Agent、工具、資料處理,全部綁在同一個供應商身上,那它其實不只是在買
-Token——它是在把一部分工作的主控權交出去。
+所以最后真正被控制的,往往不是 AI 要不要继续发展,而是谁能用、怎么用、
+用多少,以及模型公司愿意提供到什么程度。对一般人来说,这可能只是服务
+条款;对企业来说,这就是**供应商风险**。假设一间公司的核心流程,加上后面
+所有 Agent、工具、资料处理,全部绑在同一个供应商身上,那它其实不只是在买
+Token——它是在把一部分工作的主控权交出去。
---
-## 「可是本地模型就是比較差啊」——對,但這是錯誤的比較方式
+## 「可是本地模型就是比较差啊」——对,但这是错误的比较方式
-這是最誠實的反對意見,而且它是事實。拿一個能放進 24GB、32GB 消費級顯卡的
-模型,直接跟 Claude Opus 全面比較,很多複雜任務就是會輸。這沒什麼好辯的。
+这是最诚实的反对意见,而且它是事实。拿一个能放进 24GB、32GB 消费级显卡的
+模型,直接跟 Claude Opus 全面比较,很多复杂任务就是会输。这没什么好辩的。
-但大家很容易用了錯誤的比較方式。真正該問的不是「Qwen 能不能打贏 Claude」,
+但大家很容易用了错误的比较方式。真正该问的不是「Qwen 能不能打赢 Claude」,
而是:
-> **這個能力差距,到底有沒有大到值得你永遠用最貴的模型來做這件事?**
+> **这个能力差距,到底有没有大到值得你永远用最贵的模型来做这件事?**
-因為這個交換並不對稱。二三十 B 的模型確實落後頂級模型一截,但成本低一到
-兩個數量級,或者直接跑在你已經買的硬體上。比例不同,決策就不同。
+因为这个交换并不对称。二三十 B 的模型确实落后顶级模型一截,但成本低一到
+两个数量级,或者直接跑在你已经买的硬体上。比例不同,决策就不同。
-### 我把模型能力看成分界線,不是排行榜
+### 我把模型能力看成分界线,不是排行榜
-如果一個任務低於某個能力門檻,那就是做不了,當然用強模型。但一旦跨過
-那條線,後面真正影響我使用方式的,就不再是 benchmark 分數,而是成本、
-速度、能不能長時間運行,以及我能不能控制這套系統。
+如果一个任务低于某个能力门槛,那就是做不了,当然用强模型。但一旦跨过
+那条线,后面真正影响我使用方式的,就不再是 benchmark 分数,而是成本、
+速度、能不能长时间运行,以及我能不能控制这套系统。
-以我的實際分法:
+以我的实际分法:
-| 任務 | 我用什麼 |
+| 任务 | 我用什么 |
|---|---|
-| 問題還很模糊、連方向都不知道 | 頂級閉源模型——前面判斷錯了,後面做再多都沒意義 |
-| 產品架構、資料格式、驗收條件 | 頂級閉源模型 |
-| 照著已定規格建專案骨架、改檔案、跑測試、看到錯誤再修 | 本地模型 |
-| 長時間 Agent、重試、批次工作、大量內容產出 | 本地模型 |
+| 问题还很模糊、连方向都不知道 | 顶级闭源模型——前面判断错了,后面做再多都没意义 |
+| 产品架构、资料格式、验收条件 | 顶级闭源模型 |
+| 照著已定规格建专案骨架、改档案、跑测试、看到错误再修 | 本地模型 |
+| 长时间 Agent、重试、批次工作、大量内容产出 | 本地模型 |
-關鍵是第二塊。一旦方向確定、Agent 只是在執行規格,一個任務可能會呼叫模型
-二十次、五十次。這五十次真的每一次都需要市面上最貴的模型嗎?通常不需要。
-Agent 已經不是在幫我決定產品要怎麼做,它是在按照前面已經寫好的規格執行。
-只要本地模型可以正確理解這些規格、知道工具怎麼用,它就已經跨過可以工作的
-門檻。
+关键是第二块。一旦方向确定、Agent 只是在执行规格,一个任务可能会呼叫模型
+二十次、五十次。这五十次真的每一次都需要市面上最贵的模型吗?通常不需要。
+Agent 已经不是在帮我决定产品要怎么做,它是在按照前面已经写好的规格执行。
+只要本地模型可以正确理解这些规格、知道工具怎么用,它就已经跨过可以工作的
+门槛。
---
-## Agent 會把小小的價差一直放大
+## Agent 会把小小的价差一直放大
-用聊天,是問一次、回答一次。Claude 一次比本地模型貴很多,你也不會有特別
+用聊天,是问一次、回答一次。Claude 一次比本地模型贵很多,你也不会有特别
感受。
-但 Agent 不是一次。一個任務可能呼叫模型二十次、五十次,失敗之後還會重新
-跑。模型單次價格的差距,放進這種連續任務裡就會被一直放大。
+但 Agent 不是一次。一个任务可能呼叫模型二十次、五十次,失败之后还会重新
+跑。模型单次价格的差距,放进这种连续任务里就会被一直放大。
-而真正做過這些流程的人都知道,最花資源的往往還不是最後正式執行,而是前面
-測試。你會改 Prompt、換工具、重新切資料、調整工作流程,同一個東西跑十次、
+而真正做过这些流程的人都知道,最花资源的往往还不是最后正式执行,而是前面
+测试。你会改 Prompt、换工具、重新切资料、调整工作流程,同一个东西跑十次、
二十次很正常。
-每次都是 API,我自己就會很明顯感覺到:又在燒錢。用自己那張卡,當然還是有
-電費跟硬體成本,但我今天讓一個 Agent 跑五次還是五十次,不會每跑一次就多
-一筆帳單。這對我來說很重要,因為它會直接影響我敢不敢一直連續測試。很多
-真正穩定的 AI workflow,不是第一次寫完就成功,而是讓它失敗很多次之後,
-才慢慢找到什麼地方容易出問題。
+每次都是 API,我自己就会很明显感觉到:又在烧钱。用自己那张卡,当然还是有
+电费跟硬体成本,但我今天让一个 Agent 跑五次还是五十次,不会每跑一次就多
+一笔帐单。这对我来说很重要,因为它会直接影响我敢不敢一直连续测试。很多
+真正稳定的 AI workflow,不是第一次写完就成功,而是让它失败很多次之后,
+才慢慢找到什么地方容易出问题。
-本地算力其中一個很大的價值,就是你可以把這些大量試錯搬回自己的固定成本
-裡。這跟單純比較「一百萬 Token 多少錢」其實是兩件事。
+本地算力其中一个很大的价值,就是你可以把这些大量试错搬回自己的固定成本
+里。这跟单纯比较「一百万 Token 多少钱」其实是两件事。
+
+算一笔很实在的工程账:一个包含工具调用的典型 Agent 循环,跑完一次完整的代码测试或文件重构,通常要经历 30–50 轮迭代。由于每轮都需要把历史上下文和工具执行输出重新带入,平均单轮上下文在 15k–25k tokens 左右——单次 Agent 运行就要消耗 600k–1.2M tokens。如果你在调试一套新的复杂工作流,一天反复测试优化 20 次,就是 1,500 万到 2,400 万 tokens。按照顶级 API(如 Claude 3.5 Sonnet 的 $3/$15 每百万 token)计算,这一天的调试账单就在 $50 到 $150 美元;若是 Claude Opus,直接突破数百美元。
+
+而在我这台配有 12GB 显存的自托管 GPU 节点上(通过 LM Studio / llama.cpp 本地运行量化版 Qwen 2.5),整机满载功耗不过 170W 左右。一天跑 20 次还是跑 100 次,新增的边际成本只有几毛钱电费。这笔账的本质不是简单的 token 单价对比,而是决定了你在工程探索时,敢不敢给 Agent 足够的试错空间。
---
-## 開放模型已經跨過可用的線,而這條線還在移動
+## 开放模型已经跨过可用的线,而这条线还在移动
-三年前,要在消費級顯卡上跑一個真的可以幫你工作的模型,限制很多。現在
-二三十 B 的模型經過量化之後,24GB、32GB 這種顯卡已經可以處理不少工作;
-再往更大的記憶體走,語言、圖片,甚至部分影片模型都開始可以自己部署。
+三年前,要在消费级显卡上跑一个真的可以帮你工作的模型,限制很多。现在
+二三十 B 的模型经过量化之后,24GB、32GB 这种显卡已经可以处理不少工作;
+再往更大的记忆体走,语言、图片,甚至部分影片模型都开始可以自己部署。
-真正重要的不是「開源終於打贏閉源了」,而是原本只有閉源模型做得到的工作,
-正在一個一個掉進本地可以處理、而且可以被接受的範圍。假設三年前十個工作
-只有兩個能放本地,現在已經有四五個可以做——這個比例本身就已經改變了
-本地部署的價值。
+真正重要的不是「开源终于打赢闭源了」,而是原本只有闭源模型做得到的工作,
+正在一个一个掉进本地可以处理、而且可以被接受的范围。假设三年前十个工作
+只有两个能放本地,现在已经有四五个可以做——这个比例本身就已经改变了
+本地部署的价值。
-而且我買 GPU 的時候,不是在買 Qwen 這一顆模型。模型可以一直換,也會一直
-出現新的:如果之後出現一個更適合 Coding 的開放模型,我直接換權重;再過
-半年有更好的量化方式,同一張卡可能又可以裝進原本跑不動的模型。我真正買
-下來的,是**一塊自己可以控制的運算資源**,後面的模型可以一直替換。
+而且我买 GPU 的时候,不是在买 Qwen 这一颗模型。模型可以一直换,也会一直
+出现新的:如果之后出现一个更适合 Coding 的开放模型,我直接换权重;再过
+半年有更好的量化方式,同一张卡可能又可以装进原本跑不动的模型。我真正买
+下来的,是**一块自己可以控制的运算资源**,后面的模型可以一直替换。
-這就是本地跟閉源服務最不一樣的地方。閉源模型能力通常比較強,但你用的是
-某家公司現在願意提供給你的版本;本地硬體能力可能沒那麼高,但只要硬體
-撐得住,我可以自己決定今天跑什麼模型、換什麼版本、要跑多久。
+这就是本地跟闭源服务最不一样的地方。闭源模型能力通常比较强,但你用的是
+某家公司现在愿意提供给你的版本;本地硬体能力可能没那么高,但只要硬体
+撑得住,我可以自己决定今天跑什么模型、换什么版本、要跑多久。
---
## 固定算力 vs. 每次租算力
-如果 AI 永遠只是拿來問問題,我完全不覺得大家都需要買 GPU。但現在發展方向
-很明顯不是這樣:Agent 會長時間執行工作,圖片跟影片模型會需要大量生成,
-公司也會把更多固定流程交給 AI。我們不是單純使用模型的次數變多,而是模型
-開始變成一個持續工作的運算單位。
+如果 AI 永远只是拿来问问题,我完全不觉得大家都需要买 GPU。但现在发展方向
+很明显不是这样:Agent 会长时间执行工作,图片跟影片模型会需要大量生成,
+公司也会把更多固定流程交给 AI。我们不是单纯使用模型的次数变多,而是模型
+开始变成一个持续工作的运算单位。
-這時候,「固定擁有一部分算力」跟「每一次執行都向外面租」,就會開始變成
-兩種不同的成本結構。使用量少,租一定比較方便;使用量夠大、夠固定之後,
-自己有算力就能更好控制與估算成本。
+这时候,「固定拥有一部分算力」跟「每一次执行都向外面租」,就会开始变成
+两种不同的成本结构。使用量少,租一定比较方便;使用量够大、够固定之后,
+自己有算力就能更好控制与估算成本。
-它還多了一個閉源服務給不了的東西:主控權。當機器是我的,我要跑內部資料、
-接自己的工具、長時間執行 Agent,都不需要每次先確認供應商的方案、額度或者
-限制有沒有改。尤其公司真的開始把 AI 接進內部流程之後,這件事就不只是省
-Token——有些資料本來就不適合離開自己的環境,有些 Agent 權限也不可能直接
-全部交給外部服務。當模型跑在自己的環境裡,資料、工具、權限跟執行方式可以
-一起設計。這才是「控制權」真正指的東西,不只是把權重下載下來而已。
+它还多了一个闭源服务给不了的东西:主控权。当机器是我的,我要跑内部资料、
+接自己的工具、长时间执行 Agent,都不需要每次先确认供应商的方案、额度或者
+限制有没有改。尤其公司真的开始把 AI 接进内部流程之后,这件事就不只是省
+Token——有些资料本来就不适合离开自己的环境,有些 Agent 权限也不可能直接
+全部交给外部服务。当模型跑在自己的环境里,资料、工具、权限跟执行方式可以
+一起设计。这才是「控制权」真正指的东西,不只是把权重下载下来而已。
---
-## 我現在實際怎麼判斷
+## 我现在实际怎么判断
-我不會再用「它比 Claude 笨,所以沒有價值」這種方式判斷一個本地模型。我會
+我不会再用「它比 Claude 笨,所以没有价值」这种方式判断一个本地模型。我会
依序看四件事:
-1. **這顆模型能不能跨過我這個工作的門檻?**
-2. **這個任務會執行多少次?**
-3. **是不是需要大量試錯,或長時間的 Agent?**
-4. **這些資料跟系統,到底要不要留在自己的環境?**
+1. **这颗模型能不能跨过我这个工作的门槛?**
+2. **这个任务会执行多少次?**
+3. **是不是需要大量试错,或长时间的 Agent?**
+4. **这些资料跟系统,到底要不要留在自己的环境?**
-這幾個條件一疊起來,本地模型即使不是最強,還是可能比頂級閉源模型更適合
-那一段工作。而且隨著開放模型越來越強,這個範圍只會一直變大。
+这几个条件一叠起来,本地模型即使不是最强,还是可能比顶级闭源模型更适合
+那一段工作。而且随著开放模型越来越强,这个范围只会一直变大。
-所以我真正看好的,不是某一顆模型,也不是某一張 GPU,而是這個趨勢:
-**可以在自己硬體上完成的 AI 工作正在變多。** 以前買一張消費級顯示卡,
-可能只能拿來跑一些語言模型;現在開始可以接 Agent、圖片、影片,後面模型
-跟推理框架繼續優化,同樣的硬體又可能得到新的用途。
+所以我真正看好的,不是某一颗模型,也不是某一张 GPU,而是这个趋势:
+**可以在自己硬体上完成的 AI 工作正在变多。** 以前买一张消费级显示卡,
+可能只能拿来跑一些语言模型;现在开始可以接 Agent、图片、影片,后面模型
+跟推理框架继续优化,同样的硬体又可能得到新的用途。
-硬體當然會折舊,新卡也可能越來越貴,但至少模型不是綁死的。只要這台機器
-還有足夠的運算能力,我就可以一直換新的開放模型。
+硬体当然会折旧,新卡也可能越来越贵,但至少模型不是绑死的。只要这台机器
+还有足够的运算能力,我就可以一直换新的开放模型。
---
-## 一句話版本
+## 一句话版本
-我現在已經不會只看哪個模型比較聰明。我比較的是:**這件工作到底需要多強的
-模型、它要被執行多少次,以及我願意把多少控制權留在外部服務手上。**
+我现在已经不会只看哪个模型比较聪明。我比较的是:**这件工作到底需要多强的
+模型、它要被执行多少次,以及我愿意把多少控制权留在外部服务手上。**
-需要頂級推理的地方,我照樣花錢用最強的模型。但當工作開始變成大量、連續、
-固定,而且本地模型的能力已經跨過可使用門檻時,我就沒有理由每一個步驟都
-繼續用最貴的閉源模型。
+需要顶级推理的地方,我照样花钱用最强的模型。但当工作开始变成大量、连续、
+固定,而且本地模型的能力已经跨过可使用门槛时,我就没有理由每一个步骤都
+继续用最贵的闭源模型。
-濃縮成一句:
+浓缩成一句:
-> 用頂級模型決定要做什麼,用本地算力把它做上一千次。
+> 用顶级模型决定要做什么,用本地算力把它做上一千次。
-這就是我買 GPU 的原因。
+这就是我买 GPU 的原因。
diff --git a/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md b/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
index ebda9c6..5a8b225 100644
--- a/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
+++ b/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
@@ -10,6 +10,7 @@ tags: ["yue2", "comfyui", "ai-music", "local-ai", "gpu", "vram", "mandarin"]
ogImage: "/og/zh-yue2-on-a-12gb-gpu-songs-that-lost-their-endings.jpg"
banner: "/banners/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.jpg"
draft: false
+dynamicCta: true
---
YuE2 是一个 30 亿参数的开源音乐模型,能按风格提示词和歌词唱中文。我把它放在自己那台 12GB 显存的 RTX 3060 上用 ComfyUI 本地跑,一次排了 12 首原创歌 —— 结果第一批出来,**每一首的时长都恰好是 240.000 秒**。这个数字不是巧合,而且是个坏消息。
@@ -51,7 +52,7 @@ curl -s -X POST http://127.0.0.1:20129/v1/audio/transcriptions \
-F "file=@t.wav" -F "language=zh"
```
-结果没有歧义:
+(对于连末遍副歌都没唱到的曲目,我将切片窗口向前扩展到了最后 30 秒即 `-ss 210`,以准确定位截断发生时的唱段。)结果没有歧义:
| 歌 | 唱到哪 | 缺了什么 |
|---|---|---|
@@ -118,7 +119,7 @@ ComfyUI 是用 `--cache-classic` 启动的,所以重新提交一个逐字节
| 281 秒 | 12.06 GB |
| 300 秒 | 12.03 GB |
-卡总共 12.288 GB。**300 秒就是实际天花板** —— 再往上,你离"渲染到第六分钟时因为一个浏览器标签页而 OOM 崩掉"只差一步。
+显存总量为 12,288 MiB(12 GB)。**300 秒就是实际天花板** —— 再往上,你离"渲染到第六分钟时因为一个浏览器标签页而 OOM 崩掉"只差一步。
## 解法