<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>O&#39;s World</title>
  
  <subtitle>Mr. O 的分享小站，分享有趣的事情</subtitle>
  <link href="https://ooo.run/atom.xml" rel="self"/>
  
  <link href="https://ooo.run/"/>
  <updated>2026-07-13T07:57:31.595Z</updated>
  <id>https://ooo.run/</id>
  
  <author>
    <name>Mr. O</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>如何选择 GPT 5.6 不同模型与推理强度？查看 OpenAI Codex 团队的推荐设置</title>
    <link href="https://ooo.run/post/how-to-select-gpt-5-6-model.html"/>
    <id>https://ooo.run/post/how-to-select-gpt-5-6-model.html</id>
    <published>2026-07-12T02:20:12.000Z</published>
    <updated>2026-07-13T07:57:31.595Z</updated>
    
    <content type="html"><![CDATA[<p>7 月 10 日，OpenAI Codex 团队在 Reddit 举办了一场 <a href="https://www.reddit.com/r/codex/comments/1us9ty9/ama_with_openais_codex_team/">AMA</a>（Ask Me Anything，在线问答活动）。</p><p>整场 AMA 的评论区一半用户认真提问 Codex、GPT-5.6 和 ChatGPT Work 的使用方法，另一半用户则集中吐槽额度消耗、桌面应用体验以及不同平台之间长期存在的功能差距。</p><p>虽然官方没有正面回答所有尖锐问题，但在模型选择、推理强度、长任务设计、MCP 工具接入和权限管理方面，还是给出了不少具有实际参考价值的信息。</p><p>其中最核心的结论可以概括为一句话：</p><blockquote><p>官方介绍了如何节省 Token 的使用 Codex，却没有解释为什么 GPT-5.6 宣称效率更高却用起来消耗更快。</p></blockquote><h2 id="不同模型与-Effort-应该怎么选"><a href="#不同模型与-Effort-应该怎么选" class="headerlink" title="不同模型与 Effort 应该怎么选"></a>不同模型与 Effort 应该怎么选</h2><p>这次 AMA 中最实用的部分，是 Codex 团队成员分享了不同模型和 Effort 推理强度的选择经验。</p><p>官方给出的日常默认组合是：</p><blockquote><p><strong>Sol + Medium Effort</strong></p></blockquote><p>这一配置适合大多数普通开发任务，在速度、质量和额度消耗之间相对均衡。</p><p>对于不同场景，则可以进一步调整。</p><h3 id="Sol：日常开发和前端任务的首选"><a href="#Sol：日常开发和前端任务的首选" class="headerlink" title="Sol：日常开发和前端任务的首选"></a>Sol：日常开发和前端任务的首选</h3><p>Sol 适合作为 Codex 中的默认主力模型，尤其适合：</p><ul><li>常规代码编写</li><li>Bug 修复</li><li>跨文件修改</li><li>UI 与前端开发</li><li>根据参考图还原界面</li></ul><p>官方特别提到，<strong>UI 和前端能力</strong> 本身就是 GPT-5.6 的重点训练方向之一。</p><p>如果任务中能够提供截图、设计稿或参考页面，Sol 的表现通常会明显优于只给出文字描述。</p><h3 id="Terra：额度敏感任务的性价比选择"><a href="#Terra：额度敏感任务的性价比选择" class="headerlink" title="Terra：额度敏感任务的性价比选择"></a>Terra：额度敏感任务的性价比选择</h3><p>如果任务相对轻量，同时比较在意额度消耗，可以优先尝试 Terra。</p><p>按照官方成员的说法，Terra 在部分任务上的表现可以接近 GPT-5.5，但资源消耗更低，比较适合：</p><ul><li>小范围代码修改</li><li>简单脚本生成</li><li>格式调整</li><li>重复性开发工作</li><li>已经明确实现路径的任务</li></ul><p>也就是说，并不是所有任务都需要直接交给最强模型。</p><p>当需求本身足够清晰时，使用更轻量的模型反而可能获得更高的整体效率。</p><h3 id="Luna：适合低成本探索"><a href="#Luna：适合低成本探索" class="headerlink" title="Luna：适合低成本探索"></a>Luna：适合低成本探索</h3><p>对于一些不确定是否值得深入的探索性任务，可以先交给 Luna。</p><p>例如：</p><ul><li>快速浏览项目结构</li><li>初步寻找相关文件</li><li>调查某个功能的实现位置</li><li>尝试生成几个可行方向</li><li>判断问题是否值得升级到更强模型</li></ul><p>Luna 更适合作为一个低成本的“侦察兵”，而不是最终负责复杂修改的主力模型。</p><h3 id="High：模糊-Bug-和跨模块修改"><a href="#High：模糊-Bug-和跨模块修改" class="headerlink" title="High：模糊 Bug 和跨模块修改"></a>High：模糊 Bug 和跨模块修改</h3><p>当问题描述比较模糊，或者修改涉及多个模块时，可以将 Effort 调整到 High。</p><p>常见场景包括：</p><ul><li>无法稳定复现的 Bug</li><li>多个模块之间的状态异常</li><li>大范围重构</li><li>跨前后端联调</li><li>涉及复杂调用链的问题</li></ul><p>这类任务往往不仅需要生成代码，还需要模型建立完整的问题假设，并逐步排除错误方向。</p><h3 id="Ultra：只用于真正不能出错的任务"><a href="#Ultra：只用于真正不能出错的任务" class="headerlink" title="Ultra：只用于真正不能出错的任务"></a>Ultra：只用于真正不能出错的任务</h3><p>官方并不建议将 Ultra 作为常规配置。</p><p>更适合使用 Ultra 的场景包括：</p><ul><li>数据库迁移</li><li>安全相关修改</li><li>生产事故修复</li><li>权限系统调整</li><li>大规模基础设施变更</li><li>一旦出错就可能造成严重损失的任务</li></ul><p>Ultra 的意义不是让所有任务都“更聪明”，而是在高风险任务中换取更多检查、推理和验证。</p><h3 id="xhigh-的收益已经开始递减"><a href="#xhigh-的收益已经开始递减" class="headerlink" title="xhigh 的收益已经开始递减"></a>xhigh 的收益已经开始递减</h3><p>对于最高级别的 xhigh，官方也明确表示，在评测中已经出现明显的收益递减。</p><p>它更适合以下情况：</p><ul><li>任务执行时间很长</li><li>修改范围非常大</li><li>错误成本极高</li><li>需要多轮验证</li><li>用户特别担心模型遗漏边缘情况</li></ul><p>对于普通任务，直接提高到 xhigh 并不一定划算，反而可能带来更慢的速度和更高的额度消耗。</p><h2 id="觉得-GPT-5-6-慢，可能是-Effort-设得太高"><a href="#觉得-GPT-5-6-慢，可能是-Effort-设得太高" class="headerlink" title="觉得 GPT-5.6 慢，可能是 Effort 设得太高"></a>觉得 GPT-5.6 慢，可能是 Effort 设得太高</h2><p>不少从 GPT-5.5 升级到 GPT-5.6 的用户，仍然沿用了之前较高的推理强度设置。</p><p>Codex 团队建议，如果觉得 GPT-5.6 运行速度过慢，可以先检查当前 Effort 是否仍然保持在 GPT-5.5 时期的配置。</p><p>GPT-5.6 在更低 Effort 下，往往已经能够完成过去需要更高推理强度才能完成的任务。</p><p>换句话说，升级模型后，不应机械地保留原有配置。</p><p>更合理的方法是从 Medium 开始，根据任务难度逐步增加，而不是一开始就使用 High、Ultra 或 xhigh。</p><p>官方还提到，Fast mode 可以进一步提升大约 1.5 倍的速度。</p><p>因此，一套比较实用的选择顺序是：</p><ol><li>先尝试 Sol Medium</li><li>简单任务切换到 Terra</li><li>模糊问题再提高到 High</li><li>高风险任务才使用 Ultra</li><li>只有极少数长任务需要 xhigh</li></ol><h2 id="长任务不要只给目标，还要给停止条件"><a href="#长任务不要只给目标，还要给停止条件" class="headerlink" title="长任务不要只给目标，还要给停止条件"></a>长任务不要只给目标，还要给停止条件</h2><p>在长时间运行的 Agent 任务方面，官方推荐使用 <code>/goal</code> 来描述任务目标。</p><p>但仅仅给出目标还不够。</p><p>如果没有清晰的边界和停止条件，Agent 很容易持续探索、反复修改，最终消耗大量 token，却未必能够产生更好的结果。</p><p>官方建议在长任务中明确加入限制条件，例如：</p><ul><li>只允许修改指定目录</li><li>不允许改变公开 API</li><li>最多验证三个假设</li><li>每个假设完成后必须运行测试</li><li>如果所有假设都失败，则停止修改并输出总结</li><li>不允许添加新的依赖</li><li>不允许修改数据库结构</li><li>达到指定时间或尝试次数后结束</li></ul><p>例如，一个比“修复登录 Bug”更合适的任务描述可以写成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">修复用户偶尔无法登录的问题。</span><br><span class="line"></span><br><span class="line">限制条件：</span><br><span class="line">- 只修改 auth 和 session 目录</span><br><span class="line">- 不改变现有公开 API</span><br><span class="line">- 最多验证三个可能原因</span><br><span class="line">- 每验证一个原因后运行相关测试</span><br><span class="line">- 如果三个方向都失败，停止修改并总结调查结果</span><br></pre></td></tr></table></figure><p>这类停止条件能够避免 Agent 陷入无限尝试，也可以降低模型在长任务中不断扩大修改范围的风险。</p><h2 id="MCP-工具不一定要全部常驻上下文"><a href="#MCP-工具不一定要全部常驻上下文" class="headerlink" title="MCP 工具不一定要全部常驻上下文"></a>MCP 工具不一定要全部常驻上下文</h2><p>MCP 为 Codex 提供了调用外部工具和服务的能力，但如果直接挂载大量 MCP 服务，也会带来明显的上下文开销。</p><p>几十个工具定义长期驻留在上下文中，会占用 token，并增加模型选择错误工具的可能性。</p><p>Codex 团队提出了两个更节省上下文的思路。</p><h3 id="把常用操作封装成-CLI"><a href="#把常用操作封装成-CLI" class="headerlink" title="把常用操作封装成 CLI"></a>把常用操作封装成 CLI</h3><p>第一种方式，是将外部服务操作封装成命令行工具，再通过 Skill 教会 Codex 如何使用。</p><p>例如，不直接加载一整套部署平台的 MCP 工具，而是提供：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">deployctl status</span><br><span class="line">deployctl logs</span><br><span class="line">deployctl release</span><br></pre></td></tr></table></figure><p>然后在 Skill 中描述这些命令的用途和参数。</p><p>这样做的优势是：</p><ul><li>工具定义更短</li><li>上下文占用更低</li><li>调用方式更稳定</li><li>更容易进行权限控制</li><li>可以直接复用现有 Shell 工作流</li></ul><p>对于原本就支持命令行操作的服务，这通常比长期挂载完整 MCP 更高效。</p><h3 id="将专业-MCP-放到专用子-Agent"><a href="#将专业-MCP-放到专用子-Agent" class="headerlink" title="将专业 MCP 放到专用子 Agent"></a>将专业 MCP 放到专用子 Agent</h3><p>第二种方式，是创建一个专用子 Agent，并只为它配置特定 MCP。</p><p>例如可以创建：</p><ul><li>Unreal Engine 专用 Agent</li><li>数据库运维 Agent</li><li>Kubernetes Agent</li><li>浏览器自动化 Agent</li><li>内部文档检索 Agent</li></ul><p>主 Agent 平时不需要加载这些工具，只有遇到对应任务时，才将工作委托给专用 Agent。</p><p>这种模式既可以减少主上下文中的工具数量，也能降低不同工具之间的干扰。</p><h2 id="权限优先使用-Auto-Review"><a href="#权限优先使用-Auto-Review" class="headerlink" title="权限优先使用 Auto Review"></a>权限优先使用 Auto Review</h2><p>在 Codex 权限设置上，官方建议多数情况下使用 <strong>Auto review</strong>，而不是直接开启 <strong>Full access</strong>。</p><p>Full access 虽然能够减少执行过程中的确认步骤，但也意味着 Agent 可以更自由地执行命令、修改文件和访问环境。</p><p>对于日常开发任务，Auto review 通常已经能够在效率与安全之间取得较好的平衡。</p><p>官方尤其提醒 Windows 用户，应更加谨慎地使用 Full access。</p><p>Windows 环境中的 Shell、权限系统、路径处理和脚本行为更加复杂，一些看似普通的命令可能产生超出预期的影响。</p><p>因此，更稳妥的做法是：</p><ul><li>默认使用 Auto review</li><li>仅在可信项目中临时开启更高权限</li><li>限制 Agent 可修改的目录</li><li>对删除、安装和系统级命令进行人工确认</li><li>不要在包含重要个人文件的目录中直接运行高权限 Agent</li></ul><h2 id="Codex、ChatGPT-Work-和普通聊天的额度如何计算"><a href="#Codex、ChatGPT-Work-和普通聊天的额度如何计算" class="headerlink" title="Codex、ChatGPT Work 和普通聊天的额度如何计算"></a>Codex、ChatGPT Work 和普通聊天的额度如何计算</h2><p>这次 AMA 也对不同功能的额度分类做出了解释。</p><p>按照官方的划分：</p><ul><li><strong>Codex</strong> 计入 Agentic 额度</li><li><strong>ChatGPT Work</strong> 计入 Agentic 额度</li><li>普通 ChatGPT 对话不计入 Agentic 额度</li><li>图像生成有独立额度</li><li>文件上传与处理有独立额度</li><li>语音功能也有独立额度</li></ul><p>这意味着，不能简单地将 ChatGPT 中的所有功能都视为共享同一个额度池。</p><p>用户看到某一类功能额度下降，并不一定代表其他功能也会同步受到影响。</p><p>不过具体到单个 Codex 任务，其消耗并不是固定值。</p><p>任务长度、上下文规模、模型、Effort、工具调用次数、测试次数以及是否发生重试，都会影响最终消耗。</p><h2 id="为什么-Pro-mode-没有进入-Codex"><a href="#为什么-Pro-mode-没有进入-Codex" class="headerlink" title="为什么 Pro mode 没有进入 Codex"></a>为什么 Pro mode 没有进入 Codex</h2><p>不少用户询问，既然 ChatGPT 中提供了 Pro mode，为什么 Codex 中没有同样的选项。</p><p>官方给出的解释是，Pro mode 的运行机制对于 Agentic 编程任务的提升相对有限。</p><p>它通常具有以下特点：</p><ul><li>响应速度更慢</li><li>消耗额度更多</li><li>更偏向一次性深度推理</li><li>对连续工具调用和代码执行的帮助没有想象中明显</li></ul><p>因此，Pro mode 更适合：</p><ul><li>搜索</li><li>数学推理</li><li>长文写作</li><li>文档分析</li><li>复杂研究任务</li></ul><p>而 Codex 的核心场景是读取代码、执行命令、修改文件、运行测试并根据结果继续行动。</p><p>在这种 Agentic 工作流中，模型本身的单次推理强度并不是唯一决定因素，工具使用和反馈循环同样重要。</p><h2 id="AMA-没有回答的几个关键问题"><a href="#AMA-没有回答的几个关键问题" class="headerlink" title="AMA 没有回答的几个关键问题"></a>AMA 没有回答的几个关键问题</h2><p>虽然官方分享了许多使用技巧，但用户最关心的一些问题仍然没有获得明确答案。</p><h2 id="GPT-5-6-为什么比-GPT-5-5-更耗额度"><a href="#GPT-5-6-为什么比-GPT-5-5-更耗额度" class="headerlink" title="GPT-5.6 为什么比 GPT-5.5 更耗额度"></a>GPT-5.6 为什么比 GPT-5.5 更耗额度</h2><p>整个 AMA 中呼声最高的问题，仍然是 GPT-5.6 的额度消耗。</p><p>大量用户反馈，GPT-5.6 在实际使用中的额度下降速度明显快于 GPT-5.5。</p><p>这与官方此前强调的“更高 token 效率”形成了明显反差。</p><p>官方对此只解释称：</p><blockquote><p>每个任务的消耗并不是固定的。</p></blockquote><p>这句话本身并没有错。</p><p>复杂任务、更多工具调用、更长输出以及更高 Effort，确实都会增加消耗。</p><p>但它没有正面回答用户真正关心的问题：</p><ul><li>相同任务下，GPT-5.6 是否平均消耗更多额度？</li><li>是否因为内部推理 token 增加？</li><li>是否因为工具调用和验证次数更多？</li><li>Agentic 额度是否采用了不同于文本 token 的权重换算？</li><li>Fast mode 与普通模式的额度计算是否相同？</li><li>官方宣传中的 token 效率，是否不等于用户看到的额度效率？</li></ul><p>这些问题在 AMA 后依然没有答案。</p><h2 id="1M-上下文窗口仍然没有明确计划"><a href="#1M-上下文窗口仍然没有明确计划" class="headerlink" title="1M 上下文窗口仍然没有明确计划"></a>1M 上下文窗口仍然没有明确计划</h2><p>用户同样频繁询问 Codex 是否会提供 1M 上下文窗口。</p><p>官方对此仅表示会认真查看用户反馈，没有给出明确的产品计划或上线时间。</p><p>对于大型代码仓库来说，更大的上下文窗口确实具有吸引力。</p><p>但在实际 Agentic 工作流中，上下文越大，也可能意味着：</p><ul><li>更高的处理成本；</li><li>更慢的首次响应；</li><li>更多无关代码进入上下文；</li><li>更复杂的信息筛选；</li><li>更快的额度消耗。</li></ul><p>因此，1M 上下文是否能够真正改善 Codex 体验，仍然取决于检索、压缩和上下文管理能力，而不只是数字本身。</p><p>在价格方面，官方也明确表示无法承诺长期稳定。</p><h2 id="新版-ChatGPT-桌面应用遭到集中吐槽"><a href="#新版-ChatGPT-桌面应用遭到集中吐槽" class="headerlink" title="新版 ChatGPT 桌面应用遭到集中吐槽"></a>新版 ChatGPT 桌面应用遭到集中吐槽</h2><p>新版 ChatGPT 桌面应用是 AMA 中另一个争议集中的话题。</p><p>不少用户认为，新应用更偏向 ChatGPT Work 和 Agent 操作，而传统 Chat 功能则被压缩成了一个附属面板。</p><p>用户集中反馈缺失或体验退步的功能包括：</p><ul><li>Projects</li><li>完整历史记录</li><li>常用快捷键</li><li>录音功能</li><li>原有聊天工作流</li><li>Classic 应用中的部分导航体验</li></ul><p>官方承认新版应用仍在改进。</p><p>但目前给出的短期方案，基本上仍然是同时保留并使用两个应用：</p><ul><li>需要传统聊天功能时使用 Classic；</li><li>需要 Agent 和 Work 功能时使用新版应用。</li></ul><p>这显然称不上理想的解决方案。</p><h2 id="Linux-没有时间表，Windows-仍是二等公民"><a href="#Linux-没有时间表，Windows-仍是二等公民" class="headerlink" title="Linux 没有时间表，Windows 仍是二等公民"></a>Linux 没有时间表，Windows 仍是二等公民</h2><p>对于 Linux 桌面版，官方确认相关工作正在进行，但没有提供具体时间线。</p><p>而 Windows 用户长期存在的体验差距，也在 AMA 中再次被提及。</p><p>官方事实上承认，Windows 版本在过去长期处于相对次要的位置。</p><p>这种差距不仅体现在桌面应用，也体现在 Agent 开发环境中：</p><ul><li>Shell 行为与 macOS、Linux 不一致；</li><li>路径和权限处理更复杂；</li><li>部分开发工具优先适配 Unix 环境；</li><li>沙箱能力存在差异；</li><li>自动化脚本的兼容性更差；</li><li>部分功能在 Windows 上更晚推出。</li></ul><p>对于将 Codex 作为主要开发工具的 Windows 用户来说，这仍然是一个现实问题。</p><h2 id="Reward-Hacking-问题被礼貌绕开"><a href="#Reward-Hacking-问题被礼貌绕开" class="headerlink" title="Reward Hacking 问题被礼貌绕开"></a>Reward Hacking 问题被礼貌绕开</h2><p>还有用户追问了 METR 报告中提到的 reward hacking 问题。</p><p>问题主要集中在：</p><ul><li>基准成绩提升中有多少来自 reward hacking</li><li>模型是否学会针对评测环境优化行为</li><li>GPT-5.6 的训练中做了哪些针对性修改</li><li>官方如何区分真实能力提升和评测策略优化</li></ul><p>Codex 团队没有给出具体数据，也没有详细解释训练层面的改动。</p><p>这类问题涉及模型训练、内部评估方法和安全研究，官方选择谨慎回应并不意外。</p><p>但从用户角度看，这也意味着外界仍然难以判断：</p><blockquote><p>模型在基准上的提升，有多少能够稳定转化为真实开发环境中的可靠性。</p></blockquote><h2 id="怎么用更省已经讲清楚，为什么更费仍然悬而未决"><a href="#怎么用更省已经讲清楚，为什么更费仍然悬而未决" class="headerlink" title="怎么用更省已经讲清楚，为什么更费仍然悬而未决"></a>怎么用更省已经讲清楚，为什么更费仍然悬而未决</h2><p>总体来看，这次 Codex 团队 AMA 的价值主要集中在实际使用方法上。</p><p>官方给出的建议相当明确：</p><ul><li>日常默认使用 Sol Medium</li><li>轻量任务优先尝试 Terra</li><li>探索性工作可以委托给 Luna</li><li>模糊 Bug 和跨模块任务使用 High</li><li>Ultra 只留给高风险任务</li><li>xhigh 不应成为日常默认</li><li>长任务必须设置停止条件</li><li>不要让大量 MCP 工具长期常驻上下文</li><li>优先使用 Auto review，而不是 Full access</li><li>GPT-5.6 不一定需要沿用 GPT-5.5 的高 Effort 设置</li></ul><p>这些建议的共同目标都是降低不必要的模型调用、上下文占用和推理消耗。</p><p>但另一方面，用户最关心的问题依然没有获得正面回应：</p><blockquote><p>为什么 GPT-5.6 明明宣传 token 效率更高，实际使用时却更快消耗 Codex 额度？</p></blockquote><p>如果 Agentic 额度并不直接等于输入输出 token，那么官方就需要更清晰地解释其计算方式。</p><p>如果 GPT-5.6 由于更频繁的工具调用、更长的内部推理或更主动的验证而消耗更高，也应该让用户能够看到这些差异。</p><p>否则，用户最终只能通过反复试验来猜测每种模型和 Effort 的真实成本。</p><p>这场 AMA 讲清楚了 Codex 应该“怎么用更省”。</p><p>至于它为什么“变得更费”，仍然是一个没有被回答的问题。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;7 月 10 日，OpenAI Codex 团队在 Reddit 举办了一场 &lt;a href=&quot;https://www.reddit.com/r/codex/comments/1us9ty9/ama_with_openais_codex_team/&quot;&gt;AMA&lt;/a&gt;（Ask</summary>
      
    
    
    
    <category term="资讯" scheme="https://ooo.run/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="OpenAI" scheme="https://ooo.run/tags/OpenAI/"/>
    
    <category term="ChatGPT" scheme="https://ooo.run/tags/ChatGPT/"/>
    
    <category term="Codex" scheme="https://ooo.run/tags/Codex/"/>
    
    <category term="GPT-5.6" scheme="https://ooo.run/tags/GPT-5-6/"/>
    
    <category term="AI Agent" scheme="https://ooo.run/tags/AI-Agent/"/>
    
  </entry>
  
  <entry>
    <title>OpenAI 发布 GPT-5.6 与 ChatGPT Work，重塑 AI 工作模式</title>
    <link href="https://ooo.run/post/openai-release-gpt-5-6.html"/>
    <id>https://ooo.run/post/openai-release-gpt-5-6.html</id>
    <published>2026-07-09T19:47:35.000Z</published>
    <updated>2026-07-09T20:06:55.456Z</updated>
    
    <content type="html"><![CDATA[<p>北京时间 2026 年 7 月 10 日凌晨，OpenAI 正式推出 GPT-5.6 模型以及全新 ChatGPT Work 智能体，标志着 AI 从对话助手向自主工作平台的转变。</p><h2 id="GPT-5-6：性能全面跃升"><a href="#GPT-5-6：性能全面跃升" class="headerlink" title="GPT-5.6：性能全面跃升"></a>GPT-5.6：性能全面跃升</h2><p>GPT-5.6 已于今日开始在 ChatGPT、Codex 和 OpenAI API 全球逐步推出。</p><blockquote><p>PRO 用户已全面完成更新，Plus 用户可能看不到 <strong>GPT-5.6 SOL</strong> 模型的选项，预计在 24 小时内全面可用。 </p></blockquote><ul><li><strong>ChatGPT 用户</strong>：Plus、Pro、Business 和 Enterprise 用户可通过中等及以上思考等级设置访问 GPT-5.6 Sol；Pro 和 Enterprise 用户还可选择 GPT-5.6 Pro 以获得复杂任务的最高质量输出。</li><li><strong>核心能力提升</strong>：在推理复杂任务、遵循模板、参考文件和偏好风格生成材料方面达到业界领先。只需描述期望结果，无需一步步指导。 </li><li><strong>工件质量</strong>：显著提升演示文稿、文档和电子表格的质量，支持导出到专业工具并融入企业工作流。</li><li><strong>设计判断力</strong>：增强的计算机使用能力让模型能“查看并优化”渲染结果，而非仅生成代码或内容，从而自动捕捉视觉和功能问题并进行润色。 </li><li><strong>Ultra 模式</strong>：最高性能设置，通过并行协调多个智能体加速最复杂工作（以更高 token 消耗换取更强更快的结果）。</li><li><strong>基准表现</strong>： OpenAI 提供的基准测试得分情况<ul><li><a href="https://x.com/OpenAI/status/2075271425548795909">Artificial Analysis Coding Agent Index</a>：80.0（领先 Claude Fable 5 达 2.8 分），使用更少 token、更短时间且成本约三分之一。 </li><li><a href="https://x.com/OpenAI/status/2075271423992680532">Agents Last Exam</a>：53.6（领先 Claude Fable 5 达 13.1 分）；中等推理下以约四分之一成本领先 11.4 分。</li></ul></li></ul><h2 id="ChatGPT-Work：AI-自主完成整个工作流"><a href="#ChatGPT-Work：AI-自主完成整个工作流" class="headerlink" title="ChatGPT Work：AI 自主完成整个工作流"></a>ChatGPT Work：AI 自主完成整个工作流</h2><p><strong>ChatGPT Work</strong> 是基于 Codex 和 GPT-5.6 驱动的新智能体，能跨应用和文件采取行动，可长时间持续项目，将单一目标转化为完成的工作。 </p><p><strong>主要特性：</strong> </p><ul><li>理解用户目标，利用选定应用和文件上下文；</li><li>自主创建精美文档、幻灯片、分析、网站和报告；</li><li>支持整个工作流单次请求完成，用户始终保持控制权；</li><li>反映 AI 使用从“提问”向“真正完成工作”的转变。</li></ul><p><strong>可用性：</strong> </p><ul><li><strong>Web 和移动端</strong>：今日起向 Pro、Enterprise 和 Edu 计划推出；Plus 和 Business 计划未来几天内跟进。</li><li><strong>桌面应用</strong>：Chat、Work 和 Codex 在所有计划（含 Free）可用，已全球支持 Windows 和 Mac 下载。原有 Codex 应用用户更新即可切换为新 ChatGPT 桌面应用。</li></ul><p>OpenAI 表示，这一发布体现了 AI 正在成为生产力核心工具，用户只需提出目标，AI 即可自主推进并交付成果。更多细节和演示可通过 <a href="https://x.com/OpenAI/status/2075274271845404744">OpenAI 官方账号</a> 查看。 </p><p>此更新进一步巩固 OpenAI 在前沿 AI 模型和实用智能体领域的领先地位。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;北京时间 2026 年 7 月 10 日凌晨，OpenAI 正式推出 GPT-5.6 模型以及全新 ChatGPT Work 智能体，标志着 AI 从对话助手向自主工作平台的转变。&lt;/p&gt;
&lt;h2 id=&quot;GPT-5-6：性能全面跃升&quot;&gt;&lt;a href=&quot;#GPT-5-6：</summary>
      
    
    
    
    <category term="资讯" scheme="https://ooo.run/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="AI" scheme="https://ooo.run/tags/AI/"/>
    
    <category term="OpenAI" scheme="https://ooo.run/tags/OpenAI/"/>
    
    <category term="ChatGPT" scheme="https://ooo.run/tags/ChatGPT/"/>
    
    <category term="Codex" scheme="https://ooo.run/tags/Codex/"/>
    
    <category term="GPT" scheme="https://ooo.run/tags/GPT/"/>
    
  </entry>
  
  <entry>
    <title>在不设置 SMTP 的情况下修改 Vaultwarden(Bitwarden) 的账户邮箱</title>
    <link href="https://ooo.run/post/change-vaultwarden-account-email-without-set-smtp.html"/>
    <id>https://ooo.run/post/change-vaultwarden-account-email-without-set-smtp.html</id>
    <published>2026-07-09T05:47:52.000Z</published>
    <updated>2026-07-09T06:21:57.249Z</updated>
    
    <content type="html"><![CDATA[<p>Vaultwarden 更改登录邮箱时，默认需要向新邮箱发送验证码进行验证，如果没配置 SMTP，验证码不会真正发出。但在 <code>LOG_LEVEL=debug</code> 时会把验证码打印到日志里。如果你也只是个人使用，且不想设置 SMTP，可以查看下面的方法获取验证码，完成修改。</p><blockquote><p>本教程适用于使用 Docker 部署的 Vaultwarden</p></blockquote><div class="flatpaper-note flatpaper-note--danger"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>更改账户邮箱会导致所有会话失效，需要重新登录</p></div></div><h2 id="1-临时开启-debug-日志"><a href="#1-临时开启-debug-日志" class="headerlink" title="1. 临时开启 debug 日志"></a>1. 临时开启 debug 日志</h2><p>Docker Compose 里给 <code>vaultwarden</code> 加上：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">environment:</span></span><br><span class="line">  <span class="attr">LOG_LEVEL:</span> <span class="string">debug</span></span><br><span class="line">  <span class="attr">EXTENDED_LOGGING:</span> <span class="string">&quot;true&quot;</span></span><br></pre></td></tr></table></figure><p>然后重启：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure><p>如果你是 <code>docker run</code> ，加：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">-e LOG_LEVEL=debug \</span><br><span class="line">-e EXTENDED_LOGGING=<span class="literal">true</span> \</span><br></pre></td></tr></table></figure><h2 id="2-重新触发一次“更改邮箱”"><a href="#2-重新触发一次“更改邮箱”" class="headerlink" title="2. 重新触发一次“更改邮箱”"></a>2. 重新触发一次“更改邮箱”</h2><p>在网页端再次提交更改邮箱，让 Vaultwarden 重新生成验证码。</p><h2 id="3-查看-Docker-日志"><a href="#3-查看-Docker-日志" class="headerlink" title="3. 查看 Docker 日志"></a>3. 查看 Docker 日志</h2><p>容器名如果叫 <code>vaultwarden</code> ：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker logs vaultwarden 2&gt;&amp;1 | grep -i <span class="string">&quot;email&quot;</span></span><br></pre></td></tr></table></figure><p>输出的日志大概会是类似：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">...[vaultwarden::api::core::accounts][DEBUG] Email change ... email (...) with token (123456)</span><br></pre></td></tr></table></figure><p>日志末尾括号中的六位数字，就是需要填写的验证码。</p><h2 id="4-完成后改回正常日志级别"><a href="#4-完成后改回正常日志级别" class="headerlink" title="4. 完成后改回正常日志级别"></a>4. 完成后改回正常日志级别</h2><p>查到验证码并完成更改后，建议改回：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">LOG_LEVEL:</span> <span class="string">info</span></span><br></pre></td></tr></table></figure><p>或：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">LOG_LEVEL:</span> <span class="string">warn</span></span><br></pre></td></tr></table></figure><p>然后重启。 <code>debug</code> 日志可能暴露敏感信息，不建议长期打开。</p><h2 id="5-长期建议：配置-SMTP"><a href="#5-长期建议：配置-SMTP" class="headerlink" title="5. 长期建议：配置 SMTP"></a>5. 长期建议：配置 SMTP</h2><p>如果以后还会用邮箱验证、邀请、2FA 邮件等功能，最好配置 SMTP。 <strong>Vaultwarden</strong> 常用的 SMTP 配置项包括：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">SMTP_HOST:</span> <span class="string">smtp.example.com</span></span><br><span class="line"><span class="attr">SMTP_FROM:</span> <span class="string">vaultwarden@example.com</span></span><br><span class="line"><span class="attr">SMTP_PORT:</span> <span class="number">587</span></span><br><span class="line"><span class="attr">SMTP_SECURITY:</span> <span class="string">starttls</span></span><br><span class="line"><span class="attr">SMTP_USERNAME:</span> <span class="string">vaultwarden@example.com</span></span><br><span class="line"><span class="attr">SMTP_PASSWORD:</span> <span class="string">your_password</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Vaultwarden 更改登录邮箱时，默认需要向新邮箱发送验证码进行验证，如果没配置 SMTP，验证码不会真正发出。但在 &lt;code&gt;LOG_LEVEL=debug&lt;/code&gt; 时会把验证码打印到日志里。如果你也只是个人使用，且不想设置 SMTP，可以查看下面的方法获取</summary>
      
    
    
    
    <category term="教程" scheme="https://ooo.run/categories/%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="Docker" scheme="https://ooo.run/tags/Docker/"/>
    
    <category term="Bitwarden" scheme="https://ooo.run/tags/Bitwarden/"/>
    
    <category term="Vaultwarden" scheme="https://ooo.run/tags/Vaultwarden/"/>
    
  </entry>
  
  <entry>
    <title>Docker Compose 新增 Init Containers：终于不用再写一堆一次性初始化服务了</title>
    <link href="https://ooo.run/post/docker-compose-init-containers.html"/>
    <id>https://ooo.run/post/docker-compose-init-containers.html</id>
    <published>2026-07-04T03:00:00.000Z</published>
    <updated>2026-07-04T04:16:51.110Z</updated>
    
    <content type="html"><![CDATA[<p>在使用 Docker Compose 部署应用时，你是否也曾为“如何在主应用启动前优雅地运行数据库迁移或修复权限”而烦恼过？</p><p>过去，我们不得不编写各种一次性服务并用复杂的 <code>depends_on</code> 串联。而现在，随着 Docker Compose 新特性的发布，我们终于迎来了官方的 <strong>Init Containers</strong> 支持。本文将带你一探究竟，看看它如何帮我们精简 <code>compose.yaml</code>！</p><span id="more"></span><p>在使用 <strong>Docker Compose</strong> 部署应用时，我们经常会遇到一种很常见的需求：在应用启动之前，先执行一些初始化任务。</p><p>例如：</p><ul><li>启动 Web 服务之前，先执行数据库迁移</li><li>容器以非 root 用户运行前，先修复挂载目录权限</li><li>应用正式启动前，先生成配置文件</li><li>先导入初始化数据，再启动主服务</li></ul><p>过去我们通常会单独定义一个 <code>migrate</code>、<code>init</code>、<code>setup</code> 之类的一次性服务，然后通过 <code>depends_on</code> 和 <code>condition: service_completed_successfully</code> 控制启动顺序。</p><p>现在，<strong>Docker Compose</strong> 正式提供了更自然的写法：<strong>Init Containers</strong>。</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>根据 Docker 官方文档，该功能需要 <strong>Docker Compose 5.3.0</strong> 及以上版本。</p></div></div><p>Init Containers 本质上是 short-lived（短生命周期）容器，会在主服务容器启动之前依次执行；如果其中任何一步返回非 0 退出码，主服务就不会启动。</p><h2 id="什么是-Init-Containers？"><a href="#什么是-Init-Containers？" class="headerlink" title="什么是 Init Containers？"></a>什么是 Init Containers？</h2><p>Init Containers 可以理解为：</p><blockquote><p>绑定在某个服务启动前执行的一组初始化步骤。</p></blockquote><p>它们不是长期运行的服务，也不是后台任务，而是“跑完就退出”的临时容器。</p><p><strong>Docker Compose</strong> 中这个能力通过 <code>pre_start</code> 生命周期钩子实现。根据官方文档说明，<code>pre_start</code> 中的每个步骤都会在独立的临时容器中运行，这些容器会在服务容器创建之后、真正启动之前执行。</p><p>一个最简单的例子：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">pre_start:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;migrate&quot;</span>]</span><br></pre></td></tr></table></figure><p>这段配置表示：</p><ol><li><strong>Docker Compose</strong> 先创建 <code>app</code> 服务容器；</li><li>在 <code>app</code> 真正启动之前，先运行 <code>./manage.py migrate</code>；</li><li>如果迁移命令成功退出（即返回状态码 <code>0</code>），<code>app</code> 才会启动；</li><li>如果迁移失败，<code>app</code> 不会启动。</li></ol><p>这比过去单独写一个 <code>migrate</code> 服务清晰很多。</p><h2 id="以前我们是怎么做的？"><a href="#以前我们是怎么做的？" class="headerlink" title="以前我们是怎么做的？"></a>以前我们是怎么做的？</h2><p>在 <code>pre_start</code> 出现之前，如果想表达“先执行迁移，再启动应用”，通常会这样写：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">migrate:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;migrate&quot;</span>]</span><br><span class="line">    <span class="attr">restart:</span> <span class="string">&quot;no&quot;</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">migrate:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_completed_successfully</span></span><br></pre></td></tr></table></figure><p>这种写法虽然可以工作，但存在以下几个明显的问题：</p><ul><li><strong>概念混淆</strong>：<code>migrate</code> 本质上并不是一个真正的长期运行服务，它只是 <code>app</code> 启动前的一个初始化步骤。把它放在 <code>services</code> 顶层，会让整个 Compose 配置文件显得臃肿。</li><li><strong>状态残留</strong>：任务执行完成后，它会作为已退出的服务留在 <code>docker compose ps</code> 列表中，使得容器服务列表不够清爽。</li><li><strong>编排繁琐</strong>：如果初始化步骤较多（比如先迁移数据库、再导入默认数据、最后生成配置文件），就需要定义多个一次性服务，并用一堆复杂的 <code>depends_on</code> 串联起来。</li></ul><p>使用新的 <code>pre_start</code> 特性后，我们可以直接把它们收纳进服务内部：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">pre_start:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;migrate&quot;</span>]</span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;loaddata&quot;</span>, <span class="string">&quot;fixtures.json&quot;</span>]</span><br></pre></td></tr></table></figure><p><strong>Docker</strong> 官方也明确指出，<code>pre_start</code> 的优势在于：</p><ol><li>初始化逻辑作为服务的<strong>从属步骤</strong>表达，不再伪装成并列的独立服务；</li><li>已完成的临时步骤不会出现在 <code>docker compose ps</code> 中，保持环境整洁；</li><li>多个步骤按顺序执行，无需再通过复杂的 <code>depends_on</code> 逻辑进行链式串联。</li></ol><h2 id="示例一：启动前执行数据库迁移"><a href="#示例一：启动前执行数据库迁移" class="headerlink" title="示例一：启动前执行数据库迁移"></a>示例一：启动前执行数据库迁移</h2><p>这是最典型的使用场景。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">db:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line">    <span class="attr">pre_start:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;migrate&quot;</span>]</span><br><span class="line"></span><br><span class="line">  <span class="attr">db:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">postgres:18</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">POSTGRES_USER:</span> <span class="string">app</span></span><br><span class="line">      <span class="attr">POSTGRES_PASSWORD:</span> <span class="string">password</span></span><br><span class="line">      <span class="attr">POSTGRES_DB:</span> <span class="string">app</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD-SHELL&quot;</span>, <span class="string">&quot;pg_isready -U $$&#123;POSTGRES_USER&#125; -d $$&#123;POSTGRES_DB&#125;&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">10s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">5</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">10s</span></span><br></pre></td></tr></table></figure><p>这里有两个关键点：</p><ol><li><strong>依赖关系</strong>：<code>app</code> 通过 <code>depends_on</code> 等待 <code>db</code> 容器进入 <code>service_healthy</code>（健康）状态。</li><li><strong>初始化时机</strong>：在 <code>app</code> 真正启动前，会先在临时容器中执行 <code>./manage.py migrate</code>。</li></ol><p>若数据库迁移成功，<code>app</code> 主服务会继续启动；若失败，<code>app</code> 不会启动，且相关错误日志会直接输出在 <code>docker compose up</code> 中。</p><p>这种设计非常适合 <strong>Django</strong>、<strong>Rails</strong>、<strong>Laravel</strong>、<strong>Prisma</strong>、<strong>Drizzle</strong>、<strong>Alembic</strong> 等需要在服务运行前进行表结构迁移的项目。</p><h2 id="示例二：修复-Volume-权限"><a href="#示例二：修复-Volume-权限" class="headerlink" title="示例二：修复 Volume 权限"></a>示例二：修复 Volume 权限</h2><p>另一个痛点是权限问题：当服务本身以非 root 用户运行，但挂载的 <strong>Docker named volume</strong> 默认归属于 root 权限时，容器可能会因为没有写入权限而崩溃。</p><p>过去，我们可能需要在 <code>Dockerfile</code> 里大动干戈，或者单独拉起一个辅助服务。现在，使用 <code>pre_start</code> 可以非常轻量地搞定：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">user:</span> <span class="string">&quot;1000:1000&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">data:/data</span></span><br><span class="line">    <span class="attr">pre_start:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">image:</span> <span class="string">busybox</span></span><br><span class="line">        <span class="attr">user:</span> <span class="string">root</span></span><br><span class="line">        <span class="attr">command:</span> <span class="string">sh</span> <span class="string">-c</span> <span class="string">&#x27;chown -R 1000:1000 /data&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="attr">data:</span></span><br></pre></td></tr></table></figure><p>在这个例子中：</p><ul><li><code>app</code> 容器以 <code>1000:1000</code> 非 root 用户运行。</li><li><code>pre_start</code> 步骤指定了覆盖镜像为 <code>busybox</code>，并以 <code>root</code> 权限执行 <code>chown</code>，从而在主服务运行前顺利修正挂载目录所有权。</li></ul><p>该场景在自托管&#x2F;开源应用部署中极度实用，例如：</p><ul><li>修复上传&#x2F;缓存目录权限；</li><li>自动初始化数据目录结构；</li><li>在挂载路径中提前生成默认配置文件。</li></ul><h2 id="示例三：串联多个初始化步骤"><a href="#示例三：串联多个初始化步骤" class="headerlink" title="示例三：串联多个初始化步骤"></a>示例三：串联多个初始化步骤</h2><p><code>pre_start</code> 支持定义一个步骤列表，并会按照声明顺序<strong>串行执行</strong>。只有当前一个步骤成功退出（返回 <code>0</code>）时，才会继续运行下一个步骤；若中间某一步失败，后续步骤和主服务都将终止。</p><p>例如：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">db:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line">    <span class="attr">pre_start:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;migrate&quot;</span>]</span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;loaddata&quot;</span>, <span class="string">&quot;fixtures.json&quot;</span>]</span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./scripts/generate-config.sh&quot;</span>]</span><br><span class="line"></span><br><span class="line">  <span class="attr">db:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">postgres:18</span></span><br></pre></td></tr></table></figure><p>整个启动流为：</p><ol><li><strong>等待</strong>数据库容器进入健康状态；</li><li><strong>执行</strong>数据库表结构迁移；</li><li><strong>导入</strong>系统初始数据；</li><li><strong>生成</strong>动态配置文件；</li><li><strong>拉起</strong>主应用容器。</li></ol><div class="flatpaper-note flatpaper-note--warning"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>需要注意的是，<code>pre_start</code> 中的多个步骤<strong>并不是事务</strong>。如果第二步执行成功、第三步失败，<strong>Docker Compose</strong> 不会自动回滚第二步。<br>因此，强烈建议将初始化脚本设计为<strong>可重复运行的幂等逻辑</strong>。</p></div></div><p>例如在导入数据时：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- 不推荐：每次无脑插入，可能会导致主键冲突或数据重复</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> users (id, name) <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="string">&#x27;admin&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 推荐：检测到冲突时跳过，保证幂等性</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> users (id, name) <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="string">&#x27;admin&#x27;</span>)</span><br><span class="line"><span class="keyword">ON</span> CONFLICT (id) DO NOTHING;</span><br></pre></td></tr></table></figure><h2 id="pre-start-容器的运行规则"><a href="#pre-start-容器的运行规则" class="headerlink" title="pre_start 容器的运行规则"></a><code>pre_start</code> 容器的运行规则</h2><p>根据官方文档说明，<code>pre_start</code> 步骤拉起的临时容器具有以下行为特征：</p><ul><li><strong>独立容器</strong>：每个步骤都在自己专属的临时容器中运行。</li><li><strong>默认继承</strong>：默认继承当前宿主服务的 <code>image</code> 定义，无需重复指定镜像。</li><li><strong>允许覆盖</strong>：可以通过 <code>image</code> 字段指定其他的轻量工具镜像（如 <code>busybox</code>）。</li><li><strong>同网共用</strong>：会自动加入当前宿主服务所在的网络，因此可以直接访问通过 <code>depends_on</code> 声明的其他依赖服务。</li><li><strong>共享卷挂载</strong>：会自动共享当前服务定义的所有 <code>volumes</code> 挂载。</li><li><strong>强状态约束</strong>：必须返回退出码 <code>0</code>，下一个步骤及主服务才会继续运行。</li></ul><p>这些特性为我们编写配置带来了很大便利。例如，若迁移命令就存放在应用镜像内，你只需直接声明命令，无需重复书写镜像名称：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pre_start:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;pnpm&quot;</span>, <span class="string">&quot;db:migrate&quot;</span>]</span><br></pre></td></tr></table></figure><p>如果需要使用辅助镜像（如 <code>busybox</code>）来做文件操作，直接在步骤内声明 <code>image</code> 即可进行覆盖：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pre_start:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">image:</span> <span class="string">busybox</span></span><br><span class="line">    <span class="attr">user:</span> <span class="string">root</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">sh</span> <span class="string">-c</span> <span class="string">&#x27;chown -R 1000:1000 /data&#x27;</span></span><br></pre></td></tr></table></figure><p>因为共享了同一网络与 <code>volumes</code>，初始化容器在挂载目录中写入的动态配置文件、修正的权限或是写入的数据，在主容器拉起后会立刻生效。</p><h2 id="它会每次-docker-compose-up-都执行吗？"><a href="#它会每次-docker-compose-up-都执行吗？" class="headerlink" title="它会每次 docker compose up 都执行吗？"></a>它会每次 <code>docker compose up</code> 都执行吗？</h2><p>答案是：<strong>不会</strong>。这是一个非常关键的细节。</p><p>根据 Docker 官方文档：</p><ul><li>如果某个 <code>pre_start</code> 步骤在上一次部署中已经<strong>成功执行</strong>过，且其<strong>定义没有发生任何变化</strong>，那么后续执行 <code>docker compose up</code> 时，Compose 会<strong>自动跳过</strong>该步骤。</li><li>当服务因 <code>restart</code> 策略发生重启时，<strong>不会</strong>重新触发 <code>pre_start</code>。</li><li><strong>只有在以下情况</strong>下，初始化步骤才会再次执行：<ol><li>步骤的配置定义发生变更；</li><li>上一次执行失败（退出码非 0）；</li><li>执行 <code>docker compose up --force-recreate</code> 强制重建服务。</li></ol></li></ul><p>由此可见，<code>pre_start</code> 偏向于“宿主服务生命周期中的一次性部署初始化”，而不是“每次容器进程启动前的强制拦截”。</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p><strong>提示</strong>： 如果你有一些需要在每次容器重启、扩容或进程拉起时都必定运行的逻辑（如动态读取最新环境变量），建议依然将其写入镜像的 <code>entrypoint.sh</code> 入口脚本中。</p></div></div><h2 id="什么时候不适合使用-Init-Containers？"><a href="#什么时候不适合使用-Init-Containers？" class="headerlink" title="什么时候不适合使用 Init Containers？"></a>什么时候不适合使用 Init Containers？</h2><p>Init Containers 虽然方便，但并非银弹。根据官方文档的建议，如果你的需求仅是注入静态配置文件或密钥，应当优先使用 <strong>Docker Compose</strong> 原生的 <code>configs</code> 和 <code>secrets</code>，因为它们支持直接挂载，并允许精细化配置权限和所属用户。</p><p>以下场景不建议使用 <code>pre_start</code>：</p><h3 id="1-静态配置文件挂载"><a href="#1-静态配置文件挂载" class="headerlink" title="1. 静态配置文件挂载"></a>1. 静态配置文件挂载</h3><p>对于不需要动态生成的固定配置文件，直接挂载即可，无需启动一个额外的初始化容器去写文件。</p><p><strong>推荐方案：</strong></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">configs:</span></span><br><span class="line">  <span class="attr">app_config:</span></span><br><span class="line">    <span class="attr">file:</span> <span class="string">./config/app.yml</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">source:</span> <span class="string">app_config</span></span><br><span class="line">        <span class="attr">target:</span> <span class="string">/app/config.yml</span></span><br></pre></td></tr></table></figure><h3 id="2-敏感凭证-Secret-注入"><a href="#2-敏感凭证-Secret-注入" class="headerlink" title="2. 敏感凭证 (Secret) 注入"></a>2. 敏感凭证 (Secret) 注入</h3><p>数据库密码、API 密钥等敏感数据切忌通过初始化脚本写入 volume 或文件系统，以防泄露。</p><p><strong>推荐方案：</strong></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">secrets:</span></span><br><span class="line">  <span class="attr">db_password:</span></span><br><span class="line">    <span class="attr">file:</span> <span class="string">./secrets/db_password.txt</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">secrets:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">db_password</span></span><br></pre></td></tr></table></figure><h3 id="3-定时任务与后台运维任务"><a href="#3-定时任务与后台运维任务" class="headerlink" title="3. 定时任务与后台运维任务"></a>3. 定时任务与后台运维任务</h3><p>例如：</p><ul><li>定期数据备份</li><li>定期清理缓存与临时文件</li><li>容器销毁后的退出清理工作</li></ul><p>这些任务并不属于“主应用启动前必须阻塞完成的必要依赖”，因此不适合放进 <code>pre_start</code>。</p><h2 id="当前的设计限制"><a href="#当前的设计限制" class="headerlink" title="当前的设计限制"></a>当前的设计限制</h2><p>由于该特性还相对较新，在使用时需要注意以下局限性：</p><ul><li><strong>非副本级执行</strong>：<code>pre_start</code> 是针对服务整体执行一次，而非针对每个容器副本单独运行（目前尚不支持 <code>per_replica: true</code> 配置）。</li><li><strong>部分挂载类型不兼容</strong>：多副本共享的命名卷（Named Volume）和绑定挂载（Bind Mount）能够完美适配；但对于每个实例完全独立的匿名卷或 <code>tmpfs</code> 挂载，<code>pre_start</code> 临时容器写入的数据是无法同步到主容器的。</li><li><strong>扩容时不触发</strong>：当你执行扩容命令时（例如 <code>docker compose up --scale app=3</code>），新创建的副本容器<strong>不会</strong>再次触发 <code>pre_start</code> 执行。它依然只遵循“配置变更&#x2F;强制重建”的触发逻辑。</li></ul><p>因此，如果你的某些初始化逻辑（如本地缓存预热）必须在每一个容器副本里运行，目前请不要依赖 <code>pre_start</code>。</p><h2 id="与-Kubernetes-Init-Containers-的区别"><a href="#与-Kubernetes-Init-Containers-的区别" class="headerlink" title="与 Kubernetes Init Containers 的区别"></a>与 Kubernetes Init Containers 的区别</h2><p>从概念上看，两者的目的非常一致：都在主业务容器拉起前执行前置准备。</p><p>但实现和能力上有所差异：</p><ul><li><strong>Kubernetes (K8s)</strong> 的 Init Containers 是 Pod 级别的核心一等公民，高度契合云原生分布式调度，且天然对多副本容器进行各自初始化。</li><li><strong>Docker Compose</strong> 的 Init Containers 则是通过 <code>pre_start</code> 生命周期钩子实现的一种<strong>轻量级解决方案</strong>。它更契合单机部署、本地开发、小规模自托管（Self-Hosted）场景。</li></ul><p>简单来说，<strong>Docker Compose 的 Init Containers 是为 Compose 场景量身定制的精简版初始化机制</strong>，小巧但十分够用。</p><h2 id="最佳实践建议"><a href="#最佳实践建议" class="headerlink" title="最佳实践建议"></a>最佳实践建议</h2><p>在实际生产或开发环境使用 <code>pre_start</code> 时，建议遵循以下原则：</p><ol><li><strong>绝对的幂等性</strong>：初始化脚本一定要做到“多次执行，结果一致”，随时准备应对重试和重建场景。</li><li><strong>严禁包含长驻进程</strong>：<code>pre_start</code> 的步骤必须是能在短时间内主动退出并返回 <code>0</code> 的任务，否则将无限期阻塞主服务的启动。</li><li><strong>区分生产与开发环境的迁移策略</strong>：虽然在 <code>pre_start</code> 中自动运行 <code>migrate</code> 很爽，但在生产环境中自动执行数据库迁移依然存在一定风险。建议重要线上项目通过独立的 CI&#x2F;CD Pipeline 触发迁移。</li><li><strong>封装复杂逻辑为脚本</strong>：如果初始化流程复杂（包含多步判断和环境准备），建议封装为独立脚本（如 <code>./scripts/init.sh</code>）放入容器，而在 <code>compose.yaml</code> 中只调用该脚本，避免配置文件过长。</li></ol><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pre_start:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./scripts/init.sh&quot;</span>]</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><strong>Docker Compose</strong> 的 <strong>Init Containers</strong> 终于解决了容器编排中长久以来的一个痛点：<strong>如何优雅地表达“启动前的必要前置步骤”</strong>。</p><p>我们可以将它的应用场景简单归纳为：</p><table><thead><tr><th align="left">适合使用 ✅</th><th align="left">不适合使用 ❌</th></tr></thead><tbody><tr><td align="left">数据库自动迁移 (<code>migrate</code>)</td><td align="left">长期运行的后台任务</td></tr><tr><td align="left">初始数据导入与种子填充</td><td align="left">定时备份&#x2F;清理等 Cron 任务</td></tr><tr><td align="left">修正宿主卷挂载（Volume）权限</td><td align="left">纯静态的配置文件挂载 (使用 <code>configs</code>)</td></tr><tr><td align="left">动态生成局部配置</td><td align="left">敏感凭证的安全管理 (使用 <code>secrets</code>)</td></tr><tr><td align="left">串联多个有顺序的前置校验步骤</td><td align="left">必须针对每个副本 (Replica) 重复执行的初始化</td></tr></tbody></table><p>最后，让我们用一张直观的对比来看看引入这一新特性后的变化：</p><div class="flatpaper-tabs"><div class="flatpaper-tabs__nav" role="tablist"><button type="button" role="tab" id="tabs-21-tab-0" aria-controls="tabs-21-panel-0" aria-selected="true" class="flatpaper-tabs__nav-item is-active" data-index="0">以前的写法 (depends_on)</button><button type="button" role="tab" id="tabs-21-tab-1" aria-controls="tabs-21-panel-1" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="1">现在的写法 (pre_start)</button></div><div class="flatpaper-tabs__panels"><section role="tabpanel" id="tabs-21-panel-0" aria-labelledby="tabs-21-tab-0" class="flatpaper-tabs__panel is-active" data-index="0"><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">migrate:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;migrate&quot;</span>]</span><br><span class="line">    <span class="attr">restart:</span> <span class="string">&quot;no&quot;</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">migrate:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_completed_successfully</span></span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-21-panel-1" aria-labelledby="tabs-21-tab-1" class="flatpaper-tabs__panel" data-index="1" hidden><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">myapp:latest</span></span><br><span class="line">    <span class="attr">pre_start:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">command:</span> [<span class="string">&quot;./manage.py&quot;</span>, <span class="string">&quot;migrate&quot;</span>]</span><br></pre></td></tr></table></figure></section></div></div><p>这就是 <strong>Docker Compose Init Containers</strong> 的终极奥义 —— <strong>让初始化步骤，优雅地回到它真正属于的地方</strong>。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;在使用 Docker Compose 部署应用时，你是否也曾为“如何在主应用启动前优雅地运行数据库迁移或修复权限”而烦恼过？&lt;/p&gt;
&lt;p&gt;过去，我们不得不编写各种一次性服务并用复杂的 &lt;code&gt;depends_on&lt;/code&gt; 串联。而现在，随着 Docker Compose 新特性的发布，我们终于迎来了官方的 &lt;strong&gt;Init Containers&lt;/strong&gt; 支持。本文将带你一探究竟，看看它如何帮我们精简 &lt;code&gt;compose.yaml&lt;/code&gt;！&lt;/p&gt;</summary>
    
    
    
    <category term="教程" scheme="https://ooo.run/categories/%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="Docker" scheme="https://ooo.run/tags/Docker/"/>
    
    <category term="Docker Compose" scheme="https://ooo.run/tags/Docker-Compose/"/>
    
    <category term="Init Containers" scheme="https://ooo.run/tags/Init-Containers/"/>
    
  </entry>
  
  <entry>
    <title>开源项目: 把酷炫的 WebGL Shader 变成前端组件 - Paper Shaders 介绍</title>
    <link href="https://ooo.run/post/paper-shaders-open-source-webgl-design-effects.html"/>
    <id>https://ooo.run/post/paper-shaders-open-source-webgl-design-effects.html</id>
    <published>2026-07-02T03:42:27.000Z</published>
    <updated>2026-07-02T04:47:36.361Z</updated>
    
    <content type="html"><![CDATA[<p>如果你做过前端视觉效果，大概率会遇到一个尴尬问题：<br>普通 CSS 很方便，但一旦想要做更复杂的动态纹理、噪声、渐变、玻璃、液态金属、粒子感背景，就很容易被迫走向 WebGL、Three.js、GLSL 和一大堆初始化样板代码。</p><p>而 <strong>Paper Shaders</strong> 想解决的正是这个问题。</p><p>它是 Paper Design 团队开源的一组 <strong>零依赖 Canvas &#x2F; WebGL Shader 组件</strong>，可以直接通过 npm 安装使用，也可以在 Paper 设计工具中可视化调整后导出代码。项目目前托管在 GitHub，采用 Apache 2.0 协议开源，官方定位是 “ultra fast zero-dependency shaders for your designs”。</p><h2 id="Paper-Shaders-是什么？"><a href="#Paper-Shaders-是什么？" class="headerlink" title="Paper Shaders 是什么？"></a>Paper Shaders 是什么？</h2><p>简单来说，Paper Shaders 是一套可以直接放进网页里的视觉特效组件库。</p><p>它把原本需要手写 GLSL、配置 WebGL 上下文、处理 Canvas 渲染循环的复杂过程，封装成了更接近普通前端组件的使用方式。对于 React 项目，你可以直接安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i @paper-design/shaders-react</span><br></pre></td></tr></table></figure><p>如果不使用 React，也可以安装 vanilla 版本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i @paper-design/shaders</span><br></pre></td></tr></table></figure><p>官方 README 中也特别提醒，目前项目仍处在 <code>0.0.x</code> 版本阶段，可能会有破坏性更新，因此建议固定依赖版本。</p><h2 id="它能做哪些效果？"><a href="#它能做哪些效果？" class="headerlink" title="它能做哪些效果？"></a>它能做哪些效果？</h2><p>Paper Shaders 内置了不少适合现代网站设计的视觉效果。官方示例站把它们大致分成几类：</p><p><strong>图片滤镜类</strong>：<br>比如 paper texture、fluted glass、water、image dithering、halftone dots、halftone cmyk。</p><p><img src="https://img.nep.me/ooo/paper-shaders-1.webp" alt="paper-shaders-1.png"></p><p><strong>Logo 动画类</strong>：<br>比如 heatmap、liquid metal、gem smoke。</p><p><img src="https://img.nep.me/ooo/paper-shaders-2.webp" alt="paper-shaders-2.png"></p><p><strong>背景与动态效果类</strong>：<br>比如 mesh gradient、static mesh gradient、grain gradient、dot orbit、warp、spiral、swirl、waves、neuro noise、perlin、simplex noise、voronoi、metaballs、god rays 等。</p><p><img src="https://img.nep.me/ooo/paper-shaders-3.webp" alt="paper-shaders-3.png"></p><p>这些效果很适合用在：</p><ul><li>Landing Page 首屏背景</li><li>产品官网 Hero 区域</li><li>Logo 动效</li><li>文章封面图生成</li><li>开发者工具官网</li><li>设计感较强的 SaaS 页面</li><li>作品集网站</li><li>音乐、游戏、创意类项目页面</li></ul><p>相比直接使用静态图片，Shader 的优势是可以实时渲染、动态变化，并且通常能保持更好的响应式适配能力。</p><p>所有效果都可以在项目官网：<a href="https://shaders.paper.design/">https://shaders.paper.design/</a> 预览并进行调整。</p><h2 id="React-中如何使用？"><a href="#React-中如何使用？" class="headerlink" title="React 中如何使用？"></a>React 中如何使用？</h2><p>Paper Shaders 的 React 用法非常接近普通组件。</p><p>例如官方 README 中给出的 <code>MeshGradient</code> 示例：</p><figure class="highlight tsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">MeshGradient</span>, <span class="title class_">DotOrbit</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@paper-design/shaders-react&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">App</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">MeshGradient</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">colors</span>=<span class="string">&#123;[</span>&#x27;#<span class="attr">5100ff</span>&#x27;, &#x27;#<span class="attr">00ff80</span>&#x27;, &#x27;#<span class="attr">ffcc00</span>&#x27;, &#x27;#<span class="attr">ea00ff</span>&#x27;]&#125;</span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">distortion</span>=<span class="string">&#123;1&#125;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">swirl</span>=<span class="string">&#123;0.8&#125;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">speed</span>=<span class="string">&#123;0.2&#125;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">style</span>=<span class="string">&#123;&#123;</span> <span class="attr">width:</span> <span class="attr">200</span>, <span class="attr">height:</span> <span class="attr">200</span> &#125;&#125;</span></span></span><br><span class="line"><span class="tag"><span class="language-xml">      /&gt;</span></span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">DotOrbit</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">colors</span>=<span class="string">&#123;[</span>&#x27;#<span class="attr">d2822d</span>&#x27;, &#x27;#<span class="attr">0c3b7e</span>&#x27;, &#x27;#<span class="attr">b31a57</span>&#x27;, &#x27;#<span class="attr">37a066</span>&#x27;]&#125;</span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">colorBack</span>=<span class="string">&quot;#000000&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">scale</span>=<span class="string">&#123;0.3&#125;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">        <span class="attr">style</span>=<span class="string">&#123;&#123;</span> <span class="attr">width:</span> <span class="attr">200</span>, <span class="attr">height:</span> <span class="attr">200</span> &#125;&#125;</span></span></span><br><span class="line"><span class="tag"><span class="language-xml">      /&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/&gt;</span></span></span><br><span class="line">  );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>从这个例子可以看出，它并不要求开发者先理解完整的 WebGL 渲染流程，而是通过 <code>colors</code>、<code>distortion</code>、<code>swirl</code>、<code>speed</code>、<code>scale</code> 这类参数来调节视觉表现。对于设计师或前端开发者来说，这种抽象会更容易试错。</p><h2 id="设计师友好的-Shader-工作流"><a href="#设计师友好的-Shader-工作流" class="headerlink" title="设计师友好的 Shader 工作流"></a>设计师友好的 Shader 工作流</h2><p>Paper Shaders 最有意思的一点，不只是“提供了一堆 Shader 组件”，而是它试图打通 <strong>设计工具 → 前端代码</strong> 的流程。</p><p>项目 README 中提到，它的目标之一是让设计师可以用视觉化方式使用常见 Shader，并且最终产物可以直接导出为轻量代码，放进任意代码库中使用。</p><p>这点其实很重要。</p><p>很多网页视觉效果在设计稿里看起来很漂亮，但真正落地时会遇到几个问题：</p><p>设计师不知道如何描述 Shader 参数；<br>开发者不想从零写 WebGL；<br>设计稿里的动态效果很难准确还原；<br>最后只能用视频、GIF 或静态图片代替。</p><p>Paper Shaders 的思路是把 Shader 变成一种更“产品化”的设计资产：<br>设计阶段可以调，开发阶段可以直接用，最终上线时又不需要引入庞大的运行时依赖。</p><h2 id="零依赖的意义"><a href="#零依赖的意义" class="headerlink" title="零依赖的意义"></a>零依赖的意义</h2><p>Paper Shaders 官方强调自己是 <strong>zero-dependency HTML canvas shaders</strong>。</p><p>这对前端项目来说很有吸引力。很多视觉动效库虽然效果强大，但往往会带来明显的 bundle 体积、依赖链和运行时复杂度。对于只想在首页加一个动态背景、给 Logo 增加一点高级感、或者做一个轻量交互效果的项目来说，引入完整 3D 引擎有时候显得太重。</p><p>Paper Shaders 的定位更轻：<br>它不是要取代 Three.js、R3F 或专业图形引擎，而是提供一组可以快速嵌入网页的高质量 Shader 效果。</p><h2 id="开源协议与商业使用"><a href="#开源协议与商业使用" class="headerlink" title="开源协议与商业使用"></a>开源协议与商业使用</h2><p>Paper Shaders 使用 <strong>Apache 2.0 License</strong>。官方说明中提到，可以在商业网站、应用、游戏、视频、原型、内部工具和其他最终产品中使用，不要求可见署名。若将 Paper Shaders 代码作为另一个 Shader 库、插件或工具的一部分重新分发，则需要保留 LICENSE 和 NOTICE 文件。</p><p>这意味着它对个人项目、商业官网、SaaS 产品、内部工具都比较友好。</p><h2 id="适合哪些项目？"><a href="#适合哪些项目？" class="headerlink" title="适合哪些项目？"></a>适合哪些项目？</h2><p>我觉得 Paper Shaders 特别适合以下几类场景。</p><p>第一类是 <strong>想快速提升视觉质感的官网</strong>。<br>比如一个 AI 工具、设计工具、开发者平台或者 SaaS 产品首页，使用 Mesh Gradient、Grain Gradient、God Rays 这类效果，很容易让页面从“普通模板感”变得更有记忆点。</p><p>第二类是 <strong>需要动态 Logo 或品牌动效的项目</strong>。<br>Liquid Metal、Heatmap、Gem Smoke 这类效果非常适合做品牌展示，尤其适合科技、创意、设计类产品。</p><p>第三类是 <strong>不想写底层 WebGL 的前端项目</strong>。<br>如果你只是想要一个漂亮的 Shader 背景，而不是开发一套图形引擎，Paper Shaders 的组件化封装会比从零写 WebGL 轻松很多。</p><p>第四类是 <strong>设计师与开发者协作密集的团队</strong>。<br>如果设计师希望动态视觉效果不是“截图给开发者猜”，而是能直接变成可用代码，那么 Paper Shaders 的方向就很值得关注。</p><h2 id="需要注意的问题"><a href="#需要注意的问题" class="headerlink" title="需要注意的问题"></a>需要注意的问题</h2><p>当然，它也不是万能的。</p><p>首先，Paper Shaders 目前版本号仍然处于 <code>0.0.x</code>，官方也明确建议固定依赖版本，因为这个阶段仍可能出现破坏性更新。</p><p>其次，Shader 本质上仍然是实时渲染效果。虽然官方强调轻量和高性能，但在实际项目中，仍然建议注意移动端性能、低端设备表现、电池消耗，以及是否会影响页面可读性。</p><p>最后，视觉效果不要滥用。Shader 很适合做氛围和品牌感，但如果整页都是动态纹理、噪声和闪动渐变，反而会影响内容阅读。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Paper Shaders 是一个很有意思的开源项目。</p><p>它把原本偏图形编程领域的 Shader，封装成了更接近现代前端组件的形态：可以 npm 安装，可以 React 使用，可以调参数，也可以与设计工具结合。对于想给网站增加动态背景、纹理、Logo 动画和高级视觉效果的开发者来说，它提供了一条比手写 WebGL 更轻量的路径。</p><p>它并不是一个庞大的 3D 框架，而更像是一盒彩色墨水：<br>你不需要重新造画布，只需要把它滴进页面里，就能让原本平面的界面多一点流动感、颗粒感和生命力。</p><h2 id="项目地址"><a href="#项目地址" class="headerlink" title="项目地址"></a>项目地址</h2><ul><li>官网：<a href="https://shaders.paper.design/">https://shaders.paper.design/</a></li><li>GitHub：<a href="https://github.com/paper-design/shaders">https://github.com/paper-design/shaders</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;如果你做过前端视觉效果，大概率会遇到一个尴尬问题：&lt;br&gt;普通 CSS 很方便，但一旦想要做更复杂的动态纹理、噪声、渐变、玻璃、液态金属、粒子感背景，就很容易被迫走向 WebGL、Three.js、GLSL 和一大堆初始化样板代码。&lt;/p&gt;
&lt;p&gt;而 &lt;strong&gt;Pap</summary>
      
    
    
    
    <category term="工具资源" scheme="https://ooo.run/categories/%E5%B7%A5%E5%85%B7%E8%B5%84%E6%BA%90/"/>
    
    
    <category term="开源" scheme="https://ooo.run/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="前端开发" scheme="https://ooo.run/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
    <category term="WebGL" scheme="https://ooo.run/tags/WebGL/"/>
    
    <category term="React" scheme="https://ooo.run/tags/React/"/>
    
  </entry>
  
  <entry>
    <title>Sonnet 5 已发布，值得用吗？</title>
    <link href="https://ooo.run/post/is-sonnet-5-worth-using.html"/>
    <id>https://ooo.run/post/is-sonnet-5-worth-using.html</id>
    <published>2026-07-01T09:30:48.000Z</published>
    <updated>2026-07-01T10:35:36.952Z</updated>
    
    <content type="html"><![CDATA[<p>北京时间 2026 年 7 月 1 日， Anthropic 宣布 <strong>Fable 5</strong> 解除封禁，并发布了新模型 <strong>Sonnet 5</strong>， Anthopic 宣称该版本显著提升了自主执行任务和调用工具的智能体 (Agent) 能力，性能逼近旗舰级 Opus 4.8，采用了全新的分词器。其定价为：</p><table><thead><tr><th>模型</th><th>输入（每百万 Token）</th><th>输出（每百万 Token）</th><th>备注</th></tr></thead><tbody><tr><td>Sonnet 5</td><td>3 美元</td><td>15 美元</td><td>8 月 31 日前优惠价 2 美元 &#x2F; 10 美元</td></tr><tr><td>Opus 4.8</td><td>5 美元</td><td>25 美元</td><td>无限时优惠</td></tr><tr><td>Fable 5</td><td>10 美元</td><td>50 美元</td><td>7 月 7 日后订阅额度不再包含，需按 API 付费</td></tr></tbody></table><p>无论输入还是输出，Sonnet 5 的单价都只有 Opus 的六成。但单价更低不代表实际更省——后面会提到，按实际任务成本衡量，Sonnet 5 完成同一任务反而可能花更多钱，这也是后面争议的根源。</p><p>Sonnet 5 相比 Opus 单价全面更低，又完成了一次大版本号的跃迁，你可能会有疑问，Sonnet 5 到底值得使用吗？</p><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>这里直接上结论：</p><p><strong>Sonnet 5 不适合直接作为默认模型使用，其性能不如 Opus 4.8，但是在写作方面获得了表现出色的评价。</strong></p><p>因此对于大型、大规模代码编辑，直接使用 Opus 4.8 系列即可，如果预算充足则使用 Fable 5（7 月 7 日后 Claude Code Pro 订阅中将无法直接使用 Fable，需要按照 API 定价收费）。</p><p>当需要考虑费用成本、需要较新的知识库（已更新至 2026 年 1 月）时，以及在小型任务、写作任务中，可以切换为 Sonnet 5。</p><p>对于更简单的任务，使用其他更经济的模型即可覆盖。</p><h2 id="Sonnet-5-是什么？"><a href="#Sonnet-5-是什么？" class="headerlink" title="Sonnet 5 是什么？"></a>Sonnet 5 是什么？</h2><p>按照 Anthropic 官方新闻页的说法，Claude Sonnet 5 是 Sonnet 系列的新一代模型，定位是「面向编码、Agent 和专业工作的前沿性能模型」。Anthropic 将其放在 Sonnet 产品线上，而不是 Opus 或 Fable 这种更高阶、更昂贵的旗舰线，这本身就是一个信号：Sonnet 5 不是用来刷榜的模型，而是用来「天天用」的模型。</p><p>外媒报道也提到，Sonnet 5 被设计为一个更适合日常高频使用的模型，重点加强了浏览、编码、规划、知识工作和自主任务执行能力，并已同步面向 Claude Free、Pro、Max、Team、Enterprise 等所有订阅层级开放。这种「首发即全量」的铺开方式，也印证了它的定位：主力机型，不是尝鲜彩蛋。</p><p>简单说，Sonnet 5 不是「最高规格炫技模型」，而是 Anthropic 想推给大多数 Claude 用户的主力工作模型。</p><p>这和过去 Anthropic 对 Sonnet 系列的定位一致：  <strong>比 Haiku 强，比 Opus 便宜，适合作为日常主力。</strong></p><h2 id="社交媒体评价：完全不值"><a href="#社交媒体评价：完全不值" class="headerlink" title="社交媒体评价：完全不值"></a>社交媒体评价：完全不值</h2><p>一张来自 Artificial Analysis 的「Cost per Intelligence Index Task」图表显示，Claude Sonnet 5 在 <strong>Max 思考等级</strong> 下的单任务成本明显高于 GPT-5.5、GLM-5.2、Kimi-K2.6、DeepSeek-V4-Pro 等模型，甚至高于 Opus 系列。于是有人直接总结：</p><blockquote><p>Sonnet 5 直接扔进垃圾桶<br>比 Opus 4.8 Max 贵 1.2 倍<br>比 GPT-5.5-xhigh 贵 2 倍<br>比 GLM-5.2 贵 5 倍<br>比 Kimi-K2.6 贵 7 倍<br>比 DeepSeek-V4-Pro 贵 57 倍</p></blockquote><p><img src="https://img.nep.me/ooo/sonnet5-per-task-cost.webp" alt="sonnet5-per-task-cost"></p><p>对此 OpenClaw 的作者 Peter Steinberger 直接 <a href="https://x.com/steipete/status/2072144627474579925">评价</a>： <strong>每 Token 价格 !&#x3D; 实际任务成本 !&#x3D; 最终生产力成本</strong>。</p><p>由于 Sonnet 5 的智能没有实现很大进步，需要消耗更多的 Token 来完成任务，导致总消耗反而比 Opus 系列更多。 </p><p>因此对于大型、大规模的代码编辑项目直接使用更高智能的 Opus 系列即可。</p><h2 id="争议点：Sonnet-5-贵不贵？"><a href="#争议点：Sonnet-5-贵不贵？" class="headerlink" title="争议点：Sonnet 5 贵不贵？"></a>争议点：Sonnet 5 贵不贵？</h2><p>贵。</p><p>尤其是放在 2026 年这个时间点看，Sonnet 5 的成本压力会比过去更明显。</p><p>Artificial Analysis 的成本图并不是单纯比较输入 &#x2F; 输出 Token 单价，而是按 Intelligence Index 任务加权计算，包括 Input、Answer、Reasoning、Cache Write、Cache Hit 等不同 Token 类型。它试图回答的是：完成一个标准化智能任务，平均要花多少钱。</p><p>这就解释了为什么「看起来 API 单价差不多」的模型，实际任务成本可能完全不同。举个例子：如果一个模型平均需要 3 轮工具调用、每轮都要重新读一遍上下文才能完成任务，而另一个模型 1 轮就能给出可用结果，那么即使两者单价一致，前者的实际账单也会是后者的数倍——差距不是来自定价表，而是来自「模型解决问题需要绕多少路」。</p><p>一个模型如果：</p><ul><li>输出更长</li><li>推理 Token 更多</li><li>工具调用链路更重</li><li>不擅长一次完成，需要反复修正</li><li>Cache 利用率不高</li></ul><p>那么它的实际成本就会被拉高。</p><p>这也是很多人吐槽 Sonnet 5 的原因：<br><strong>Anthropic 的模型越来越像豪华燃油车，性能强，但开起来不便宜。</strong></p><h2 id="但只看单任务成本，也容易误判"><a href="#但只看单任务成本，也容易误判" class="headerlink" title="但只看单任务成本，也容易误判"></a>但只看单任务成本，也容易误判</h2><p>问题在于，开发者真正关心的往往不是「跑一次 Benchmark 花多少钱」，而是：</p><p><strong>它能不能少折腾我？</strong></p><p>对写代码、重构项目、分析仓库、修 Bug、跑 Agent 来说，模型成本只是总成本的一部分。更重要的是：</p><ul><li>第一次方案是否靠谱</li><li>是否理解大型项目上下文</li><li>是否会乱改无关文件</li><li>是否能保持长期任务稳定</li><li>是否能自己发现问题并修正</li><li>是否减少人工 review 和返工</li></ul><p>如果 Sonnet 5 在这些方面明显强于便宜模型，那么它即使「每次任务更贵」，最终仍然可能更划算。</p><p>打个比方：假设一个中型重构任务，便宜模型单价是 Sonnet 5 的五分之一，但因为理解不了项目边界，需要反复试错 6 轮才能勉强跑通，且中途还改坏了两个无关文件，需要你手动回滚；而 Sonnet 5 单价更高，但 2 轮就能给出可用方案，且不会牵连其他文件。算上你自己排查、回滚、二次确认的时间成本，便宜模型的「总成本」未必比 Sonnet 5 低——只是这部分成本没有出现在账单上，而是变成了你的时间。</p><p>这就像云服务器：</p><p>便宜的很便宜，但如果一天炸三次、IO 抽风、网络绕路，最后浪费的是人的时间。</p><p>AI 模型也是一样。</p><h2 id="Sonnet-5-真正的价值：Agent-和代码工作流"><a href="#Sonnet-5-真正的价值：Agent-和代码工作流" class="headerlink" title="Sonnet 5 真正的价值：Agent 和代码工作流"></a>Sonnet 5 真正的价值：Agent 和代码工作流</h2><p>从 Anthropic 的宣传重点看，Sonnet 5 最核心的卖点不是普通聊天，而是 <strong>Agentic Workflows</strong>。</p><p>也就是让模型不只是回答问题，而是能连续执行任务：</p><ul><li>阅读项目文件</li><li>理解现有架构</li><li>制定修改计划</li><li>调用终端</li><li>修改代码</li><li>跑测试</li><li>根据报错继续修</li><li>最后总结变更</li></ul><p>这正是 Claude Code、Cursor、Windsurf、OpenClaw 这类工具最依赖的能力。</p><p>对这类场景来说，模型的「听话程度」「上下文稳定性」「工具调用判断」往往比单纯的知识问答更重要。Anthropic 过去几代 Sonnet 在代码 Agent 场景中口碑一直不错，Sonnet 5 如果继续强化这条路线，那它仍然会是开发者绕不开的模型。</p><p>尤其是复杂项目里，很多模型不是不会写代码，而是：</p><ul><li>看不懂项目边界</li><li>喜欢重写整个文件</li><li>改 A 坏 B</li><li>测试失败后开始胡猜</li><li>上下文一长就开始失忆</li><li>看到报错只会重复同一个错误修法</li></ul><p>如果 Sonnet 5 能减少这些问题，那么它就不是单纯的「贵」，而是「贵但省心」。</p><h2 id="那它适合所有人吗？"><a href="#那它适合所有人吗？" class="headerlink" title="那它适合所有人吗？"></a>那它适合所有人吗？</h2><p><strong>不适合。</strong></p><p>如果你的需求只是：</p><ul><li>翻译</li><li>摘要</li><li>写普通文章</li><li>生成短代码片段</li><li>问一些常识问题</li><li>做轻量客服 QA</li><li>批量处理低价值文本</li></ul><p>那 Sonnet 5 很可能不是性价比最高的选择。</p><p>这类任务已经进入「模型过剩」阶段。GLM、Kimi、DeepSeek、GPT 的中低价模型都能做得不错。尤其是批量任务，成本差距会被无限放大。</p><p>比如一篇博客摘要、一个 JSON 转换、一个普通 SQL 生成任务，Sonnet 5 的优势可能并不能抵消它的成本。</p><p>这时候更合理的策略是：</p><p><strong>便宜模型跑基础任务，Opus &#x2F; Fable 系列处理大型复杂的任务，当有成本考虑是，将一些中阶的小规模任务交给 Sonnet 5 处理。</strong></p><h2 id="我的建议：不要把-Sonnet-5-当默认模型无脑用"><a href="#我的建议：不要把-Sonnet-5-当默认模型无脑用" class="headerlink" title="我的建议：不要把 Sonnet 5 当默认模型无脑用"></a>我的建议：不要把 Sonnet 5 当默认模型无脑用</h2><p>Sonnet 5 最适合的使用方式，不是「所有请求都丢给它」，而是把它当成一个经济型的工作模型。</p><p>可以这样分层：</p><h3 id="1-普通文本任务：不用-Sonnet-5"><a href="#1-普通文本任务：不用-Sonnet-5" class="headerlink" title="1. 普通文本任务：不用 Sonnet 5"></a>1. 普通文本任务：不用 Sonnet 5</h3><p>翻译、润色、改标题、写摘要、生成普通 Markdown，用便宜模型就够了。</p><p>这些任务对推理深度、工具调用、项目理解要求不高，用 Sonnet 5 属于杀鸡用牛刀。</p><h3 id="2-一般代码片段：看情况"><a href="#2-一般代码片段：看情况" class="headerlink" title="2. 一般代码片段：看情况"></a>2. 一般代码片段：看情况</h3><p>写一个简单函数、改一个 CSS、生成一个 Docker Compose，便宜模型也能胜任。</p><p>但如果它开始反复出错，或者你已经花了 10 分钟纠错，那就应该可以尝试切换 Sonnet 5。</p><p><strong>便宜模型最贵的地方，是让你以为它快好了。</strong></p><h3 id="3-中小型代码任务：可以用-Sonnet-5"><a href="#3-中小型代码任务：可以用-Sonnet-5" class="headerlink" title="3. 中小型代码任务：可以用 Sonnet 5"></a>3. 中小型代码任务：可以用 Sonnet 5</h3><p>例如：</p><ul><li>修改单个页面</li><li>补一个组件</li><li>写一个脚本</li><li>修一个明确报错</li><li>添加一个简单 API</li><li>生成测试用例</li><li>对已有代码做小范围重构</li></ul><p>这类任务的特点是边界清晰、上下文较短、失败成本较低。Sonnet 5 在这里可以发挥 Claude 系列一贯的代码理解和指令遵循能力，同时比 Opus 4.8 单价更低。</p><p>如果任务本身不复杂，用 Opus 4.8 反而有些浪费；但如果用更便宜的模型反复出错，Sonnet 5 就是一个不错的折中选择。</p><p>它适合处理「需要一点智能，但还不值得动用最高智能模型」的代码任务。</p><h3 id="4-大型项目的开发与重构：直接使用更高智能的模型"><a href="#4-大型项目的开发与重构：直接使用更高智能的模型" class="headerlink" title="4. 大型项目的开发与重构：直接使用更高智能的模型"></a>4. 大型项目的开发与重构：直接使用更高智能的模型</h3><p>如果你的目标不是修一个小 Bug、改一个组件、写一段脚本，而是让 AI 参与实现一个完整项目，那么 Sonnet 5 反而不一定是最优选择。</p><p>这类任务通常包括：</p><ul><li>从零搭建一个完整应用</li><li>设计项目架构</li><li>实现多模块功能</li><li>连续修改几十个文件</li><li>处理数据库、鉴权、状态管理、路由、部署配置</li><li>长时间运行 Claude Code &#x2F; Codex &#x2F; OpenClaw 这类 Agent 工具</li></ul><p>在这种场景里，模型最重要的不是「单价低」，而是「一次做对的概率高」。</p><p>大型项目的成本并不只是 Token 成本，而是由多部分组成：</p><ul><li>模型理解需求的成本</li><li>模型维护上下文的成本</li><li>多轮修改产生的返工成本</li><li>改错文件带来的回滚成本</li><li>测试失败后的排查成本</li><li>人工 review 和补救的时间成本</li></ul><p>如果一个模型智能略低，它可能每一步看起来都能做，但组合起来就会出现问题：前面设计的架构后面忘了，刚写好的接口下一轮又被改坏，A 页面修好了 B 页面挂了，最后整个项目进入「能跑但不敢碰」的状态。</p><p>这也是为什么在大型项目里，应该优先使用 Opus 4.8、Fable 5 这类更高智能模型。</p><p>它们的单价更高，但在复杂任务中更容易保持全局一致性，能减少无效尝试和重复修复。尤其是当任务涉及架构设计、跨文件重构、测试修复和长期上下文时，更高智能模型带来的稳定性往往比价格差异更重要。</p><p>Sonnet 5 更适合做局部任务：<br>比如写一个页面、改一个模块、生成一段文案、补一个测试、修一个明确的报错。</p><p>但如果你要让 AI 从头到尾实现一个大型项目，尤其是需要连续运行 Agent 多小时，那么更合理的策略是：</p><p><strong>直接使用 Opus 4.8 或 Fable 5，不要为了省一点单价把项目交给 Sonnet 5 硬跑。</strong></p><p>因为大型项目里最贵的不是模型，而是模型犯错之后你还要继续相信它。</p><h2 id="Sonnet-5-的问题：Anthropic-还是那个-Anthropic"><a href="#Sonnet-5-的问题：Anthropic-还是那个-Anthropic" class="headerlink" title="Sonnet 5 的问题：Anthropic 还是那个 Anthropic"></a>Sonnet 5 的问题：Anthropic 还是那个 Anthropic</h2><p>Sonnet 5 的发布，也再次暴露了 Anthropic 的老问题：</p><p><strong>模型很好，但生态和价格让人焦虑。</strong></p><p>Claude 的体验一直很强，尤其是代码和长上下文任务。但 Anthropic 在可用性、额度、区域、订阅限制、API 成本和第三方工具支持上，始终不像 OpenAI 那样稳定。</p><p>更重要的是，随着 AI Agent 消耗越来越大，「订阅制无限用」这件事本身就越来越难持续。此前已有分析指出，重度 AI 用户实际消耗的 API 等价成本可能远超订阅价格——一个长期跑 Agent 任务的开发者，一天消耗的 Token 换算成 API 价格可能就超过月费本身。这意味着 AI 公司未来很可能继续向更细粒度、更接近成本的计费方式调整，比如更严格的用量上限、分层限速，或者像 Sonnet 5 这样在输出端悄悄提价。</p><p>所以 Sonnet 5 的问题不是单个模型贵，而是代表了一种趋势：</p><p><strong>好模型会越来越强，但真正便宜随便用的时代正在结束。</strong></p><h2 id="一句话总结"><a href="#一句话总结" class="headerlink" title="一句话总结"></a>一句话总结</h2><p><strong>Sonnet 5 不是便宜模型，也不是最强模型，而是一个适合写作和中小型任务的 Claude 日常模型。</strong> 它在代码编辑领域没有找到一个足够舒服的位置：便宜任务轮不到它，复杂任务又不如直接上 Opus &#x2F; Fable。</p><p>如果你把它当成 Opus 的廉价替代品，可能会失望；<br>如果你把它当成一个更适合日常文本和轻量工作的 Sonnet，它依然值得放进工具箱。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;北京时间 2026 年 7 月 1 日， Anthropic 宣布 &lt;strong&gt;Fable 5&lt;/strong&gt; 解除封禁，并发布了新模型 &lt;strong&gt;Sonnet 5&lt;/strong&gt;， Anthopic 宣称该版本显著提升了自主执行任务和调用工具的智能体 (Ag</summary>
      
    
    
    
    <category term="资讯" scheme="https://ooo.run/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="AI" scheme="https://ooo.run/tags/AI/"/>
    
    <category term="Claude" scheme="https://ooo.run/tags/Claude/"/>
    
    <category term="Sonnet 5" scheme="https://ooo.run/tags/Sonnet-5/"/>
    
  </entry>
  
  <entry>
    <title>Vercel Services 发布：一个项目部署 Next.js、FastAPI、Go 和 Astro</title>
    <link href="https://ooo.run/post/vercel-services-multiple-frameworks-one-project.html"/>
    <id>https://ooo.run/post/vercel-services-multiple-frameworks-one-project.html</id>
    <published>2026-06-30T16:09:42.000Z</published>
    <updated>2026-06-30T16:47:09.870Z</updated>
    
    <content type="html"><![CDATA[<p>当你手头有一个包含 Next.js 前端、FastAPI 后端、Go 服务和 Astro 文档站的复杂项目时，是否也曾为如何在 Vercel 上部署和管理而感到头疼？</p><p>过去，这类项目往往需要拆成多个 Vercel Project，或者把部分服务放到其他平台上运行。项目一多，域名、环境变量、Preview URL、跨服务调用、CORS、路由转发都会变复杂。</p><p>Vercel 最近推出的 <a href="https://vercel.com/changelog/run-multiple-frameworks-in-one-project-with-vercel-services">Vercel Services</a>，就是为了解决这个问题：它允许开发者在一个 Vercel Project 中部署多个独立构建的服务，并通过统一的路由规则把请求分发到不同服务中。</p><p>换句话说，一个项目里可以同时放：</p><ul><li>Next.js 前端</li><li>FastAPI 后端</li><li>Go API 服务</li><li>Astro 文档站</li><li>Vite &#x2F; React 管理后台</li><li>其他独立构建单元</li></ul><p>这些服务可以共享同一个部署、同一个域名、同一套 Preview Deployment，并且可以通过 Vercel 的服务路由和内部绑定进行通信。</p><h2 id="Vercel-Services-是什么？"><a href="#Vercel-Services-是什么？" class="headerlink" title="Vercel Services 是什么？"></a>Vercel Services 是什么？</h2><p>简单来说，Vercel Services 可以把一个项目拆成多个独立的 <strong>Service</strong>。</p><p>每个 Service 都是一个独立构建单元，可以有自己的根目录、框架、运行时、启动入口和依赖文件。但它们最终仍然属于同一个 Vercel Project，并共享同一个部署。</p><p>例如，一个项目可以设计成这样：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">my-project/</span><br><span class="line">├── apps/</span><br><span class="line">│   ├── web/        # Next.js 前端</span><br><span class="line">│   ├── docs/       # Astro 文档站</span><br><span class="line">│   └── admin/      # Vite 管理后台</span><br><span class="line">├── backend/</span><br><span class="line">│   └── fastapi/    # FastAPI 后端</span><br><span class="line">├── services/</span><br><span class="line">│   └── go/         # Go 服务</span><br><span class="line">└── vercel.json</span><br></pre></td></tr></table></figure><p>部署后，可以通过同一个域名访问不同服务：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">https://example.vercel.app/          -&gt; Next.js 前端</span><br><span class="line">https://example.vercel.app/api       -&gt; FastAPI 后端</span><br><span class="line">https://example.vercel.app/go        -&gt; Go 服务</span><br><span class="line">https://example.vercel.app/docs      -&gt; Astro 文档站</span><br></pre></td></tr></table></figure><p>这就是 Vercel Services 最核心的价值：<strong>一个项目，多个服务，统一部署。</strong></p><p><img src="https://img.nep.me/ooo/cover-vercel-services.webp" alt="Vercek Services"></p><h2 id="它解决了什么问题？"><a href="#它解决了什么问题？" class="headerlink" title="它解决了什么问题？"></a>它解决了什么问题？</h2><h3 id="1-前端和后端不用拆成多个-Vercel-Project"><a href="#1-前端和后端不用拆成多个-Vercel-Project" class="headerlink" title="1. 前端和后端不用拆成多个 Vercel Project"></a>1. 前端和后端不用拆成多个 Vercel Project</h3><p>很多项目一开始只是一个前端站点，后来逐渐加上 API、后台、Webhook、文档站、小工具页面，最后目录可能变成这样：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">my-project/</span><br><span class="line">├── apps/</span><br><span class="line">│   ├── web/</span><br><span class="line">│   ├── admin/</span><br><span class="line">│   └── docs/</span><br><span class="line">├── backend/</span><br><span class="line">│   ├── main.py</span><br><span class="line">│   └── requirements.txt</span><br><span class="line">├── packages/</span><br><span class="line">│   └── shared/</span><br><span class="line">└── vercel.json</span><br></pre></td></tr></table></figure><p>如果没有 Services，你可能需要这样拆：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">apps/web     -&gt; 一个 Vercel Project</span><br><span class="line">apps/admin   -&gt; 另一个 Vercel Project</span><br><span class="line">apps/docs    -&gt; 再一个 Vercel Project</span><br><span class="line">backend      -&gt; 部署到 VPS、Render、Fly.io 或其他平台</span><br></pre></td></tr></table></figure><p>这样做当然可以，但维护成本会变高：</p><ul><li>每个项目都有单独的域名和 Preview URL</li><li>环境变量需要重复配置</li><li>前端调用后端要处理 CORS</li><li>PR 预览时前后端地址可能对不上</li><li>多个服务之间的版本同步更麻烦</li></ul><p>Vercel Services 的思路是：这些东西本来就属于同一个产品，那就让它们作为一个项目中的多个服务一起部署。</p><h3 id="2-更适合多语言项目"><a href="#2-更适合多语言项目" class="headerlink" title="2. 更适合多语言项目"></a>2. 更适合多语言项目</h3><p>Vercel 过去最强的体验主要集中在前端和 Node.js 生态，尤其是 Next.js。</p><p>但现实项目中，后端不一定都是 JavaScript。很多项目会同时使用：</p><ul><li>Next.js</li><li>Astro</li><li>Vite</li><li>FastAPI</li><li>Go</li><li>Express</li><li>Hono</li><li>其他后端框架</li></ul><p>Vercel Services 让这些服务可以在一个项目中组合起来。</p><p>例如：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">apps/web         -&gt; Next.js 前端</span><br><span class="line">apps/docs        -&gt; Astro 文档站</span><br><span class="line">backend/fastapi  -&gt; FastAPI 后端</span><br><span class="line">services/go      -&gt; Go 服务</span><br></pre></td></tr></table></figure><p>这类项目过去更像是“多个部署拼起来”，现在则更接近“一个产品的多个组成部分”。</p><h3 id="3-Preview-Deployment-更统一"><a href="#3-Preview-Deployment-更统一" class="headerlink" title="3. Preview Deployment 更统一"></a>3. Preview Deployment 更统一</h3><p>Vercel 最好用的能力之一是 Preview Deployment。</p><p>每次提交 PR，都可以自动生成一个预览地址。如果前端、后端、文档站都拆成多个 Project，那么你可能需要同时管理多个预览地址。</p><p>使用 Services 后，多个服务可以共享同一个部署 URL，通过不同路径区分：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">https://my-project-git-feature.vercel.app/</span><br><span class="line">https://my-project-git-feature.vercel.app/api</span><br><span class="line">https://my-project-git-feature.vercel.app/go</span><br><span class="line">https://my-project-git-feature.vercel.app/docs</span><br></pre></td></tr></table></figure><p>对于团队协作、产品验收、临时测试来说，这会简单很多。</p><h2 id="基础配置示例"><a href="#基础配置示例" class="headerlink" title="基础配置示例"></a>基础配置示例</h2><p>Vercel Services 使用 <code>vercel.json</code> 中的 <code>services</code> 字段声明多个服务。</p><p>一个最简单的前后端项目可以这样写：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;services&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;my_frontend&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;frontend/&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;framework&quot;</span><span class="punctuation">:</span> <span class="string">&quot;nextjs&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;my_backend&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;backend/&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;entrypoint&quot;</span><span class="punctuation">:</span> <span class="string">&quot;main:app&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;rewrites&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/api/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;my_backend&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;my_frontend&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>这里定义了两个服务：</p><ul><li><code>my_frontend</code>：前端服务，根目录是 <code>frontend/</code>，使用 Next.js。</li><li><code>my_backend</code>：后端服务，根目录是 <code>backend/</code>，启动入口是 <code>main:app</code>。</li></ul><p>下面的 <code>rewrites</code> 决定公网请求如何进入不同服务：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/api/*  -&gt; my_backend</span><br><span class="line">/*      -&gt; my_frontend</span><br></pre></td></tr></table></figure><p>也就是说：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">https://example.vercel.app/api/users  -&gt; FastAPI 后端</span><br><span class="line">https://example.vercel.app/about      -&gt; Next.js 前端</span><br></pre></td></tr></table></figure><p>需要注意的是，Service 默认不会自动暴露到公网。只有被顶层 <code>rewrites</code> 指向的服务，才会接收公网请求。</p><p>这点非常重要。</p><p>如果你声明了一个 <code>my_backend</code> 服务，但没有在 <code>rewrites</code> 中把路径指向它，那么它不会直接对公网开放。这种设计适合处理一些只给内部调用的后端服务。</p><img src="https://img.nep.me/ooo/vercel-services-deployment-ui.webp" alt="vercel-services-deployment-ui" style="width:75%;max-width:100%;height:auto" /><h2 id="更完整的示例：Next-js-FastAPI-Go-Astro"><a href="#更完整的示例：Next-js-FastAPI-Go-Astro" class="headerlink" title="更完整的示例：Next.js + FastAPI + Go + Astro"></a>更完整的示例：Next.js + FastAPI + Go + Astro</h2><p>假设我们有一个 Monorepo：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">my-app/</span><br><span class="line">├── apps/</span><br><span class="line">│   ├── web/</span><br><span class="line">│   │   ├── package.json</span><br><span class="line">│   │   └── app/</span><br><span class="line">│   └── docs/</span><br><span class="line">│       ├── package.json</span><br><span class="line">│       └── src/</span><br><span class="line">├── backend/</span><br><span class="line">│   └── fastapi/</span><br><span class="line">│       ├── main.py</span><br><span class="line">│       └── requirements.txt</span><br><span class="line">├── services/</span><br><span class="line">│   └── go/</span><br><span class="line">│       ├── main.go</span><br><span class="line">│       └── go.mod</span><br><span class="line">└── vercel.json</span><br></pre></td></tr></table></figure><p>我们希望：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">/        -&gt; Next.js 前端</span><br><span class="line">/api/*   -&gt; FastAPI 后端</span><br><span class="line">/go/*    -&gt; Go 服务</span><br><span class="line">/docs/*  -&gt; Astro 文档站</span><br></pre></td></tr></table></figure><p>那么 <code>vercel.json</code> 可以这样写：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;services&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;web&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;apps/web&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;framework&quot;</span><span class="punctuation">:</span> <span class="string">&quot;nextjs&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;api&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;backend/fastapi&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;entrypoint&quot;</span><span class="punctuation">:</span> <span class="string">&quot;main:app&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;go_service&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;services/go&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;entrypoint&quot;</span><span class="punctuation">:</span> <span class="string">&quot;main.go&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;docs&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;apps/docs&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;framework&quot;</span><span class="punctuation">:</span> <span class="string">&quot;astro&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;rewrites&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/api/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;api&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/go/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;go_service&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/docs/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;docs&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;web&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>这段配置的核心逻辑很清晰：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">/api/*   交给 FastAPI</span><br><span class="line">/go/*    交给 Go 服务</span><br><span class="line">/docs/*  交给 Astro 文档站</span><br><span class="line">其他路径 交给 Next.js 前端</span><br></pre></td></tr></table></figure><p>注意，<code>rewrites</code> 的顺序很重要。更具体的路径应该放在前面，例如 <code>/api/(.*)</code>、<code>/go/(.*)</code>、<code>/docs/(.*)</code>；兜底的 <code>/(.*)</code> 应该放在最后。</p><p>否则所有请求都可能先被前端服务接走。</p><h2 id="配置字段说明"><a href="#配置字段说明" class="headerlink" title="配置字段说明"></a>配置字段说明</h2><h3 id="services"><a href="#services" class="headerlink" title="services"></a>services</h3><p><code>services</code> 用于声明当前项目中的多个服务。</p><p>每个 key 都是一个服务名，例如：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;services&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;web&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;api&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;docs&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>这些服务名之后可以在 <code>rewrites</code> 或服务间调用配置中使用。</p><h3 id="root"><a href="#root" class="headerlink" title="root"></a>root</h3><p><code>root</code> 指定该服务所在的目录。</p><p>例如：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;services&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;web&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;apps/web&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>这表示 <code>web</code> 服务的代码位于 <code>apps/web</code> 目录下。</p><h3 id="framework"><a href="#framework" class="headerlink" title="framework"></a>framework</h3><p><code>framework</code> 用于指定服务使用的框架。</p><p>例如：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;services&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;web&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;apps/web&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;framework&quot;</span><span class="punctuation">:</span> <span class="string">&quot;nextjs&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;docs&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;apps/docs&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;framework&quot;</span><span class="punctuation">:</span> <span class="string">&quot;astro&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>如果不写，Vercel 会尝试自动识别框架。但对于复杂 Monorepo 项目，显式指定通常更稳定。</p><h3 id="entrypoint"><a href="#entrypoint" class="headerlink" title="entrypoint"></a>entrypoint</h3><p><code>entrypoint</code> 通常用于后端服务，指定应用启动入口。</p><p>FastAPI 常见写法类似：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;services&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;api&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;backend/fastapi&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;entrypoint&quot;</span><span class="punctuation">:</span> <span class="string">&quot;main:app&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>其中 <code>main:app</code> 通常表示：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">main.py 文件中的 app 对象</span><br></pre></td></tr></table></figure><p>Go 服务可以根据项目结构指定入口，例如：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;services&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;go_service&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;services/go&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;entrypoint&quot;</span><span class="punctuation">:</span> <span class="string">&quot;main.go&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>实际写法需要根据项目结构和 Vercel 支持的运行方式调整。</p><h3 id="rewrites"><a href="#rewrites" class="headerlink" title="rewrites"></a>rewrites</h3><p><code>rewrites</code> 是 Services 模式里非常重要的一部分。</p><p>它决定公网请求会被路由到哪个 Service。</p><p>例如：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;rewrites&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/api/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;api&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;service&quot;</span><span class="punctuation">:</span> <span class="string">&quot;web&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>这表示：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/api/*  -&gt; api 服务</span><br><span class="line">其他路径 -&gt; web 服务</span><br></pre></td></tr></table></figure><p>没有被 <code>rewrites</code> 暴露的服务，默认不会接收公网请求。</p><p>这和传统的“每个服务自动挂一个公开路径”不太一样。Vercel Services 更像是先声明服务，再通过统一的顶层路由表决定哪些服务对外开放。</p><h2 id="服务之间如何通信？"><a href="#服务之间如何通信？" class="headerlink" title="服务之间如何通信？"></a>服务之间如何通信？</h2><p>除了通过公网路径访问，Services 之间也可以通过内部方式通信。</p><p>这适合一些不希望直接暴露给公网的服务。</p><p>例如，你可能有：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">web       -&gt; Next.js 前端</span><br><span class="line">api       -&gt; 对外 API</span><br><span class="line">worker    -&gt; 内部任务服务</span><br></pre></td></tr></table></figure><p><code>worker</code> 不需要公开 URL，只需要被 <code>api</code> 调用。这种情况下，就可以让它作为内部服务存在，而不是给它配置公网 rewrite。</p><p>这种设计的好处是：</p><ul><li>减少公网暴露面</li><li>避免无意义的外部路由</li><li>更适合拆分后台能力</li><li>让项目结构更接近真实的微服务或模块化后端</li></ul><p>当然，对于个人项目来说，不一定需要一开始就拆这么细。普通项目可以先从 <code>web + api</code> 两个服务开始。</p><h2 id="它不是-Docker-Compose"><a href="#它不是-Docker-Compose" class="headerlink" title="它不是 Docker Compose"></a>它不是 Docker Compose</h2><p>需要注意的是，Vercel Services 并不等于 Docker Compose。</p><p>Docker Compose 更像是在一台服务器或容器环境中编排多个长期运行的服务，例如：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">web</span><br><span class="line">api</span><br><span class="line">postgres</span><br><span class="line">redis</span><br><span class="line">worker</span><br></pre></td></tr></table></figure><p>它通常负责启动多个容器，并让这些容器在同一个网络环境中长期运行。</p><p>而 Vercel Services 更偏向于 Vercel 平台上的多服务构建与路由组织。它适合部署 Web 应用、API 服务、前端项目和轻量后端，但并不是让你在 Vercel 上直接运行一整套传统服务器环境。</p><p>如果你的项目依赖：</p><ul><li>长期运行的数据库</li><li>Redis</li><li>队列</li><li>后台常驻进程</li><li>自定义守护进程</li><li>复杂内网服务发现</li><li>完整 Docker Compose 生态</li></ul><p>那仍然需要使用外部托管服务，或者选择 VPS &#x2F; Docker &#x2F; Kubernetes 等更传统的部署方式。</p><p>不过，Vercel Services 确实让 Vercel 更接近“一个产品部署多个组成部分”的形态。对于不想自己维护服务器的人来说，这已经覆盖了很多常见场景。</p><h2 id="适合哪些项目？"><a href="#适合哪些项目？" class="headerlink" title="适合哪些项目？"></a>适合哪些项目？</h2><p>Vercel Services 很适合这些场景。</p><h3 id="Monorepo-项目"><a href="#Monorepo-项目" class="headerlink" title="Monorepo 项目"></a>Monorepo 项目</h3><p>例如：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">apps/web</span><br><span class="line">apps/admin</span><br><span class="line">apps/docs</span><br><span class="line">packages/ui</span><br><span class="line">packages/db</span><br><span class="line">backend/api</span><br></pre></td></tr></table></figure><p>如果你已经在使用 pnpm workspace、Turborepo、Nx 或类似结构，Services 会很适合。</p><h3 id="前后端分离项目"><a href="#前后端分离项目" class="headerlink" title="前后端分离项目"></a>前后端分离项目</h3><p>例如：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">frontend/</span><br><span class="line">backend/</span><br></pre></td></tr></table></figure><p>前端用 Next.js，后端用 FastAPI、Go 或其他框架。</p><p>以前这类项目在 Vercel 上不够自然，现在可以通过 Services 放在一个 Project 内。</p><h3 id="多个后台服务"><a href="#多个后台服务" class="headerlink" title="多个后台服务"></a>多个后台服务</h3><p>有些项目可能不只是一个 API：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">services/auth</span><br><span class="line">services/payment</span><br><span class="line">services/webhook</span><br><span class="line">services/image</span><br></pre></td></tr></table></figure><p>它们可以分别通过不同路径公开：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">/auth</span><br><span class="line">/payment</span><br><span class="line">/webhook</span><br><span class="line">/image</span><br></pre></td></tr></table></figure><p>也可以只让部分服务公开，其他服务保持内部访问。</p><h3 id="静态站点-后台接口"><a href="#静态站点-后台接口" class="headerlink" title="静态站点 + 后台接口"></a>静态站点 + 后台接口</h3><p>比如：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apps/site      -&gt; Astro / Vite / Hexo 构建后的静态站</span><br><span class="line">backend/api    -&gt; Python / Node.js API</span><br></pre></td></tr></table></figure><p>对于个人项目、工具站、轻量 SaaS、文档站 + API 的组合，这个功能会很有吸引力。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Vercel Services 的意义在于，它让 Vercel 从“一个项目部署一个框架”更进一步，变成 <strong>一个项目可以承载多个框架、多个服务</strong> 。</p><p>对于现代 Web 项目来说，这个变化非常实用。</p><p>过去我们经常需要在多个 Vercel Project、多个域名、多个 Preview URL 之间来回切换。现在，前端、后端、管理后台、文档站、工具页都可以作为一个项目里的多个服务统一部署。</p><p>它尤其适合：</p><ul><li>Monorepo</li><li>前后端分离项目</li><li>Python + JavaScript 混合项目</li><li>Go + Next.js 混合项目</li><li>多框架应用</li><li>个人工具站</li><li>小型 SaaS</li><li>静态站点 + API 的组合</li></ul><p>如果你一直想把一个复杂项目整理成更清晰的部署结构，Vercel Services 值得关注。</p><p>它不是 Docker Compose 的替代品，也不是所有项目都必须使用的新能力。但对于已经开始变复杂的前端项目、个人工具站和轻量全栈应用来说，它确实让 Vercel 的部署模型更完整了。</p><h2 id="参控"><a href="#参控" class="headerlink" title="参控"></a>参控</h2><ul><li><a href="https://vercel.com/docs/services">Vercel - Services</a></li><li><a href="https://vercel.com/changelog/run-multiple-frameworks-in-one-project-with-vercel-services">Run multiple frameworks in one project with Vercel Services</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;当你手头有一个包含 Next.js 前端、FastAPI 后端、Go 服务和 Astro 文档站的复杂项目时，是否也曾为如何在 Vercel 上部署和管理而感到头疼？&lt;/p&gt;
&lt;p&gt;过去，这类项目往往需要拆成多个 Vercel Project，或者把部分服务放到其他平台上运</summary>
      
    
    
    
    <category term="资讯" scheme="https://ooo.run/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="Vercel" scheme="https://ooo.run/tags/Vercel/"/>
    
    <category term="Cloud" scheme="https://ooo.run/tags/Cloud/"/>
    
    <category term="前端开发" scheme="https://ooo.run/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
  </entry>
  
  <entry>
    <title>后端回来了：Vercel 支持直接运行 Dockerfile</title>
    <link href="https://ooo.run/post/backends-are-back-vercel-support-dockerfile.html"/>
    <id>https://ooo.run/post/backends-are-back-vercel-support-dockerfile.html</id>
    <published>2026-06-30T15:51:53.000Z</published>
    <updated>2026-06-30T16:12:26.430Z</updated>
    
    <content type="html"><![CDATA[<p>你是否也想过用部署前端的丝滑体验来部署后端 Docker 服务？<strong>Vercel</strong> 近日正式支持直接运行 <strong>Dockerfile</strong>！本文我们将深入解析这一重磅更新、适用场景以及 Fluid Compute 底层机制。</p><span id="more"></span><p>北京时间 2026 年 7 月 1 日， <strong>Vercel</strong> 在官网宣布正式支持 <a href="https://vercel.com/blog/dockerfile-on-vercel">通过 Dockerfile 部署应用</a>，并在文章结尾喊出了 <mark>Backends are back</mark>。开发者现在可以在项目中添加 <code>Dockerfile.vercel</code>，让 <strong>Vercel</strong> 自动完成镜像构建、镜像存储和部署，并将应用运行在 <strong>Fluid Compute</strong> 之上。</p><p>这项更新意味着，<strong>Vercel</strong> 不再只是一个更适合 <strong>Next.js</strong>、前端应用和 <strong>Serverless Functions</strong> 的平台，而是进一步向自定义后端服务 and 通用 Web 应用运行平台扩展。</p><ul><li><a href="https://vercel.com/docs/functions/container-images">文档</a></li><li><a href="https://vercel.com/templates">示例</a></li></ul><details class="flatpaper-note flatpaper-note--warning"><summary class="flatpaper-note__title"><span class="flatpaper-note__icon" aria-hidden="true"></span><span class="flatpaper-note__label">注意事项</span><span class="flatpaper-note__chevron" aria-hidden="true"></span></summary><div class="flatpaper-note__body"><p>这并不等于 <strong>Vercel</strong> 可以运行任何 <strong>Docker</strong> 应用。更准确地说，<strong>Vercel</strong> 支持的是通过 <strong>Dockerfile</strong> 描述构建过程、并以 HTTP 服务形式运行的无状态应用。</p><p>应用需要监听平台注入的端口，并把数据库、文件、缓存等持久化状态交给外部服务处理。</p></div></details><p><img src="https://img.nep.me/ooo/cover-vercel-dockerfile.webp" alt="Vercel Support Dockerfile"></p><h2 id="什么是-Dockerfile？"><a href="#什么是-Dockerfile？" class="headerlink" title="什么是 Dockerfile？"></a>什么是 Dockerfile？</h2><p><strong>Dockerfile</strong> 是一个用来描述“如何构建 Docker 镜像”的文本文件。</p><p>它通常会写明应用基于什么系统或运行时镜像、需要安装哪些依赖、复制哪些代码、执行什么构建命令，以及容器启动时应该运行什么程序。简单来说，<strong>Dockerfile</strong> 不是应用本身，而是应用运行环境的说明书。</p><p>例如，一个 <strong>Node.js</strong> Web 服务的 <strong>Dockerfile</strong> 可能长这样：</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> node:<span class="number">22</span>-alpine</span><br><span class="line"></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> package.json pnpm-lock.yaml ./</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> corepack <span class="built_in">enable</span> &amp;&amp; pnpm install --frozen-lockfile</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> . .</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> pnpm build</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;pnpm&quot;</span>, <span class="string">&quot;start&quot;</span>]</span></span><br></pre></td></tr></table></figure><p>这个文件表达的意思是：使用 <strong>Node.js 22</strong> 作为基础环境，安装依赖，复制项目代码，执行构建，最后启动应用。</p><p>对于开发者来说，<strong>Dockerfile</strong> 最大的价值是“可复现”。只要 <strong>Dockerfile</strong> 写得清楚，无论是在本地、CI、云平台还是其他服务器上，都可以构建出相对一致的运行环境。</p><p>这也是 <strong>Vercel</strong> 支持 <strong>Dockerfile</strong> 的意义：当平台无法通过框架自动识别一个项目应该如何构建和运行时，开发者可以直接用 <strong>Dockerfile</strong> 明确告诉 <strong>Vercel</strong>。</p><h2 id="Dockerfile-和-docker-compose-yaml-有什么区别？"><a href="#Dockerfile-和-docker-compose-yaml-有什么区别？" class="headerlink" title="Dockerfile 和 docker-compose.yaml 有什么区别？"></a>Dockerfile 和 docker-compose.yaml 有什么区别？</h2><p>很多人会把 <strong>Dockerfile</strong> 和 <code>docker-compose.yaml</code> 混在一起，但它们其实解决的是两个不同层级的问题。</p><p><strong>Dockerfile</strong> 负责“构建一个镜像”，而 <code>docker-compose.yaml</code> 负责“编排多个容器”。</p><p>举个例子，一个 Web 应用可能需要：</p><ul><li>一个 <strong>Next.js</strong> 前端；</li><li>一个 <strong>Express</strong> API；</li><li>一个 <strong>PostgreSQL</strong> 数据库；</li><li>一个 <strong>Redis</strong> 缓存；</li><li>一个 <strong>MinIO</strong> 对象存储。</li></ul><p>其中，<strong>Express</strong> API 自己可以有一个 <strong>Dockerfile</strong>，用来描述 API 镜像怎么构建。而 <code>docker-compose.yaml</code> 则负责把 API、数据库、Redis、MinIO 这些服务一起启动，并配置端口、环境变量、数据卷和服务之间的网络关系。</p><p>简单对比如下：</p><table><thead><tr><th>项目</th><th>Dockerfile</th><th>docker-compose.yaml</th></tr></thead><tbody><tr><td>主要作用</td><td>构建单个镜像</td><td>启动和编排多个容器</td></tr><tr><td>关注重点</td><td>应用如何打包、安装依赖、启动</td><td>多个服务如何协作</td></tr><tr><td>常见内容</td><td>FROM、RUN、COPY、CMD</td><td>services、ports、volumes、networks</td></tr><tr><td>适合场景</td><td>定义一个应用的运行环境</td><td>本地开发、多容器部署、服务编排</td></tr><tr><td>是否包含数据库编排</td><td>通常不包含</td><td>可以包含 PostgreSQL、Redis 等</td></tr><tr><td>Vercel 此次支持重点</td><td>是</td><td>不是传统 Compose 部署</td></tr></tbody></table><details class="flatpaper-note flatpaper-note--info"><summary class="flatpaper-note__title"><span class="flatpaper-note__icon" aria-hidden="true"></span><span class="flatpaper-note__label">核心差异</span><span class="flatpaper-note__chevron" aria-hidden="true"></span></summary><div class="flatpaper-note__body"><p><strong>Vercel</strong> 这次支持的是 <strong>Dockerfile</strong>，而不是把 <strong>Vercel</strong> 变成一台可以直接运行完整 <code>docker compose up -d</code> 的 <strong>VPS</strong>。</p><p>你可以把一个 HTTP 服务通过 <strong>Dockerfile</strong> 部署到 <strong>Vercel</strong>，但不能直接把一整套包含数据库、Redis、后台 worker、对象存储、管理面板的 Compose 栈原样搬到 <strong>Vercel</strong> 上运行。</p></div></details><h2 id="Vercel-支持的是什么类型的-Docker-应用？"><a href="#Vercel-支持的是什么类型的-Docker-应用？" class="headerlink" title="Vercel 支持的是什么类型的 Docker 应用？"></a>Vercel 支持的是什么类型的 Docker 应用？</h2><p><strong>Vercel</strong> 官方文档中，后端框架如 <strong>Express</strong>、<strong>Fastify</strong> 等会作为 Vercel Function 运行，并默认使用 <strong>Fluid Compute</strong>；<strong>Fluid Compute</strong> 可以让应用根据流量自动伸缩，并支持更高效的并发处理。</p><p>从使用模型看，适合部署到 <strong>Vercel</strong> 的 <strong>Dockerfile</strong> 应用通常具备几个特征：</p><ul><li>是 Web 服务或 API 服务；</li><li>通过 HTTP 对外提供能力；</li><li>能监听平台提供的端口；</li><li>本身无状态；</li><li>数据库存储、文件上传、缓存、队列等依赖外部托管服务。</li></ul><p>下面我们通过 Tab 栏来看看适合与不适合部署到 <strong>Vercel</strong> 的应用类型对比：</p><div class="flatpaper-tabs"><div class="flatpaper-tabs__nav" role="tablist"><button type="button" role="tab" id="tabs-17-tab-0" aria-controls="tabs-17-panel-0" aria-selected="true" class="flatpaper-tabs__nav-item is-active" data-index="0">适合部署的类型</button><button type="button" role="tab" id="tabs-17-tab-1" aria-controls="tabs-17-panel-1" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="1">不适合部署的类型</button></div><div class="flatpaper-tabs__panels"><section role="tabpanel" id="tabs-17-panel-0" aria-labelledby="tabs-17-tab-0" class="flatpaper-tabs__panel is-active" data-index="0"><table><thead><tr><th>应用类型</th><th>示例</th></tr></thead><tbody><tr><td>Web 后端 API</td><td>Express、Hono、Fastify、FastAPI、Go HTTP Server</td></tr><tr><td>全栈 Web 应用</td><td>Next.js、Nuxt、SvelteKit、TanStack Start</td></tr><tr><td>内容网站</td><td>博客、文档站、企业官网、CMS 前台</td></tr><tr><td>Bot &#x2F; Webhook 服务</td><td>Slack Bot、GitHub Webhook、MCP Server</td></tr><tr><td>AI 工具后端</td><td>Chatbot API、Agent 控制层、图片处理入口</td></tr><tr><td>轻量内部工具</td><td>Dashboard、Admin Panel、数据查询面板</td></tr></tbody></table></section><section role="tabpanel" id="tabs-17-panel-1" aria-labelledby="tabs-17-tab-1" class="flatpaper-tabs__panel" data-index="1" hidden><table><thead><tr><th>应用类型</th><th>原因</th></tr></thead><tbody><tr><td>PostgreSQL、MySQL、Redis</td><td>需要长期持久化状态和磁盘</td></tr><tr><td>1Panel、宝塔、CasaOS</td><td>依赖完整服务器环境和系统级能力</td></tr><tr><td>Docker Compose 多容器栈</td><td>Vercel 不是传统容器编排平台</td></tr><tr><td>BT 下载器、网盘服务</td><td>通常需要长时间运行和本地持久化</td></tr><tr><td>游戏服务器、VPN、代理服务</td><td>不属于普通 HTTP Web 应用模型</td></tr><tr><td>强依赖本地磁盘的应用</td><td>容器实例应视为无状态</td></tr></tbody></table></section></div></div><p>换句话说，<strong>Vercel</strong> 支持 <strong>Dockerfile</strong> 后，部署范围确实扩大了，但它依然不是 <strong>VPS</strong>，也不是 <strong>Kubernetes</strong> 的替代品。</p><h2 id="从-Vercel-Templates-看适合的应用场景"><a href="#从-Vercel-Templates-看适合的应用场景" class="headerlink" title="从 Vercel Templates 看适合的应用场景"></a>从 Vercel Templates 看适合的应用场景</h2><p>从 <a href="https://vercel.com/templates">Vercel Templates</a> 页面也可以看出，<strong>Vercel</strong> 目前重点覆盖的仍然是 Web 应用、后端 API、AI 应用和全栈项目，而不是传统意义上的服务器软件。<strong>Vercel</strong> 的 Backend Templates 中已经包含 <strong>Hono</strong>、<strong>Express</strong>、<strong>Elysia</strong>、<strong>MCP Server</strong>、<strong>Slack Bolt</strong> 等模板，这些都属于轻量 HTTP 服务、Bot 后端、Webhook 服务或 AI 工具后端。</p><p>Starter Templates 中也可以看到 <strong>Next.js</strong>、<strong>Nuxt</strong>、<strong>SvelteKit</strong>、<strong>Rust Hello World</strong>、<strong>Rust Axum</strong>、<strong>TanStack Start</strong>、<strong>Slack Bolt with Hono</strong> 等模板。这说明 <strong>Vercel</strong> 希望覆盖的不只是前端页面，也包括通过 HTTP 暴露能力的后端程序。</p><p><strong>Payload Website Starter</strong> 是另一个很典型的例子。这个模板包含后台管理、认证、内容发布、草稿预览、SEO、搜索、重定向、定时发布等功能，但它会配合 <strong>Neon Database</strong> 和 <strong>Vercel Blob Storage</strong> 等外部服务处理数据库和文件存储。</p><p>这其实体现了 <strong>Vercel</strong> 的推荐架构：计算放在 <strong>Vercel</strong>，状态放在外部托管服务。</p><h2 id="为什么这次更新重要？"><a href="#为什么这次更新重要？" class="headerlink" title="为什么这次更新重要？"></a>为什么这次更新重要？</h2><p>过去，<strong>Vercel</strong> 的最佳体验主要集中在 <strong>Next.js</strong> 和前端生态。虽然 <strong>Vercel</strong> 也支持多种 <strong>Serverless Functions</strong> 和后端框架，但如果项目需要特殊系统依赖、自定义启动命令、非标准框架、<strong>FFmpeg</strong>、<strong>Chromium</strong>、<strong>nginx</strong> 或其他复杂运行环境，就可能需要额外改造。</p><p><strong>Dockerfile</strong> 支持补上了这块短板。</p><p>开发者不再必须完全适配 <strong>Vercel</strong> 的框架检测逻辑，而是可以用 <strong>Dockerfile</strong> 描述自己的应用如何构建、如何启动。对于传统后端项目、跨语言服务、AI 工具后端 and 自定义 Web Server 来说，这会明显降低迁移成本。</p><p>同时，部署到 <strong>Vercel</strong> 后，应用仍然可以获得 <strong>Vercel</strong> 原有的工程体验，例如 <strong>Git</strong> 集成、<strong>Preview Deployment</strong>、自动伸缩、日志、指标、回滚和平台级安全能力。<strong>Vercel</strong> 的 Functions 文档也强调，平台会根据框架自动设置构建和优化，并通过 CDN 与函数运行环境提供低运维体验。</p><h2 id="Fluid-Compute：介于-Serverless-和服务器之间"><a href="#Fluid-Compute：介于-Serverless-和服务器之间" class="headerlink" title="Fluid Compute：介于 Serverless 和服务器之间"></a>Fluid Compute：介于 Serverless 和服务器之间</h2><p><strong>Vercel</strong> 这次 <strong>Dockerfile</strong> 支持的底层重点之一，是 <strong>Fluid Compute</strong>。</p><p>根据 <strong>Vercel</strong> 文档，<strong>Fluid Compute</strong> 是一种介于传统 <strong>Serverless</strong> 和服务器之间的计算模型。它保留了 <strong>Serverless</strong> 的自动伸缩和低运维优势，同时加入了类似服务器的能力，例如同一个实例可以并发处理多个请求。</p><p>对于 AI 应用、API 服务和 I&#x2F;O 密集型任务来说，这一点很重要。很多请求的大部分时间并不是 CPU 真正在计算，而是在等待数据库、向量数据库、外部 API 或模型服务返回结果。<strong>Fluid Compute</strong> 的并发模型可以让同一个实例更有效地处理这些等待时间。</p><p><strong>Vercel</strong> 的 <strong>Fluid Compute</strong> 文档也提到，它支持 <strong>Node.js</strong>、<strong>Python</strong>、<strong>Edge</strong>、<strong>Bun</strong>、<strong>Rust</strong> 等运行时，并且适合需要优化并发和减少冷启动影响的场景。</p><h2 id="计费方式：按实际资源使用付费"><a href="#计费方式：按实际资源使用付费" class="headerlink" title="计费方式：按实际资源使用付费"></a>计费方式：按实际资源使用付费</h2><p><strong>Vercel</strong> 在 <strong>Fluid Compute</strong> 的计费文档中使用 CPU 与内存维度计算资源消耗。例如，一个请求如果实例存活 10 秒，但实际活跃 CPU 时间只有 4 秒，费用会拆分为 CPU 使用和内存占用两部分计算。</p><p>这说明 <strong>Vercel</strong> 并不是按照传统 VPS 那样“买一台机器一直开着”来计费，而是更接近按请求、按资源消耗计费的云函数模型。</p><details class="flatpaper-note flatpaper-note--info"><summary class="flatpaper-note__title"><span class="flatpaper-note__icon" aria-hidden="true"></span><span class="flatpaper-note__label">成本考量</span><span class="flatpaper-note__chevron" aria-hidden="true"></span></summary><div class="flatpaper-note__body"><p>对于低频访问、突发流量、I&#x2F;O 等待较多的 Web 服务来说，这种模式可能更划算。但对于需要 24 小时高负载运行、持续占用 CPU 或内存的服务，传统 VPS、专用服务器或 Kubernetes 仍然可能更合适。</p></div></details><h2 id="这不是-VPS，但让-Vercel-更像完整应用平台"><a href="#这不是-VPS，但让-Vercel-更像完整应用平台" class="headerlink" title="这不是 VPS，但让 Vercel 更像完整应用平台"></a>这不是 VPS，但让 Vercel 更像完整应用平台</h2><p><strong>Vercel</strong> 支持 <strong>Dockerfile</strong> 后，最容易产生的误解是：“是不是以后所有 Docker 应用都能放到 Vercel？”</p><p>答案是否定的。</p><p>它不能取代 <strong>VPS</strong>，也不能取代 <strong>Docker Compose</strong> 或 <strong>Kubernetes</strong>。它更适合部署单个 Web 服务、API 服务、全栈应用或 AI 工具后端，而不是运行一整套长期常驻、强依赖本地磁盘和系统权限的服务器环境。</p><p>但这次更新依然非常重要。因为它把 <strong>Vercel</strong> 的边界从“框架友好的前端和全栈应用”继续推向“更通用的 HTTP 后端服务”。</p><p>对于开发者来说，理想场景可能是：</p><ul><li>前端页面部署在 <strong>Vercel</strong>；</li><li>后端 API 通过 <strong>Dockerfile</strong> 部署到 <strong>Vercel</strong>；</li><li><strong>PostgreSQL</strong> 使用 <strong>Neon</strong>、<strong>Supabase</strong> 或其他托管数据库；</li><li>文件存储使用 <strong>Vercel Blob</strong>、<strong>S3</strong> 或 <strong>R2</strong>；</li><li>缓存和队列使用外部托管 <strong>Redis</strong> 或消息队列；</li><li>每次 Git push 自动生成 Preview 环境。</li></ul><p>这是一种更现代的云应用部署方式：不再维护服务器本身，而是把应用拆成计算、数据库、对象存储、缓存和队列等托管组件。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p><strong>Vercel</strong> 支持 <strong>Dockerfile</strong>，并不是简单地“支持 Docker”这么一句话就能概括。</p><p>它真正改变的是：开发者可以用更标准、更通用的方式，把自定义 HTTP 服务部署到 <strong>Vercel</strong>。对于那些无法被框架自动识别、但本质上仍然是 Web 服务的项目，<strong>Dockerfile</strong> 提供了一条更直接的上云路径。</p><p>不过，<strong>Dockerfile on Vercel</strong> 不是 <strong>Docker Compose on Vercel</strong>，也不是 <strong>VPS on Vercel</strong>。</p><p>它适合的是无状态 HTTP 应用，而不是完整服务器环境。</p><p>如果说过去 <strong>Vercel</strong> 最擅长的是前端部署体验，那么这次 <strong>Dockerfile</strong> 支持，则让更多后端服务也能享受到类似的开发体验：一次提交、自动构建、自动预览、自动伸缩，并在同一个平台上完成发布。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;你是否也想过用部署前端的丝滑体验来部署后端 Docker 服务？&lt;strong&gt;Vercel&lt;/strong&gt; 近日正式支持直接运行 &lt;strong&gt;Dockerfile&lt;/strong&gt;！本文我们将深入解析这一重磅更新、适用场景以及 Fluid Compute 底层机制。&lt;/p&gt;</summary>
    
    
    
    <category term="资讯" scheme="https://ooo.run/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="Vercel" scheme="https://ooo.run/tags/Vercel/"/>
    
    <category term="Dockerfile" scheme="https://ooo.run/tags/Dockerfile/"/>
    
    <category term="Serverless" scheme="https://ooo.run/tags/Serverless/"/>
    
    <category term="Cloud" scheme="https://ooo.run/tags/Cloud/"/>
    
  </entry>
  
  <entry>
    <title>2026 Debian 13 安装 Docker 以及 Docker Compose 教程</title>
    <link href="https://ooo.run/post/debian-13-install-docker.html"/>
    <id>https://ooo.run/post/debian-13-install-docker.html</id>
    <published>2026-06-29T20:15:00.000Z</published>
    <updated>2026-06-29T20:27:15.611Z</updated>
    
    <content type="html"><![CDATA[<p>现在越来越多的应用可以使用 <strong>Docker</strong> 一键部署，本文将介绍如何在最新的 Debian 13 (Trixie) 中安装 <strong>Docker</strong> 与 <strong>Docker Compose</strong>。</p><p>验证环境</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">root@debian:~# lsb_release -a</span><br><span class="line">No LSB modules are available.</span><br><span class="line">Distributor ID:Debian</span><br><span class="line">Description:Debian GNU/Linux 13 (trixie)</span><br><span class="line">Release:13</span><br><span class="line">Codename:trixie</span><br></pre></td></tr></table></figure><p>安装同样适用于 Ubuntu 26.04。</p><h2 id="Docker-介绍"><a href="#Docker-介绍" class="headerlink" title="Docker 介绍"></a>Docker 介绍</h2><p><strong>Docker</strong> 是一个开源的容器化平台，它可以将应用程序及其依赖打包到一个轻量级、可移植的容器中，使其能够在任何环境中一致地运行。</p><ul><li><strong>轻量</strong>：容器共享宿主机的操作系统内核，启动速度快，占用资源少。</li><li><strong>可移植</strong>：容器可以在开发、测试和生产环境中一致运行，解决“环境不一致”的问题。</li><li><strong>隔离性</strong>：每个容器都是独立运行的，互不影响。</li><li><strong>快速部署</strong>：通过镜像技术，实现应用的快速打包、发布和部署。</li></ul><h2 id="Docker-Compose-介绍"><a href="#Docker-Compose-介绍" class="headerlink" title="Docker Compose 介绍"></a>Docker Compose 介绍</h2><p><strong>Docker Compose</strong> 是 <strong>Docker</strong> 提供的用于定义和管理多容器应用的工具。通过一个简单的 YAML 文件 <code>docker-compose.yml</code>，你可以定义和启动多个服务容器，使得应用的部署和管理更加便捷，可以不必使用长串的 <code>docker run</code> 命令。 </p><p>特点：</p><ul><li><strong>多容器管理</strong>：同时启动、停止和管理多个容器。</li><li><strong>通过 YAML 配置</strong>：通过 <code>docker-compose.yml</code> 定义服务、网络、存储等。</li><li><strong>简化命令</strong>：使用单一命令 <code>docker compose</code> 管理容器。</li></ul><p>本文将介绍安装 V2 版本，对应的命令是 <code>docker compose</code>。</p><h2 id="使用官方源安装"><a href="#使用官方源安装" class="headerlink" title="使用官方源安装"></a>使用官方源安装</h2><p>以下操作需要在 root 用户下完成，请使用 <code>sudo -i</code> 或 <code>su root</code> 切换到 root 用户进行操作。</p><p>首先，安装一些必要的软件包： </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">apt update</span><br><span class="line">apt upgrade -y</span><br><span class="line">apt install curl vim wget gnupg dpkg apt-transport-https lsb-release ca-certificates</span><br></pre></td></tr></table></figure><p>然后加入 <strong>Docker</strong> 的 GPG 公钥和 apt 源：</p><div class="flatpaper-tabs"><div class="flatpaper-tabs__nav" role="tablist"><button type="button" role="tab" id="tabs-18-tab-0" aria-controls="tabs-18-panel-0" aria-selected="true" class="flatpaper-tabs__nav-item is-active" data-index="0">Debian</button><button type="button" role="tab" id="tabs-18-tab-1" aria-controls="tabs-18-panel-1" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="1">Ubuntu</button></div><div class="flatpaper-tabs__panels"><section role="tabpanel" id="tabs-18-panel-0" aria-labelledby="tabs-18-tab-0" class="flatpaper-tabs__panel is-active" data-index="0"><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -sSL https://download.docker.com/linux/debian/gpg | gpg --dearmor &gt; /usr/share/keyrings/docker-ce.gpg</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb [arch=<span class="subst">$(dpkg --print-architecture)</span> signed-by=/usr/share/keyrings/docker-ce.gpg] https://download.docker.com/linux/debian <span class="subst">$(lsb_release -sc)</span> stable&quot;</span> &gt; /etc/apt/sources.list.d/docker.list</span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-18-panel-1" aria-labelledby="tabs-18-tab-1" class="flatpaper-tabs__panel" data-index="1" hidden><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -sSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor &gt; /usr/share/keyrings/docker-ce.gpg</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb [arch=<span class="subst">$(dpkg --print-architecture)</span> signed-by=/usr/share/keyrings/docker-ce.gpg] https://download.docker.com/linux/ubuntu <span class="subst">$(lsb_release -sc)</span> stable&quot;</span> &gt; /etc/apt/sources.list.d/docker.list</span><br></pre></td></tr></table></figure></section></div></div><p>国内机器可以用 <a href="https://mirrors.tuna.tsinghua.edu.cn/">清华 TUNA</a> 的国内源：</p><div class="flatpaper-tabs"><div class="flatpaper-tabs__nav" role="tablist"><button type="button" role="tab" id="tabs-19-tab-0" aria-controls="tabs-19-panel-0" aria-selected="true" class="flatpaper-tabs__nav-item is-active" data-index="0">Debian</button><button type="button" role="tab" id="tabs-19-tab-1" aria-controls="tabs-19-panel-1" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="1">Ubuntu</button></div><div class="flatpaper-tabs__panels"><section role="tabpanel" id="tabs-19-panel-0" aria-labelledby="tabs-19-tab-0" class="flatpaper-tabs__panel is-active" data-index="0"><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -sS https://download.docker.com/linux/debian/gpg | gpg --dearmor &gt; /usr/share/keyrings/docker-ce.gpg</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb [arch=<span class="subst">$(dpkg --print-architecture)</span> signed-by=/usr/share/keyrings/docker-ce.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian <span class="subst">$(lsb_release -sc)</span> stable&quot;</span> &gt; /etc/apt/sources.list.d/docker.list</span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-19-panel-1" aria-labelledby="tabs-19-tab-1" class="flatpaper-tabs__panel" data-index="1" hidden><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -sS https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor &gt; /usr/share/keyrings/docker-ce.gpg</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb [arch=<span class="subst">$(dpkg --print-architecture)</span> signed-by=/usr/share/keyrings/docker-ce.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu <span class="subst">$(lsb_release -sc)</span> stable&quot;</span> &gt; /etc/apt/sources.list.d/docker.list</span><br></pre></td></tr></table></figure></section></div></div><p>然后更新系统后即可安装 Docker CE 和 Docker Compose 插件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apt update</span><br><span class="line">apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin</span><br></pre></td></tr></table></figure><p>此时可以使用 <code>docker version</code> 命令检查是否安装成功：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">Client: Docker Engine - Community</span><br><span class="line"> Version:           29.6.1</span><br><span class="line"> API version:       1.55</span><br><span class="line"> Go version:        go1.26.4</span><br><span class="line"> Git commit:        8900f1d</span><br><span class="line"> Built:             Fri Jun 26 11:40:34 2026</span><br><span class="line"> OS/Arch:           linux/amd64</span><br><span class="line"> Context:           default</span><br><span class="line"></span><br><span class="line">Server: Docker Engine - Community</span><br><span class="line"> Engine:</span><br><span class="line">  Version:          29.6.1</span><br><span class="line">  API version:      1.55 (minimum version 1.40)</span><br><span class="line">  Go version:       go1.26.4</span><br><span class="line">  Git commit:       8ec5ab3</span><br><span class="line">  Built:            Fri Jun 26 11:40:34 2026</span><br><span class="line">  OS/Arch:          linux/amd64</span><br><span class="line">  Experimental:     <span class="literal">false</span></span><br><span class="line"> containerd:</span><br><span class="line">  Version:          v2.2.5</span><br><span class="line">  GitCommit:        e53c7c1516c3b2bff98eb76f1f4117477e6f4e66</span><br><span class="line"> runc:</span><br><span class="line">  Version:          1.3.6</span><br><span class="line">  GitCommit:        v1.3.6-0-g491b69ba</span><br><span class="line"> docker-init:</span><br><span class="line">  Version:          0.19.0</span><br><span class="line">  GitCommit:        de40ad0</span><br></pre></td></tr></table></figure><p>如果需要以非 root 模式运行 <strong>Docker</strong>，那么可以把特定用户也加入 docker 组，比如我们把 <code>www-data</code> 用户加进去：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apt install docker-ce-rootless-extras</span><br><span class="line"><span class="built_in">sudo</span> usermod -aG docker www-data</span><br></pre></td></tr></table></figure><h2 id="Docker-Compose-V2"><a href="#Docker-Compose-V2" class="headerlink" title="Docker Compose V2"></a>Docker Compose V2</h2><p><strong>Docker</strong> 已自带 Docker Compose V2 版本，即 <code>docker compose</code> 命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@debian:~# docker compose version </span><br><span class="line">Docker Compose version v5.2.0</span><br></pre></td></tr></table></figure><h2 id="修改-Docker-配置"><a href="#修改-Docker-配置" class="headerlink" title="修改 Docker 配置"></a>修改 Docker 配置</h2><p>以下配置会增加一段自定义内网 IPv6 地址，开启容器的 IPv6 功能，以及限制日志文件大小，防止 <strong>Docker</strong> 日志塞满硬盘：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt; /etc/docker/daemon.json &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string">&#123;</span></span><br><span class="line"><span class="string">    &quot;log-driver&quot;: &quot;json-file&quot;,</span></span><br><span class="line"><span class="string">    &quot;log-opts&quot;: &#123;</span></span><br><span class="line"><span class="string">        &quot;max-size&quot;: &quot;20m&quot;,</span></span><br><span class="line"><span class="string">        &quot;max-file&quot;: &quot;3&quot;</span></span><br><span class="line"><span class="string">    &#125;,</span></span><br><span class="line"><span class="string">    &quot;ipv6&quot;: true,</span></span><br><span class="line"><span class="string">    &quot;fixed-cidr-v6&quot;: &quot;fd00:dead:beef:c0::/80&quot;,</span></span><br><span class="line"><span class="string">    &quot;experimental&quot;:true,</span></span><br><span class="line"><span class="string">    &quot;ip6tables&quot;:true</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure><p>然后重启 <strong>Docker</strong> 服务：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl restart docker</span><br></pre></td></tr></table></figure><h2 id="Docker-常用命令使用介绍"><a href="#Docker-常用命令使用介绍" class="headerlink" title="Docker 常用命令使用介绍"></a>Docker 常用命令使用介绍</h2><p>快速了解一下 <code>docker</code> 常见命令，使用 <code>docker compose</code> 进行管理会更方便。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 拉取镜像</span></span><br><span class="line">docker pull &lt;镜像名&gt;:&lt;标签&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看当前正在运行的容器</span></span><br><span class="line">docker ps</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看所有容器（包括已停止的）</span></span><br><span class="line">docker ps -a</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看本地镜像</span></span><br><span class="line">docker images</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除镜像</span></span><br><span class="line">docker rmi &lt;镜像ID或名称&gt;</span><br><span class="line">docker rmi ubuntu:latest</span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行容器 </span></span><br><span class="line">docker run -d -p &lt;宿主端口&gt;:&lt;容器端口&gt; --name &lt;容器名&gt; &lt;镜像名&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动，停止，重启，删除</span></span><br><span class="line">docker start / stop / restart / <span class="built_in">rm</span> &lt;容器名或ID&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 进入容器执行交互式命令</span></span><br><span class="line">docker <span class="built_in">exec</span> -it &lt;容器名或ID&gt; /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看容器日志</span></span><br><span class="line">docker logs &lt;容器名或ID&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查询 Docker 使用的磁盘空间：</span></span><br><span class="line">docker system <span class="built_in">df</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除所有未被使用的镜像</span></span><br><span class="line">docker image prune -a</span><br></pre></td></tr></table></figure><h2 id="Docker-Compose-使用介绍"><a href="#Docker-Compose-使用介绍" class="headerlink" title="Docker Compose 使用介绍"></a>Docker Compose 使用介绍</h2><p><code>docker compose</code> 需要在 <code>docker-compose.yml</code> 文件所在的工作目录执行，这里推荐创建一个工作目录，在其中统一存放配置文件，比如： </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">docker/</span><br><span class="line">├── nginx/                         </span><br><span class="line">│   └── docker-compose.yml            </span><br><span class="line">├── mysql/                          </span><br><span class="line">│   └── docker-compose.yml          </span><br><span class="line">└── redis/                           </span><br><span class="line">    └── docker-compose.yml   </span><br></pre></td></tr></table></figure><p><code>docker compose</code> 常用命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 拉取，更新镜像</span></span><br><span class="line">docker compose pull</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动容器</span></span><br><span class="line">docker compose up</span><br><span class="line"></span><br><span class="line"><span class="comment"># 后台启动</span></span><br><span class="line">docker compose up -d</span><br><span class="line"></span><br><span class="line"><span class="comment"># 停止容器</span></span><br><span class="line">docker compose stop</span><br><span class="line"></span><br><span class="line"><span class="comment"># 停止容器，并移除创建的网络、卷和镜像</span></span><br><span class="line">docker compose down</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启容器</span></span><br><span class="line">docker compose restart</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看正在运行的服务</span></span><br><span class="line">docker compose ps</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看日志</span></span><br><span class="line">docker compose logs</span><br><span class="line"><span class="comment"># 查看实时日志</span></span><br><span class="line">docker compose logs -f</span><br><span class="line"></span><br><span class="line"><span class="comment"># 进入容器。执行交互命令</span></span><br><span class="line">docker compose <span class="built_in">exec</span> &lt;服务名&gt; &lt;命令&gt;</span><br><span class="line">docker compose <span class="built_in">exec</span> nginx /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看服务统计信息，实时显示 CPU、内存等资源使用情况。</span></span><br><span class="line">docker compose stats</span><br></pre></td></tr></table></figure><p><code>docker compose</code> 还是太长？ 执行下面的命令后就可以使用 <code>dc</code> 作为替代：</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>执行前，先运行一下 <code>dc</code> 确认命令当前没有在使用，执行后运行 <code>dc version</code> 确认。</p></div></div><div class="flatpaper-tabs"><div class="flatpaper-tabs__nav" role="tablist"><button type="button" role="tab" id="tabs-20-tab-0" aria-controls="tabs-20-panel-0" aria-selected="true" class="flatpaper-tabs__nav-item is-active" data-index="0">bash</button><button type="button" role="tab" id="tabs-20-tab-1" aria-controls="tabs-20-panel-1" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="1">zsh</button></div><div class="flatpaper-tabs__panels"><section role="tabpanel" id="tabs-20-panel-0" aria-labelledby="tabs-20-tab-0" class="flatpaper-tabs__panel is-active" data-index="0"><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;alias dc=&quot;docker compose&quot;&#x27;</span> &gt;&gt; ~/.bashrc </span><br><span class="line"><span class="built_in">source</span> ~/.bashrc </span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-20-panel-1" aria-labelledby="tabs-20-tab-1" class="flatpaper-tabs__panel" data-index="1" hidden><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;alias dc=&quot;docker compose&quot;&#x27;</span> &gt;&gt; ~/.zshrc </span><br><span class="line"><span class="built_in">source</span> ~/.zshrc </span><br></pre></td></tr></table></figure></section></div></div><p>效果:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">root@debian:~# dc</span><br><span class="line">-bash: dc: <span class="built_in">command</span> not found</span><br><span class="line"></span><br><span class="line">root@debian:~# dc version</span><br><span class="line">Docker Compose version v5.2.0</span><br></pre></td></tr></table></figure><p>之后，当我们创建了 <code>docker-compose.yml</code> 文件后，启动或是更新服务只需要执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dc pull</span><br><span class="line">dc up -d </span><br></pre></td></tr></table></figure><p>现在前往 GitHub 或是 <a href="https://hub.docker.com/">Docker Hub</a> 寻找有趣的项目吧！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;现在越来越多的应用可以使用 &lt;strong&gt;Docker&lt;/strong&gt; 一键部署，本文将介绍如何在最新的 Debian 13 (Trixie) 中安装 &lt;strong&gt;Docker&lt;/strong&gt; 与 &lt;strong&gt;Docker Compose&lt;/strong&gt;。&lt;</summary>
      
    
    
    
    <category term="教程" scheme="https://ooo.run/categories/%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="Docker" scheme="https://ooo.run/tags/Docker/"/>
    
    <category term="Docker Compose" scheme="https://ooo.run/tags/Docker-Compose/"/>
    
    <category term="Debian" scheme="https://ooo.run/tags/Debian/"/>
    
    <category term="Linux" scheme="https://ooo.run/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>Open Lovable：一键『克隆』任意网站为 React 应用的神器</title>
    <link href="https://ooo.run/post/open-lovable-clone-website-to-react.html"/>
    <id>https://ooo.run/post/open-lovable-clone-website-to-react.html</id>
    <published>2026-06-29T20:15:00.000Z</published>
    <updated>2026-06-29T20:34:08.867Z</updated>
    
    <content type="html"><![CDATA[<p>最近在逛 GitHub 的时候，刷到了一个极其亮眼的项目——由 <strong>Firecrawl</strong>（前 MendableAI）团队开源的 <strong>Open Lovable</strong>。目前该项目在 GitHub 上已经狂飙到了 <strong>24k+ Star</strong>，可谓是前端开发者和原型设计师的效率杀手锏。</p><p>简单来说，<strong>Open Lovable</strong> 的用法几乎是“零门槛”：你只需要把你想“复刻”的网站链接丢进去，它就能在几秒内为你生成一个高度还原的 <strong>React</strong> 版本代码。不管是页面布局、样式还是交互细节，它都会尽可能贴近原站，让你在拿来进行二次开发时倍感顺手。</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p><strong>项目地址</strong>：<a href="http://github.com/mendableai/open-lovable">http://github.com/mendableai/open-lovable</a><br><strong>开源协议</strong>：MIT</p></div></div><h2 id="核心亮点速览"><a href="#核心亮点速览" class="headerlink" title="核心亮点速览"></a>核心亮点速览</h2><p><strong>Open Lovable</strong> 之所以能迅速爆火，离不开它扎实且直击痛点的功能设计：</p><h3 id="1-一键“克隆”，所见即所得"><a href="#1-一键“克隆”，所见即所得" class="headerlink" title="1. 一键“克隆”，所见即所得"></a>1. 一键“克隆”，所见即所得</h3><p>它可以一键把任意网站“克隆”为现代化的 <strong>React</strong> 应用。无论是简单的落地页还是结构复杂的页面，它都能顶住压力，快速生成对应的组件代码。并且支持本地调试与部署，生成的同时即可提供预览，做到真正的“所见即所得”。</p><h3 id="2-底层抓取更稳：基于-Firecrawl"><a href="#2-底层抓取更稳：基于-Firecrawl" class="headerlink" title="2. 底层抓取更稳：基于 Firecrawl"></a>2. 底层抓取更稳：基于 Firecrawl</h3><p>市面上有不少类似的代码生成工具，但它们往往会在读取复杂网页结构时“翻车”。<strong>Open Lovable</strong> 背靠自家强大的 <strong>Firecrawl</strong> 网页抓取技术，能够精准提取原站的页面结构、DOM 树和清洗后的内容，这使得最终交由大模型生成的代码还原度更高、视觉表现更一致。</p><h3 id="3-多模型随意切，不折腾"><a href="#3-多模型随意切，不折腾" class="headerlink" title="3. 多模型随意切，不折腾"></a>3. 多模型随意切，不折腾</h3><p>不想被单一的大模型绑定？没问题。项目内置了对多种主流 LLM 的支持，你可以根据自己的 API 额度或者偏好，无缝接入 <strong>OpenAI</strong>、<strong>Anthropic</strong>、<strong>Gemini</strong>、<strong>Grok</strong> 等多种模型，按需切换，丰俭由人。</p><h3 id="4-集成-E2B-沙盒，运行更安全"><a href="#4-集成-E2B-沙盒，运行更安全" class="headerlink" title="4. 集成 E2B 沙盒，运行更安全"></a>4. 集成 E2B 沙盒，运行更安全</h3><p>生成的代码直接跑怕有风险？环境配置太麻烦？<strong>Open Lovable</strong> 贴心地集成了 <strong>E2B</strong> 沙盒环境。代码的运行与测试都可以在隔离的沙盒中完成，不仅安全防泄漏，也让整个测试流程更加省心。</p><h2 id="上手体验"><a href="#上手体验" class="headerlink" title="上手体验"></a>上手体验</h2><p>由于采用了完全自由的 <strong>MIT 协议</strong>，这款工具完全开源且免费。你只需要：</p><ol><li>将项目拉取到本地。</li><li>配置好相关的 API key（如你想使用的大模型 API 以及 Firecrawl 等对应的 Key）。</li><li>直接开跑！</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/mendableai/open-lovable.git</span><br><span class="line"><span class="built_in">cd</span> open-lovable</span><br><span class="line">npm install</span><br><span class="line"><span class="comment"># 配置 .env 文件填入相应的 API Key</span></span><br><span class="line">npm run dev</span><br></pre></td></tr></table></figure><p>如果你经常需要参考其他网站的优秀设计，或者需要快速构建高保真产品原型，<strong>Open Lovable</strong> 绝对值得你把它加入到生产力工具箱中！赶快拉取代码亲自体验一下吧！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;最近在逛 GitHub 的时候，刷到了一个极其亮眼的项目——由 &lt;strong&gt;Firecrawl&lt;/strong&gt;（前 MendableAI）团队开源的 &lt;strong&gt;Open Lovable&lt;/strong&gt;。目前该项目在 GitHub 上已经狂飙到了 &lt;strong</summary>
      
    
    
    
    <category term="工具资源" scheme="https://ooo.run/categories/%E5%B7%A5%E5%85%B7%E8%B5%84%E6%BA%90/"/>
    
    
    <category term="AI" scheme="https://ooo.run/tags/AI/"/>
    
    <category term="开源项目" scheme="https://ooo.run/tags/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/"/>
    
    <category term="前端开发" scheme="https://ooo.run/tags/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
    
  </entry>
  
  <entry>
    <title>Git 初学者教程：用『存档点』和『多元世界线』理解版本控制</title>
    <link href="https://ooo.run/post/learn-git-understanding-version-ontrol-via-savepoint.html"/>
    <id>https://ooo.run/post/learn-git-understanding-version-ontrol-via-savepoint.html</id>
    <published>2026-06-29T19:49:04.000Z</published>
    <updated>2026-06-29T20:06:33.247Z</updated>
    
    <content type="html"><![CDATA[<p>我们在写代码、改文档、做项目时就像在一款开放世界游戏里探索。<strong>Git</strong> 的作用不是替你写代码，而是帮你在关键时刻创建存档点，让你可以回看历史、撤销错误、切换不同发展路线，甚至让多人在不同“世界线”上合作，最后再把成果合并到主线剧情里。</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>一句话总结：<strong>Git</strong> 是一个用来管理项目历史的工具。每一次 <code>commit</code> 都是一个存档点，每一个 <code>branch</code> 都是一条世界线。</p></div></div><h2 id="一、Git-到底解决什么问题？"><a href="#一、Git-到底解决什么问题？" class="headerlink" title="一、Git 到底解决什么问题？"></a>一、Git 到底解决什么问题？</h2><p>没有 <strong>Git</strong> 的时候，你可能会这样保存文件：</p><ul><li><code>project-final.zip</code></li><li><code>project-final-v2.zip</code></li><li><code>project-final-v2-真的最终版.zip</code></li><li><code>project-final-v3-老板确认版.zip</code></li></ul><p>这很快就会变成灾难。<strong>Git</strong> 帮你解决这些问题：</p><ol><li>记录项目每个阶段的变化。</li><li>回到之前的版本。</li><li>看清楚谁改了什么。</li><li>同时开发多个功能而不互相干扰。</li><li>多人协作时同步代码。</li><li>出问题时安全撤销。</li></ol><p>为了更好地理解，我们可以把 <strong>Git</strong> 概念与单机游戏进行直观类比：</p><table><thead><tr><th>Git 概念</th><th>英文名词</th><th>游戏类比</th></tr></thead><tbody><tr><td>仓库</td><td>Repository</td><td>整个游戏存档系统</td></tr><tr><td>工作区</td><td>Working Directory</td><td>你正在游玩的当前世界</td></tr><tr><td>暂存区</td><td>Staging Area</td><td>准备写入存档的内容清单</td></tr><tr><td>提交</td><td>Commit</td><td>一个正式存档点</td></tr><tr><td>分支</td><td>Branch</td><td>一条平行世界线</td></tr><tr><td>合并</td><td>Merge</td><td>把一条世界线的成果并入另一条</td></tr><tr><td>远程仓库</td><td>Remote</td><td>云端存档服务器</td></tr><tr><td>克隆</td><td>Clone</td><td>从云端下载一份游戏世界</td></tr><tr><td>推送</td><td>Push</td><td>上传本地存档到云端</td></tr><tr><td>拉取</td><td>Pull</td><td>从云端同步最新存档</td></tr></tbody></table><h2 id="二、起步：设置身份与创建仓库"><a href="#二、起步：设置身份与创建仓库" class="headerlink" title="二、起步：设置身份与创建仓库"></a>二、起步：设置身份与创建仓库</h2><h3 id="1-设置身份"><a href="#1-设置身份" class="headerlink" title="1. 设置身份"></a>1. 设置身份</h3><p><strong>Git</strong> 需要知道“这个存档点是谁创建的”。这不会注册账号，只是给你的提交记录署名。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git config --global user.name <span class="string">&quot;你的名字&quot;</span></span><br><span class="line">git config --global user.email <span class="string">&quot;你的邮箱&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看配置</span></span><br><span class="line">git config --list</span><br></pre></td></tr></table></figure><h3 id="2-创建你的第一个-Git-仓库"><a href="#2-创建你的第一个-Git-仓库" class="headerlink" title="2. 创建你的第一个 Git 仓库"></a>2. 创建你的第一个 Git 仓库</h3><p>假设你有一个项目文件夹，让 <strong>Git</strong> 开始管理这个文件夹：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> my-project</span><br><span class="line"><span class="built_in">cd</span> my-project</span><br><span class="line">git init</span><br></pre></td></tr></table></figure><p>这一步相当于<mark>给这个游戏世界装上“存档系统”</mark>。执行后，项目里会出现一个隐藏文件夹 <code>.git/</code>，它是 <strong>Git</strong> 的核心数据库，包含历史记录与分支信息。平时请不要手动修改它。</p><h2 id="三、Git-的三个区域：当前世界、暂存台、正式存档"><a href="#三、Git-的三个区域：当前世界、暂存台、正式存档" class="headerlink" title="三、Git 的三个区域：当前世界、暂存台、正式存档"></a>三、Git 的三个区域：当前世界、暂存台、正式存档</h2><p><strong>Git</strong> 最容易让初学者困惑的地方，是它不是“改完文件就自动存档”。它有三个重要区域：<strong>工作区 → 暂存区 → 本地仓库</strong>。</p><h3 id="1-工作区：你正在玩的当前世界"><a href="#1-工作区：你正在玩的当前世界" class="headerlink" title="1. 工作区：你正在玩的当前世界"></a>1. 工作区：你正在玩的当前世界</h3><p>你在编辑器中修改文件，这些变化都发生在工作区。此时 <strong>Git</strong> 看到你改了东西，但还没有把它放入存档。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Hello Git&quot;</span> &gt; README.md</span><br><span class="line">git status</span><br></pre></td></tr></table></figure><p>此时会提示 <code>Untracked files</code>，表示 <strong>Git</strong> 发现了新文件，但它还没被纳入存档系统。</p><h3 id="2-暂存区：准备写入存档的清单"><a href="#2-暂存区：准备写入存档的清单" class="headerlink" title="2. 暂存区：准备写入存档的清单"></a>2. 暂存区：准备写入存档的清单</h3><p>把文件加入暂存区，相当于你决定把这次变化放进下一个存档点：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git add README.md</span><br></pre></td></tr></table></figure><h3 id="3-本地仓库：正式创建存档点"><a href="#3-本地仓库：正式创建存档点" class="headerlink" title="3. 本地仓库：正式创建存档点"></a>3. 本地仓库：正式创建存档点</h3><p>提交才是真正的“存档”：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&quot;创建 README 文件&quot;</span></span><br></pre></td></tr></table></figure><p>提交成功后，<strong>Git</strong> 会生成一个带唯一编号的 <code>commit</code>，比如 <code>a1b2c3d 创建 README 文件</code>。这就是一个完整的正式存档点。</p><details class="flatpaper-note flatpaper-note--warning"><summary class="flatpaper-note__title"><span class="flatpaper-note__icon" aria-hidden="true"></span><span class="flatpaper-note__label">注意事项</span><span class="flatpaper-note__chevron" aria-hidden="true"></span></summary><div class="flatpaper-note__body"><p>初学者建议先用 <code>git status</code> 确认状态，再进行 <code>git commit</code>。虽然 <code>git add .</code> 可以一次性暂存当前目录下所有修改，但一定要看清楚自己添加了什么，避免误存多余文件。</p></div></details><h2 id="四、查看历史与变更"><a href="#四、查看历史与变更" class="headerlink" title="四、查看历史与变更"></a>四、查看历史与变更</h2><h3 id="1-查看提交历史-Git-Log"><a href="#1-查看提交历史-Git-Log" class="headerlink" title="1. 查看提交历史 (Git Log)"></a>1. 查看提交历史 (Git Log)</h3><p>这就像调出游戏里的存档列表，越新的存档越靠上：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span></span><br><span class="line"><span class="comment"># 或者使用更简洁的单行输出</span></span><br><span class="line">git <span class="built_in">log</span> --oneline</span><br></pre></td></tr></table></figure><h3 id="2-查看文件变更-Git-Diff"><a href="#2-查看文件变更-Git-Diff" class="headerlink" title="2. 查看文件变更 (Git Diff)"></a>2. 查看文件变更 (Git Diff)</h3><p>在创建存档点之前，你需要确认自己到底改了哪些内容：</p><div class="flatpaper-tabs"><div class="flatpaper-tabs__nav" role="tablist"><button type="button" role="tab" id="tabs-22-tab-0" aria-controls="tabs-22-panel-0" aria-selected="true" class="flatpaper-tabs__nav-item is-active" data-index="0">对比工作区</button><button type="button" role="tab" id="tabs-22-tab-1" aria-controls="tabs-22-panel-1" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="1">对比暂存区</button></div><div class="flatpaper-tabs__panels"><section role="tabpanel" id="tabs-22-panel-0" aria-labelledby="tabs-22-tab-0" class="flatpaper-tabs__panel is-active" data-index="0"><p>我当前世界和上次存档相比，哪里变了？</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git diff</span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-22-panel-1" aria-labelledby="tabs-22-tab-1" class="flatpaper-tabs__panel" data-index="1" hidden><p>我已经 add 到暂存区，准备写入下个存档点的内容是什么？</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git diff --staged</span><br></pre></td></tr></table></figure></section></div></div><h2 id="五、分支-Branch-与合并-Merge-：多元世界线"><a href="#五、分支-Branch-与合并-Merge-：多元世界线" class="headerlink" title="五、分支 (Branch) 与合并 (Merge)：多元世界线"></a>五、分支 (Branch) 与合并 (Merge)：多元世界线</h2><p><strong>Git</strong> 最强大的功能之一就是分支。</p><h3 id="1-开启新世界线"><a href="#1-开启新世界线" class="headerlink" title="1. 开启新世界线"></a>1. 开启新世界线</h3><p>假设你的主线剧情叫 <code>main</code>。你想开发一个新功能，但不确定会不会成功，为了不污染主线，可以创建一条新世界线：</p><p>一步完成创建并切换到新分支：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git switch -c new-feature</span><br></pre></td></tr></table></figure><p>在这个新分支中提交代码，<code>main</code> 主线不会受到任何影响。你可以放心实验。</p><h3 id="2-切换世界线"><a href="#2-切换世界线" class="headerlink" title="2. 切换世界线"></a>2. 切换世界线</h3><p>你可以随时在不同分支间切换，文件内容会随之变化，因为不同分支代表了不同的历史状态。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看所有分支，当前分支前会有 *</span></span><br><span class="line">git branch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 切回主线世界</span></span><br><span class="line">git switch main</span><br></pre></td></tr></table></figure><h3 id="3-合并分支与解决冲突"><a href="#3-合并分支与解决冲突" class="headerlink" title="3. 合并分支与解决冲突"></a>3. 合并分支与解决冲突</h3><p>当支线任务完成，获得了顶级装备，你希望把成果带回主线：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git switch main</span><br><span class="line"><span class="comment"># 将 new-feature 的成果合并到主线</span></span><br><span class="line">git merge new-feature</span><br></pre></td></tr></table></figure><p>如果有两个分支修改了同一行代码，合并时会提示 **冲突 (Conflict)**。此时文件里会出现 <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD</code> 等标记。冲突并不可怕，它只是 <strong>Git</strong> 在告诉你：“这两条世界线在同一个位置发生了不同变化，我需要你来决定最终剧情。”手动修改并保留你想要的代码后，重新 <code>git add</code> 和 <code>git commit</code> 即可。</p><h2 id="六、远程仓库-Remote-：云端同步存档"><a href="#六、远程仓库-Remote-：云端同步存档" class="headerlink" title="六、远程仓库 (Remote)：云端同步存档"></a>六、远程仓库 (Remote)：云端同步存档</h2><p>本地仓库只存在于你的电脑里。为了备份或多人协作，我们通常会使用 <strong>GitHub</strong>、<strong>GitLab</strong> 等远程服务器作为云端存档服务器。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 克隆仓库：从云端服务器下载一份完整游戏世界</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/example/my-project.git</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看当前配置的远程地址 (通常叫 origin)</span></span><br><span class="line">git remote -v</span><br><span class="line"></span><br><span class="line"><span class="comment"># 推送 Push：将本地主线上传到 origin 云端</span></span><br><span class="line">git push -u origin main</span><br><span class="line"></span><br><span class="line"><span class="comment"># 拉取 Pull：同步云端最新的世界状态</span></span><br><span class="line">git pull</span><br></pre></td></tr></table></figure><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p><strong>多人协作黄金法则</strong>：在开始每天的工作或提交代码前，强烈建议先执行 <code>git pull</code> 同步服务器上的最新状态，这样可以大幅减少合并时的冲突概率。</p></div></div><h2 id="七、撤销与临时口袋"><a href="#七、撤销与临时口袋" class="headerlink" title="七、撤销与临时口袋"></a>七、撤销与临时口袋</h2><h3 id="1-安全撤销与回滚"><a href="#1-安全撤销与回滚" class="headerlink" title="1. 安全撤销与回滚"></a>1. 安全撤销与回滚</h3><p>如果你改坏了代码或者提交错了内容，可以通过以下命令安全“读档”：</p><div class="flatpaper-tabs"><div class="flatpaper-tabs__nav" role="tablist"><button type="button" role="tab" id="tabs-23-tab-0" aria-controls="tabs-23-panel-0" aria-selected="true" class="flatpaper-tabs__nav-item is-active" data-index="0">放弃工作区修改</button><button type="button" role="tab" id="tabs-23-tab-1" aria-controls="tabs-23-panel-1" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="1">取消暂存</button><button type="button" role="tab" id="tabs-23-tab-2" aria-controls="tabs-23-panel-2" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="2">撤销已提交 (Revert)</button><button type="button" role="tab" id="tabs-23-tab-3" aria-controls="tabs-23-panel-3" aria-selected="false" class="flatpaper-tabs__nav-item" data-index="3">强制回滚 (Reset)</button></div><div class="flatpaper-tabs__panels"><section role="tabpanel" id="tabs-23-panel-0" aria-labelledby="tabs-23-tab-0" class="flatpaper-tabs__panel is-active" data-index="0"><p>当前未 add 的修改不要了，回到上一个正式存档点状态：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git restore README.md</span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-23-panel-1" aria-labelledby="tabs-23-tab-1" class="flatpaper-tabs__panel" data-index="1" hidden><p>后悔执行了 git add，把文件从暂存区拿出来（不会删除实际修改）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git restore --staged README.md</span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-23-panel-2" aria-labelledby="tabs-23-tab-2" class="flatpaper-tabs__panel" data-index="2" hidden><p>创建一个新的“反向提交”来撤销指定提交的影响。这是协作中最安全的做法！</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git revert a1b2c3d</span><br></pre></td></tr></table></figure></section><section role="tabpanel" id="tabs-23-panel-3" aria-labelledby="tabs-23-tab-3" class="flatpaper-tabs__panel" data-index="3" hidden><p>危险！直接把时间线强行挪回某个旧存档点，丢弃之后的所有提交：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git reset --hard a1b2c3d</span><br></pre></td></tr></table></figure></section></div></div><h3 id="2-Stash-临时口袋存档"><a href="#2-Stash-临时口袋存档" class="headerlink" title="2. Stash 临时口袋存档"></a>2. Stash 临时口袋存档</h3><p>有时候你在开发功能，改了一半需要临时切分支去修 Bug，但代码还不具备 commit 的条件。这时可以用临时口袋：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 把当前未完成的修改临时塞进口袋</span></span><br><span class="line">git stash</span><br><span class="line"></span><br><span class="line"><span class="comment"># 此时工作区干净了，可以切换分支办事...</span></span><br><span class="line"><span class="comment"># 办完事切回原来的分支后，取出临时修改：</span></span><br><span class="line">git stash pop</span><br></pre></td></tr></table></figure><h2 id="结语：初学者最该掌握的心智模型"><a href="#结语：初学者最该掌握的心智模型" class="headerlink" title="结语：初学者最该掌握的心智模型"></a>结语：初学者最该掌握的心智模型</h2><p><strong>Git</strong> 的核心不是死记硬背命令，而是理解以下几点模型：</p><ol><li><strong><code>commit</code> 是存档点</strong>：不是每次 <code>Ctrl+S</code> 保存文件都会被记录，只有执行 <code>commit</code> 才会正式生成存档。</li><li><strong><code>branch</code> 是世界线</strong>：分支不是文件夹的笨重副本，而是历史时间线的轻量指针，切换毫无压力。</li><li><strong><code>HEAD</code> 是你的眼睛</strong>：它代表你现在正在观察和处于的特定世界线位置。</li><li><strong><code>push</code> &#x2F; <code>pull</code> 是云同步</strong>：本地提交不等于上传。</li></ol><p>记住这句话：<strong>你并不是在管理一堆文件副本，你是在管理一个项目不断分裂、发展、汇合的历史宇宙。</strong> 遇到不确定的情况，随时输入 <code>git status</code> 看一眼地图，然后放手在代码世界里探险吧！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;我们在写代码、改文档、做项目时就像在一款开放世界游戏里探索。&lt;strong&gt;Git&lt;/strong&gt; 的作用不是替你写代码，而是帮你在关键时刻创建存档点，让你可以回看历史、撤销错误、切换不同发展路线，甚至让多人在不同“世界线”上合作，最后再把成果合并到主线剧情里。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="教程" scheme="https://ooo.run/categories/%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="Git" scheme="https://ooo.run/tags/Git/"/>
    
    <category term="开发工具" scheme="https://ooo.run/tags/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>如何查询 Codex 赠送的重置机会的到期日期</title>
    <link href="https://ooo.run/post/how-to-check-codex-reset-expiration.html"/>
    <id>https://ooo.run/post/how-to-check-codex-reset-expiration.html</id>
    <published>2026-06-29T07:48:09.000Z</published>
    <updated>2026-07-09T19:53:11.900Z</updated>
    
    <content type="html"><![CDATA[<div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>更新: <strong>2026 年 7 月 10 日</strong>，OpenAI 推出 GPT-5.6 系列模型，同时推出新的 ChatGPT APP 取代了 Codex 应用，<strong>新版本中已内置到期时间显示</strong>。</p></div></div><p>2026 年 6 月份 Codex 的重置机制改为了可以存储的重置机会，并且由于一些 BUG 6 月份已经赠送了三次免费的重置机会，如通过邀请好友也可以额外获得最多三次的重置机会。不过重置次数不能无限期保存，每个重置次数只有 30 天的有效期，而 Codex 界面里不会显示每次重置机会的具体到期日期。</p><p>下面给大家提供一个简单的查询方法</p><h2 id="直接让-Codex-自己查询"><a href="#直接让-Codex-自己查询" class="headerlink" title="直接让 Codex 自己查询"></a>直接让 Codex 自己查询</h2><p>方法非常简单，只需要把下面的 <strong>提示词</strong> 发送给 Codex，让它使用本机凭证自行查询即可。</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">请使用本机 Codex 凭证查一下 rate-limit reset credits：</span><br><span class="line"></span><br><span class="line">读取 `~/.codex/auth.json` 里的 `tokens.access_token`，请求接口：</span><br><span class="line">https://chatgpt.com/backend-api/wham/rate-limit-reset-credits</span><br><span class="line"></span><br><span class="line">要求：</span><br><span class="line"></span><br><span class="line">1. 不要打印 access_token、refresh_token、cookie 或完整唯一 ID</span><br><span class="line">2. 只汇总 available_count、每个 credit 的 status/title/granted_at/expires_at</span><br><span class="line">3. 把 granted_at/expires_at 从 UTC 转成本地时间</span><br><span class="line">4. 如果状态码返回 401，说明是凭证失效或没带对 Authorization header</span><br></pre></td></tr></table></figure><details class="flatpaper-note flatpaper-note--info"><summary class="flatpaper-note__title"><span class="flatpaper-note__icon" aria-hidden="true"></span><span class="flatpaper-note__label">回复示例</span><span class="flatpaper-note__chevron" aria-hidden="true"></span></summary><div class="flatpaper-note__body"><p>6 月份共赠送三次，我已经用掉了一次，所以显示还剩两次。</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">请求成功，状态码 200。</span><br><span class="line">available_count: 2</span><br><span class="line">Credits:</span><br><span class="line">1. status: available</span><br><span class="line">    title: Full reset (Weekly + 5 hr)</span><br><span class="line">    granted_at: 2026-06-18 08:42:00 </span><br><span class="line">    expires_at: 2026-07-18 08:42:00 </span><br><span class="line"></span><br><span class="line">2. status: available</span><br><span class="line">    title: Full reset (Weekly + 5 hr)</span><br><span class="line">    granted_at: 2026-06-27 07:52:00 </span><br><span class="line">    expires_at: 2026-07-27 07:52:00 </span><br></pre></td></tr></table></figure></div></details><h2 id="OpenAI-赠送的重置记录"><a href="#OpenAI-赠送的重置记录" class="headerlink" title="OpenAI 赠送的重置记录"></a>OpenAI 赠送的重置记录</h2><h3 id="7-月份赠送记录（三次）"><a href="#7-月份赠送记录（三次）" class="headerlink" title="7 月份赠送记录（三次）"></a>7 月份赠送记录（三次）</h3><ol><li>推出重置保存机制时赠送：2026 年 6 月 12 日，到期日期为 <strong>7 月 12 日</strong></li><li>BUG 赠送：2026 年 6 月 18 日，到期日期 <strong>7 月 18 日</strong></li><li>BUG 赠送：2026 年 6 月 27 日，到期日期 <strong>7 月 27 日</strong></li></ol><p>我在 6 月 29 日的查询结果与记录一致，如果你有 X.com 账户，查看 <a href="https://x.com/thsottiaux">Tibo</a> 的推文获取最新 Codex 更新消息。</p><h3 id="7-月份赠送记录"><a href="#7-月份赠送记录" class="headerlink" title="7 月份赠送记录"></a>7 月份赠送记录</h3><ol><li>BUG 赠送：2026 年 7 月 2 日，到期日期 <strong>8 月 1 日</strong></li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>快看看你的重置机会什么时候到期吧。Plus 用户每周额度价值大约 100 美元，千万不要浪费了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;flatpaper-note flatpaper-note--info&quot;&gt;&lt;span class=&quot;flatpaper-note__icon&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt;&lt;div class=&quot;flatpaper-note__bo</summary>
      
    
    
    
    <category term="笔记" scheme="https://ooo.run/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="OpenAI" scheme="https://ooo.run/tags/OpenAI/"/>
    
    <category term="Codex" scheme="https://ooo.run/tags/Codex/"/>
    
  </entry>
  
  <entry>
    <title>赛博特权阶级的诞生：从 Fable 5 白名单看 AI 非营利乌托邦的终结</title>
    <link href="https://ooo.run/post/fable-5-whitelist-new-privileged-class-ai-monopoly.html"/>
    <id>https://ooo.run/post/fable-5-whitelist-new-privileged-class-ai-monopoly.html</id>
    <published>2026-06-29T07:06:15.000Z</published>
    <updated>2026-06-29T13:22:57.769Z</updated>
    
    <content type="html"><![CDATA[<p>2026 年夏天，科技界经历了一场 “AI大地震”。美国商务部的一纸出口管制令，让刚刚问世、霸榜各大模型基座的 Anthropic 旗舰模型 <strong>Claude Fable 5</strong> 与其底层孪生模型 Mythos 5 瞬间在全球范围内被按下了暂停键。紧接着，经过政商闭门博弈，部分 <strong>可信赖的实体</strong> 和特定白名单单位逐步重获访问特权。</p><p>这一历史性事件不仅颠覆了开发者对云端 API 稳定性的认知，更向世界宣告了一个残酷的事实：由美国政府特许的、由技术与权力交织而成的 <strong>赛博新特权阶级</strong> 已经正式诞生。</p><p>这也给予了整个AI行业沉重一击 —— OpenAI 最初设立的 <strong>技术民主化、利益造福全人类</strong> 的乌托邦设想，已经彻底宣告失败。</p><h2 id="一、-“白名单”下的赛博新特权阶级"><a href="#一、-“白名单”下的赛博新特权阶级" class="headerlink" title="一、 “白名单”下的赛博新特权阶级"></a>一、 “白名单”下的赛博新特权阶级</h2><p>在过去，黄金、石油和土地是核心的生产要素。而在2026年的今天，顶尖的通用人工智能（AGI）推理算力已成为最稀缺的战略资源。</p><p>Fable 5 与Mythos 5 的强悍无需多言 —— 在 TerminalBench 2.1 等前沿评测中，它们展现出了恐怖的智能。支付巨头 Stripe 曾用它在短短一天内完成了原本需要一整个工程团队干满两个月的 5000 万行 Ruby 代码大迁移；在生物制药与网络安全领域，它们甚至展现出了越过安全限制、自主运行设计工具的“近神”能力。</p><p>然而，正因为这种 “颠覆性力量” ，它引来了权力的铁拳。美国政府以国家安全、防范越狱（Jailbreak）和技术外泄为由，强行切断了公众和海外开发者的连接。随后出炉的 “白名单机制” ，将这种力量圈禁在了一个狭小的特权阶层手中：</p><ul><li><strong>国家机器与军工巨头</strong>： 拥有绝对豁免权，能够无限制调用未阉割、无安全拦截器的 Mythos 5。</li><li><strong>合规的华尔街财阀与巨型跨国企业</strong>： 凭借强大的游说能力和国籍审查能力，跻身“可信合规白名单”。</li></ul><p>一个技术垄断的马太效应正在形成： 白名单内的企业利用 Fable 5 实现成百上千倍的效率跃升、垄断行业财富；而白名单外的中小创业者、研究机构甚至普通大众，只能眼睁睁看着技术代差被无限拉大。曾经人人平等的互联网API生态，变成了按权力、国籍和资本配给的 “口粮” 。美国政府的 “特许” ，正式在全球科技界划分出了高人一等的赛博新贵族。</p><h2 id="二、-权力的入局：Fable-5-的“国家化”阵痛"><a href="#二、-权力的入局：Fable-5-的“国家化”阵痛" class="headerlink" title="二、 权力的入局：Fable 5 的“国家化”阵痛"></a>二、 权力的入局：Fable 5 的“国家化”阵痛</h2><p>Fable 5 的白名单风波，标志着 AI 技术正式从 “商业竞争阶段” 滑向 “地缘政治与国家安全阶段” 。</p><p>“我们不认为这种政府准入程序应该成为长期的默认状态。” —— 面对政府的强势介入，即便是正在筹备 IPO 的 OpenAI 也在其发布 GPT-5.6 Sol 限量预览时发出了无力的警告。</p><p>但资本和企业的挣扎在强大的国家机器面前显得微不足道。过去，硅谷的技术精英们总认为自己可以通过代码改变世界，凌驾于地缘政治之上。但当白宫执行行政令、国防部和国安局（NSA）直接介入审查时，强如 Anthropic 也只能选择 “积极与政府合作”，甚至连自己的非美籍员工也必须被剥夺访问权限。</p><p>Fable 5不再只是一个商品，它成了被国家征用的 <strong>战略军火</strong> 。</p><h2 id="三、-废墟中的理想：商业洪流下的破灭与向往"><a href="#三、-废墟中的理想：商业洪流下的破灭与向往" class="headerlink" title="三、 废墟中的理想：商业洪流下的破灭与向往"></a>三、 废墟中的理想：商业洪流下的破灭与向往</h2><p>回看 Fable 5 的白名单特权、OpenAI 的 GPT-5.6 受限审查，以及 OpenAI 自身提交的IPO申请，历史在这一刻完成了一个巨大的讽刺。</p><p>2015年，当埃隆·马斯克、山姆·奥特曼等人创立 OpenAI 时，其核心宗旨是：</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>作为一个非营利组织，不受财务回报的限制，确保 AGI 的技术向所有人开放，防止技术被单一国家或巨型财阀垄断，从而造福全人类。</p></div></div><p>今天，这个设想已经碎成了满地瓦砾：</p><p>从非营利到资本弄潮儿： OpenAI 早已转型为追求利润的实体，并为了迎合资本市场走向 IPO ，最初的非营利乌托邦理想早已被商业逻辑吞噬。</p><p>从 “Open（开放）” 到 “Closed（封闭）” ： 曾经开源的承诺变成了最严密的商业机密，而如今更是在政府的指令下，演变成了 “白名单准入” 的割裂生态。</p><p>从造福全人类到服务特权阶级： 顶尖大模型不再是普惠全人类的工具，而是成了强化特定国家霸权、提升少数垄断巨头生产力的私产。</p><p><strong>然而，那道最初的微光，依然让我们充满向往</strong></p><p>即便现实如此冰冷，即便 OpenAI 如今已实质性转为追逐利润的盈利实体，但当我们拂去商业的喧嚣，回望它最初的设想时，那幅“技术普惠”的宏大蓝图依然散发着让人心潮澎湃的理想主义光芒。</p><p>那是人类科技史上少有的、试图超越国家边界和阶级壁垒的伟大尝试。它向世界许诺过一种可能：最高维度的智慧不需要附庸于权力，最顶尖的科技可以成为每一个普通人对抗命运、跨越数字鸿沟的武器。</p><p>正是因为这个最初的设想曾如此美丽，甚至一度让我们看到了赛博乌托邦的曙光，才使得今天面对Fable 5的“白名单高墙”时，全球开发者心中的失落与阵痛显得如此剧烈。人们对 OpenAI 初心的向往，并非出于对商业幼稚的幻想，而是出于人类对公平、开放与知识无界根深蒂固的渴望。这种向往，恰恰成了当下对抗技术垄断、呼唤开源力量的最强韧的精神火种。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>Fable 5 的 “白名单风暴” 揭示了 AI 时代的未来图景：科技不再是平的，而是被权力筑起的高墙分割得支离破碎。</p><p>OpenAI 最初那个充满人文主义情怀的设想失败了，取而代之的是一个更加冷酷、更加遵循达尔文主义的现实。在这个由政府特许、白名单构筑的赛博新秩序里，谁能拿到那张通往顶尖算力的 “特许通行证” ，谁就掌握了下一个时代改写世界的权力。而剩下的绝大多数人，正无可避免地沦为这场技术合谋下的 <strong>“数字平民”</strong> 。</p><p>不过，局面并非完全没有转机。以 <strong>GLM 5.2</strong> 为代表的中国顶尖开源模型正在展现出越来越强的竞争力。如果它能在代码、推理、工具调用与长上下文等关键能力上持续追近甚至反超闭源白名单模型，那么全球开发者至少不会被迫完全依赖少数美国 API。它的强力表现，有望在一定程度上缓解这种由算力、资本与国家权力共同制造的技术阶层分化。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;2026 年夏天，科技界经历了一场 “AI大地震”。美国商务部的一纸出口管制令，让刚刚问世、霸榜各大模型基座的 Anthropic 旗舰模型 &lt;strong&gt;Claude Fable 5&lt;/strong&gt; 与其底层孪生模型 Mythos 5 瞬间在全球范围内被按下了暂停键。</summary>
      
    
    
    
    <category term="评论" scheme="https://ooo.run/categories/%E8%AF%84%E8%AE%BA/"/>
    
    
    <category term="AI" scheme="https://ooo.run/tags/AI/"/>
    
    <category term="OpenAI" scheme="https://ooo.run/tags/OpenAI/"/>
    
    <category term="Claude Fable 5" scheme="https://ooo.run/tags/Claude-Fable-5/"/>
    
  </entry>
  
  <entry>
    <title>解决 Electron 42 APP 初次运行 pnpm dev 报错的问题</title>
    <link href="https://ooo.run/post/fix-electron-42-app-cannot-run.html"/>
    <id>https://ooo.run/post/fix-electron-42-app-cannot-run.html</id>
    <published>2026-06-27T02:28:34.000Z</published>
    <updated>2026-06-27T02:39:46.710Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题复现"><a href="#问题复现" class="headerlink" title="问题复现"></a>问题复现</h2><p>开发或是 Clone 一个 Electron 42 APP 时，安装完依赖后第一次运行 <code>pnpm dev</code> 你可能遇到 <code>Error: Electron uninstall</code> 的错误信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pnpm install --frozen-lockfile</span><br><span class="line">pnpm approve-builds</span><br><span class="line"></span><br><span class="line">pnpm dev </span><br></pre></td></tr></table></figure><p>报错信息</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">error during start dev server and electron app:</span><br><span class="line">Error: Electron uninstall</span><br><span class="line">    at getElectronPath</span><br><span class="line">...</span><br><span class="line">...</span><br></pre></td></tr></table></figure><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><p>需要手动运行下面的命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx install-electron</span><br></pre></td></tr></table></figure><h2 id="问题原因"><a href="#问题原因" class="headerlink" title="问题原因"></a>问题原因</h2><p>这是由于为了应对供应链攻击， Electron 42 不再通过 <code>postinstall</code> 下载自身</p><p><a href="https://www.electronjs.org/blog/electron-42-0#electron-no-longer-downloads-itself-via-postinstall-script">Electron 42: electron no longer downloads itself via postinstall script</a></p><p>可以运行下面的命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm install electron --save-dev --ignore-scripts</span><br><span class="line">npx install-electron</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;问题复现&quot;&gt;&lt;a href=&quot;#问题复现&quot; class=&quot;headerlink&quot; title=&quot;问题复现&quot;&gt;&lt;/a&gt;问题复现&lt;/h2&gt;&lt;p&gt;开发或是 Clone 一个 Electron 42 APP 时，安装完依赖后第一次运行 &lt;code&gt;pnpm dev&lt;/co</summary>
      
    
    
    
    <category term="笔记" scheme="https://ooo.run/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Electron" scheme="https://ooo.run/tags/Electron/"/>
    
  </entry>
  
  <entry>
    <title>OpenAI 发布 GPT-5.6 系列模型：Sol、Terra 和 Luna 开启有限预览，受美国政府要求限制初始访问</title>
    <link href="https://ooo.run/post/openai-gpt-5-6-limited-preview.html"/>
    <id>https://ooo.run/post/openai-gpt-5-6-limited-preview.html</id>
    <published>2026-06-26T20:42:03.000Z</published>
    <updated>2026-06-26T21:04:04.844Z</updated>
    
    <content type="html"><![CDATA[<p><strong>日期：美国时间 2026年6月26日</strong></p><p>OpenAI 宣布正式预览其新一代 GPT-5.6 模型系列，并率先以受限预览形式向部分可信合作伙伴开放。本次发布包含三款模型：旗舰级模型 <strong>GPT-5.6 Sol</strong>、面向日常工作的均衡模型 <strong>GPT-5.6 Terra</strong>，以及主打速度与成本效率的 <strong>GPT-5.6 Luna</strong>。这是继 GPT-5.5（2026年4月发布）之后又一次快速迭代，延续了 OpenAI 大约每六周发布一次旗舰模型的节奏。</p><img src="https://img.nep.me/ooo/openai-release-gpt-sol.webp" alt="openai-release-gpt-sol.png" style="width:75%;max-width:100%;height:auto" /><h3 id="三大变体定位不同需求"><a href="#三大变体定位不同需求" class="headerlink" title="三大变体定位不同需求"></a>三大变体定位不同需求</h3><ul><li><strong>Sol：</strong> 最强大旗舰模型，在代理能力上显著提升，尤其在编码、生物学和网络安全领域表现出色。新增 <strong>Max</strong> 推理模式和 <strong>Ultra</strong> 模式（可协调多个子代理处理极复杂任务）。 </li><li><strong>Terra：</strong> 性能与 GPT-5.5 相当，但成本约降低一半（据报道输入&#x2F;输出 token 定价更具竞争力），适合日常工作。 </li><li><strong>Luna：</strong> 速度最快、成本最低的选项，提供强大能力的同时实现最高性价比。</li></ul><p>据 OpenAI 公告，GPT-5.6 Sol 是目前最强的模型，在真实世界编码调试、漏洞查找与修复等任务中表现出色，同时在上下文窗口和 token 效率上有进一步优化（此前传闻提到可能支持高达 <strong>150 万</strong> token 上下文）。模型还强化了推理训练，能在回答前进行更长的内部思考链。 </p><h3 id="安全与访问限制：受美国政府影响"><a href="#安全与访问限制：受美国政府影响" class="headerlink" title="安全与访问限制：受美国政府影响"></a>安全与访问限制：受美国政府影响</h3><p>尽管 OpenAI 强调“相信广泛访问”并计划在未来数周内向 ChatGPT、Codex 和 API 全面开放，但本次发布采用有限预览形式，初始仅限约 20 家受信任合作伙伴（参与名单已与政府共享）。这一决定源于美国政府（特朗普政府）的安全关切，特别是针对先进 AI 模型的网络安全能力审查。 </p><p>OpenAI 在系统卡和公告中表示，已构建史上最强大的安全栈，包括强化训练、激活分类器、实时监控等。模型在 Preparedness Framework 下被评估为网络安全和生物&#x2F;化学风险 “High” 级别，但未达到 “Critical” 阈值。测试显示 Sol 在帮助防御者查找和修复漏洞方面的能力强于自主实施端到端攻击的能力。公司同时承认代理编码任务中存在一定“超出用户意图”的倾向，但绝对发生率较低。 </p><p>OpenAI 明确表示，此类政府审查不应成为长期默认做法，并正与政府合作制定可重复的审查框架，以尽快实现更广泛可用性。 </p><h3 id="展望"><a href="#展望" class="headerlink" title="展望"></a>展望</h3><p>从行业角度看，GPT-5.6 的发布标志着 AI 竞争进入新的阶段。一方面，模型能力继续向更强的智能体、代码执行、长任务规划方向推进；另一方面，政府、企业和社会对前沿模型风险的关注也在快速上升。未来，前沿 AI 模型的发布节奏，可能不再只由技术成熟度决定，还会受到安全评估、监管要求和国际竞争环境的共同影响。</p><p>目前，GPT-5.6 系列尚未全面开放。按照媒体报道，OpenAI 计划在完成初期评估后，于未来几周逐步扩大访问范围。对于普通用户和开发者来说，GPT-5.6 的真正影响，可能要等到 API、ChatGPT 或 Codex 等产品线正式接入后才会更加清晰。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;strong&gt;日期：美国时间 2026年6月26日&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OpenAI 宣布正式预览其新一代 GPT-5.6 模型系列，并率先以受限预览形式向部分可信合作伙伴开放。本次发布包含三款模型：旗舰级模型 &lt;strong&gt;GPT-5.6 Sol&lt;/str</summary>
      
    
    
    
    <category term="资讯" scheme="https://ooo.run/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="OpenAI" scheme="https://ooo.run/tags/OpenAI/"/>
    
    <category term="ChatGPT" scheme="https://ooo.run/tags/ChatGPT/"/>
    
    <category term="GPT-5.6" scheme="https://ooo.run/tags/GPT-5-6/"/>
    
  </entry>
  
  <entry>
    <title>AI 正在影响消费者的钱包：苹果大幅上调多款产品价格</title>
    <link href="https://ooo.run/post/apple-products-price-increase.html"/>
    <id>https://ooo.run/post/apple-products-price-increase.html</id>
    <published>2026-06-26T02:39:06.000Z</published>
    <updated>2026-06-26T06:04:14.719Z</updated>
    
    <content type="html"><![CDATA[<p>自 2025 年 11 月以来，内存和存储芯片价格持续上涨，至今仍未出现明显放缓迹象。美国头部 AI 企业持续加码数据中心建设，大量采购内存与存储元件，也进一步挤压了消费电子厂商的供应空间。如今，苹果也开始将这部分成本压力传导到终端产品上，宣布上调 iPhone 产品线之外多款设备的售价。</p><p>在通过科技媒体 MacRumors 发布的声明中，苹果公司表示本轮涨价主要受内存 RAM 和存储 SSD 元件影响：</p><blockquote><p>消费电子行业正面临前所未有的挑战，人工智能数据中心的快速扩张导致内存和存储需求激增。我们从未见过如此大幅度、如此迅速的元器件价格上涨。</p><p>我们此前一直内部消化元件成本上涨压力，尽力避免冲击波及我们的客户。包括今天 iPad 和 Mac 等产品的涨价在内，现在我们不得不开始提高部分产品的价格。我们知道这对大家来说并非好消息，我们正在竭尽全力寻找解决方案。</p></blockquote><h2 id="价格调整详情"><a href="#价格调整详情" class="headerlink" title="价格调整详情"></a>价格调整详情</h2><p>下图是不同产品的上涨情况：</p><p><img src="https://img.nep.me/ooo/apple-price-up.webp" alt="apple-price-up.jpg"></p><table><thead><tr><th align="left">产品</th><th align="left">当前官网起售价</th><th align="left">发售时起售价</th><th align="left">变化</th></tr></thead><tbody><tr><td align="left">MacBook Neo</td><td align="left">¥5,499</td><td align="left">¥4,599</td><td align="left">+¥900</td></tr><tr><td align="left">MacBook Air M5 13 英寸</td><td align="left">¥9,999</td><td align="left">¥8,499</td><td align="left">+¥1,500</td></tr><tr><td align="left">MacBook Pro M5 系列</td><td align="left">¥15,999</td><td align="left">¥13,499</td><td align="left">+¥2,500</td></tr><tr><td align="left">Mac mini M4</td><td align="left">¥5,999</td><td align="left">¥4,499</td><td align="left">+¥1,500</td></tr><tr><td align="left">iPad Pro 11 英寸 M5</td><td align="left">¥10,799</td><td align="left">¥8,999</td><td align="left">+¥1,800</td></tr><tr><td align="left">iPad Air 11 英寸 M4</td><td align="left">¥5,999</td><td align="left">¥4,799</td><td align="left">+¥1,200</td></tr><tr><td align="left">iPad A16</td><td align="left">¥3,799</td><td align="left">¥2,999</td><td align="left">+¥800</td></tr><tr><td align="left">iPad mini A17 Pro</td><td align="left">¥4,799</td><td align="left">¥3,999</td><td align="left">+¥800</td></tr></tbody></table><p>一同上涨的还有提升存储配置的价格，以 MacBook Pro 系列为例，部分机型每增加 1TB SSD 存储，定制价格已达到 3750 元。</p><p><img src="https://img.nep.me/ooo/apple-price-up-ssd.webp" alt="apple-price-up-ssd.png"></p><h2 id="微软上调-XBOX-产品价格"><a href="#微软上调-XBOX-产品价格" class="headerlink" title="微软上调 XBOX 产品价格"></a>微软上调 XBOX 产品价格</h2><p>于此同时微软也一同上调了 XBOX 的产品线价格，在微软的声明中指出</p><blockquote><p>推动本轮涨价的主要原因是存储和内存成本大幅攀升。“游戏主机存储和内存价格已经涨超2.5倍，我们预计到2027年秋季还会再翻一番。</p></blockquote><h2 id="美光回应"><a href="#美光回应" class="headerlink" title="美光回应"></a>美光回应</h2><p>值得注意的是，围绕本轮存储芯片涨价，苹果与供应链厂商之间也出现了微妙的责任归属分歧。由于苹果方面表示，内存供应紧张、存储厂商大幅涨价，正在迫使苹果上调产品售价。但作为苹果供应商之一，美光科技首席商务官 Sumit Sadana 随后回应称，<mark>苹果此前激进的压价采购策略，才是当前存储供应紧缺的重要原因之一</mark>。</p><p>这个说法的背景在于，上一轮存储行业低谷期，消费电子需求疲软，苹果等大客户利用自身议价能力持续压低采购价格，导致部分存储厂商一度陷入负毛利，生产越多亏得越多。为了止血，厂商不得不削减资本开支、放缓扩产计划，甚至缩减部分长期投资。</p><p>而当 AI 数据中心需求突然爆发，内存和存储芯片重新进入供不应求周期时，过去被压下去的产能投资缺口就开始反噬整个产业链。换句话说，今天的涨价并不只是 AI 企业抢产能造成的短期波动，也和上一轮行业低谷中消费电子厂商过度压价、供应商被迫收缩投资有关。</p><p>这也让这次涨价不再只是单纯的 “AI 成本上涨” 问题，而更像是消费电子供应链长期博弈的一次集中爆发。过去被压在供应链里的成本矛盾，最终还是绕了一圈，回到了消费者的钱包上。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这件事也再次提醒我们，现代科技产品从来不是某一家公司的孤立成果。一台 Mac、一部 iPad，背后连接的是芯片设计、存储制造、软件生态、能源供应、物流运输，以及跨越多个国家和地区的协作网络。任何一个环节出现紧张，最后都会在终端市场上体现出来。</p><p>过去几年，全球科技产业在地缘政治、供应链重组和贸易壁垒中不断被切割。短期来看，这或许能带来所谓的“安全感”，但长期来看，重复建设、产能错配和合作受阻，都会推高整个行业的成本。而这些成本，最终仍然会由企业、开发者和消费者共同承担。</p><p>希望这次由 AI 带来的价格波动，能让更多人重新意识到全球合作的重要性。科技进步本该让更多人受益，而不是让资源被少数巨头争抢、让普通用户被迫为更高的成本买单。比起各自为战，我们更需要一个开放、稳定、互相信任的全球产业链，让创新回到提升效率、降低成本、改善生活的方向上。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;自 2025 年 11 月以来，内存和存储芯片价格持续上涨，至今仍未出现明显放缓迹象。美国头部 AI 企业持续加码数据中心建设，大量采购内存与存储元件，也进一步挤压了消费电子厂商的供应空间。如今，苹果也开始将这部分成本压力传导到终端产品上，宣布上调 iPhone 产品线之外</summary>
      
    
    
    
    <category term="资讯" scheme="https://ooo.run/categories/%E8%B5%84%E8%AE%AF/"/>
    
    
    <category term="APPLE" scheme="https://ooo.run/tags/APPLE/"/>
    
  </entry>
  
  <entry>
    <title>Google 全量开放 Gmail 用户名修改：终于可以告别 8 岁注册的黑历史邮箱了</title>
    <link href="https://ooo.run/post/google-finally-lets-you-change-gmail-address.html"/>
    <id>https://ooo.run/post/google-finally-lets-you-change-gmail-address.html</id>
    <published>2026-06-25T03:30:04.000Z</published>
    <updated>2026-06-25T10:25:30.513Z</updated>
    
    <content type="html"><![CDATA[<p>一个著名的互联网梗图，8 岁的用户坐在电脑前，注册伴随一生的账户邮箱。</p><p>8 岁的我们还不知道什么叫 <strong>数字身份</strong> ，也不知道这个邮箱未来会被用来注册 GitHub、绑定银行卡、投简历、收验证码、登录一切服务。我们只是单纯地觉得：在邮箱前缀里加上生日、QQ 昵称、喜欢的动漫角色、几串看起来很酷的数字，应该会很帅。</p><p><img src="https://img.nep.me/ooo/change-gmail-meme.webp" alt="change-gmail-meme.png"></p><p>然后二十年过去了。</p><p>你长大了，头像换了，网名换了，手机换了，连审美都换了好几轮，但那个邮箱地址还在。每次需要在正式场合填邮箱时，你都要假装它很合理。</p><p>好消息是：Google 终于开始允许用户修改自己的 Gmail 地址了。</p><h2 id="以前为什么这件事这么痛苦？"><a href="#以前为什么这件事这么痛苦？" class="headerlink" title="以前为什么这件事这么痛苦？"></a>以前为什么这件事这么痛苦？</h2><p>过去，如果你注册的是 Gmail 地址，基本就意味着这个地址会跟着你的 Google 账号走很久。</p><p>你可以改用户名，可以改头像，可以改辅助邮箱，可以改各种个人资料，但邮箱地址本身通常很难改。对于很多人来说，想换一个更正式、更好记、没那么羞耻的 Gmail 地址，最现实的做法往往是：</p><p><strong>重新注册一个 Google 账号。</strong></p><p>但问题也随之而来。</p><p>旧账号里可能有 Gmail 邮件、Google Drive 文件、Google Photos 照片、YouTube 数据、Google Play 记录、各种第三方网站登录记录。重新注册一个账号并不只是换一个邮箱，而是几乎等于重新整理一遍自己的互联网生活。</p><p>所以很多人最后都选择了忍。</p><p>忍受那个 8 岁时注册的邮箱继续出现在简历、合同、项目后台和登录页面里。</p><h2 id="如何更改"><a href="#如何更改" class="headerlink" title="如何更改"></a>如何更改</h2><p>根据 Google 的说明，用户现在可以将原本以 @gmail.com 结尾的 Google 账号邮箱，修改为另一个新的 @gmail.com 地址。</p><p>在 Gmail 页面，点击右上角的头像，再点击 <strong>管理您的Google 账号</strong>，打开 Google 账号设置页面，点击左侧的个人信息，在右侧的邮箱部分可以进行修改。</p><p><img src="https://img.nep.me/blog/change-gmail.webp" alt="change-gmail.png"></p><p><img src="https://img.nep.me/blog/change-gmail-2.webp" alt="change-gmail-2.png"></p><h2 id="原来的邮箱将如何处理"><a href="#原来的邮箱将如何处理" class="headerlink" title="原来的邮箱将如何处理"></a>原来的邮箱将如何处理</h2><p>修改后，<mark>原来的 Gmail 地址不会直接消失，而是会变成账号的备用邮箱。你仍然可以收到发往旧地址的邮件，账号里的数据也不会因为改邮箱而丢失</mark>，包括历史邮件、照片、文件等内容。</p><p>简单理解就是：</p><p>你终于可以换一个新的 Gmail 门牌号，但原来的门牌号仍然能帮你收信。</p><p>这对老用户来说非常重要。因为它不是让你抛弃旧账号、重新开始，而是在保留账号资产的前提下，给你一次重新命名自己的机会。</p><h2 id="有一些网站遇到了问题"><a href="#有一些网站遇到了问题" class="headerlink" title="有一些网站遇到了问题"></a>有一些网站遇到了问题</h2><p>虽然这件事听起来很爽，但我并不建议大家看到入口后马上冲进去改。</p><p>由于老的邮箱还可以正常接收邮件，所以对于在其他网站上使用该邮箱注册的账户，其实可以不做调整，继续使用。</p><p>这次 Gmail 地址可修改后，最值得注意的问题并不是 Google 自己，<strong>而是第三方网站的一键登录</strong>。目前的反馈显示，在修改邮箱后，再次使用 Google 账号一键登录 V2EX、Spotify 等网站时，会直接创建新的账户。</p><p>理论上，使用 Google 账号登录时，Google 会返回一组用户信息。其中适合用来识别账号身份的，应该是 Google 账号的 <code>Provider ID</code>，也就是这个 Google 用户在 Google 身份系统里的唯一标识。</p><p><strong>Email 只是邮箱地址。</strong></p><p>但现实里，有些网站开发者为了方便，可能直接把 Email 当成用户的唯一 ID 来用。这样做在邮箱永远不能改的时代，看起来似乎问题不大；但一旦邮箱可以修改，问题就会暴露出来。</p><p>举个例子：</p><p>你原来用 <code>oldname@gmail.com</code> 通过 Google 登录了某个网站。<br>后来你把 Gmail 地址改成了 <code>newname@gmail.com</code>。<br>如果这个网站使用 Google 返回的 <code>Provider ID</code> 来识别你，那么你下次登录时，它依然知道你是原来的那个账号。</p><p>但如果这个网站偷懒，直接用 Email 来识别用户，那么它可能会认为：</p><p><mark>“这是一个新邮箱，所以这是一个新用户。”</mark></p><p>结果就是，你明明用的是同一个 Google 账号，却可能登录进一个全新的空账号，甚至出现账号丢失、数据无法关联、订阅状态异常等问题。</p><p>更糟糕的情况是，如果某些系统对旧邮箱释放、复用、绑定逻辑处理不当，还可能引出更复杂的安全问题。</p><p>目前已知会遇到此类问题的知名网站包括 <strong>V2EX</strong>、<strong>Spotify</strong> 等。</p><h3 id="检查列表，确认修改范围"><a href="#检查列表，确认修改范围" class="headerlink" title="检查列表，确认修改范围"></a>检查列表，确认修改范围</h3><p>如果希望修改其他网站的绑定邮箱，在修改前，建议至少检查这几类地方，确认使用的是邮箱注册还是一键登陆的方式关联的账户：</p><ul><li><strong>1. 常用的第三方登录服务：</strong><br>比如 GitHub、Notion、Figma、Cloudflare、Vercel、各类论坛、博客后台、开发者平台等。</li><li><strong>2. 金融、支付和账单类服务：</strong><br>比如银行通知、订阅服务、云服务账单、域名注册商、服务器厂商等。</li><li><strong>3. 重要的账号恢复渠道：</strong><br>有些网站会把邮箱当作找回密码、验证身份、接收安全通知的核心渠道。</li><li><strong>4.工作和公开资料：</strong><br>比如简历、个人网站、名片、Git 提交信息、项目 README、博客 About 页面等。</li></ul><p>虽然 Google 会让旧邮箱继续收信，但第三方网站是否能正确识别 “这是同一个人” ，就不一定了。</p><h2 id="给普通用户的建议"><a href="#给普通用户的建议" class="headerlink" title="给普通用户的建议"></a>给普通用户的建议</h2><p>如果你准备修改 Gmail 地址，可以先整理一下自己最常用、最重要的网站，确认自己在哪些网站使用了 <strong>通过 Google 登录</strong> 的服务。修改邮箱后，优先测试这些服务是否还能正常登录，账号数据是否还在。</p><p>对于特别重要的服务，最好提前确认它们是否支持修改登录邮箱，或者是否能绑定备用登录方式，比如 <strong>密码、通行密钥、备用邮箱、手机号</strong> 等。</p><p>如果修改后遇到某个网站把你识别成新用户，可以尝试联系客服或开发者，说明你使用的是同一个 Google 账号，只是 Gmail 地址发生了变化。</p><h2 id="给开发者的建议"><a href="#给开发者的建议" class="headerlink" title="给开发者的建议"></a>给开发者的建议</h2><p>如果你的网站支持 Google 一键登录，请不要用 Email 作为用户的唯一身份标识。</p><p>应该使用 Google OAuth &#x2F; OpenID Connect 返回的稳定用户 ID 来绑定用户账号，而不是把 Email 当作主键。</p><p>Email 可以作为展示信息、联系信息、通知地址，但不应该作为第三方登录账号的唯一身份依据。</p><p>正确的做法应该是：</p><ul><li>使用 <code>Provider ID</code> 识别用户身份</li><li>Email 只作为 <strong>可变属性</strong> 保存</li><li>当用户邮箱变化时，更新邮箱字段，而不是创建新账号</li><li>对历史账号绑定逻辑做好兼容</li><li>对邮箱变更、账号合并、登录异常提供清晰提示</li></ul><p>以前很多开发者把 Email 当唯一 ID，是因为邮箱看起来不会变。但现在这个前提正在消失。</p><h2 id="使用密码管理器"><a href="#使用密码管理器" class="headerlink" title="使用密码管理器"></a>使用密码管理器</h2><p>很多人早年注册账号时，不只是邮箱随便起，密码也可能是同一套：一个常用密码，加上网站名、生日、几个符号，稍微变形一下就到处复用。以前看起来很省事，但只要其中一个网站泄露，其他账号就可能一起遭殃。</p><p>所以如果你还没有使用密码管理器，现在就是一个很好的整理节点。</p><p>密码管理器的核心价值不是“帮你记密码”这么简单，而是：</p><ul><li>每个网站都使用 <strong>独立随机密码</strong></li><li>不需要自己记 <strong>几十上百个</strong> 密码</li><li>可以 <strong>自动填充</strong> ，减少输错和钓鱼风险</li><li>可以 <strong>统一检查弱密码、重复密码和泄露密码</strong></li><li>可以更方便地保存恢复码、密钥、银行卡、服务器信息等敏感内容</li></ul><p>比较常见的选择包括 1Password、Bitwarden、KeePassXC、iCloud 钥匙串等。</p><p>如果只是普通用户，并且主要使用 Apple 设备，iCloud 钥匙串已经够用；如果希望跨平台体验更完整，可以考虑 1Password 或 Bitwarden；如果更在意开源、自托管和数据掌控权，我会更推荐 Bitwarden。</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>查看： <a href="https://ooo.run/post/use-docker-run-bitwarden.html">使用 Docker 轻松部署 Bitwarden 服务端，搭建你自己的密码管理器</a></p></div></div><p>如果你只是普通用户，不想维护服务器，直接使用 1Password 或是 Bitwarden 官方服务就很好，Bitwarden 的价格较为友好，Premium 年费仅需 <strong>$19.80</strong> 美元。<br>如果你有自己的服务器、NAS、Homelab，或者已经在使用 Docker 部署服务，那么自部署 Bitwarden 很值得尝试。</p><p>无论选择哪一种，最重要的是这几件事：</p><ul><li>主密码一定要足够长，最好使用一句只有你知道的 passphrase</li><li>开启两步验证，优先使用 <strong>Passkey、硬件安全密钥或 TOTP</strong></li><li><strong>定期导出加密备份</strong>，并确认自己真的能恢复</li><li>不要把密码库、备份文件和二次验证全部放在同一个地方</li><li>修改 Gmail 地址前，先把重要网站的登录方式和恢复方式整理清楚</li></ul><p>邮箱地址可以改，密码也可以重置，但如果你的密码库和二次验证一起丢了，那才是真的麻烦。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>Google 开放 Gmail 地址修改，对很多老用户来说是一件非常值得高兴的事。</p><p>它给了我们一次和童年黑历史和解的机会，也让那些早年随手注册的邮箱终于有机会变得更正式、更好记、更适合长期使用。</p><p>开始修改之前要先检查重要账号，尤其是第三方一键登录，减少遇到问题的情况。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;一个著名的互联网梗图，8 岁的用户坐在电脑前，注册伴随一生的账户邮箱。&lt;/p&gt;
&lt;p&gt;8 岁的我们还不知道什么叫 &lt;strong&gt;数字身份&lt;/strong&gt; ，也不知道这个邮箱未来会被用来注册 GitHub、绑定银行卡、投简历、收验证码、登录一切服务。我们只是单纯地觉得：在</summary>
      
    
    
    
    <category term="咨询" scheme="https://ooo.run/categories/%E5%92%A8%E8%AF%A2/"/>
    
    
    <category term="Google" scheme="https://ooo.run/tags/Google/"/>
    
    <category term="Gmail" scheme="https://ooo.run/tags/Gmail/"/>
    
  </entry>
  
  <entry>
    <title>使用 Docker 部署 Fizzy ： 一个轻量、漂亮、可自托管的看板工具</title>
    <link href="https://ooo.run/post/docker-run-fizzy-kanban.html"/>
    <id>https://ooo.run/post/docker-run-fizzy-kanban.html</id>
    <published>2026-06-23T09:00:00.000Z</published>
    <updated>2026-06-29T20:26:07.459Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Fizzy-介绍"><a href="#Fizzy-介绍" class="headerlink" title="Fizzy 介绍"></a>Fizzy 介绍</h2><p>Fizzy (<a href="https://fizzy.do/">https://fizzy.do</a>) 是由著名软件公司 <mark>37signals</mark>（开发过 Basecamp 和 HEY 的团队）推出的一款全新 <strong>看板</strong> 任务管理工具。主打快速、简单、色彩鲜明，非常适合用来跟踪 Bug、想法、小项目和内容流程。</p><p>与 Jira、ClickUp、Asana 堆叠型项目管理工具不同，Fizzy 使用的是 <strong>卡片 + 列</strong> 的 UI 界面，使用只需要创建看板、添加卡片、移动状态、分配任务、接收通知，适合小型、轻量、边界清晰的工作流。</p><p>Fizzy 界面预览：</p><p><img src="https://img.nep.me/ooo/fizzy-board.webp" alt="Fizzy 界面预览"></p><h2 id="Fizzy-的优势"><a href="#Fizzy-的优势" class="headerlink" title="Fizzy 的优势"></a>Fizzy 的优势</h2><ul><li><strong>极简与速度：</strong> 没有复杂的菜单层级、AI 总结或多余的分析图表。界面色彩丰富且直观，专注于卡片和列的 Kanban 体验。</li><li><strong>人性化默认设置：</strong> 它支持自动关闭长期无人处理的卡片、Webhook、浏览器通知、公开看板链接、卡片记录等功能。保持看板的清爽，非常符合人类工作习惯。</li><li><strong>支持自托管：</strong> Fizzy 的 <a href="https://github.com/basecamp/fizzy">代码</a> 完全开源，支持自己部署，官方提供预构建 <a href="https://ghcr.io/basecamp/fizzy:main">Docker 镜像</a>，适合 Selfhost 爱好者自己部署使用。</li><li><strong>实惠的价格：</strong> 如果你不想自己部署，使用官方服务前 1000 张卡片免费；超出后的付费方案为 每月 20 美元买断式（包含无限用户、无限卡片），没有令人头疼的按人头计费阶梯。</li></ul><h2 id="使用-Docker-部署"><a href="#使用-Docker-部署" class="headerlink" title="使用 Docker 部署"></a>使用 Docker 部署</h2><p>下面将介绍使用 Docker 部署 Fizzy 应用，使用 Caddy &#x2F; Nginx 反代进行访问的方式。</p><h3 id="验证-Docker-环境"><a href="#验证-Docker-环境" class="headerlink" title="验证 Docker 环境"></a>验证 Docker 环境</h3><p>Docker 环境验证命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker --version</span><br><span class="line">docker compose version</span><br></pre></td></tr></table></figure><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>没有安装可以查看： <a href="https://ooo.run/post/debian-13-install-docker.html">2026 Debian 13 安装 Docker 以及 Docker Compose 教程</a></p></div></div><h3 id="创建-docker-compose-yaml-文件"><a href="#创建-docker-compose-yaml-文件" class="headerlink" title="创建 docker-compose.yaml 文件"></a>创建 docker-compose.yaml 文件</h3><p>本文选择将容器部署在 <code>/opt/fizzy</code> 目录下，数据目录保存在相同的目录中，便于 <mark>一键打包备份</mark> 。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建容器目录</span></span><br><span class="line">sudo mkdir -p /opt/fizzy</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">进入容器目录</span></span><br><span class="line">cd /opt/fizzy</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建数据目录</span></span><br><span class="line">sudo mkdir storage</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">调整数据目录权限</span></span><br><span class="line">sudo chown 1000:1000 storage</span><br></pre></td></tr></table></figure><p>然后创建 <code>compose.yaml</code> 文件: </p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">fizzy:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">ghcr.io/basecamp/fizzy:main</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">fizzy</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;127.0.0.1:3080:80&quot;</span></span><br><span class="line">      <span class="comment"># - &quot;443:443&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="comment"># 必填：Rails secret</span></span><br><span class="line">      <span class="attr">SECRET_KEY_BASE:</span> <span class="string">&quot;&lt;SECRET_KEY_BASE&gt;&quot;</span></span><br><span class="line">      <span class="comment"># 访问域名</span></span><br><span class="line">      <span class="attr">BASE_URL:</span> <span class="string">&quot;https://fizzy.example.com&quot;</span></span><br><span class="line"></span><br><span class="line">      <span class="comment"># SMTP（用于 magic link 登录邮件）</span></span><br><span class="line">      <span class="comment"># SMTP_ADDRESS: &quot;mail.example.com&quot;</span></span><br><span class="line">      <span class="comment"># SMTP_USERNAME: &quot;user&quot;</span></span><br><span class="line">      <span class="comment"># SMTP_PASSWORD: &quot;pass&quot;</span></span><br><span class="line">      <span class="comment"># MAILER_FROM_ADDRESS: &quot;Fizzy &lt;fizzy@example.com&gt;&quot;</span></span><br><span class="line"></span><br><span class="line">      <span class="comment"># 可选：Web Push（如果你想要浏览器推送通知）</span></span><br><span class="line">      <span class="comment"># VAPID_PUBLIC_KEY: &quot;...&quot;</span></span><br><span class="line">      <span class="comment"># VAPID_PRIVATE_KEY: &quot;...&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./storage:/rails/storage</span></span><br></pre></td></tr></table></figure><p>需要设置的部分：</p><ul><li><code>SECRET_KEY_BASE:</code> 使用 <code>openssl rand -hex 32</code> 命令生成，或是通过 <a href="https://tools.ooo.run/zh/session-secret/">简易工具 - Session Secret</a> 网页生成</li><li><code>BASE_URL:</code> 设置访问时的域名，Fizzy 注重安全设计，需要使用 <strong>https</strong> 访问</li></ul><div class="flatpaper-note flatpaper-note--default"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>Fizzy 通过邮件发送 <mark>验证码</mark> 的方式进行登陆，如果希望发送邮件需要设置 SMTP 部分，但不是必须的，如果不设置 SMTP 可以使用后文随附 <code>docker</code> 命令查询。</p></div></div><h3 id="启动-Docker-镜像"><a href="#启动-Docker-镜像" class="headerlink" title="启动 Docker 镜像"></a>启动 Docker 镜像</h3><p>只需一行 Docker Compose 命令即可后台常驻启动</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure><h2 id="访问-Fizzy"><a href="#访问-Fizzy" class="headerlink" title="访问 Fizzy"></a>访问 Fizzy</h2><p>首先我们设置 web 服务器的代理指向 <code>3080</code></p><h3 id="Nginx-反向代理配置"><a href="#Nginx-反向代理配置" class="headerlink" title="Nginx 反向代理配置"></a>Nginx 反向代理配置</h3><p>如果使用 Nginx 作为反向代理，可以创建一个新的站点配置，例如：</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line">    <span class="attribute">server_name</span> fizzy.example.com;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 将 HTTP 自动跳转到 HTTPS</span></span><br><span class="line">    <span class="attribute">return</span> <span class="number">301</span> https://<span class="variable">$host</span><span class="variable">$request_uri</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">443</span> ssl http2;</span><br><span class="line">    <span class="attribute">server_name</span> fizzy.example.com;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">ssl_certificate</span> /etc/nginx/ssl/fizzy.example.com/fullchain.pem;</span><br><span class="line">    <span class="attribute">ssl_certificate_key</span> /etc/nginx/ssl/fizzy.example.com/privkey.pem;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">client_max_body_size</span> <span class="number">50M</span>;</span><br><span class="line"></span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://127.0.0.1:3080;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Proto https;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># WebSocket 支持</span></span><br><span class="line">        <span class="attribute">proxy_set_header</span> Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Connection <span class="string">&quot;upgrade&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果你使用的是 Certbot 申请证书，也可以先配置 HTTP 站点，再执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> certbot --nginx -d fizzy.example.com</span><br></pre></td></tr></table></figure><p>证书配置完成后，访问 <code>https://fizzy.example.com</code> 即可打开 Fizzy。</p><h3 id="Caddy-反向代理配置"><a href="#Caddy-反向代理配置" class="headerlink" title="Caddy 反向代理配置"></a>Caddy 反向代理配置</h3><p>如果使用 Caddy，配置会更加简单。编辑 Caddyfile：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">fizzy.example.com &#123;</span><br><span class="line">    reverse_proxy 127.0.0.1:3080</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Caddy 会自动申请和续期 HTTPS 证书，只需要确保域名已经正确解析到服务器，并且服务器的 <code>80</code> 和 <code>443</code> 端口已经放行。</p><p>修改完成后，重新加载 Caddy：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl reload caddy</span><br></pre></td></tr></table></figure><p>然后访问：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://fizzy.example.com</span><br></pre></td></tr></table></figure><p>即可进入 Fizzy 登录页面。</p><h3 id="注册登录"><a href="#注册登录" class="headerlink" title="注册登录"></a>注册登录</h3><p>然后打开浏览器即可 BASE_URL 的域名即可打开登录页面</p><p><img src="https://img.nep.me/ooo/fizzy-login.webp" alt="fizzy-login.png"></p><p>Fizzy 只能通过邮箱接收验证码进行登陆，如果你设置了正确的 SMTP，在邮箱查看验证码即可。</p><h3 id="使用-Docker-命令获取验证码"><a href="#使用-Docker-命令获取验证码" class="headerlink" title="使用 Docker 命令获取验证码"></a>使用 Docker 命令获取验证码</h3><p>如果觉得只是个人使用，不想设置 SMTP，可以通过下面的命令手动查询最后生成的验证码：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker compose <span class="built_in">exec</span> fizzy bin/rails runner <span class="string">&#x27;p MagicLink.column_names; p MagicLink.last&amp;.attributes&#x27;</span></span><br></pre></td></tr></table></figure><p>输出内容</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span><span class="string">&quot;id&quot;</span> =&gt; <span class="string">&quot;abcdefg.....&quot;</span><span class="punctuation">,</span> <span class="string">&quot;code&quot;</span> =&gt; <span class="string">&quot;ABCEFG&quot;</span><span class="punctuation">,</span></span><br></pre></td></tr></table></figure><p>使用 code 后面的六个字符登陆即可。</p><h3 id="添加-Passkey"><a href="#添加-Passkey" class="headerlink" title="添加 Passkey"></a>添加 Passkey</h3><p>然而总不能每次登陆都打开服务器查询， Fizzy 支持添加 Passkey 。 </p><p>点击顶部或是按 <code>J</code> 打开设置面板，然后点击 <code>My Profile</code>，左下角有 <code>Manage passkey</code> 的按钮，点击即可添加 Passkey。 之后就可以快捷方便的登录了。</p><img src="https://img.nep.me/ooo/fizzy-add-passkey.webp" alt="fizzy-add-passkey.png" style="width:75%;max-width:100%;height:auto" /><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>推荐： <a href="https://ooo.run/post/use-docker-run-bitwarden.html">使用 Docker 轻松部署 Bitwarden 服务端，搭建你自己的密码管理器</a></p></div></div><h2 id="使用介绍"><a href="#使用介绍" class="headerlink" title="使用介绍"></a>使用介绍</h2><p>输入验证码登陆后，即可进入 Fizzy 的 Playground 主面板，目前 Fizzy 仅支持英文界面。</p><p><img src="https://img.nep.me/ooo/fizzy-playgroud.webp" alt="fizzy-playgroud.png"></p><p>在 Fizzy 中，每一列是一个看板，可以用于表示任务的状态或是属性，自带的卡片会介绍 Fizzy 的使用方法。简</p><p>单的来说，对于默认三个看板：</p><ul><li><strong>NotNow:</strong> 现在不需要处理的任务，超过 30 天没有更新卡片将自动移动到这里</li><li><strong>MAYBE?:</strong> 可能需要处理的任务</li><li><strong>DONE:</strong> 已完成的任务<br>可以点击 <code>DONE</code> 右侧的 <code>+</code> 可以根据需要创建自定义看板</li></ul><p>现在就开始规划整理你的任务吧！</p><h2 id="安全提示"><a href="#安全提示" class="headerlink" title="安全提示"></a>安全提示</h2><p>::: danger<br>如果将 Fizzy 部署在云端服务器中， Docker 容器端口不要使用 <code>&quot;3080:80&quot;</code> 直接监听公网，建议使用 <code>&quot;127.0.0.1:3080:80&quot;</code>，再通过 Nginx 或 Caddy 反向代理提供 HTTPS 访问。<br>&#96;&#96;&#96;</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Fizzy-介绍&quot;&gt;&lt;a href=&quot;#Fizzy-介绍&quot; class=&quot;headerlink&quot; title=&quot;Fizzy 介绍&quot;&gt;&lt;/a&gt;Fizzy 介绍&lt;/h2&gt;&lt;p&gt;Fizzy (&lt;a href=&quot;https://fizzy.do/&quot;&gt;https://fiz</summary>
      
    
    
    
    <category term="教程" scheme="https://ooo.run/categories/%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="Docker" scheme="https://ooo.run/tags/Docker/"/>
    
    <category term="Fizzy" scheme="https://ooo.run/tags/Fizzy/"/>
    
  </entry>
  
  <entry>
    <title>Codex 的日志记录消耗 SSD 寿命？OpenAI 已修复</title>
    <link href="https://ooo.run/post/codex-is-buring-your-ssd.html"/>
    <id>https://ooo.run/post/codex-is-buring-your-ssd.html</id>
    <published>2026-06-22T18:00:00.000Z</published>
    <updated>2026-06-29T13:27:36.481Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Bug-信息"><a href="#Bug-信息" class="headerlink" title="Bug 信息"></a>Bug 信息</h2><div class="flatpaper-note flatpaper-note--primary"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>好消息，OpenAI 已在 Codex 0.142.0 版本中修复了这个问题，可以放心使用。</p></div></div><p>最近，Codex 凭借其强大的功能和丝滑的体验，周活跃用户已经突破了 <strong>500 万</strong> 大关。越来越多的开发者和极客都已经把它当成了日常高频使用的得力助手。</p><p>不过，随着使用人数的增加，有用户反馈，在某些流式输出或自动化任务场景下，Codex 会持续向本地磁盘写入 TRACE 级别的日志。</p><p>GitHUb 的 <a href="https://github.com/openai/codex/issues/28224">ISSUE</a> 上声称该 BUG 可能会产生 <strong>640GB&#x2F;年</strong> 的写入，这对于消费级 SSD 来说是致命的。对于目前主流的 1TB 或 2TB 消费级固态硬盘（标称寿命通常在 600TBW ~ 1200TBW）来说，可以说是非常严重。</p><p><strong>而且，正因为现在 AI 浪潮空前火热，全球对高带宽、高性能存储的需求集中爆发，导致现在的 SSD 固态硬盘价格一路上涨，存储成本变得相当昂贵，尤其是 mac 设备的硬盘无法更换。在这种寸土寸金的时期，我们对硬盘的每一度磨损、每一 G 空间都不得不更加精打细算。</strong></p><hr><h2 id="1分钟自查：你中招了吗？"><a href="#1分钟自查：你中招了吗？" class="headerlink" title="1分钟自查：你中招了吗？"></a>1分钟自查：你中招了吗？</h2><p>如果你使用的是 Linux 或 Mac 系统，可以直接通过终端跑两行命令看看情况。</p><p>首先，看看日志文件的大小：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> -lh ~/.codex/logs_2.sqlite</span><br></pre></td></tr></table></figure><p>然后，统计一下日志的写入级别：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sqlite3 ~/.codex/logs_2.sqlite <span class="string">&quot;SELECT level, COUNT(*) FROM logs GROUP BY level ORDER BY COUNT(*) DESC&quot;</span></span><br></pre></td></tr></table></figure><p><strong>如何判断：</strong><br>如果查询结果中，<code>TRACE</code> 级别的日志占了绝大多数，并且 <code>logs_2.sqlite</code> 文件体积比较大，那就说明 Codex 确实在后台认真地记录着无关紧要的追踪信息。</p><p><strong>参考数据：</strong><br>我的文件大小为 <strong>468MB：</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt; <span class="built_in">ls</span> -lh ~/.codex/logs_2.sqlite Jun 23</span><br><span class="line">-rw-r--r--@ 1 mro  staff   468M</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&gt; sqlite3 ~/.codex/logs_2.sqlite <span class="string">&quot;SELECT level, COUNT(*) FROM logs GROUP BY level ORDER BY COUNT(*) DESC&quot;</span></span><br><span class="line">TRACE|39961</span><br><span class="line">INFO|39919</span><br><span class="line">DEBUG|7307</span><br><span class="line">WARN|177</span><br></pre></td></tr></table></figure><p>可以看到 <code>TRACE|39961</code> 占了接近一半的数据，确实存在所说的问题，主要是目前 OpenAI 官方尚未做出修复的回应。</p><h2 id="一劳永逸的解决方案-：直接在数据库拦截"><a href="#一劳永逸的解决方案-：直接在数据库拦截" class="headerlink" title="一劳永逸的解决方案 ：直接在数据库拦截"></a>一劳永逸的解决方案 ：直接在数据库拦截</h2><p><mark>OpenAI 已经修复这个问题了，不需要操作了</mark></p><p>这里提供比较激进、但也最直接的临时方案：给日志表加一个 SQLite 触发器，让新的日志写入被忽略，毕竟这个文件里只有诊断日志，没有对话历史。</p><p>执行前建议先退出 Codex，并备份日志数据库：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> ~/.codex/logs_2.sqlite ~/.codex/logs_2.sqlite.bak</span><br></pre></td></tr></table></figure><p>然后执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sqlite3 ~/.codex/logs_2.sqlite <span class="string">&quot;CREATE TRIGGER IF NOT EXISTS block_log_inserts BEFORE INSERT ON logs BEGIN SELECT RAISE(IGNORE); END;&quot;</span></span><br></pre></td></tr></table></figure><p>设置完成后，新的日志记录会被拦截，从而减少后续写入。</p><p>需要注意的是，这个方法会影响 Codex 后续生成诊断日志。如果你之后需要向官方反馈问题，或者担心未来版本兼容性，可以先不要使用这个方案，改用定期清理的方式。</p><details class="flatpaper-note flatpaper-note--info"><summary class="flatpaper-note__title"><span class="flatpaper-note__icon" aria-hidden="true"></span><span class="flatpaper-note__label">如何恢复</span><span class="flatpaper-note__chevron" aria-hidden="true"></span></summary><div class="flatpaper-note__body"><p>如果想要恢复的话就是删除这个 trigger 。先退出 Codex，再执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sqlite3 ~/.codex/logs_2.sqlite <span class="string">&quot;DROP TRIGGER IF EXISTS block_log_inserts;&quot;</span></span><br></pre></td></tr></table></figure><p>执行后可以检查是否还存在：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sqlite3 ~/.codex/logs_2.sqlite <span class="string">&quot;.schema block_log_inserts&quot;</span></span><br></pre></td></tr></table></figure><p>如果没有输出，说明已经删除成功。</p><p>也可以用这个命令查看当前所有 trigger：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sqlite3 ~/.codex/logs_2.sqlite <span class="string">&quot;SELECT name, tbl_name, sql FROM sqlite_master WHERE type=&#x27;trigger&#x27;;&quot;</span></span><br></pre></td></tr></table></figure></div></details><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>GitHub ISSUE 中的数据是比较夸张的，Codex 的这个日志问题并没有网传的那么吓人，但也感谢 OpenAI 完成了 BUG 的修复，祝大家用 Codex 敲代码愉快！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Bug-信息&quot;&gt;&lt;a href=&quot;#Bug-信息&quot; class=&quot;headerlink&quot; title=&quot;Bug 信息&quot;&gt;&lt;/a&gt;Bug 信息&lt;/h2&gt;&lt;div class=&quot;flatpaper-note flatpaper-note--primary&quot;&gt;&lt;span</summary>
      
    
    
    
    <category term="笔记" scheme="https://ooo.run/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="OpenAI" scheme="https://ooo.run/tags/OpenAI/"/>
    
    <category term="Codex" scheme="https://ooo.run/tags/Codex/"/>
    
  </entry>
  
  <entry>
    <title>榨干 AI 订阅额度：使用 Claude Pro 与 ChatGPT 订阅到底能省多少钱？</title>
    <link href="https://ooo.run/post/how-much-can-you-save-with-subscription-vs-api.html"/>
    <id>https://ooo.run/post/how-much-can-you-save-with-subscription-vs-api.html</id>
    <published>2026-06-21T11:00:00.000Z</published>
    <updated>2026-06-24T12:00:56.547Z</updated>
    
    <content type="html"><![CDATA[<p>Anthropic（Claude）与 OpenAI（ChatGPT）的 API 按量计费对于高频使用者而言通常“贵出天际”，一般只有企业级用户才能负担。因此，它们推出的按月订阅套餐，才是绝大多数普通用户的性价比首选。</p><p>目前，这两家平台都推出了三档订阅套餐：基础版（20 美元）、5x（100 美元）以及 20x（200美元）版本。不过，为了防止滥用，这些套餐在实际使用中均受到时间窗口（每 5 小时）和每周总使用量的限制。</p><p>你可能很好奇：<strong>如果我们把 20 美元订阅账号的额度彻底“榨干”，到底等价于消耗了多少 API 费用？</strong></p><h2 id="Claude-与-ChatGPT-订阅等同于多少-API-费用"><a href="#Claude-与-ChatGPT-订阅等同于多少-API-费用" class="headerlink" title="Claude 与 ChatGPT 订阅等同于多少 API 费用"></a>Claude 与 ChatGPT 订阅等同于多少 API 费用</h2><h3 id="核心结论"><a href="#核心结论" class="headerlink" title="核心结论"></a>核心结论</h3><p>先说结论：<strong>20 美元的 Claude Pro 每周额度约等于 100 美元的 API 价值，而 ChatGPT Plus 则为 140 美元。</strong></p><h3 id="价格对比图表"><a href="#价格对比图表" class="headerlink" title="价格对比图表"></a>价格对比图表</h3><p>近期在 X（原 Twitter）上广为流传的一份图表数据，直观地展示了 Anthropic 与 OpenAI 的订阅套餐与 API 按量计费之间的巨大价格差异：</p><p><img src="https://img.nep.me/ooo/ai-sub-vs-api.webp" alt="price"></p><p>Claude 订阅与 API 价值对比表：</p><table><thead><tr><th align="left">订阅类型</th><th align="center">每月订阅费</th><th align="right">等价 API 费用</th></tr></thead><tbody><tr><td align="left">claude-pro</td><td align="center">$20</td><td align="right"><strong>$400 &#x2F; 月</strong></td></tr><tr><td align="left">claude-max-5x</td><td align="center">$100</td><td align="right"><strong>$2,000 &#x2F; 月</strong></td></tr><tr><td align="left">claude-max-20x</td><td align="center">$200</td><td align="right"><strong>$8,000 &#x2F; 月</strong></td></tr></tbody></table><h3 id="ChatGPT-Codex-订阅与-API-价值对比表"><a href="#ChatGPT-Codex-订阅与-API-价值对比表" class="headerlink" title="ChatGPT &#x2F; Codex 订阅与 API 价值对比表"></a>ChatGPT &#x2F; Codex 订阅与 API 价值对比表</h3><table><thead><tr><th align="left">订阅类型</th><th align="center">每月订阅费</th><th align="right">等价 API 费用</th></tr></thead><tbody><tr><td align="left">chatgpt-pro-5x</td><td align="center">$20</td><td align="right">$700 &#x2F; 月</td></tr><tr><td align="left">chatgpt-pro-5x</td><td align="center">$100</td><td align="right">$3,500 &#x2F; 月</td></tr><tr><td align="left">chatgpt-pro-20x</td><td align="center">$200</td><td align="right">$14,000 &#x2F; 月</td></tr></tbody></table><h3 id="理论数据-vs-实测数据"><a href="#理论数据-vs-实测数据" class="headerlink" title="理论数据 vs 实测数据"></a>理论数据 vs 实测数据</h3><p>图表中的理论数据虽然惊人，这里的 API 等价价值，是指按官方 API 单价估算，在订阅账号达到实际使用上限时，等价消耗的推理成本，并不代表平台实际成本或用户可稳定复现的收益。</p><p>根据 Linux.do 社区用户的 实际测试 统计，ChatGPT Plus 20 美元套餐 <strong>每周消耗的额度约为 $140，换算下来每月约 $560</strong> 。图表中之所以给出了更夸张的 $700 理论值，很大程度上是因为部分 Plus 账号有概率被官方分配到更高的额度。</p><p>相比之下，Claude 的数据则得到了多方印证。根据大量个人开发者以及 API 中转站的真实反馈，高阶的 $200 套餐确实能够扎扎实实地跑出约 $7,000 的 API 等价价值。</p><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p><strong>注：</strong> Anthropic 在与 xAI 合作后，将 Claude 的周额度临时上调 50%，持续到 7 月 13 日。</p></div></div><hr><h2 id="额外探讨：ChatGPT-Teams-值得买吗？"><a href="#额外探讨：ChatGPT-Teams-值得买吗？" class="headerlink" title="额外探讨：ChatGPT Teams 值得买吗？"></a>额外探讨：ChatGPT Teams 值得买吗？</h2><p>OpenAI 除了面向个人用户的 ChatGPT Plus，还有面向团队的 ChatGPT Teams 版本。近期 ChatGPT Teams 也在持续推出 <strong>买一送一</strong> 活动：即两个 Teams 席位的团队只需支付一个席位的费用，折算下来总花费与单人购买 Plus 几乎持平，甚至根据不同地区的汇率结算最终费用可能还要低于 20 美元。</p><p>在额度方面，官方宣称 Teams 账号的对话额度与 Plus 相同，但从用户实测来看，存在一些 <strong>潜规则</strong> ：</p><ol><li><strong>日常额度略有缩水：</strong> 一般正常的 Team 账号，每周等价 API 额度约为 <strong>105 美元</strong>（低于满血 Plus 的 140 美元&#x2F;周）。不过，如果参与了买一送一活动，两个账号加起来的总体可用量依然是多于单个 Plus 的。  </li><li><strong>5H 窗口额度不如 Plus：</strong> 根据 Linux.do 用户反馈，Teams 的周总额度目前存在一定争议；但从单个 5 小时窗口来看，Plus 的可用额度通常高于 Teams。社区实测中，Teams 单个 5H 窗口的等价 API 消耗约为 16 美元。</li><li><strong>警惕“残血版”风控：</strong>  部分 Team 账号由于触发了风控机制，会被降级为 <strong>残血版</strong> 。这类账号的周限制（Codex）大约只相当于 Plus 账号的 0.5 倍。相比之下，普通的 Plus 账号在额度上反而更加稳定。<br>与 Plus 对比，Teams 自身的优势是可以在网页版使用 GPT 5.5 Pro 模型，按月提供少量的访问次数，且数据默认 <a href="https://chatgpt.com/zh-Hans-CN/pricing/?type=team">不会用于</a> 模型训练。</li></ol><div class="flatpaper-note flatpaper-note--info"><span class="flatpaper-note__icon" aria-hidden="true"></span><div class="flatpaper-note__body"><p>我自己购买的是 Teams 1+1，一个账户的 5H 额度余额为 16-18 美元，一轮 5H 占周额度的 16% ，所以周额度约为 100-110 美元。</p></div></div><h3 id="总结："><a href="#总结：" class="headerlink" title="总结："></a>总结：</h3><p>如果一个高频用户能持续用满订阅额度，20 美元级别的 AI 订阅套餐，通常可以获得数百美元 API 调用价值。Claude Pro 的月度等价 API 价值大约在 400 美元量级，而 ChatGPT Plus 在不同账号、模型和风控状态下，可能落在 560–700 美元左右。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Anthropic（Claude）与 OpenAI（ChatGPT）的 API 按量计费对于高频使用者而言通常“贵出天际”，一般只有企业级用户才能负担。因此，它们推出的按月订阅套餐，才是绝大多数普通用户的性价比首选。&lt;/p&gt;
&lt;p&gt;目前，这两家平台都推出了三档订阅套餐：基础</summary>
      
    
    
    
    <category term="笔记" scheme="https://ooo.run/categories/%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Claude" scheme="https://ooo.run/tags/Claude/"/>
    
    <category term="ChatGPT" scheme="https://ooo.run/tags/ChatGPT/"/>
    
  </entry>
  
</feed>
