<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Token on 鬼哥的空间</title><link>https://luoli523.github.io/tags/token/</link><description>Recent content in Token on 鬼哥的空间</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 22 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://luoli523.github.io/tags/token/index.xml" rel="self" type="application/rss+xml"/><item><title>后端上下文工程：一个开源工具把 Claude Code 的账单砍掉 2/3</title><link>https://luoli523.github.io/p/backend-context-engineering/</link><pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate><guid>https://luoli523.github.io/p/backend-context-engineering/</guid><description>&lt;img src="https://luoli523.github.io/" alt="Featured image of post 后端上下文工程：一个开源工具把 Claude Code 的账单砍掉 2/3" /&gt;&lt;p&gt;最近我一直在观察一件事：&lt;strong&gt;模型越来越强，但 Agent 的账单却越来越贵&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这听起来像个悖论。按理说模型更聪明了，应该一步到位，少走弯路，反而更省 token 才对。但现实里，我自己跑 Claude Code 也好，同事跑 Cursor Agent 也罢，同一个任务，换了更强的模型之后 token 账单反而涨了一截。&lt;/p&gt;
&lt;p&gt;前两天刷到 Avi Chawla 写的这篇 &lt;a class="link" href="https://x.com/_avichawla/status/2046500537584218438" target="_blank" rel="noopener"
 &gt;How to cut Claude Code costs by 3x&lt;/a&gt;，一下子把我憋了好久的一个直觉讲清楚了——&lt;strong&gt;问题不在模型，在后端。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;更具体点：问题在后端是怎么把自己的状态&amp;quot;交代&amp;quot;给 Agent 的。这件事 Karpathy 在讲上下文工程（context engineering）的时候其实提过，但大部分人只把它当成一个&amp;quot;写 prompt 的技巧&amp;quot;，没意识到后端本身就是上下文的一部分。&lt;/p&gt;
&lt;h2 id="一个反直觉的数字"&gt;一个反直觉的数字
&lt;/h2&gt;&lt;p&gt;先看一张图，这是 MCPMark V2 跑的基准测试，21 个数据库任务，Supabase 的 MCP server 被调用产生的后端 token 消耗：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sonnet 4.5：11.6M tokens&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sonnet 4.6：17.9M tokens&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Sonnet 4.5 到 4.6，后端 token 反而涨了 50%" class="gallery-image" data-flex-basis="525px" data-flex-grow="218" height="548" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/token-gap.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/token-gap_hu_b0cc01d1b6c97101.webp 800w, https://luoli523.github.io/p/backend-context-engineering/token-gap.webp 1199w" width="1199"&gt;&lt;/p&gt;
&lt;p&gt;模型变聪明了，消耗反而多了 50%。&lt;/p&gt;
&lt;p&gt;这个结果第一次看到我是懵的，但仔细想一下其实合理：&lt;strong&gt;当后端给出的信息不完整时，更聪明的模型不会&amp;quot;跳过空白&amp;quot;，它会花更多 token 去推理那个空白&lt;/strong&gt;——多跑几次发现式查询，多重试几次，多尝试几种 workaround。&lt;/p&gt;
&lt;p&gt;换句话说，&amp;ldquo;缺失的上下文&amp;quot;不会因为你换了更好的模型就消失，它只会变得更贵。&lt;/p&gt;
&lt;h2 id="为什么-supabase-的-mcp-是个-token-黑洞"&gt;为什么 Supabase 的 MCP 是个 token 黑洞
&lt;/h2&gt;&lt;p&gt;Supabase 本身是个好产品，但它&lt;strong&gt;不是为 AI Agent 设计的&lt;/strong&gt;——MCP server 是后来贴上去的，继承了所有面向人类开发者的设计假设。三个机制直接导致 token 爆炸：&lt;/p&gt;
&lt;h3 id="1文档检索给一勺米端来一锅饭"&gt;1）文档检索：给一勺米，端来一锅饭
&lt;/h3&gt;&lt;p&gt;当 Claude Code 要在 Supabase 上配 Google OAuth，它会去调用 &lt;code&gt;search_docs&lt;/code&gt; 这个 MCP tool。Supabase 的实现是——&lt;strong&gt;每次调用都返回整块 GraphQL schema metadata&lt;/strong&gt;，token 量是 Agent 实际需要的 5-10 倍。&lt;/p&gt;
&lt;p&gt;&lt;img alt="每次 search_docs 都把整块域的文档全砸过来" class="gallery-image" data-flex-basis="480px" data-flex-grow="200" height="599" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/docs-overhead.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/docs-overhead_hu_864d64815bc06072.webp 800w, https://luoli523.github.io/p/backend-context-engineering/docs-overhead.webp 1200w" width="1200"&gt;&lt;/p&gt;
&lt;p&gt;你问 OAuth 怎么配，它把 email/password、magic link、phone auth、SAML、SSO 全给你一遍。&lt;/p&gt;
&lt;p&gt;这个模式发生在每一次 &lt;code&gt;search_docs&lt;/code&gt; 调用上——查数据库、查 storage 配置、查 edge function 部署……每次都是一整片 domain 的 metadata dump 下来。一个 session 里光这部分的&amp;quot;文档 overhead&amp;quot;就能消耗掉几千 token，而这些 token 里真正被用上的不到两成。&lt;/p&gt;
&lt;h3 id="2后端状态agent-看不到仪表盘"&gt;2）后端状态：Agent 看不到仪表盘
&lt;/h3&gt;&lt;p&gt;当你作为人类开发者用 Supabase 时，你打开 dashboard，一眼扫过去就知道：启用了哪些 auth provider，有哪些表，RLS 策略是什么，storage bucket 怎么配的，edge function 部署到哪一步了……&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent 看不到 dashboard。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Supabase 没有\"一次性返回整个后端拓扑\"的接口" class="gallery-image" data-flex-basis="466px" data-flex-grow="194" height="617" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/no-backend-visibility.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/no-backend-visibility_hu_9b7ac3a2612e1bcf.webp 800w, https://luoli523.github.io/p/backend-context-engineering/no-backend-visibility.webp 1200w" width="1200"&gt;&lt;/p&gt;
&lt;p&gt;Supabase 的 MCP 确实暴露了一些状态查询接口——&lt;code&gt;list_tables&lt;/code&gt;、&lt;code&gt;execute_sql&lt;/code&gt; 之类——但&lt;strong&gt;没有一个接口能回答&amp;quot;我这个后端整体长什么样&amp;rdquo;&lt;/strong&gt;。Agent 只能一个个工具串着调，每次拿回来一小块，部分信息（比如哪些 auth provider 启用了）甚至根本不在 MCP 里。&lt;/p&gt;
&lt;p&gt;这个&amp;quot;拼图式&amp;quot;的状态发现过程本身就烧 token，而且经常拼不完整，要回头补查。&lt;/p&gt;
&lt;h3 id="3错误信息只告诉你-401不告诉你为什么-401"&gt;3）错误信息：只告诉你 401，不告诉你为什么 401
&lt;/h3&gt;&lt;p&gt;出错是必然的，因为 Agent 在猜。而 Supabase 返回的错误是&lt;strong&gt;原始错误信息&lt;/strong&gt;：RLS 拒绝了个 403，edge function 配错了给你 500，就这些。&lt;/p&gt;
&lt;p&gt;人类开发者看到错误，会去翻 dashboard、交叉比对日志、查 Supabase 的状态面板，最后定位问题。Agent 没有这个路径，它只能&lt;strong&gt;根据错误信息的字面意思去猜可能的原因，改一遍代码，再试一次&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;猜错了，再来一轮。&lt;strong&gt;每一轮重试都会把之前整个对话历史重新发一遍&lt;/strong&gt;，token 成本像滚雪球一样涨。&lt;/p&gt;
&lt;p&gt;这三个机制一叠加，Sonnet 4.6 这种&amp;quot;推理更深入&amp;quot;的模型反而会把 token gap 拉得更大——因为它每一步探索都更细、更花 token。&lt;/p&gt;
&lt;h2 id="上下文工程在后端长什么样"&gt;上下文工程在后端长什么样
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;修复方案不是换模型，而是给 Agent 一个结构化的后端上下文&lt;/strong&gt;，让它不用探索、不用猜。&lt;/p&gt;
&lt;p&gt;这正是 Karpathy 说的那句话：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Context engineering: the delicate art and science of filling the context window with just the right information for the next step.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Karpathy 明确把&lt;strong&gt;工具和状态&lt;/strong&gt;列入了 context 的一部分。大部分人把这个概念用在 prompt 和 RAG 检索上，但&lt;strong&gt;后端也是上下文窗口的一部分&lt;/strong&gt;——而且是目前几乎没人在优化的那部分。&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/InsForge/InsForge" target="_blank" rel="noopener"
 &gt;InsForge&lt;/a&gt;（开源，8k star）就是冲这个问题去设计的。&lt;/p&gt;
&lt;p&gt;&lt;img alt="InsForge 的三层架构：Skills + CLI + MCP" class="gallery-image" data-flex-basis="257px" data-flex-grow="107" height="847" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/insforge-overview.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/insforge-overview_hu_7fbe3ce946f7e7a7.webp 800w, https://luoli523.github.io/p/backend-context-engineering/insforge-overview.webp 910w" width="910"&gt;&lt;/p&gt;
&lt;p&gt;它提供和 Supabase 类似的原语——Postgres + pgvector、auth、storage、edge functions、realtime——但&lt;strong&gt;信息层是按&amp;quot;Agent 消费效率&amp;quot;来组织的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;核心架构是三层协作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Skills&lt;/strong&gt; 承载静态知识&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI&lt;/strong&gt; 负责直接执行后端操作&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP&lt;/strong&gt; 只用来做实时状态查询&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一层解决一个具体问题，为不同原因省 token。&lt;/p&gt;
&lt;h3 id="1skills静态知识零往返"&gt;1）Skills：静态知识零往返
&lt;/h3&gt;&lt;p&gt;InsForge 选择用 Agent Skills 作为主要的知识承载方式——&lt;strong&gt;在 session 启动时就直接加载进 Agent context&lt;/strong&gt;，SDK 用法、代码示例、各种边界情况都不用走 tool call 就能拿到。&lt;/p&gt;
&lt;p&gt;而且 Skills 用的是&lt;strong&gt;渐进式披露&lt;/strong&gt;：初始只加载元信息（name、description，大概 70-150 token/skill），只有当 Agent 判断当前任务匹配才加载完整内容。这意味着你可以装上百个 Skills 也不会把 context 撑爆——这是 MCP 的&amp;quot;要么全加载要么不加载&amp;quot;做不到的。&lt;/p&gt;
&lt;p&gt;&lt;img alt="四个 Skill 各司其职" class="gallery-image" data-flex-basis="416px" data-flex-grow="173" height="650" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/insforge-four-skills.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/insforge-four-skills_hu_2a67fca0f3631f3b.webp 800w, https://luoli523.github.io/p/backend-context-engineering/insforge-four-skills.webp 1128w" width="1128"&gt;&lt;/p&gt;
&lt;p&gt;四个 Skill 覆盖全栈，每个都有明确的边界：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Skill&lt;/th&gt;
 &lt;th&gt;职责&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;insforge&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;前端代码怎么和后端对话&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;insforge-cli&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;后端基础设施管理&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;insforge-debug&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;结构化错误诊断（auth 错、慢查询、edge function 失败、RLS 拒绝等）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;insforge-integrations&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;第三方 auth provider（Clerk、Auth0、WorkOS、Kinde、Stytch）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一行命令全装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx skills add insforge/insforge-skills
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="2cli给-agent-的命令行手柄"&gt;2）CLI：给 Agent 的&amp;quot;命令行手柄&amp;quot;
&lt;/h3&gt;&lt;p&gt;真正执行后端操作——建表、跑 SQL、部署 function、管理 secret——InsForge 把 &lt;strong&gt;CLI 作为主要入口&lt;/strong&gt;，而不是 MCP。&lt;/p&gt;
&lt;p&gt;每个命令都支持 &lt;code&gt;--json&lt;/code&gt; 输出结构化结果，&lt;code&gt;-y&lt;/code&gt; 跳过确认，返回&lt;strong&gt;语义化的 exit code&lt;/strong&gt;，让 Agent 能直接通过返回码判断是 auth 失败、项目不存在还是权限问题。&lt;/p&gt;
&lt;p&gt;这个设计的好处是 Claude Code 可以把 CLI 输出接到 &lt;code&gt;jq&lt;/code&gt;、&lt;code&gt;grep&lt;/code&gt;、&lt;code&gt;awk&lt;/code&gt; 管道里，这是同样功能要用 MCP 实现时得连续调用好几次的事情。&lt;/p&gt;
&lt;p&gt;Scalekit 跑的对比基准显示：&lt;strong&gt;CLI+Skills 在单用户 workflow 里的 token 效率比等价 MCP 方案高 10-35 倍&lt;/strong&gt;，成功率接近 100%。&lt;/p&gt;
&lt;p&gt;一些典型的 Agent 实际执行的命令长这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 后端状态探查（Agent 第一件事就干这个）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli metadata --json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 数据库操作&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli db query &lt;span class="s2"&gt;&amp;#34;CREATE TABLE posts (...)&amp;#34;&lt;/span&gt; --json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli db policies
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Edge functions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli functions deploy my-handler
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli functions invoke my-handler --data &lt;span class="s1"&gt;&amp;#39;{&amp;#34;action&amp;#34;:&amp;#34;test&amp;#34;}&amp;#39;&lt;/span&gt; --json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli storage create-bucket documents --json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli storage upload ./file.pdf --bucket documents
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 诊断&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx @insforge/cli diagnose db --check connections,locks,slow-queries
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Agent 直接 parse JSON，然后根据 exit code 处理错误——干净、确定、可脚本化。&lt;/p&gt;
&lt;h3 id="3mcp只用来看活的状态"&gt;3）MCP：只用来看&amp;quot;活的状态&amp;quot;
&lt;/h3&gt;&lt;p&gt;MCP 这个路径也保留了，但&lt;strong&gt;用途变得很窄&lt;/strong&gt;——只用来查后端当前的实时状态。&lt;/p&gt;
&lt;p&gt;InsForge 的 MCP server 只暴露了一个轻量的 &lt;code&gt;get_backend_metadata&lt;/code&gt; 工具，一次调用返回整个后端的拓扑：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;auth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;providers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;google&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;github&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;jwt_secret&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;configured&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tables&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;users&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;columns&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;created_at&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;rls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;posts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;columns&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;author_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;rls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;storage&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;buckets&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;avatars&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;documents&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;ai&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;models&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gpt-4o&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;capabilities&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;chat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;vision&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]}]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hints&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Use RPC for batch operations&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Storage accepts files up to 50MB&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;一次调用、大约 500 token，Agent 就掌握了整个后端拓扑&lt;/strong&gt;。其中 &lt;code&gt;hints&lt;/code&gt; 字段是 Agent 专用的使用提示，能直接减少 API 误用。&lt;/p&gt;
&lt;p&gt;关键的设计选择是：&lt;strong&gt;MCP 只做&amp;quot;会变化的状态查询&amp;quot;，不做&amp;quot;静态文档检索&amp;quot;&lt;/strong&gt;——这和业界默认的用法正好反过来，也是 InsForge 比 Supabase 省 token 的根本原因。&lt;/p&gt;
&lt;h2 id="实战对比用-claude-code-造同一个-rag-应用"&gt;实战对比：用 Claude Code 造同一个 RAG 应用
&lt;/h2&gt;&lt;p&gt;作者选了一个应用叫 DocuRAG：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google OAuth 登录&lt;/li&gt;
&lt;li&gt;上传 PDF&lt;/li&gt;
&lt;li&gt;自动 chunk + embed（&lt;code&gt;text-embedding-3-small&lt;/code&gt;，1536 维）&lt;/li&gt;
&lt;li&gt;向量存进 pgvector&lt;/li&gt;
&lt;li&gt;用户问问题，系统 embed 查询、检索相关 chunk、GPT-4o 生成回答&lt;/li&gt;
&lt;li&gt;RLS 隔离不同用户的文档&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一次覆盖：&lt;strong&gt;auth、storage、documents 表、vector embedding、embedding 生成、chat completion、retrieval edge function、RLS&lt;/strong&gt;——几乎所有后端原语都碰上了。&lt;/p&gt;
&lt;p&gt;同一份 prompt，唯一的差别是 Supabase 版本要声明&amp;quot;LLMs/embedding models via the OpenAI API&amp;quot;（两套系统要接），InsForge 版本只需要&amp;quot;also for the model gateway&amp;quot;（一套系统）。&lt;/p&gt;
&lt;p&gt;作者把两次完整的 Claude Code session 录下来了：&lt;/p&gt;
&lt;p&gt;&lt;img alt="video" class="gallery-image" data-flex-basis="315px" data-flex-grow="131" height="822" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/video-poster.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/video-poster_hu_4a361166cee4e3ef.webp 800w, https://luoli523.github.io/p/backend-context-engineering/video-poster.webp 1080w" width="1080"&gt;&lt;/p&gt;
&lt;video controls style="max-width:100%;height:auto;"&gt;
 &lt;source src="video-001.mp4" type="video/mp4"&gt;
&lt;/video&gt;
&lt;p&gt;&lt;strong&gt;顺便提一句录像里没捕捉到的细节&lt;/strong&gt;：Supabase 那次，Google OAuth 需要手动在 Google Cloud Console 里建 OAuth 2.0 Client ID、配 consent screen、加测试用户、复制 Client ID 和 Secret 粘回 Supabase dashboard——这些都不在 Claude Code 的控制范围内。InsForge 则完全不用这一步。&lt;/p&gt;
&lt;p&gt;先看最后的账单：&lt;/p&gt;
&lt;p&gt;&lt;img alt="最终 token 和成本对比" class="gallery-image" data-flex-basis="679px" data-flex-grow="283" height="424" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/final-stats.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/final-stats_hu_c477a596566a29d3.webp 800w, https://luoli523.github.io/p/backend-context-engineering/final-stats.webp 1200w" width="1200"&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;后端&lt;/th&gt;
 &lt;th&gt;Token&lt;/th&gt;
 &lt;th&gt;成本&lt;/th&gt;
 &lt;th&gt;用户消息&lt;/th&gt;
 &lt;th&gt;错误报告&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Supabase&lt;/td&gt;
 &lt;td&gt;10.4M&lt;/td&gt;
 &lt;td&gt;$9.21&lt;/td&gt;
 &lt;td&gt;12 条&lt;/td&gt;
 &lt;td&gt;10 条&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;InsForge&lt;/td&gt;
 &lt;td&gt;3.7M&lt;/td&gt;
 &lt;td&gt;$2.81&lt;/td&gt;
 &lt;td&gt;1 条&lt;/td&gt;
 &lt;td&gt;0 条&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;3x 的差距&lt;/strong&gt;。现在我们看看两次 session 具体发生了什么。&lt;/p&gt;
&lt;h2 id="supabase104m-token-的大部分都花在调错上"&gt;Supabase：10.4M token 的大部分都花在调错上
&lt;/h2&gt;&lt;p&gt;初始构建其实很顺。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Supabase 首次构建：schema、edge function 都搞定了" class="gallery-image" data-flex-basis="427px" data-flex-grow="177" height="503" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/supabase-initial-build.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/supabase-initial-build_hu_b57ce3bf2ff2b9f6.webp 800w, https://luoli523.github.io/p/backend-context-engineering/supabase-initial-build.webp 895w" width="895"&gt;&lt;/p&gt;
&lt;p&gt;Agent 加载了 &lt;code&gt;supabase&lt;/code&gt; skill，用 MCP 的 &lt;code&gt;list_tables&lt;/code&gt;、&lt;code&gt;list_extensions&lt;/code&gt;、&lt;code&gt;execute_sql&lt;/code&gt; 把后端状态摸了一遍，scaffold 了 Next.js 项目，建了库表，写了两个 edge function（&lt;code&gt;ingest-document&lt;/code&gt; 和 &lt;code&gt;query-document&lt;/code&gt;），部署完成，build 通过。&lt;/p&gt;
&lt;p&gt;然后开始翻车。&lt;/p&gt;
&lt;h3 id="第一个坑登录直接不工作"&gt;第一个坑：登录直接不工作
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Google OAuth 登录失败" class="gallery-image" data-flex-basis="602px" data-flex-grow="251" height="358" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/supabase-login-error.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/supabase-login-error_hu_b1bf3ebfcc2a8a3.webp 800w, https://luoli523.github.io/p/backend-context-engineering/supabase-login-error.webp 899w" width="899"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="OAuth 回调报错" class="gallery-image" data-flex-basis="602px" data-flex-grow="251" height="358" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/supabase-oauth-fail.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/supabase-oauth-fail_hu_b1bf3ebfcc2a8a3.webp 800w, https://luoli523.github.io/p/backend-context-engineering/supabase-oauth-fail.webp 899w" width="899"&gt;&lt;/p&gt;
&lt;p&gt;问题在于 Next.js 下 OAuth 回调跑在 server 端，但 Agent 给你装的是&lt;strong&gt;客户端 Supabase 库&lt;/strong&gt;，把 session 存在浏览器里——server 端拿不到，登录整个崩了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="换成 @supabase/ssr 后重新连通" class="gallery-image" data-flex-basis="297px" data-flex-grow="123" height="742" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/supabase-ssr-fix.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/supabase-ssr-fix_hu_db5246a124c81120.webp 800w, https://luoli523.github.io/p/backend-context-engineering/supabase-ssr-fix.webp 920w" width="920"&gt;&lt;/p&gt;
&lt;p&gt;Agent 切到 &lt;code&gt;@supabase/ssr&lt;/code&gt;，重写了 session 处理，重新构建——算是过了。&lt;/p&gt;
&lt;h3 id="第二个坑上传文档连续-8-轮失败"&gt;第二个坑：上传文档，连续 8 轮失败
&lt;/h3&gt;&lt;p&gt;登录修好之后试上传，edge function 报错。我报错 → Agent 改 → 失败 → 再报错 → 再改 → 同一个错。&lt;strong&gt;这个循环跑了 8 次&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img alt="8 轮修复尝试" class="gallery-image" data-flex-basis="326px" data-flex-grow="136" height="881" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/supabase-retry-loop.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/supabase-retry-loop_hu_af9d4f675ad9a206.webp 800w, https://luoli523.github.io/p/backend-context-engineering/supabase-retry-loop.webp 1200w" width="1200"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;加 auth header → 同样错误&lt;/li&gt;
&lt;li&gt;加日志重新部署 → 同样错误&lt;/li&gt;
&lt;li&gt;打印真实错误信息 → 变成 CORS 错误&lt;/li&gt;
&lt;li&gt;修 CORS → 回到原来的错误&lt;/li&gt;
&lt;li&gt;换一种读取用户 token 的方法 → 同样错误&lt;/li&gt;
&lt;li&gt;换另一种鉴权方式 → 同样错误&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;8 轮之后，Agent 终于说了句：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;The 401s may be happening at the platform&amp;rsquo;s verify_jwt gate before our code even runs.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="verify_jwt 在平台层直接拒绝了请求" class="gallery-image" data-flex-basis="543px" data-flex-grow="226" height="445" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/supabase-verify-jwt.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/supabase-verify-jwt_hu_5d533ab5d1ab6f7b.webp 800w, https://luoli523.github.io/p/backend-context-engineering/supabase-verify-jwt.webp 1008w" width="1008"&gt;&lt;/p&gt;
&lt;p&gt;翻译一下：&lt;strong&gt;Supabase 在平台层有个自动 token 检查，发生在你的 edge function 代码执行之前&lt;/strong&gt;。前面换 &lt;code&gt;@supabase/ssr&lt;/code&gt; 的时候，新库发送的 token 格式平台层不认，所有请求在&amp;quot;门口&amp;quot;就被拒了，function 代码根本没跑起来——所以 8 轮代码级别的修复全都不对。&lt;/p&gt;
&lt;p&gt;解法很简单：&lt;strong&gt;关掉平台的自动 token 检查，在 function 内部自己做鉴权&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但这 8 轮里 edge function 被重新部署了 8 次（加上最初的 2 次就是 10 次），每一次重新部署、每一次看日志、每一次重试，&lt;strong&gt;都会把越来越长的对话历史重新塞进 context&lt;/strong&gt;——token 就是这么滚起来的。&lt;/p&gt;
&lt;p&gt;Supabase 的最终统计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;12 条用户消息（其中 10 条是报错）&lt;/li&gt;
&lt;li&gt;135 次 tool call&lt;/li&gt;
&lt;li&gt;30+ 次 MCP 调用&lt;/li&gt;
&lt;li&gt;10.4M token&lt;/li&gt;
&lt;li&gt;$9.21&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="insforge37m-token零错误干预"&gt;InsForge：3.7M token，零错误干预
&lt;/h2&gt;&lt;p&gt;InsForge 这边，&lt;strong&gt;全程没有一次需要我介入的错误&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Agent 第一件事是 &lt;code&gt;npx @insforge/cli metadata --json&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img alt="一次调用拿到整个后端状态" class="gallery-image" data-flex-basis="312px" data-flex-grow="130" height="739" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/insforge-metadata.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/insforge-metadata_hu_318261f56e5bc32d.webp 800w, https://luoli523.github.io/p/backend-context-engineering/insforge-metadata.webp 962w" width="962"&gt;&lt;/p&gt;
&lt;p&gt;一次返回：auth provider、现有表、storage bucket、可用 AI 模型、realtime channel。&lt;strong&gt;Agent 在写任何代码之前就已经对这个后端有了完整认知&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对比 Supabase 那次要调多个 MCP tool 才能拼出类似认知，而且还漏掉了 &lt;code&gt;verify_jwt&lt;/code&gt; 这种关键细节——差距在这里就已经拉开了。&lt;/p&gt;
&lt;p&gt;Schema 建立跑了 6 条 CLI 命令，全部成功：&lt;/p&gt;
&lt;p&gt;&lt;img alt="6 条 CLI 命令一次过" class="gallery-image" data-flex-basis="252px" data-flex-grow="105" height="896" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/insforge-schema.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/insforge-schema_hu_75da054265089458.webp 800w, https://luoli523.github.io/p/backend-context-engineering/insforge-schema.webp 942w" width="942"&gt;&lt;/p&gt;
&lt;p&gt;启用 pgvector、建 &lt;code&gt;documents&lt;/code&gt; 和 &lt;code&gt;chunks&lt;/code&gt; 表（带 &lt;code&gt;vector(1536)&lt;/code&gt; 列）、在两张表上开 RLS、创建访问策略、建 &lt;code&gt;match_chunks&lt;/code&gt; 相似度搜索函数。每一条都返回结构化输出确认执行了什么，Agent 逐步验证。&lt;/p&gt;
&lt;p&gt;&lt;img alt="两个 edge function 一次部署成功" class="gallery-image" data-flex-basis="316px" data-flex-grow="132" height="858" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/insforge-functions.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/insforge-functions_hu_15aca105a5864f57.webp 800w, https://luoli523.github.io/p/backend-context-engineering/insforge-functions.webp 1133w" width="1133"&gt;&lt;/p&gt;
&lt;p&gt;Supabase 那边的 auth 和 edge function 坑——这边一个都没撞上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;insforge&lt;/code&gt; skill 自带了 Next.js 下正确的客户端库用法，Agent 一次写对&lt;/li&gt;
&lt;li&gt;两个 edge function（&lt;code&gt;embed-chunks&lt;/code&gt; 和 &lt;code&gt;query-rag&lt;/code&gt;）因为 &lt;strong&gt;embedding 和 chat completion 都在同一个 model gateway 里&lt;/strong&gt;，直接调就行，不用单独接 OpenAI、不用管第二套 API key、不用处理跨服务鉴权&lt;/li&gt;
&lt;li&gt;metadata 里已经列出了 &lt;code&gt;text-embedding-3-small&lt;/code&gt; 和 &lt;code&gt;gpt-4o&lt;/code&gt;，Agent 通过 InsForge SDK 直接调用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 条用户消息&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;77 次 tool call&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;0 次 MCP 调用&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;3.7M token&lt;/li&gt;
&lt;li&gt;$2.81&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作者让 Claude 生成的对照表：&lt;/p&gt;
&lt;p&gt;&lt;img alt="完整对照表" class="gallery-image" data-flex-basis="308px" data-flex-grow="128" height="933" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/summary-table.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/summary-table_hu_961c980bfd773236.webp 800w, https://luoli523.github.io/p/backend-context-engineering/summary-table.webp 1200w" width="1200"&gt;&lt;/p&gt;
&lt;h2 id="我自己的体感"&gt;我自己的体感
&lt;/h2&gt;&lt;p&gt;看完这个对比，我最大的感慨不是&amp;quot;InsForge 比 Supabase 强&amp;quot;——&lt;strong&gt;这不是产品优劣的问题，是架构假设的问题&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt="给人用的后端，和给 Agent 用的后端，根本不是一回事" class="gallery-image" data-flex-basis="466px" data-flex-grow="194" height="617" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://luoli523.github.io/p/backend-context-engineering/assumption-broken.webp" srcset="https://luoli523.github.io/p/backend-context-engineering/assumption-broken_hu_9b7ac3a2612e1bcf.webp 800w, https://luoli523.github.io/p/backend-context-engineering/assumption-broken.webp 1200w" width="1200"&gt;&lt;/p&gt;
&lt;p&gt;我过去几个月用 Claude Code 跑全栈任务，有个特别直观的感受：&lt;strong&gt;Agent 花在&amp;quot;搞清楚现在是什么状态&amp;quot;上的 token，常常比&amp;quot;写代码&amp;quot;还多&lt;/strong&gt;。你看它在那里 &lt;code&gt;ls&lt;/code&gt; 来 &lt;code&gt;ls&lt;/code&gt; 去，&lt;code&gt;grep&lt;/code&gt; 来 &lt;code&gt;grep&lt;/code&gt; 去，尝试各种命令去探测配置……每一步都是 token。&lt;/p&gt;
&lt;p&gt;Supabase 这类后端本来就是给人类开发者设计的：人类可以看 dashboard、可以翻多个 tab 对比、可以凭经验&amp;quot;感觉到&amp;quot;问题大概在哪一层。Agent 一样都做不到——&lt;strong&gt;它只能从你返回给它的字节里推理&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如果后端返回的字节里不包含&amp;quot;verify_jwt 把请求在门口挡掉了&amp;quot;这个信号，它就永远不知道问题在上游，只会在代码层打转。&lt;/p&gt;
&lt;p&gt;这件事反过来对我写代码也有启发：&lt;strong&gt;当你给 Agent 提供接口或工具的时候，得用&amp;quot;Agent 视角&amp;quot;重新设计一遍返回值&lt;/strong&gt;——错误信息要结构化、状态查询要原子化、成功失败要有明确的语义码、文档要按任务切片而不是按资源切片。&lt;/p&gt;
&lt;p&gt;这不是 nice-to-have，是 cost driver。&lt;/p&gt;
&lt;h2 id="takeaway"&gt;Takeaway
&lt;/h2&gt;&lt;p&gt;如果要我用一句话总结这篇文章的价值：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;修的不是模型，也不是 context window，是后端怎么把自己交代给 Agent 这件事本身。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;几个可以直接拿走的判断：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Token 账单涨了不一定是模型的锅&lt;/strong&gt;。先去看看 tool call 的 input/output 形状——尤其是那些每次 dump 一大坨 metadata 的&amp;quot;便利接口&amp;quot;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP 不该用来查文档&lt;/strong&gt;。静态知识走 Skills（进 context 一次就够），MCP 只留给&amp;quot;活的状态&amp;quot;。这和业界默认用法是反的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI 是被低估的 Agent 接口&lt;/strong&gt;。&lt;code&gt;--json&lt;/code&gt; 输出 + 语义化 exit code + 标准 Unix 管道，在大多数场景比 MCP 工具链更省 token、更易验证。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误信号的结构，比错误信息的文字更重要&lt;/strong&gt;。如果你的平台只告诉 Agent &amp;ldquo;401&amp;rdquo;，它会花 8 轮去猜 401 是谁发的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设计后端接口的时候，问自己一个问题&lt;/strong&gt;：一个刚接入的 Agent，看完我的 metadata/docs/error，能不能一次就知道&amp;quot;下一步该干什么&amp;quot;？如果不能，你的 token 账单就在这里。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;InsForge 本身只是这个思路的一个落地，但&lt;strong&gt;这个思路是通用的&lt;/strong&gt;——无论你用什么后端、什么 Agent 框架，&amp;ldquo;把上下文主动喂过去&amp;quot;永远比&amp;quot;让 Agent 探索式发现&amp;quot;便宜一个量级。&lt;/p&gt;
&lt;p&gt;Karpathy 说得对：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;填满 context window 的&amp;quot;正确信息&amp;rdquo;，是做 Agent 最核心的技能。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;而后端基础设施，是这些&amp;quot;正确信息&amp;quot;最大的一块来源——而这恰恰是大多数人都还没开始做的地方。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="参考资料"&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;原推文：&lt;a class="link" href="https://x.com/_avichawla/status/2046500537584218438" target="_blank" rel="noopener"
 &gt;Avi Chawla — How to cut Claude Code costs by 3x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;InsForge 开源仓库：&lt;a class="link" href="https://github.com/InsForge/InsForge" target="_blank" rel="noopener"
 &gt;github.com/InsForge/InsForge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Karpathy 的 Context Engineering 原贴（作者引用的出处）&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>